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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.distribution.reception.handling.sdc;
24 import java.io.FileOutputStream;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.List;
33 import org.onap.policy.common.logging.flexlogger.FlexLogger;
34 import org.onap.policy.common.logging.flexlogger.Logger;
35 import org.onap.policy.common.parameters.ParameterService;
36 import org.onap.policy.distribution.model.CloudArtifact;
37 import org.onap.policy.distribution.model.Csar;
38 import org.onap.policy.distribution.model.GsonUtil;
39 import org.onap.policy.distribution.model.VfModuleModel;
40 import org.onap.policy.distribution.reception.decoding.PolicyDecodingException;
41 import org.onap.policy.distribution.reception.handling.AbstractReceptionHandler;
42 import org.onap.policy.distribution.reception.handling.sdc.SdcClientHandler.SdcClientOperationType;
43 import org.onap.policy.distribution.reception.handling.sdc.exceptions.ArtifactDownloadException;
44 import org.onap.policy.distribution.reception.statistics.DistributionStatisticsManager;
45 import org.onap.sdc.api.IDistributionClient;
46 import org.onap.sdc.api.consumer.IComponentDoneStatusMessage;
47 import org.onap.sdc.api.consumer.IDistributionStatusMessage;
48 import org.onap.sdc.api.consumer.INotificationCallback;
49 import org.onap.sdc.api.notification.IArtifactInfo;
50 import org.onap.sdc.api.notification.INotificationData;
51 import org.onap.sdc.api.notification.IResourceInstance;
52 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
53 import org.onap.sdc.api.results.IDistributionClientResult;
54 import org.onap.sdc.impl.DistributionClientFactory;
55 import org.onap.sdc.utils.DistributionActionResultEnum;
56 import org.onap.sdc.utils.DistributionStatusEnum;
59 * Handles reception of inputs from ONAP Service Design and Creation (SDC) from which policies may be decoded.
61 public class SdcReceptionHandler extends AbstractReceptionHandler implements INotificationCallback {
63 private static final Logger LOGGER = FlexLogger.getLogger(SdcReceptionHandler.class);
64 private static final String SECONDS = "Seconds";
66 private SdcReceptionHandlerStatus sdcReceptionHandlerStatus = SdcReceptionHandlerStatus.STOPPED;
67 private IDistributionClient distributionClient;
68 private SdcConfiguration sdcConfig;
69 private volatile int nbOfNotificationsOngoing = 0;
70 private int retryDelay;
71 private SdcClientHandler sdcClientHandler;
73 private enum DistributionStatusType {
78 protected void initializeReception(final String parameterGroupName) {
79 final SdcReceptionHandlerConfigurationParameterGroup handlerParameters =
80 ParameterService.get(parameterGroupName);
81 retryDelay = handlerParameters.getRetryDelay() < 30 ? 30 : handlerParameters.getRetryDelay();
82 sdcConfig = new SdcConfiguration(handlerParameters);
83 distributionClient = createSdcDistributionClient();
84 sdcClientHandler = new SdcClientHandler(this, SdcClientOperationType.START, retryDelay);
88 public void destroy() {
89 if (distributionClient != null) {
90 sdcClientHandler = new SdcClientHandler(this, SdcClientOperationType.STOP, retryDelay);
95 public void activateCallback(final INotificationData notificationData) {
96 LOGGER.debug("Receieved the notification from SDC with ID: " + notificationData.getDistributionID());
97 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.BUSY);
98 //Process only the resource artifacts in MC
99 for (IResourceInstance resource : notificationData.getResources()) {
100 // We process only VNF resource in MC
101 if ("VF".equals(resource.getResourceType())) {
102 this.processVfModulesArtifacts(notificationData,resource);
105 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
106 LOGGER.debug("Processed the notification from SDC with ID: " + notificationData.getDistributionID());
110 * Method to change the status of this reception handler instance.
112 * @param newStatus the new status
114 private final synchronized void changeSdcReceptionHandlerStatus(final SdcReceptionHandlerStatus newStatus) {
118 sdcReceptionHandlerStatus = newStatus;
121 handleIdleStatusChange(newStatus);
124 ++nbOfNotificationsOngoing;
125 sdcReceptionHandlerStatus = newStatus;
133 * Creates an instance of {@link IDistributionClient} from {@link DistributionClientFactory}.
135 * @return the {@link IDistributionClient} instance
137 protected IDistributionClient createSdcDistributionClient() {
138 return DistributionClientFactory.createDistributionClient();
142 * Method to initialize the SDC client.
145 protected void initializeSdcClient() {
147 LOGGER.debug("Initializing the SDC Client...");
148 if (sdcReceptionHandlerStatus != SdcReceptionHandlerStatus.STOPPED) {
149 LOGGER.error("The SDC Client is already initialized");
152 final IDistributionClientResult clientResult = distributionClient.init(sdcConfig, this);
153 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
154 LOGGER.error("SDC client initialization failed with reason:" + clientResult.getDistributionMessageResult()
155 + ". Initialization will be retried after " + retryDelay + SECONDS);
158 LOGGER.debug("SDC Client is initialized successfully");
159 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.INIT);
163 * Method to start the SDC client.
166 protected void startSdcClient() {
168 LOGGER.debug("Going to start the SDC Client...");
169 if (sdcReceptionHandlerStatus != SdcReceptionHandlerStatus.INIT) {
170 LOGGER.error("The SDC Client is not initialized");
173 final IDistributionClientResult clientResult = distributionClient.start();
174 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
175 LOGGER.error("SDC client start failed with reason:" + clientResult.getDistributionMessageResult()
176 + ". Start will be retried after " + retryDelay + SECONDS);
179 LOGGER.debug("SDC Client is started successfully");
180 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
181 sdcClientHandler.cancel();
185 * Method to stop the SDC client.
188 protected void stopSdcClient() {
189 LOGGER.debug("Going to stop the SDC Client...");
190 final IDistributionClientResult clientResult = distributionClient.stop();
191 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
192 LOGGER.error("SDC client stop failed with reason:" + clientResult.getDistributionMessageResult()
193 + ". Stop will be retried after " + retryDelay + SECONDS);
196 LOGGER.debug("SDC Client is stopped successfully");
197 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.STOPPED);
198 sdcClientHandler.cancel();
202 * Method to process VF MODULES_METADATA artifacts from incoming SDC notification.
204 * @param artifact the item needs to check if it has been stored in DBB or not
206 private boolean checkArtifactAlreadyStored(IArtifactInfo artifact) {
213 * Method to process VF MODULES_METADATA artifacts from incoming SDC notification.
215 * @param notificationData the notification from SDC
216 * @param resource every resource of the service from SDC
218 public void processVfModulesArtifacts(final INotificationData notificationData, IResourceInstance resource) {
219 boolean artifactsProcessedSuccessfully = true;
220 DistributionStatisticsManager.updateTotalDistributionCount();
221 List<String> relevantArtifactTypes = sdcConfig.getRelevantArtifactTypes();
222 Path path = Paths.get("/data");
223 List<VfModuleModel> vfModuleModels = null;
224 Map<String, IArtifactInfo> artifactMap = null;//key is UUID, value is artifact for shared folder
225 String vfArtifactData = null;
227 for (final IArtifactInfo artifact : resource.getArtifacts()) {
228 artifactMap.put(artifact.getArtifactUUID(),artifact);
230 //extract the artifactlist and write them into MongoDB
231 if (artifact.getArtifactType().equals("VF_MODULES_METADATA")) {
233 final IDistributionClientDownloadResult resultArtifact =
234 downloadTheArtifact(artifact,notificationData);
235 vfArtifactData = new String(resultArtifact.getArtifactPayload());
236 vfModuleModels= GsonUtil.parseJsonArrayWithGson(vfArtifactData,VfModuleModel.class);
237 } catch (final ArtifactDownloadException exp) {
238 LOGGER.error("Failed to process csar service artifacts ", exp);
239 artifactsProcessedSuccessfully = false;
240 sendDistributionStatus(DistributionStatusType.DEPLOY, artifact.getArtifactURL(),
241 notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,
242 "Failed to deploy the artifact due to: " + exp.getMessage());
247 //foreach(vf_module_metadata)
248 // 1. create a dir like /data/UUID1
249 // 2. put the vfmodule-meta.json into it
250 // 3. put the service-meta.json into it
251 // 3. go through each aritfact uuid under artifact_list of vf_module and download
252 for (final VfModuleModel vfModule : vfModuleModels) {
255 Path temp = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID());
256 path = Files.createDirectory(temp);//create UUID path
257 //store the value to vfmodule-meta.json
258 String filePath = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID(),"vfmodule-meta.json").toString();
259 writeFileByFileWriter(filePath, vfArtifactData);
260 //store the service level info to serivce-meta.json
261 filePath = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID(),"service-meta.json").toString();
262 writeFileByFileWriter(filePath, notificationData.toString());
263 } catch (final IOException exp) {
264 LOGGER.error("Failed to create directory artifact file", exp);
267 for(final String uuid : vfModule.getArtifacts()) {
269 IArtifactInfo artifact = artifactMap.get(uuid);
270 final IDistributionClientDownloadResult resultArtifact = downloadTheArtifact(artifact, notificationData);
271 writeArtifactToDir(artifact,resultArtifact,path);
272 } catch (final ArtifactDownloadException exp) {
273 LOGGER.error("Failed to process csar service artifacts ", exp);
274 artifactsProcessedSuccessfully = false;
275 sendDistributionStatus(DistributionStatusType.DEPLOY, artifactMap.get(uuid).getArtifactURL(),
276 notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,
277 "Failed to deploy the artifact due to: " + exp.getMessage());
284 final CloudArtifact cloudArtifact = new CloudArtifact(vfModuleModels, artifactMap);
285 inputReceived(cloudArtifact);
286 } catch ( final PolicyDecodingException exp) {
287 LOGGER.error("Failed to process cloud artifacts ", exp);
288 artifactsProcessedSuccessfully = false;
291 if (artifactsProcessedSuccessfully) {
292 DistributionStatisticsManager.updateDistributionSuccessCount();
293 sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_OK,
296 DistributionStatisticsManager.updateDistributionFailureCount();
297 sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_ERROR,
298 "Failed to process the artifact");
303 * Method to download the distribution artifact.
305 * @param artifact the artifact
306 * @return the download result
307 * @throws ArtifactDownloadException if download fails
309 private IDistributionClientDownloadResult downloadTheArtifact(final IArtifactInfo artifact,
310 final INotificationData notificationData) throws ArtifactDownloadException {
312 DistributionStatisticsManager.updateTotalDownloadCount();
313 final IDistributionClientDownloadResult downloadResult = distributionClient.download(artifact);
314 if (!downloadResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
315 DistributionStatisticsManager.updateDownloadFailureCount();
316 final String message = "Failed to download artifact with name: " + artifact.getArtifactName() + " due to: "
317 + downloadResult.getDistributionMessageResult();
318 LOGGER.error(message);
319 sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
320 notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_ERROR, message);
321 throw new ArtifactDownloadException(message);
323 DistributionStatisticsManager.updateDownloadSuccessCount();
324 sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
325 notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_OK, null);
326 return downloadResult;
330 * Method to write a string to a file
331 * @Param filePath the file's path
332 * @Param content the data to be writen
333 * @throws IOException if error happends
335 private static void writeFileByFileWriter(String filePath, String content) throws IOException {
336 File file = new File(filePath);
337 synchronized (file) {
338 FileWriter fw = new FileWriter(filePath);
344 * Method to write the downloaded distribution artifact to local file system with specified dir.
346 * @param artifact the notification artifact
347 * @param resultArtifact the download result artifact
348 * @return the local path of written file
349 * @throws ArtifactDownloadException if error occurs while writing the artifact
351 private Path writeArtifactToDir(final IArtifactInfo artifact,
352 final IDistributionClientDownloadResult resultArtifact, Path path) throws ArtifactDownloadException {
354 final byte[] payloadBytes = resultArtifact.getArtifactPayload();
355 //final File tempArtifactFile = File.createTempFile(artifact.getArtifactName(), ".csar");
356 File tempArtifactFile = new File(path.toString() + "/" + artifact.getArtifactName());
357 try (FileOutputStream fileOutputStream = new FileOutputStream(tempArtifactFile)) {
358 fileOutputStream.write(payloadBytes, 0, payloadBytes.length);
359 return tempArtifactFile.toPath();
361 } catch (final Exception exp) {
362 final String message = "Failed to write artifact to local repository";
363 LOGGER.error(message, exp);
364 throw new ArtifactDownloadException(message, exp);
369 * Method to write the downloaded distribution artifact to local file system.
371 * @param artifact the notification artifact
372 * @param resultArtifact the download result artifact
373 * @return the local path of written file
374 * @throws ArtifactDownloadException if error occurs while writing the artifact
376 private Path writeArtifactToFile(final IArtifactInfo artifact,
377 final IDistributionClientDownloadResult resultArtifact) throws ArtifactDownloadException {
379 final byte[] payloadBytes = resultArtifact.getArtifactPayload();
380 final File tempArtifactFile = File.createTempFile(artifact.getArtifactName(), ".csar");
381 try (FileOutputStream fileOutputStream = new FileOutputStream(tempArtifactFile)) {
382 fileOutputStream.write(payloadBytes, 0, payloadBytes.length);
383 return tempArtifactFile.toPath();
385 } catch (final Exception exp) {
386 final String message = "Failed to write artifact to local repository";
387 LOGGER.error(message, exp);
388 throw new ArtifactDownloadException(message, exp);
393 * Method to delete the downloaded notification artifact from local file system.
395 * @param filePath the path of file
397 private void deleteArtifactFile(final Path filePath) {
399 Files.deleteIfExists(filePath);
400 } catch (final IOException exp) {
401 LOGGER.error("Failed to delete the downloaded artifact file", exp);
406 * Sends the distribution status to SDC using the input values.
408 * @param statusType the status type
409 * @param artifactUrl the artifact url
410 * @param distributionId the distribution id
411 * @param status the status
412 * @param errorReason the error reason
414 private void sendDistributionStatus(final DistributionStatusType statusType, final String artifactUrl,
415 final String distributionId, final DistributionStatusEnum status, final String errorReason) {
417 IDistributionClientResult clientResult;
418 final DistributionStatusMessageBuilder messageBuilder = new DistributionStatusMessageBuilder()
419 .setArtifactUrl(artifactUrl).setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
420 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
421 final IDistributionStatusMessage message = new DistributionStatusMessage(messageBuilder);
422 if (DistributionStatusType.DOWNLOAD.equals(statusType)) {
423 if (errorReason != null) {
424 clientResult = distributionClient.sendDownloadStatus(message, errorReason);
426 clientResult = distributionClient.sendDownloadStatus(message);
429 if (errorReason != null) {
430 clientResult = distributionClient.sendDeploymentStatus(message, errorReason);
432 clientResult = distributionClient.sendDeploymentStatus(message);
435 final StringBuilder loggerMessage = new StringBuilder();
436 loggerMessage.append("distribution status to SDC with values - ").append("DistributionId")
437 .append(distributionId).append(" Artifact: ").append(artifactUrl).append(" StatusType: ")
438 .append(statusType.name()).append(" Status: ").append(status.name());
439 if (errorReason != null) {
440 loggerMessage.append(" ErrorReason: ").append(errorReason);
442 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
443 loggerMessage.insert(0, "Failed sending ");
444 LOGGER.debug(loggerMessage);
446 loggerMessage.insert(0, "Successfully Sent ");
447 LOGGER.debug(loggerMessage);
452 * Sends the component done status to SDC using the input values.
454 * @param distributionId the distribution Id
455 * @param status the distribution status
456 * @param errorReason the error reason
458 private void sendComponentDoneStatus(final String distributionId, final DistributionStatusEnum status,
459 final String errorReason) {
460 IDistributionClientResult clientResult;
461 final ComponentDoneStatusMessageBuilder messageBuilder = new ComponentDoneStatusMessageBuilder()
462 .setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
463 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
464 final IComponentDoneStatusMessage message = new ComponentDoneStatusMessage(messageBuilder);
465 if (errorReason == null) {
466 clientResult = distributionClient.sendComponentDoneStatus(message);
468 clientResult = distributionClient.sendComponentDoneStatus(message, errorReason);
471 final StringBuilder loggerMessage = new StringBuilder();
472 loggerMessage.append("component done status to SDC with values - ").append("DistributionId")
473 .append(distributionId).append(" Status: ").append(status.name());
474 if (errorReason != null) {
475 loggerMessage.append(" ErrorReason: ").append(errorReason);
477 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
478 loggerMessage.insert(0, "Failed sending ");
479 LOGGER.debug(loggerMessage);
481 loggerMessage.insert(0, "Successfully Sent ");
482 LOGGER.debug(loggerMessage);
487 * Handle the status change of {@link SdcReceptionHandler} to Idle.
489 * @param newStatus the new status
491 private void handleIdleStatusChange(final SdcReceptionHandlerStatus newStatus) {
492 if (nbOfNotificationsOngoing > 1) {
493 --nbOfNotificationsOngoing;
495 nbOfNotificationsOngoing = 0;
496 sdcReceptionHandlerStatus = newStatus;