e727078daa95b3936b7ddac79afa7f9156831778
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019, Nordix Foundation. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.etsi;
22
23 import static org.openecomp.sdc.tosca.csar.CSARConstants.ARTIFACTS_FOLDER;
24 import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_MF_FILE_NAME;
25 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA;
26 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS;
27 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ETSI_ENTRY_CHANGE_LOG;
28 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ETSI_ENTRY_MANIFEST;
29 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ORIG_PATH_FILE_NAME;
30 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME;
31
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.nio.charset.StandardCharsets;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Optional;
42 import java.util.stream.Collectors;
43 import org.apache.commons.collections.MapUtils;
44 import org.apache.commons.io.IOUtils;
45 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
46 import org.onap.sdc.tosca.parser.utils.YamlToObjectConverter;
47 import org.onap.sdc.tosca.services.YamlUtil;
48 import org.openecomp.core.utilities.file.FileContentHandler;
49 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
50 import org.openecomp.sdc.logging.api.Logger;
51 import org.openecomp.sdc.logging.api.LoggerFactory;
52 import org.openecomp.sdc.tosca.csar.Manifest;
53 import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata;
54 import org.openecomp.sdc.tosca.csar.SOL004ManifestOnboarding;
55 import org.openecomp.sdc.tosca.csar.ToscaMetadata;
56 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
57
58 public class ETSIServiceImpl implements ETSIService {
59
60     private static final Logger LOGGER = LoggerFactory.getLogger(ETSIServiceImpl.class);
61
62     private Configuration configuration;
63
64     public ETSIServiceImpl() throws IOException {
65         final InputStream io = getClass().getClassLoader().getResourceAsStream("nonManoConfig.yaml");
66         if (io == null) {
67             throw new IOException("Non Mano configuration not found");
68         }
69         final String data = IOUtils.toString(io, StandardCharsets.UTF_8);
70         final YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter();
71         configuration = yamlToObjectConverter.convertFromString(data, Configuration.class);
72     }
73
74     public ETSIServiceImpl(Configuration configuration) {
75         this.configuration = configuration;
76     }
77
78     @Override
79     public boolean isSol004WithToscaMetaDirectory(FileContentHandler handler) throws IOException {
80         final Map<String, byte[]> templates = handler.getFiles();
81         return isMetaFilePresent(templates) && hasMetaMandatoryEntries(getMetadata(handler));
82     }
83
84     @Override
85     public Optional<Map<String, Path>> moveNonManoFileToArtifactFolder(final FileContentHandler handler) throws IOException {
86         final Manifest manifest;
87         try {
88             manifest = getManifest(handler);
89         } catch (final IOException ex) {
90             if (LOGGER.isErrorEnabled()) {
91                 LOGGER.error("An error occurred while getting the manifest file", ex);
92             }
93             throw ex;
94         }
95         final Path originalManifestPath;
96         try {
97             originalManifestPath = getOriginalManifestPath(handler);
98         } catch (final IOException ex) {
99             if (LOGGER.isErrorEnabled()) {
100                 LOGGER.error("An error occurred while getting the original manifest path", ex);
101             }
102             throw ex;
103         }
104         final Map<String, Path> fromToPathMap = new HashMap<>();
105         final Map<String, NonManoType> nonManoKeyFolderMapping = configuration.getNonManoKeyFolderMapping();
106         manifest.getNonManoSources().entrySet().stream()
107             .filter(manifestNonManoSourceEntry -> nonManoKeyFolderMapping.containsKey(manifestNonManoSourceEntry.getKey()))
108             .forEach(manifestNonManoSourceEntry -> {
109                 final NonManoType nonManoType = nonManoKeyFolderMapping.get(manifestNonManoSourceEntry.getKey());
110                 final List<String> nonManoFileList = manifestNonManoSourceEntry.getValue();
111                 final Map<String, Path> actualFromToPathMap = nonManoFileList.stream()
112                     .map(nonManoFilePath -> {
113                         final Path normalizedFilePath = resolveNonManoFilePath(originalManifestPath, nonManoFilePath);
114                         final Optional<Path> changedPath = updateNonManoPathInHandler(handler, nonManoType, normalizedFilePath);
115                         if (changedPath.isPresent()) {
116                             final Map<String, Path> fromAndToPathMap = new HashMap<>();
117                             fromAndToPathMap.put(nonManoFilePath, Paths.get(ARTIFACTS_FOLDER).resolve(changedPath.get()));
118                             return fromAndToPathMap;
119                         }
120                         return null;
121                     })
122                     .filter(Objects::nonNull)
123                     .collect(Collectors.toMap(
124                         fromToPathEntry -> fromToPathEntry.keySet().iterator().next(),
125                         fromToPathEntry -> fromToPathEntry.values().iterator().next()
126                     ));
127                 fromToPathMap.putAll(actualFromToPathMap);
128             });
129
130         return MapUtils.isEmpty(fromToPathMap) ? Optional.empty() : Optional.of(fromToPathMap);
131     }
132
133     /**
134      * Resolves the non mano file path based on the original manifest path of the onboarded package.
135      *
136      * @param originalManifestPath The original path from the onboarded package manifest
137      * @param nonManoFilePath The non mano file path defined in the manifest
138      * @return The resolved and normalized non mano path.
139      */
140     private Path resolveNonManoFilePath(final Path originalManifestPath, final String nonManoFilePath) {
141         return originalManifestPath.resolve(Paths.get(nonManoFilePath)).normalize();
142     }
143
144     /**
145      * Updates the non mano file path in the package file handler based on the non mano type.
146      *
147      * @param handler The package file handler
148      * @param nonManoType The Non Mano type of the file to update
149      * @param nonManoOriginalFilePath The Non Mano file original path
150      * @return The new file path if it was updated in the package file handler, otherwise empty.
151      */
152     private Optional<Path> updateNonManoPathInHandler(final FileContentHandler handler, final NonManoType nonManoType,
153                                                       final Path nonManoOriginalFilePath) {
154         final Path fixedSourcePath = fixNonManoPath(nonManoOriginalFilePath);
155         final Map<String, byte[]> packageFileMap = handler.getFiles();
156         if (packageFileMap.containsKey(fixedSourcePath.toString())) {
157             final Path newNonManoPath = Paths.get(nonManoType.getType(), nonManoType.getLocation()
158                 , fixedSourcePath.getFileName().toString());
159             if (!packageFileMap.containsKey(newNonManoPath.toString())) {
160                 packageFileMap.put(newNonManoPath.toString(), packageFileMap.remove(fixedSourcePath.toString()));
161                 return Optional.of(newNonManoPath);
162             }
163         }
164
165         return Optional.empty();
166     }
167
168     /**
169      * Fix the original non mano file path to the ONAP package file path.
170      *
171      * Non mano artifacts that were inside the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} path
172      * are not moved when parsed to ONAP package, but the Manifest declaration can still have the {@link
173      * org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} reference in it. If so, that reference is removed.
174      *
175      * @param nonManoOriginalFilePath The original non mano file path
176      * @return The non mano fixed path to ONAP package structure.
177      */
178     private Path fixNonManoPath(final Path nonManoOriginalFilePath) {
179         final Path rootArtifactsPath = Paths.get("/", ARTIFACTS_FOLDER);
180         if (nonManoOriginalFilePath.startsWith(rootArtifactsPath)) {
181             return rootArtifactsPath.relativize(nonManoOriginalFilePath);
182         }
183         final Path relativeArtifactsPath = Paths.get(ARTIFACTS_FOLDER);
184         if (nonManoOriginalFilePath.startsWith(relativeArtifactsPath)) {
185             return relativeArtifactsPath.relativize(nonManoOriginalFilePath);
186         }
187
188         return nonManoOriginalFilePath;
189     }
190
191     @Override
192     public void updateMainDescriptorPaths(final ToscaServiceModel toscaServiceModel,
193                                           final Map<String, Path> fromToMovedArtifactMap) {
194         final ServiceTemplate entryDefinition = toscaServiceModel.getServiceTemplates()
195             .get(toscaServiceModel.getEntryDefinitionServiceTemplate());
196         final YamlUtil yamlUtil = new YamlUtil();
197         final String[] entryDefinitionYaml = {yamlUtil.objectToYaml(entryDefinition)};
198         fromToMovedArtifactMap.forEach((fromPath, toPath) -> entryDefinitionYaml[0] = entryDefinitionYaml[0]
199             .replaceAll(fromPath, toPath.toString()));
200
201         toscaServiceModel.addServiceTemplate(toscaServiceModel.getEntryDefinitionServiceTemplate()
202             , yamlUtil.yamlToObject(entryDefinitionYaml[0], ServiceTemplate.class));
203     }
204
205     private boolean hasMetaMandatoryEntries(final ToscaMetadata toscaMetadata) {
206         final Map<String, String> metaDataEntries = toscaMetadata.getMetaEntries();
207         return metaDataEntries.containsKey(TOSCA_META_ENTRY_DEFINITIONS) && metaDataEntries
208             .containsKey(TOSCA_META_ETSI_ENTRY_MANIFEST)
209             && metaDataEntries.containsKey(TOSCA_META_ETSI_ENTRY_CHANGE_LOG);
210     }
211
212     private boolean isMetaFilePresent(Map<String, byte[]> handler) {
213         return handler.containsKey(TOSCA_META_PATH_FILE_NAME) || handler.containsKey(TOSCA_META_ORIG_PATH_FILE_NAME);
214     }
215
216     public ResourceTypeEnum getResourceType(FileContentHandler handler) throws IOException {
217         ToscaMetadata metadata = getMetadata(handler);
218         Manifest manifest = getManifest(handler, metadata.getMetaEntries().get(TOSCA_META_ETSI_ENTRY_MANIFEST));
219         return getResourceType(manifest);
220     }
221
222     public ResourceTypeEnum getResourceType(Manifest manifest) {
223         // Valid manifest should contain whether vnf or pnf related metadata data exclusively in SOL004 standard,
224         // validation of manifest done during package upload stage
225         if (manifest != null && !manifest.getMetadata().isEmpty()
226             && MANIFEST_PNF_METADATA.stream().anyMatch(e -> manifest.getMetadata().containsKey(e))) {
227             return ResourceTypeEnum.PNF;
228         }
229         // VNF is default resource type
230         return ResourceTypeEnum.VF;
231     }
232
233     public Manifest getManifest(FileContentHandler handler) throws IOException {
234         ToscaMetadata metadata = getMetadata(handler);
235         return getManifest(handler, metadata.getMetaEntries().get(TOSCA_META_ETSI_ENTRY_MANIFEST));
236     }
237
238     private Manifest getManifest(FileContentHandler handler, String manifestLocation) throws IOException {
239         try (InputStream manifestInputStream = getManifestInputStream(handler, manifestLocation)) {
240             Manifest onboardingManifest = new SOL004ManifestOnboarding();
241             onboardingManifest.parse(manifestInputStream);
242             return onboardingManifest;
243         }
244     }
245
246     public Path getOriginalManifestPath(final FileContentHandler handler) throws IOException {
247         final ToscaMetadata metadata = getOriginalMetadata(handler);
248         final String originalMetadataPath = metadata.getMetaEntries().get(TOSCA_META_ETSI_ENTRY_MANIFEST);
249         final Path path = Paths.get(originalMetadataPath);
250         return path.getParent() == null ? Paths.get("") : path.getParent();
251     }
252
253     private ToscaMetadata getMetadata(FileContentHandler handler) throws IOException {
254         ToscaMetadata metadata;
255         if (handler.containsFile(TOSCA_META_PATH_FILE_NAME)) {
256             metadata = OnboardingToscaMetadata
257                 .parseToscaMetadataFile(handler.getFileContent(TOSCA_META_PATH_FILE_NAME));
258         } else if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
259             metadata = OnboardingToscaMetadata
260                 .parseToscaMetadataFile(handler.getFileContent(TOSCA_META_ORIG_PATH_FILE_NAME));
261         } else {
262             throw new IOException("TOSCA.meta file not found!");
263         }
264         return metadata;
265     }
266
267     private ToscaMetadata getOriginalMetadata(final FileContentHandler handler) throws IOException {
268         if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
269             return OnboardingToscaMetadata
270                 .parseToscaMetadataFile(handler.getFileContent(TOSCA_META_ORIG_PATH_FILE_NAME));
271         } else {
272             throw new IOException(String.format("%s file not found", TOSCA_META_ORIG_PATH_FILE_NAME));
273         }
274     }
275
276     private InputStream getManifestInputStream(FileContentHandler handler, String manifestLocation) throws IOException {
277         InputStream io;
278         if (manifestLocation == null || !handler.containsFile(manifestLocation)) {
279             io = handler.getFileContent(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME);
280         } else {
281             io = handler.getFileContent(manifestLocation);
282         }
283
284         if (io == null) {
285             throw new IOException("Manifest file not found!");
286         }
287         return io;
288     }
289 }