Implement improved MinIo client
[sdc.git] / openecomp-be / api / openecomp-sdc-rest-webapp / vendor-software-products-rest / vendor-software-products-rest-services / src / main / java / org / openecomp / sdcrests / vsp / rest / services / OrchestrationTemplateCandidateImpl.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  * Copyright © 2021 Nokia
4  * Copyright © 2021 Nordix Foundation
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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  * ================================================================================
21  */
22 package org.openecomp.sdcrests.vsp.rest.services;
23
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
34 import java.io.ByteArrayInputStream;
35 import java.io.FileInputStream;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Optional;
47 import java.util.UUID;
48 import javax.activation.DataHandler;
49 import javax.inject.Named;
50 import javax.ws.rs.core.Response;
51 import org.apache.commons.lang3.tuple.Pair;
52 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
53 import org.openecomp.sdc.activitylog.ActivityLogManager;
54 import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
55 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
56 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
57 import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
58 import org.openecomp.sdc.be.csar.storage.ArtifactStorageConfig;
59 import org.openecomp.sdc.be.csar.storage.ArtifactStorageManager;
60 import org.openecomp.sdc.be.csar.storage.PackageSizeReducer;
61 import org.openecomp.sdc.be.csar.storage.StorageFactory;
62 import org.openecomp.sdc.be.csar.storage.exception.ArtifactStorageException;
63 import org.openecomp.sdc.common.util.ValidationUtils;
64 import org.openecomp.sdc.common.utils.SdcCommon;
65 import org.openecomp.sdc.datatypes.error.ErrorLevel;
66 import org.openecomp.sdc.datatypes.error.ErrorMessage;
67 import org.openecomp.sdc.logging.api.Logger;
68 import org.openecomp.sdc.logging.api.LoggerFactory;
69 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
70 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
71 import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
72 import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
73 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
74 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
75 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
76 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
77 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
78 import org.openecomp.sdc.vendorsoftwareproduct.types.OrchestrationTemplateActionResponse;
79 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
80 import org.openecomp.sdc.vendorsoftwareproduct.types.ValidationResponse;
81 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
82 import org.openecomp.sdc.versioning.dao.types.Version;
83 import org.openecomp.sdcrests.vendorsoftwareproducts.types.FileDataStructureDto;
84 import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplateActionResponseDto;
85 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
86 import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto;
87 import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
88 import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidate;
89 import org.openecomp.sdcrests.vsp.rest.mapping.MapFilesDataStructureToDto;
90 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
91 import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto;
92 import org.springframework.beans.factory.annotation.Autowired;
93 import org.springframework.context.annotation.Scope;
94 import org.springframework.stereotype.Service;
95
96 @Named
97 @Service("orchestrationTemplateCandidate")
98 @Scope(value = "prototype")
99 public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplateCandidate {
100
101     private static final Logger LOGGER = LoggerFactory.getLogger(OrchestrationTemplateCandidateImpl.class);
102     private final OrchestrationTemplateCandidateManager candidateManager;
103     private final VendorSoftwareProductManager vendorSoftwareProductManager;
104     private final ActivityLogManager activityLogManager;
105     private final ArtifactStorageManager artifactStorageManager;
106     private final StorageFactory storageFactory;
107     private final PackageSizeReducer packageSizeReducer;
108     private final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
109
110     @Autowired
111     public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
112         this.candidateManager = OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
113         this.vendorSoftwareProductManager = VspManagerFactory.getInstance().createInterface();
114         this.activityLogManager = ActivityLogManagerFactory.getInstance().createInterface();
115         LOGGER.info("Instantiating artifactStorageManager");
116         this.storageFactory = new StorageFactory();
117         this.artifactStorageManager = storageFactory.createArtifactStorageManager();
118         LOGGER.info("Instantiating packageSizeReducer");
119         this.packageSizeReducer = storageFactory.createPackageSizeReducer().orElse(null);
120         this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
121     }
122
123     // Constructor used in test to avoid mock static
124     public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateManager candidateManager,
125                                               final VendorSoftwareProductManager vendorSoftwareProductManager,
126                                               final ActivityLogManager activityLogManager,
127                                               final ArtifactStorageManager artifactStorageManager,
128                                               final PackageSizeReducer packageSizeReducer,
129                                               final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
130         this.candidateManager = candidateManager;
131         this.vendorSoftwareProductManager = vendorSoftwareProductManager;
132         this.activityLogManager = activityLogManager;
133         this.artifactStorageManager = artifactStorageManager;
134         this.storageFactory = new StorageFactory();
135         this.packageSizeReducer = packageSizeReducer;
136         this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
137     }
138
139     @Override
140     public Response upload(String vspId, String versionId, final Attachment fileToUpload, final String user) {
141         LOGGER.debug("STARTED -> OrchestrationTemplateCandidateImpl.upload");
142         vspId = ValidationUtils.sanitizeInputString(vspId);
143         versionId = ValidationUtils.sanitizeInputString(versionId);
144         final Response response;
145         VspUploadStatusDto vspUploadStatus = null;
146         try {
147             vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user);
148             final byte[] fileToUploadBytes;
149             final DataHandler dataHandler = fileToUpload.getDataHandler();
150             final var filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
151             ArtifactInfo artifactInfo = null;
152             final ArtifactStorageManager artifactStorageManager = storageFactory.createArtifactStorageManager();
153             if (artifactStorageManager.isEnabled()) {
154                 artifactInfo = handleArtifactStorage(vspId, versionId, filename, dataHandler);
155                 fileToUploadBytes = artifactInfo.getBytes();
156             } else {
157                 fileToUploadBytes = fileToUpload.getObject(byte[].class);
158             }
159
160             vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInValidation(vspId, versionId, user);
161             final var onboardingPackageProcessor =
162                 new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
163             final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
164             if (onboardingPackageProcessor.hasErrors()) {
165                 orchestrationTemplateCandidateUploadManager
166                     .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
167                 return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
168             }
169             final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
170             if (onboardPackageInfo == null) {
171                 final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
172                     new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
173                 orchestrationTemplateCandidateUploadManager
174                     .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
175                 return Response.ok(uploadFileResponseDto).build();
176             }
177             final var version = new Version(versionId);
178             final var vspDetails = vendorSoftwareProductManager.getVsp(vspId, version);
179             vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInProcessing(vspId, versionId, user);
180             response = processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
181             final UploadFileResponseDto entity = (UploadFileResponseDto) response.getEntity();
182             if (artifactStorageManager.isEnabled()) {
183                 if (entity.getErrors().isEmpty()) {
184                     artifactStorageManager.put(vspId, versionId + ".reduced", new ByteArrayInputStream(fileToUploadBytes));
185                 } else {
186                     artifactStorageManager.delete(artifactInfo);
187                 }
188             }
189             orchestrationTemplateCandidateUploadManager
190                 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.SUCCESS, user);
191         } catch (final Exception ex) {
192             if (vspUploadStatus != null) {
193                 orchestrationTemplateCandidateUploadManager
194                     .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
195             }
196             throw ex;
197         }
198         LOGGER.debug("FINISHED -> OrchestrationTemplateCandidateImpl.upload");
199         return response;
200     }
201
202     private ArtifactInfo handleArtifactStorage(final String vspId, final String versionId, final String filename,
203                                                final DataHandler artifactDataHandler) {
204         final Path tempArtifactPath;
205         try {
206             final ArtifactStorageConfig storageConfiguration = artifactStorageManager.getStorageConfiguration();
207
208             final Path folder = Path.of(storageConfiguration.getTempPath()).resolve(vspId).resolve(versionId);
209             tempArtifactPath = folder.resolve(UUID.randomUUID().toString());
210             Files.createDirectories(folder);
211             LOGGER.debug("STARTED -> Transfer to '{}'", tempArtifactPath.toString());
212             try (final InputStream packageInputStream = artifactDataHandler.getInputStream();
213                 final var fileOutputStream = new FileOutputStream(tempArtifactPath.toFile())) {
214                 packageInputStream.transferTo(fileOutputStream);
215             }
216             LOGGER.debug("FINISHED -> Transfer to '{}'", tempArtifactPath.toString());
217         } catch (final Exception e) {
218             throw new ArtifactStorageException(UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename));
219         }
220         final ArtifactInfo artifactInfo;
221         try (final InputStream inputStream = new FileInputStream(tempArtifactPath.toFile())) {
222             artifactInfo = artifactStorageManager.upload(vspId, versionId, inputStream);
223         } catch (final Exception e) {
224             LOGGER.error("Package Size Reducer not configured", e);
225             throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename));
226         }
227         try {
228             LOGGER.debug("STARTED -> reducing '{}'", tempArtifactPath.toString());
229             artifactInfo.setBytes(packageSizeReducer.reduce(tempArtifactPath));
230             LOGGER.debug("FINISHED -> reducing '{}'", tempArtifactPath.toString());
231             Files.delete(tempArtifactPath);
232         } catch (final Exception e) {
233             LOGGER.error("Package Size Reducer not configured", e);
234             throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(filename));
235         }
236         return artifactInfo;
237     }
238
239     private Response processOnboardPackage(final OnboardPackageInfo onboardPackageInfo, final VspDetails vspDetails,
240                                            final ErrorMessage... errorMessages) {
241         final UploadFileResponse uploadFileResponse = candidateManager.upload(vspDetails, onboardPackageInfo);
242         final UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
243             .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
244         if (errorMessages.length > 0) {
245             uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
246         }
247         return Response.ok(uploadFileResponseDto).build();
248     }
249
250     private Map<String, List<ErrorMessage>> getErrorMap(ErrorMessage[] errorMessages) {
251         final Map<String, List<ErrorMessage>> errorMap = new HashMap<>();
252         final List<ErrorMessage> errorMessageList = new ArrayList<>();
253         Collections.addAll(errorMessageList, errorMessages);
254         errorMap.put(SdcCommon.UPLOAD_FILE, errorMessageList);
255         return errorMap;
256     }
257
258     private UploadFileResponseDto buildUploadResponseWithError(final ErrorMessage... errorMessages) {
259         final UploadFileResponseDto uploadFileResponseDto = new UploadFileResponseDto();
260         uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
261         return uploadFileResponseDto;
262     }
263
264     @Override
265     public Response get(String vspId, String versionId, String user) throws IOException {
266         Optional<Pair<String, byte[]>> zipFile = candidateManager.get(vspId, new Version(versionId));
267         String fileName;
268         if (zipFile.isPresent()) {
269             fileName = "Candidate." + zipFile.get().getLeft();
270         } else {
271             zipFile = vendorSoftwareProductManager.get(vspId, new Version((versionId)));
272             if (zipFile.isEmpty()) {
273                 ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
274                     getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
275                 LOGGER.error(errorMessage.getMessage());
276                 return Response.status(NOT_FOUND).build();
277             }
278             fileName = "Processed." + zipFile.get().getLeft();
279         }
280         Response.ResponseBuilder response = Response.ok(zipFile.get().getRight());
281         response.header("Content-Disposition", "attachment; filename=" + fileName);
282         return response.build();
283     }
284
285     @Override
286     public Response abort(String vspId, String versionId) {
287         candidateManager.abort(vspId, new Version(versionId));
288         return Response.ok().build();
289     }
290
291     @Override
292     public Response process(String vspId, String versionId, String user) {
293         Version version = new Version(versionId);
294         OrchestrationTemplateActionResponse response = candidateManager.process(vspId, version);
295         activityLogManager.logActivity(new ActivityLogEntity(vspId, version, ActivityType.Upload_Network_Package, user, true, "", ""));
296         OrchestrationTemplateActionResponseDto responseDto = copyOrchestrationTemplateActionResponseToDto(response);
297         return Response.ok(responseDto).build();
298     }
299
300     @Override
301     public Response updateFilesDataStructure(String vspId, String versionId, FileDataStructureDto fileDataStructureDto, String user) {
302         FilesDataStructure fileDataStructure = copyFilesDataStructureDtoToFilesDataStructure(fileDataStructureDto);
303         ValidationResponse response = candidateManager.updateFilesDataStructure(vspId, new Version(versionId), fileDataStructure);
304         if (!response.isValid()) {
305             return Response.status(EXPECTATION_FAILED)
306                 .entity(new MapValidationResponseToDto().applyMapping(response, ValidationResponseDto.class))
307                 .build();
308         }
309         return Response.ok(fileDataStructureDto).build();
310     }
311
312     @Override
313     public Response getFilesDataStructure(String vspId, String versionId, String user) {
314         Optional<FilesDataStructure> filesDataStructure = candidateManager.getFilesDataStructure(vspId, new Version(versionId));
315         if (filesDataStructure.isEmpty()) {
316             filesDataStructure = vendorSoftwareProductManager.getOrchestrationTemplateStructure(vspId, new Version(versionId));
317         }
318         FileDataStructureDto fileDataStructureDto = filesDataStructure
319             .map(dataStructure -> new MapFilesDataStructureToDto().applyMapping(dataStructure, FileDataStructureDto.class))
320             .orElse(new FileDataStructureDto());
321         return Response.ok(fileDataStructureDto).build();
322     }
323
324     private OrchestrationTemplateActionResponseDto copyOrchestrationTemplateActionResponseToDto(OrchestrationTemplateActionResponse response) {
325         OrchestrationTemplateActionResponseDto result = new OrchestrationTemplateActionResponseDto();
326         result.setErrors(response.getErrors());
327         result.setFileNames(response.getFileNames());
328         result.setStatus(response.getStatus());
329         return result;
330     }
331
332     private FilesDataStructure copyFilesDataStructureDtoToFilesDataStructure(FileDataStructureDto fileDataStructureDto) {
333         FilesDataStructure filesDataStructure = new FilesDataStructure();
334         filesDataStructure.setArtifacts(fileDataStructureDto.getArtifacts());
335         filesDataStructure.setModules(fileDataStructureDto.getModules());
336         filesDataStructure.setNested(fileDataStructureDto.getNested());
337         filesDataStructure.setUnassigned(fileDataStructureDto.getUnassigned());
338         return filesDataStructure;
339     }
340 }