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;
23 import com.google.gson.Gson;
24 import com.google.gson.reflect.TypeToken;
26 import java.io.FileOutputStream;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.lang.reflect.Type;
38 import org.onap.policy.common.logging.flexlogger.FlexLogger;
39 import org.onap.policy.common.logging.flexlogger.Logger;
40 import org.onap.policy.common.parameters.ParameterService;
41 import org.onap.policy.distribution.model.CloudArtifact;
42 import org.onap.policy.distribution.model.Csar;
43 import org.onap.policy.distribution.model.GsonUtil;
44 import org.onap.policy.distribution.model.VfModuleModel;
45 import org.onap.policy.distribution.reception.decoding.PolicyDecodingException;
46 import org.onap.policy.distribution.reception.handling.AbstractReceptionHandler;
47 import org.onap.policy.distribution.reception.handling.sdc.SdcClientHandler.SdcClientOperationType;
48 import org.onap.policy.distribution.reception.handling.sdc.exceptions.ArtifactDownloadException;
49 import org.onap.policy.distribution.reception.statistics.DistributionStatisticsManager;
50 import org.onap.sdc.api.IDistributionClient;
51 import org.onap.sdc.api.consumer.IComponentDoneStatusMessage;
52 import org.onap.sdc.api.consumer.IDistributionStatusMessage;
53 import org.onap.sdc.api.consumer.INotificationCallback;
54 import org.onap.sdc.api.notification.IArtifactInfo;
55 import org.onap.sdc.api.notification.INotificationData;
56 import org.onap.sdc.api.notification.IResourceInstance;
57 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
58 import org.onap.sdc.api.results.IDistributionClientResult;
59 import org.onap.sdc.impl.DistributionClientFactory;
60 import org.onap.sdc.utils.DistributionActionResultEnum;
61 import org.onap.sdc.utils.DistributionStatusEnum;
64 * Handles reception of inputs from ONAP Service Design and Creation (SDC) from which policies may be decoded.
66 public class SdcReceptionHandler extends AbstractReceptionHandler implements INotificationCallback {
68 private static final Logger LOGGER = FlexLogger.getLogger(SdcReceptionHandler.class);
69 private static final String SECONDS = "Seconds";
71 private SdcReceptionHandlerStatus sdcReceptionHandlerStatus = SdcReceptionHandlerStatus.STOPPED;
72 private IDistributionClient distributionClient;
73 private SdcConfiguration sdcConfig;
74 private volatile int nbOfNotificationsOngoing = 0;
75 private int retryDelay;
76 private SdcClientHandler sdcClientHandler;
78 private enum DistributionStatusType {
83 protected void initializeReception(final String parameterGroupName) {
84 final SdcReceptionHandlerConfigurationParameterGroup handlerParameters =
85 ParameterService.get(parameterGroupName);
86 retryDelay = handlerParameters.getRetryDelay() < 30 ? 30 : handlerParameters.getRetryDelay();
87 sdcConfig = new SdcConfiguration(handlerParameters);
88 distributionClient = createSdcDistributionClient();
89 sdcClientHandler = new SdcClientHandler(this, SdcClientOperationType.START, retryDelay);
93 public void destroy() {
94 if (distributionClient != null) {
95 sdcClientHandler = new SdcClientHandler(this, SdcClientOperationType.STOP, retryDelay);
100 public void activateCallback(final INotificationData notificationData) {
101 LOGGER.debug("Receieved the notification from SDC with ID: " + notificationData.getDistributionID());
102 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.BUSY);
103 //Process only the resource artifacts in MC
104 for (IResourceInstance resource : notificationData.getResources()) {
105 // We process only VNF resource in MC
106 if ("VF".equals(resource.getResourceType())) {
107 this.processVfModulesArtifacts(notificationData,resource);
110 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
111 LOGGER.debug("Processed the notification from SDC with ID: " + notificationData.getDistributionID());
115 * Method to change the status of this reception handler instance.
117 * @param newStatus the new status
119 private final synchronized void changeSdcReceptionHandlerStatus(final SdcReceptionHandlerStatus newStatus) {
123 sdcReceptionHandlerStatus = newStatus;
126 handleIdleStatusChange(newStatus);
129 ++nbOfNotificationsOngoing;
130 sdcReceptionHandlerStatus = newStatus;
138 * Creates an instance of {@link IDistributionClient} from {@link DistributionClientFactory}.
140 * @return the {@link IDistributionClient} instance
142 protected IDistributionClient createSdcDistributionClient() {
143 return DistributionClientFactory.createDistributionClient();
147 * Method to initialize the SDC client.
150 protected void initializeSdcClient() {
152 LOGGER.debug("Initializing the SDC Client...");
153 if (sdcReceptionHandlerStatus != SdcReceptionHandlerStatus.STOPPED) {
154 LOGGER.error("The SDC Client is already initialized");
157 final IDistributionClientResult clientResult = distributionClient.init(sdcConfig, this);
158 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
159 LOGGER.error("SDC client initialization failed with reason:" + clientResult.getDistributionMessageResult()
160 + ". Initialization will be retried after " + retryDelay + SECONDS);
163 LOGGER.debug("SDC Client is initialized successfully");
164 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.INIT);
168 * Method to start the SDC client.
171 protected void startSdcClient() {
173 LOGGER.debug("Going to start the SDC Client...");
174 if (sdcReceptionHandlerStatus != SdcReceptionHandlerStatus.INIT) {
175 LOGGER.error("The SDC Client is not initialized");
178 final IDistributionClientResult clientResult = distributionClient.start();
179 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
180 LOGGER.error("SDC client start failed with reason:" + clientResult.getDistributionMessageResult()
181 + ". Start will be retried after " + retryDelay + SECONDS);
184 LOGGER.debug("SDC Client is started successfully");
185 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.IDLE);
186 sdcClientHandler.cancel();
190 * Method to stop the SDC client.
193 protected void stopSdcClient() {
194 LOGGER.debug("Going to stop the SDC Client...");
195 final IDistributionClientResult clientResult = distributionClient.stop();
196 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
197 LOGGER.error("SDC client stop failed with reason:" + clientResult.getDistributionMessageResult()
198 + ". Stop will be retried after " + retryDelay + SECONDS);
201 LOGGER.debug("SDC Client is stopped successfully");
202 changeSdcReceptionHandlerStatus(SdcReceptionHandlerStatus.STOPPED);
203 sdcClientHandler.cancel();
207 * Method to process VF MODULES_METADATA artifacts from incoming SDC notification.
209 * @param artifact the item needs to check if it has been stored in DBB or not
211 private boolean checkArtifactAlreadyStored(IArtifactInfo artifact) {
218 * Method to process VF MODULES_METADATA artifacts from incoming SDC notification.
220 * @param notificationData the notification from SDC
221 * @param resource every resource of the service from SDC
223 public void processVfModulesArtifacts(final INotificationData notificationData, IResourceInstance resource) {
224 boolean artifactsProcessedSuccessfully = true;
225 LOGGER.debug("start process VF MODULES_METADATA: " );
226 DistributionStatisticsManager.updateTotalDistributionCount();
227 List<String> relevantArtifactTypes = sdcConfig.getRelevantArtifactTypes();
228 Path path = Paths.get("/data");
229 ArrayList<VfModuleModel> vfModuleModels = new ArrayList<>();
230 HashMap<String, IArtifactInfo> artifactMap = new HashMap<>();//key is UUID, value is artifact for shared folder
231 String vfArtifactData = null;
232 IArtifactInfo vfModuleMetaDataArtifact = null;
234 for (final IArtifactInfo artifact : resource.getArtifacts()) {
235 artifactMap.put(artifact.getArtifactUUID(),artifact);
237 //extract the artifactlist and write them into MongoDB
238 if (artifact.getArtifactType().equals("VF_MODULES_METADATA")) {
240 final IDistributionClientDownloadResult resultArtifact =
241 downloadTheArtifact(artifact,notificationData);
242 if (resultArtifact != null) {
243 vfArtifactData = new String(resultArtifact.getArtifactPayload(),"UTF-8");
244 LOGGER.debug("VF_MODULE_ARTIFACT: " + new String(resultArtifact.getArtifactPayload(),"UTF-8"));
246 Type listType = new TypeToken<ArrayList<VfModuleModel>>(){}.getType();
247 vfModuleModels = new Gson().fromJson(vfArtifactData,listType);
248 LOGGER.debug("pass to process VF_MODULES_METADATA artifacts ");
249 vfModuleMetaDataArtifact = artifact;
250 } catch (final ArtifactDownloadException | UnsupportedEncodingException exp) {
251 LOGGER.error("Failed to process csar VF_MODULES_METADATA artifacts ", exp);
252 artifactsProcessedSuccessfully = false;
253 sendDistributionStatus(DistributionStatusType.DEPLOY, artifact.getArtifactURL(),
254 notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,
255 "Failed to deploy the artifact due to: " + exp.getMessage());
260 //foreach(vf_module_metadata)
261 // 1. create a dir like /data/UUID1
262 // 2. put the vfmodule-meta.json into it
263 // 3. put the service-meta.json into it
264 // 3. go through each aritfact uuid under artifact_list of vf_module and download
265 for (final VfModuleModel vfModule : vfModuleModels) {
268 Path temp = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID());
269 path = Files.createDirectory(temp);//create UUID path
270 //store the value to vfmodule-meta.json
271 String filePath = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID(),
272 "vfmodule-meta.json").toString();
273 writeFileByFileWriter(filePath, vfArtifactData);
274 //store the service level info to serivce-meta.json
275 filePath = Paths.get("/data",vfModule.getVfModuleModelCustomizationUUID(),
276 "service-meta.json").toString();
277 writeFileByFileWriter(filePath, notificationData.toString());
278 LOGGER.debug("pass to create directory artifact file");
279 } catch (final IOException exp) {
280 LOGGER.error("Failed to create directory artifact file", exp);
283 for (final String uuid : vfModule.getArtifacts()) {
285 IArtifactInfo artifact = artifactMap.get(uuid);
286 final IDistributionClientDownloadResult resultArtifact = downloadTheArtifact(artifact, notificationData);
287 writeArtifactToDir(artifact,resultArtifact,path);
288 LOGGER.debug("pass to write Artifact to dir ");
289 } catch (final ArtifactDownloadException exp) {
290 LOGGER.error("Failed to write artifact to dir ", exp);
291 artifactsProcessedSuccessfully = false;
292 sendDistributionStatus(DistributionStatusType.DEPLOY, artifactMap.get(uuid).getArtifactURL(),
293 notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_ERROR,
294 "Failed to deploy the artifact due to: " + exp.getMessage());
301 final CloudArtifact cloudArtifact = new CloudArtifact(vfModuleModels, artifactMap);
302 inputReceived(cloudArtifact);
303 LOGGER.debug("pass to process cloud artifacts ");
304 } catch ( final PolicyDecodingException exp) {
305 LOGGER.error("Failed to process cloud artifacts ", exp);
306 artifactsProcessedSuccessfully = false;
309 if (artifactsProcessedSuccessfully) {
310 DistributionStatisticsManager.updateDistributionSuccessCount();
311 sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_OK,
313 if (vfModuleMetaDataArtifact != null) {
314 LOGGER.debug("one vfModuleMetaDataArtifact found" );
315 sendDistributionStatus(DistributionStatusType.DEPLOY, vfModuleMetaDataArtifact.getArtifactURL(),
316 notificationData.getDistributionID(), DistributionStatusEnum.DEPLOY_OK, null);
318 LOGGER.debug("no vfModuleMetaDataArtifact found" );
322 DistributionStatisticsManager.updateDistributionFailureCount();
323 sendComponentDoneStatus(notificationData.getDistributionID(), DistributionStatusEnum.COMPONENT_DONE_ERROR,
324 "Failed to process the artifact");
326 LOGGER.debug("end process VF MODULES_METADATA: " );
330 * Method to download the distribution artifact.
332 * @param artifact the artifact
333 * @return the download result
334 * @throws ArtifactDownloadException if download fails
336 private IDistributionClientDownloadResult downloadTheArtifact(final IArtifactInfo artifact,
337 final INotificationData notificationData) throws ArtifactDownloadException {
339 DistributionStatisticsManager.updateTotalDownloadCount();
340 final IDistributionClientDownloadResult downloadResult = distributionClient.download(artifact);
341 if (!downloadResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
342 DistributionStatisticsManager.updateDownloadFailureCount();
343 final String message = "Failed to download artifact with name: " + artifact.getArtifactName() + " due to: "
344 + downloadResult.getDistributionMessageResult();
345 LOGGER.error(message);
346 sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
347 notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_ERROR, message);
348 throw new ArtifactDownloadException(message);
350 DistributionStatisticsManager.updateDownloadSuccessCount();
351 sendDistributionStatus(DistributionStatusType.DOWNLOAD, artifact.getArtifactURL(),
352 notificationData.getDistributionID(), DistributionStatusEnum.DOWNLOAD_OK, null);
353 return downloadResult;
357 * Method to write a string to a file
358 * @Param filePath the file's path
359 * @Param content the data to be writen
360 * @throws IOException if error happends
362 private static void writeFileByFileWriter(String filePath, String content) throws IOException {
363 File file = new File(filePath);
364 synchronized (file) {
365 try (FileWriter fw = new FileWriter(filePath)) {
367 } catch (final IOException exp) {
368 LOGGER.error("Failed to write File by File Writer ", exp);
373 * Method to write the downloaded distribution artifact to local file system with specified dir.
375 * @param artifact the notification artifact
376 * @param resultArtifact the download result artifact
377 * @return the local path of written file
378 * @throws ArtifactDownloadException if error occurs while writing the artifact
380 private Path writeArtifactToDir(final IArtifactInfo artifact,
381 final IDistributionClientDownloadResult resultArtifact, Path path) throws ArtifactDownloadException {
383 final byte[] payloadBytes = resultArtifact.getArtifactPayload();
384 //final File tempArtifactFile = File.createTempFile(artifact.getArtifactName(), ".csar");
385 File tempArtifactFile = new File(path.toString() + "/" + artifact.getArtifactName());
386 try (FileOutputStream fileOutputStream = new FileOutputStream(tempArtifactFile)) {
387 fileOutputStream.write(payloadBytes, 0, payloadBytes.length);
388 return tempArtifactFile.toPath();
390 } catch (final Exception exp) {
391 final String message = "Failed to write artifact to local repository";
392 LOGGER.error(message, exp);
393 throw new ArtifactDownloadException(message, exp);
398 * Method to write the downloaded distribution artifact to local file system.
400 * @param artifact the notification artifact
401 * @param resultArtifact the download result artifact
402 * @return the local path of written file
403 * @throws ArtifactDownloadException if error occurs while writing the artifact
405 private Path writeArtifactToFile(final IArtifactInfo artifact,
406 final IDistributionClientDownloadResult resultArtifact) throws ArtifactDownloadException {
408 final byte[] payloadBytes = resultArtifact.getArtifactPayload();
409 final File tempArtifactFile = File.createTempFile(artifact.getArtifactName(), ".csar");
410 try (FileOutputStream fileOutputStream = new FileOutputStream(tempArtifactFile)) {
411 fileOutputStream.write(payloadBytes, 0, payloadBytes.length);
412 return tempArtifactFile.toPath();
414 } catch (final Exception exp) {
415 final String message = "Failed to write artifact to local repository";
416 LOGGER.error(message, exp);
417 throw new ArtifactDownloadException(message, exp);
422 * Method to delete the downloaded notification artifact from local file system.
424 * @param filePath the path of file
426 private void deleteArtifactFile(final Path filePath) {
428 Files.deleteIfExists(filePath);
429 } catch (final IOException exp) {
430 LOGGER.error("Failed to delete the downloaded artifact file", exp);
435 * Sends the distribution status to SDC using the input values.
437 * @param statusType the status type
438 * @param artifactUrl the artifact url
439 * @param distributionId the distribution id
440 * @param status the status
441 * @param errorReason the error reason
443 private void sendDistributionStatus(final DistributionStatusType statusType, final String artifactUrl,
444 final String distributionId, final DistributionStatusEnum status, final String errorReason) {
446 IDistributionClientResult clientResult;
447 final DistributionStatusMessageBuilder messageBuilder = new DistributionStatusMessageBuilder()
448 .setArtifactUrl(artifactUrl).setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
449 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
450 final IDistributionStatusMessage message = new DistributionStatusMessage(messageBuilder);
451 if (DistributionStatusType.DOWNLOAD.equals(statusType)) {
452 if (errorReason != null) {
453 clientResult = distributionClient.sendDownloadStatus(message, errorReason);
455 clientResult = distributionClient.sendDownloadStatus(message);
458 if (errorReason != null) {
459 clientResult = distributionClient.sendDeploymentStatus(message, errorReason);
461 clientResult = distributionClient.sendDeploymentStatus(message);
464 final StringBuilder loggerMessage = new StringBuilder();
465 loggerMessage.append("distribution status to SDC with values - ").append("DistributionId")
466 .append(distributionId).append(" Artifact: ").append(artifactUrl).append(" StatusType: ")
467 .append(statusType.name()).append(" Status: ").append(status.name());
468 if (errorReason != null) {
469 loggerMessage.append(" ErrorReason: ").append(errorReason);
471 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
472 loggerMessage.insert(0, "Failed sending ");
473 LOGGER.debug(loggerMessage);
475 loggerMessage.insert(0, "Successfully Sent ");
476 LOGGER.debug(loggerMessage);
481 * Sends the component done status to SDC using the input values.
483 * @param distributionId the distribution Id
484 * @param status the distribution status
485 * @param errorReason the error reason
487 private void sendComponentDoneStatus(final String distributionId, final DistributionStatusEnum status,
488 final String errorReason) {
489 IDistributionClientResult clientResult;
490 final ComponentDoneStatusMessageBuilder messageBuilder = new ComponentDoneStatusMessageBuilder()
491 .setConsumerId(sdcConfig.getConsumerID()).setDistributionId(distributionId)
492 .setDistributionStatus(status).setTimestamp(System.currentTimeMillis());
493 final IComponentDoneStatusMessage message = new ComponentDoneStatusMessage(messageBuilder);
494 if (errorReason == null) {
495 clientResult = distributionClient.sendComponentDoneStatus(message);
497 clientResult = distributionClient.sendComponentDoneStatus(message, errorReason);
500 final StringBuilder loggerMessage = new StringBuilder();
501 loggerMessage.append("component done status to SDC with values - ").append("DistributionId")
502 .append(distributionId).append(" Status: ").append(status.name());
503 if (errorReason != null) {
504 loggerMessage.append(" ErrorReason: ").append(errorReason);
506 if (!clientResult.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
507 loggerMessage.insert(0, "Failed sending ");
508 LOGGER.debug(loggerMessage);
510 loggerMessage.insert(0, "Successfully Sent ");
511 LOGGER.debug(loggerMessage);
516 * Handle the status change of {@link SdcReceptionHandler} to Idle.
518 * @param newStatus the new status
520 private void handleIdleStatusChange(final SdcReceptionHandlerStatus newStatus) {
521 if (nbOfNotificationsOngoing > 1) {
522 --nbOfNotificationsOngoing;
524 nbOfNotificationsOngoing = 0;
525 sdcReceptionHandlerStatus = newStatus;