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