2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 European Software Marketing Ltd.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 package org.onap.aai.modelloader.notification;
23 import java.time.ZonedDateTime;
24 import java.time.format.DateTimeFormatter;
25 import java.util.Base64;
26 import java.util.List;
28 import java.util.stream.Collectors;
29 import org.onap.aai.babel.service.data.BabelArtifact;
30 import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType;
31 import org.onap.aai.cl.api.Logger;
32 import org.onap.aai.cl.eelf.LoggerFactory;
33 import org.onap.aai.cl.mdc.MdcContext;
34 import org.onap.aai.cl.mdc.MdcOverride;
35 import org.onap.aai.modelloader.config.ModelLoaderConfig;
36 import org.onap.aai.modelloader.entity.Artifact;
37 import org.onap.aai.modelloader.entity.model.BabelArtifactParsingException;
38 import org.onap.aai.modelloader.entity.model.IModelParser;
39 import org.onap.aai.modelloader.entity.model.NamedQueryArtifactParser;
40 import org.onap.aai.modelloader.extraction.InvalidArchiveException;
41 import org.onap.aai.modelloader.extraction.VnfCatalogExtractor;
42 import org.onap.aai.modelloader.restclient.BabelServiceClient;
43 import org.onap.aai.modelloader.restclient.BabelServiceClientException;
44 import org.onap.aai.modelloader.service.BabelServiceClientFactory;
45 import org.onap.aai.modelloader.service.ModelLoaderMsgs;
46 import org.onap.sdc.api.IDistributionClient;
47 import org.onap.sdc.api.notification.IArtifactInfo;
48 import org.onap.sdc.api.notification.INotificationData;
49 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
50 import org.onap.sdc.utils.ArtifactTypeEnum;
51 import org.onap.sdc.utils.DistributionActionResultEnum;
54 * This class is responsible for downloading the artifacts from the ASDC.
56 * The downloads can be TOSCA_CSAR files or VNF_CATALOG files.
58 * The status of the download is published. The status of the extraction of yml files from a TOSCA_CSAR file is also
59 * published as a deployment event.
61 * TOSCA_CSAR file artifacts will be converted into XML and returned as model artifacts.
63 public class ArtifactDownloadManager {
65 private static Logger logger = LoggerFactory.getInstance().getLogger(ArtifactDownloadManager.class);
67 private IDistributionClient client;
68 private NotificationPublisher notificationPublisher;
69 private BabelArtifactConverter babelArtifactConverter;
70 private ModelLoaderConfig config;
71 private BabelServiceClientFactory clientFactory;
72 private VnfCatalogExtractor vnfCatalogExtractor;
74 public ArtifactDownloadManager(IDistributionClient client, ModelLoaderConfig config,
75 BabelServiceClientFactory clientFactory) {
78 this.clientFactory = clientFactory;
82 * This method downloads the artifacts from the ASDC.
84 * @param data data about the notification that is being processed
85 * @param artifacts the specific artifacts found in the data.
86 * @param modelArtifacts collection of artifacts for model query specs
87 * @param catalogArtifacts collection of artifacts that represent vnf catalog files
88 * @return boolean <code>true</code> if the download process was successful otherwise <code>false</code>
90 boolean downloadArtifacts(INotificationData data, List<IArtifactInfo> artifacts, List<Artifact> modelArtifacts,
91 List<Artifact> catalogArtifacts) {
92 boolean success = true;
94 for (IArtifactInfo artifact : artifacts) {
96 IDistributionClientDownloadResult downloadResult = downloadIndividualArtifacts(data, artifact);
97 processDownloadedArtifacts(modelArtifacts, catalogArtifacts, artifact, downloadResult, data);
98 } catch (DownloadFailureException e) {
99 getNotificationPublisher().publishDownloadFailure(client, data, artifact, e.getMessage());
101 } catch (Exception e) {
102 getNotificationPublisher().publishDeployFailure(client, data, artifact);
114 private IDistributionClientDownloadResult downloadIndividualArtifacts(INotificationData data,
115 IArtifactInfo artifact) throws DownloadFailureException {
116 // Grab the current time so we can measure the download time for the metrics log
117 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
118 MdcOverride override = new MdcOverride();
119 override.addAttribute(MdcContext.MDC_START_TIME, ZonedDateTime.now().format(formatter));
121 IDistributionClientDownloadResult downloadResult = client.download(artifact);
123 logger.info(ModelLoaderMsgs.DOWNLOAD_COMPLETE, downloadResult.getDistributionActionResult().toString(),
124 downloadResult.getArtifactPayload() == null ? "null"
125 : Base64.getEncoder().encodeToString(downloadResult.getArtifactPayload()));
127 if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {
128 logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Downloaded artifact: " + artifact.getArtifactName());
129 getNotificationPublisher().publishDownloadSuccess(client, data, artifact);
131 throw new DownloadFailureException(downloadResult.getDistributionMessageResult());
134 return downloadResult;
137 private void processDownloadedArtifacts(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts,
138 IArtifactInfo artifactInfo, IDistributionClientDownloadResult downloadResult, INotificationData data)
139 throws ProcessToscaArtifactsException, InvalidArchiveException, BabelArtifactParsingException {
140 if ("TOSCA_CSAR".equalsIgnoreCase(artifactInfo.getArtifactType())) {
141 processToscaArtifacts(modelArtifacts, catalogArtifacts, downloadResult.getArtifactPayload(), artifactInfo,
142 data.getDistributionID(), data.getServiceVersion());
143 } else if (ArtifactTypeEnum.MODEL_QUERY_SPEC.toString().equalsIgnoreCase(artifactInfo.getArtifactType())) {
144 processModelQuerySpecArtifact(modelArtifacts, downloadResult);
146 logger.info(ModelLoaderMsgs.UNSUPPORTED_ARTIFACT_TYPE, artifactInfo.getArtifactName(),
147 artifactInfo.getArtifactType());
148 throw new InvalidArchiveException("Unsupported artifact type: " + artifactInfo.getArtifactType());
152 public void processToscaArtifacts(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, byte[] payload,
153 IArtifactInfo artifactInfo, String distributionId, String serviceVersion)
154 throws ProcessToscaArtifactsException, InvalidArchiveException {
155 // Get translated artifacts from Babel Service
156 invokeBabelService(modelArtifacts, catalogArtifacts, payload, artifactInfo, distributionId, serviceVersion);
158 // Get VNF Catalog artifacts directly from CSAR
159 List<Artifact> csarCatalogArtifacts = getVnfCatalogExtractor().extract(payload, artifactInfo.getArtifactName());
161 // Throw an error if VNF Catalog data is present in the Babel payload and directly in the CSAR
162 if (!catalogArtifacts.isEmpty() && !csarCatalogArtifacts.isEmpty()) {
163 logger.error(ModelLoaderMsgs.DUPLICATE_VNFC_DATA_ERROR, artifactInfo.getArtifactName());
164 throw new InvalidArchiveException("CSAR: " + artifactInfo.getArtifactName()
165 + " contains VNF Catalog data in the format of both TOSCA and XML files. Only one format can be used for each CSAR file.");
166 } else if (!csarCatalogArtifacts.isEmpty()) {
167 catalogArtifacts.addAll(csarCatalogArtifacts);
171 public void invokeBabelService(List<Artifact> modelArtifacts, List<Artifact> catalogArtifacts, byte[] payload,
172 IArtifactInfo artifactInfo, String distributionId, String serviceVersion)
173 throws ProcessToscaArtifactsException {
175 BabelServiceClient babelClient = createBabelServiceClient(artifactInfo, serviceVersion);
177 logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT,
178 "Posting artifact: " + artifactInfo.getArtifactName() + ", service version: " + serviceVersion
179 + ", artifact version: " + artifactInfo.getArtifactVersion());
181 List<BabelArtifact> babelArtifacts =
182 babelClient.postArtifact(payload, artifactInfo.getArtifactName(), serviceVersion, distributionId);
184 // Sort Babel artifacts based on type
185 Map<ArtifactType, List<BabelArtifact>> artifactMap =
186 babelArtifacts.stream().collect(Collectors.groupingBy(BabelArtifact::getType));
188 if (artifactMap.containsKey(BabelArtifact.ArtifactType.MODEL)) {
189 modelArtifacts.addAll(
190 getBabelArtifactConverter().convertToModel(artifactMap.get(BabelArtifact.ArtifactType.MODEL)));
191 artifactMap.remove(BabelArtifact.ArtifactType.MODEL);
194 if (artifactMap.containsKey(BabelArtifact.ArtifactType.VNFCATALOG)) {
195 catalogArtifacts.addAll(getBabelArtifactConverter()
196 .convertToCatalog(artifactMap.get(BabelArtifact.ArtifactType.VNFCATALOG)));
197 artifactMap.remove(BabelArtifact.ArtifactType.VNFCATALOG);
200 // Log unexpected artifact types
201 if (!artifactMap.isEmpty()) {
202 logger.warn(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR,
203 artifactInfo.getArtifactName() + " " + serviceVersion
204 + ". Unexpected artifact types returned by the babel service: "
205 + artifactMap.keySet().toString());
208 } catch (BabelArtifactParsingException e) {
209 logger.error(ModelLoaderMsgs.ARTIFACT_PARSE_ERROR,
210 "Error for artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + e);
211 throw new ProcessToscaArtifactsException(
212 "An error occurred while trying to parse the Babel artifacts: " + e.getLocalizedMessage());
213 } catch (Exception e) {
214 logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(),
215 "Error posting artifact " + artifactInfo.getArtifactName() + " " + serviceVersion + " to Babel: "
216 + e.getLocalizedMessage());
217 throw new ProcessToscaArtifactsException(
218 "An error occurred while calling the Babel service: " + e.getLocalizedMessage());
222 BabelServiceClient createBabelServiceClient(IArtifactInfo artifact, String serviceVersion)
223 throws ProcessToscaArtifactsException {
224 BabelServiceClient babelClient;
226 logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Creating Babel client");
227 babelClient = clientFactory.create(config);
228 } catch (BabelServiceClientException e) {
229 logger.error(ModelLoaderMsgs.BABEL_REST_REQUEST_ERROR, e, "POST", config.getBabelBaseUrl(),
230 "Error posting artifact " + artifact.getArtifactName() + " " + serviceVersion + " to Babel: "
231 + e.getLocalizedMessage());
232 throw new ProcessToscaArtifactsException(
233 "An error occurred tyring to convert the tosca artifacts to xml artifacts: "
234 + e.getLocalizedMessage());
240 private void processModelQuerySpecArtifact(List<Artifact> modelArtifacts,
241 IDistributionClientDownloadResult downloadResult) throws BabelArtifactParsingException {
242 logger.debug(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Processing named query artifact.");
244 IModelParser parser = new NamedQueryArtifactParser();
246 List<Artifact> parsedArtifacts =
247 parser.parse(new String(downloadResult.getArtifactPayload()), downloadResult.getArtifactFilename());
249 if (parsedArtifactsExist(parsedArtifacts)) {
250 modelArtifacts.addAll(parsedArtifacts);
252 throw new BabelArtifactParsingException(
253 "Could not parse generated XML: " + new String(downloadResult.getArtifactPayload()));
257 private boolean parsedArtifactsExist(List<Artifact> parsedArtifacts) {
258 return parsedArtifacts != null && !parsedArtifacts.isEmpty();
261 private NotificationPublisher getNotificationPublisher() {
262 if (notificationPublisher == null) {
263 notificationPublisher = new NotificationPublisher();
266 return notificationPublisher;
269 private BabelArtifactConverter getBabelArtifactConverter() {
270 if (babelArtifactConverter == null) {
271 babelArtifactConverter = new BabelArtifactConverter();
274 return babelArtifactConverter;
277 private VnfCatalogExtractor getVnfCatalogExtractor() {
278 if (vnfCatalogExtractor == null) {
279 vnfCatalogExtractor = new VnfCatalogExtractor();
282 return vnfCatalogExtractor;