2 * Copyright © 2016-2018 European Support Limited
3 * Copyright © 2021 Nokia
4 * Copyright © 2021 Nordix Foundation
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ============LICENSE_END=========================================================
18 * Modifications copyright (c) 2019 Nokia
19 * Modifications copyright (c) 2021 Nordix Foundation
20 * ================================================================================
22 package org.openecomp.sdcrests.vsp.rest.services;
24 import static javax.ws.rs.core.Response.Status.EXPECTATION_FAILED;
25 import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
26 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
27 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
28 import static org.openecomp.sdc.common.errors.Messages.ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT;
29 import static org.openecomp.sdc.common.errors.Messages.ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE;
30 import static org.openecomp.sdc.common.errors.Messages.NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST;
31 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_ERROR;
32 import static org.openecomp.sdc.common.errors.Messages.UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING;
33 import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspUploadAlreadyInProgress;
35 import java.io.ByteArrayInputStream;
36 import java.io.FileInputStream;
37 import java.io.FileOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.nio.file.Files;
41 import java.nio.file.Path;
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.List;
47 import java.util.Optional;
48 import java.util.UUID;
49 import javax.activation.DataHandler;
50 import javax.inject.Named;
51 import javax.ws.rs.core.Response;
52 import org.apache.commons.lang3.tuple.Pair;
53 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
54 import org.openecomp.sdc.activitylog.ActivityLogManager;
55 import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
56 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
57 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
58 import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
59 import org.openecomp.sdc.be.csar.storage.ArtifactStorageConfig;
60 import org.openecomp.sdc.be.csar.storage.ArtifactStorageManager;
61 import org.openecomp.sdc.be.csar.storage.PackageSizeReducer;
62 import org.openecomp.sdc.be.csar.storage.StorageFactory;
63 import org.openecomp.sdc.be.csar.storage.exception.ArtifactStorageException;
64 import org.openecomp.sdc.common.util.ValidationUtils;
65 import org.openecomp.sdc.common.utils.SdcCommon;
66 import org.openecomp.sdc.datatypes.error.ErrorLevel;
67 import org.openecomp.sdc.datatypes.error.ErrorMessage;
68 import org.openecomp.sdc.logging.api.Logger;
69 import org.openecomp.sdc.logging.api.LoggerFactory;
70 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
71 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
72 import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
73 import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
74 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
75 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
76 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
77 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
78 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
79 import org.openecomp.sdc.vendorsoftwareproduct.types.OrchestrationTemplateActionResponse;
80 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
81 import org.openecomp.sdc.vendorsoftwareproduct.types.ValidationResponse;
82 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
83 import org.openecomp.sdc.versioning.dao.types.Version;
84 import org.openecomp.sdcrests.vendorsoftwareproducts.types.FileDataStructureDto;
85 import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplateActionResponseDto;
86 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
87 import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto;
88 import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
89 import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidate;
90 import org.openecomp.sdcrests.vsp.rest.mapping.MapFilesDataStructureToDto;
91 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
92 import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto;
93 import org.springframework.beans.factory.annotation.Autowired;
94 import org.springframework.context.annotation.Scope;
95 import org.springframework.stereotype.Service;
98 @Service("orchestrationTemplateCandidate")
99 @Scope(value = "prototype")
100 public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplateCandidate {
102 private static final Logger LOGGER = LoggerFactory.getLogger(OrchestrationTemplateCandidateImpl.class);
103 private final OrchestrationTemplateCandidateManager candidateManager;
104 private final VendorSoftwareProductManager vendorSoftwareProductManager;
105 private final ActivityLogManager activityLogManager;
106 private final ArtifactStorageManager artifactStorageManager;
107 private final StorageFactory storageFactory;
108 private final PackageSizeReducer packageSizeReducer;
109 private final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
112 public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
113 this.candidateManager = OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
114 this.vendorSoftwareProductManager = VspManagerFactory.getInstance().createInterface();
115 this.activityLogManager = ActivityLogManagerFactory.getInstance().createInterface();
116 LOGGER.info("Instantiating artifactStorageManager");
117 this.storageFactory = new StorageFactory();
118 this.artifactStorageManager = storageFactory.createArtifactStorageManager();
119 LOGGER.info("Instantiating packageSizeReducer");
120 this.packageSizeReducer = storageFactory.createPackageSizeReducer().orElse(null);
121 this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
124 // Constructor used in test to avoid mock static
125 public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateManager candidateManager,
126 final VendorSoftwareProductManager vendorSoftwareProductManager,
127 final ActivityLogManager activityLogManager,
128 final ArtifactStorageManager artifactStorageManager,
129 final PackageSizeReducer packageSizeReducer,
130 final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
131 this.candidateManager = candidateManager;
132 this.vendorSoftwareProductManager = vendorSoftwareProductManager;
133 this.activityLogManager = activityLogManager;
134 this.artifactStorageManager = artifactStorageManager;
135 this.storageFactory = new StorageFactory();
136 this.packageSizeReducer = packageSizeReducer;
137 this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
141 public Response upload(String vspId, String versionId, final Attachment fileToUpload, final String user) {
142 LOGGER.debug("STARTED -> OrchestrationTemplateCandidateImpl.upload");
143 vspId = ValidationUtils.sanitizeInputString(vspId);
144 versionId = ValidationUtils.sanitizeInputString(versionId);
145 final Response response;
146 VspUploadStatusDto vspUploadStatus = null;
148 vspUploadStatus = getVspUploadStatus(vspId, versionId, user);
150 if (vspUploadStatus.getStatus() != VspUploadStatus.UPLOADING) {
151 throw vspUploadAlreadyInProgress(vspId, versionId).get();
153 final byte[] fileToUploadBytes;
154 final DataHandler dataHandler = fileToUpload.getDataHandler();
155 final var filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
156 ArtifactInfo artifactInfo = null;
157 final ArtifactStorageManager artifactStorageManager = storageFactory.createArtifactStorageManager();
158 if (artifactStorageManager.isEnabled()) {
159 artifactInfo = handleArtifactStorage(vspId, versionId, filename, dataHandler);
160 fileToUploadBytes = artifactInfo.getBytes();
162 fileToUploadBytes = fileToUpload.getObject(byte[].class);
165 vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInValidation(vspId, versionId, user);
166 final var onboardingPackageProcessor =
167 new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
168 final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
169 if (onboardingPackageProcessor.hasErrors()) {
170 orchestrationTemplateCandidateUploadManager
171 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
172 return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
174 final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
175 if (onboardPackageInfo == null) {
176 final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
177 new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
178 orchestrationTemplateCandidateUploadManager
179 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
180 return Response.ok(uploadFileResponseDto).build();
182 final var version = new Version(versionId);
183 final var vspDetails = vendorSoftwareProductManager.getVsp(vspId, version);
184 vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInProcessing(vspId, versionId, user);
185 response = processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
186 final UploadFileResponseDto entity = (UploadFileResponseDto) response.getEntity();
187 if (artifactStorageManager.isEnabled()) {
188 if (entity.getErrors().isEmpty()) {
189 artifactStorageManager.put(vspId, versionId + ".reduced", new ByteArrayInputStream(fileToUploadBytes));
191 artifactStorageManager.delete(artifactInfo);
194 orchestrationTemplateCandidateUploadManager
195 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.SUCCESS, user);
196 } catch (final Exception ex) {
197 if (vspUploadStatus != null) {
198 orchestrationTemplateCandidateUploadManager
199 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
203 LOGGER.debug("FINISHED -> OrchestrationTemplateCandidateImpl.upload");
207 private VspUploadStatusDto getVspUploadStatus(final String vspId, final String versionId, final String user) {
208 final Optional<VspUploadStatusDto> vspUploadStatusOpt =
209 orchestrationTemplateCandidateUploadManager.findLatestStatus(vspId, versionId, user);
210 if (vspUploadStatusOpt.isEmpty() || vspUploadStatusOpt.get().isComplete()) {
211 return orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user);
214 return vspUploadStatusOpt.get();
217 private ArtifactInfo handleArtifactStorage(final String vspId, final String versionId, final String filename,
218 final DataHandler artifactDataHandler) {
219 final Path tempArtifactPath;
221 final ArtifactStorageConfig storageConfiguration = artifactStorageManager.getStorageConfiguration();
223 final Path folder = Path.of(storageConfiguration.getTempPath()).resolve(vspId).resolve(versionId);
224 tempArtifactPath = folder.resolve(UUID.randomUUID().toString());
225 Files.createDirectories(folder);
226 LOGGER.debug("STARTED -> Transfer to '{}'", tempArtifactPath.toString());
227 try (final InputStream packageInputStream = artifactDataHandler.getInputStream();
228 final var fileOutputStream = new FileOutputStream(tempArtifactPath.toFile())) {
229 packageInputStream.transferTo(fileOutputStream);
231 LOGGER.debug("FINISHED -> Transfer to '{}'", tempArtifactPath.toString());
232 } catch (final Exception e) {
233 throw new ArtifactStorageException(UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename));
235 final ArtifactInfo artifactInfo;
236 try (final InputStream inputStream = new FileInputStream(tempArtifactPath.toFile())) {
237 artifactInfo = artifactStorageManager.upload(vspId, versionId, inputStream);
238 } catch (final Exception e) {
239 LOGGER.error("Package Size Reducer not configured", e);
240 throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename));
243 LOGGER.debug("STARTED -> reducing '{}'", tempArtifactPath.toString());
244 artifactInfo.setBytes(packageSizeReducer.reduce(tempArtifactPath));
245 LOGGER.debug("FINISHED -> reducing '{}'", tempArtifactPath.toString());
246 Files.delete(tempArtifactPath);
247 } catch (final Exception e) {
248 LOGGER.error("Package Size Reducer not configured", e);
249 throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(filename));
254 private Response processOnboardPackage(final OnboardPackageInfo onboardPackageInfo, final VspDetails vspDetails,
255 final ErrorMessage... errorMessages) {
256 final UploadFileResponse uploadFileResponse = candidateManager.upload(vspDetails, onboardPackageInfo);
257 final UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
258 .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
259 if (errorMessages.length > 0) {
260 uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
262 return Response.ok(uploadFileResponseDto).build();
265 private Map<String, List<ErrorMessage>> getErrorMap(ErrorMessage[] errorMessages) {
266 final Map<String, List<ErrorMessage>> errorMap = new HashMap<>();
267 final List<ErrorMessage> errorMessageList = new ArrayList<>();
268 Collections.addAll(errorMessageList, errorMessages);
269 errorMap.put(SdcCommon.UPLOAD_FILE, errorMessageList);
273 private UploadFileResponseDto buildUploadResponseWithError(final ErrorMessage... errorMessages) {
274 final UploadFileResponseDto uploadFileResponseDto = new UploadFileResponseDto();
275 uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
276 return uploadFileResponseDto;
280 public Response get(String vspId, String versionId, String user) throws IOException {
281 Optional<Pair<String, byte[]>> zipFile = candidateManager.get(vspId, new Version(versionId));
283 if (zipFile.isPresent()) {
284 fileName = "Candidate." + zipFile.get().getLeft();
286 zipFile = vendorSoftwareProductManager.get(vspId, new Version((versionId)));
287 if (zipFile.isEmpty()) {
288 ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
289 getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
290 LOGGER.error(errorMessage.getMessage());
291 return Response.status(NOT_FOUND).build();
293 fileName = "Processed." + zipFile.get().getLeft();
295 Response.ResponseBuilder response = Response.ok(zipFile.get().getRight());
296 response.header("Content-Disposition", "attachment; filename=" + fileName);
297 return response.build();
301 public Response abort(String vspId, String versionId) {
302 candidateManager.abort(vspId, new Version(versionId));
303 return Response.ok().build();
307 public Response process(String vspId, String versionId, String user) {
308 Version version = new Version(versionId);
309 OrchestrationTemplateActionResponse response = candidateManager.process(vspId, version);
310 activityLogManager.logActivity(new ActivityLogEntity(vspId, version, ActivityType.Upload_Network_Package, user, true, "", ""));
311 OrchestrationTemplateActionResponseDto responseDto = copyOrchestrationTemplateActionResponseToDto(response);
312 return Response.ok(responseDto).build();
316 public Response updateFilesDataStructure(String vspId, String versionId, FileDataStructureDto fileDataStructureDto, String user) {
317 FilesDataStructure fileDataStructure = copyFilesDataStructureDtoToFilesDataStructure(fileDataStructureDto);
318 ValidationResponse response = candidateManager.updateFilesDataStructure(vspId, new Version(versionId), fileDataStructure);
319 if (!response.isValid()) {
320 return Response.status(EXPECTATION_FAILED)
321 .entity(new MapValidationResponseToDto().applyMapping(response, ValidationResponseDto.class))
324 return Response.ok(fileDataStructureDto).build();
328 public Response getFilesDataStructure(String vspId, String versionId, String user) {
329 Optional<FilesDataStructure> filesDataStructure = candidateManager.getFilesDataStructure(vspId, new Version(versionId));
330 if (filesDataStructure.isEmpty()) {
331 filesDataStructure = vendorSoftwareProductManager.getOrchestrationTemplateStructure(vspId, new Version(versionId));
333 FileDataStructureDto fileDataStructureDto = filesDataStructure
334 .map(dataStructure -> new MapFilesDataStructureToDto().applyMapping(dataStructure, FileDataStructureDto.class))
335 .orElse(new FileDataStructureDto());
336 return Response.ok(fileDataStructureDto).build();
339 private OrchestrationTemplateActionResponseDto copyOrchestrationTemplateActionResponseToDto(OrchestrationTemplateActionResponse response) {
340 OrchestrationTemplateActionResponseDto result = new OrchestrationTemplateActionResponseDto();
341 result.setErrors(response.getErrors());
342 result.setFileNames(response.getFileNames());
343 result.setStatus(response.getStatus());
347 private FilesDataStructure copyFilesDataStructureDtoToFilesDataStructure(FileDataStructureDto fileDataStructureDto) {
348 FilesDataStructure filesDataStructure = new FilesDataStructure();
349 filesDataStructure.setArtifacts(fileDataStructureDto.getArtifacts());
350 filesDataStructure.setModules(fileDataStructureDto.getModules());
351 filesDataStructure.setNested(fileDataStructureDto.getNested());
352 filesDataStructure.setUnassigned(fileDataStructureDto.getUnassigned());
353 return filesDataStructure;