diff options
Diffstat (limited to 'src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java')
-rw-r--r-- | src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java new file mode 100644 index 0000000..bdd101e --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/notification/ArtifactDownloadManager.java @@ -0,0 +1,250 @@ +/** + * ============LICENSE_START========================================== + * org.onap.aai + * =================================================================== + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + */ +package org.onap.aai.modelloader.notification; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.cl.mdc.MdcOverride; +import org.onap.aai.modelloader.config.ModelLoaderConfig; +import org.onap.aai.modelloader.entity.Artifact; +import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException; +import org.onap.aai.modelloader.entity.model.IModelParser; +import org.onap.aai.modelloader.entity.model.NamedQueryArtifactParser; +import org.onap.aai.modelloader.extraction.InvalidArchiveException; +import org.onap.aai.modelloader.restclient.BabelServiceClient; +import org.onap.aai.modelloader.service.ModelLoaderMsgs; +import org.openecomp.sdc.api.IDistributionClient; +import org.openecomp.sdc.api.notification.IArtifactInfo; +import org.openecomp.sdc.api.notification.INotificationData; +import org.openecomp.sdc.api.results.IDistributionClientDownloadResult; +import org.openecomp.sdc.utils.ArtifactTypeEnum; +import org.openecomp.sdc.utils.DistributionActionResultEnum; + +/** + * This class is responsible for downloading the artifacts from the ASDC. + * + * The downloads can be TOSCA_CSAR files or VNF_CATALOG files. + * + * The status of the download is published. The status of the extraction of yml files from a TOSCA_CSAR file is also + * published as a deployment event. + * + * TOSCA_CSAR file artifacts will be converted into XML and returned as model artifacts. + */ +public class ArtifactDownloadManager { + + private static Logger logger = LoggerFactory.getInstance().getLogger(ArtifactDownloadManager.class); + + private IDistributionClient client; + private NotificationPublisher notificationPublisher; + private BabelArtifactConverter babelArtifactConverter; + private ModelLoaderConfig config; + + public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config) { + this.client = client; + this.config = config; + } + + /** + * This method downloads the artifacts from the ASDC. + * + * @param data data about the notification that is being processed + * @param artifacts the specific artifacts found in the data. + * @param modelArtifacts collection of artifacts for model query specs + * @param catalogArtifacts collection of artifacts that represent vnf catalog files + * @return boolean <code>true</code> if the download process was successful otherwise <code>false</code> + */ + boolean downloadArtifacts(INotificationData data, List<IArtifactInfo> artifacts, List<Artifact> modelArtifacts, + List<Artifact> catalogArtifacts) { + boolean success = true; + + for (IArtifactInfo artifact : artifacts) { + try { + IDistributionClientDownloadResult downloadResult = downloadIndividualArtifacts(data, artifact); + processDownloadedArtifacts(modelArtifacts, catalogArtifacts, artifact, downloadResult, data); + } catch (DownloadFailureException e) { + getNotificationPublisher().publishDownloadFailure(client, data, artifact, e.getMessage()); + success = false; + } catch (Exception e) { + getNotificationPublisher().publishDeployFailure(client, data, artifact); + success = false; + } + + if (!success) { + break; + } + } + + return success; + } + + private IDistributionClientDownloadResult downloadIndividualArtifacts(INotificationData data, + IArtifactInfo artifact) throws DownloadFailureException { + // Grab the current time so we can measure the download time for the metrics log + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + MdcOverride override = new MdcOverride(); + override.addAttribute(MdcContext.MDC_START_TIME, ZonedDateTime.now().format(formatter)); + + IDistributionClientDownloadResult downloadResult = client.download(artifact); + + logger.info(ModelLoaderMsgs.DOWNLOAD_COMPLETE, downloadResult.getDistributionActionResult().toString(), + downloadResult.getArtifactPayload() == null ? "null" + : Base64.getEncoder().encodeToString(downloadResult.getArtifactPayload())); + + if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) { + logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Downloaded artifact: " + artifact.getArtifactName()); + getNotificationPublisher().publishDownloadSuccess(client, data, artifact); + } else { + throw new DownloadFailureException(downloadResult.getDistributionMessageResult()); + } + + return downloadResult; + } + + private void processDownloadedArtifacts(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, + IArtifactInfo artifactInfo, IDistributionClientDownloadResult downloadResult, INotificationData data) + throws ProcessToscaArtifactsException, InvalidArchiveException, BabelArtifactParsingException { + if ("TOSCA_CSAR".equalsIgnoreCase(artifactInfo.getArtifactType())) { + processToscaArtifacts(modelArtifacts, catalogArtifacts, downloadResult.getArtifactPayload(), artifactInfo, + data.getDistributionID(), data.getServiceVersion()); + } else if (ArtifactTypeEnum.MODEL_QUERY_SPEC.toString().equalsIgnoreCase(artifactInfo.getArtifactType())) { + processModelQuerySpecArtifact(modelArtifacts, downloadResult); + } else { + logger.info(ModelLoaderMsgs.UNSUPPORTED_ARTIFACT_TYPE, artifactInfo.getArtifactName(), + artifactInfo.getArtifactType()); + throw new InvalidArchiveException("Unsupported artifact type: " + artifactInfo.getArtifactType()); + } + } + + public void processToscaArtifacts(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, byte[] payload, + IArtifactInfo artifactInfo, String distributionId, String serviceVersion) + throws ProcessToscaArtifactsException { + try { + BabelServiceClient babelClient = createBabelServiceClient(artifactInfo, serviceVersion); + + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, + "Posting artifact: " + artifactInfo.getArtifactName() + ", version: " + serviceVersion); + + List<BabelArtifact> babelArtifacts = + babelClient.postArtifact(payload, artifactInfo.getArtifactName(), serviceVersion, distributionId); + + // Sort Babel artifacts based on type + Map<ArtifactType, List<BabelArtifact>> artifactMap = + babelArtifacts.stream().collect(Collectors.groupingBy(BabelArtifact::getType)); + + if (artifactMap.containsKey(BabelArtifact.ArtifactType.MODEL)) { + modelArtifacts.addAll( + getBabelArtifactConverter().convertToModel(artifactMap.get(BabelArtifact.ArtifactType.MODEL))); + artifactMap.remove(BabelArtifact.ArtifactType.MODEL); + } + + if (artifactMap.containsKey(BabelArtifact.ArtifactType.VNFCATALOG)) { + catalogArtifacts.addAll(getBabelArtifactConverter() + .convertToCatalog(artifactMap.get(BabelArtifact.ArtifactType.VNFCATALOG))); + artifactMap.remove(BabelArtifact.ArtifactType.VNFCATALOG); + } + + // Log unexpected artifact types + if (!artifactMap.isEmpty()) { + logger.warn(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + artifactInfo.getArtifactName() + " " + serviceVersion + + ". Unexpected artifact types returned by the babel service: " + + artifactMap.keySet().toString()); + } + + } catch (BabelArtifactParsingException e) { + logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR, + "Error for artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + e); + throw new ProcessToscaArtifactsException( + "An error occurred while trying to parse the Babel artifacts: " + e.getLocalizedMessage()); + } catch (Exception e) { + logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(), + "Error posting artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + " to Babel: " + + e.getLocalizedMessage()); + throw new ProcessToscaArtifactsException( + "An error occurred while calling the Babel service: " + e.getLocalizedMessage()); + } + } + + private BabelServiceClient createBabelServiceClient(IArtifactInfo artifact, String serviceVersion) + throws ProcessToscaArtifactsException { + BabelServiceClient babelClient; + try { + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Creating Babel client"); + babelClient = new BabelServiceClient(config); + } catch (Exception e) { + logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(), + "Error posting artifact " + artifact.getArtifactName() + " " + serviceVersion + " to Babel: " + + e.getLocalizedMessage()); + throw new ProcessToscaArtifactsException( + "An error occurred tyring to convert the tosca artifacts to xml artifacts: " + + e.getLocalizedMessage()); + } + + return babelClient; + } + + private void processModelQuerySpecArtifact(List<Artifact> modelArtifacts, + IDistributionClientDownloadResult downloadResult) throws BabelArtifactParsingException { + logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Processing named query artifact."); + + IModelParser parser = new NamedQueryArtifactParser(); + + List<Artifact> parsedArtifacts = + parser.parse(new String(downloadResult.getArtifactPayload()), downloadResult.getArtifactFilename()); + + if (parsedArtifactsExist(parsedArtifacts)) { + modelArtifacts.addAll(parsedArtifacts); + } else { + throw new BabelArtifactParsingException( + "Could not parse generated XML: " + new String(downloadResult.getArtifactPayload())); + } + } + + private boolean parsedArtifactsExist(List<Artifact> parsedArtifacts) { + return parsedArtifacts != null && !parsedArtifacts.isEmpty(); + } + + private NotificationPublisher getNotificationPublisher() { + if (notificationPublisher == null) { + notificationPublisher = new NotificationPublisher(); + } + + return notificationPublisher; + } + + private BabelArtifactConverter getBabelArtifactConverter() { + if (babelArtifactConverter == null) { + babelArtifactConverter = new BabelArtifactConverter(); + } + + return babelArtifactConverter; + } +} |