1281d611cb8d66f6a90c13644f23508701903e14
[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_ORIG_PATH_FILE_NAME;
27 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ENTRY_DEFINITIONS;
28 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ETSI_ENTRY_CHANGE_LOG;
29 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ETSI_ENTRY_MANIFEST;
30 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_PATH_FILE_NAME;
31
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.nio.file.Path;
35 import java.nio.file.Paths;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.Optional;
41 import java.util.stream.Collectors;
42 import org.apache.commons.collections.MapUtils;
43 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
44 import org.onap.sdc.tosca.services.YamlUtil;
45 import org.openecomp.core.utilities.file.FileContentHandler;
46 import org.openecomp.sdc.be.config.NonManoConfiguration;
47 import org.openecomp.sdc.be.config.NonManoConfigurationManager;
48 import org.openecomp.sdc.be.config.NonManoFolderType;
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 final NonManoConfiguration nonManoConfiguration;
63
64     public ETSIServiceImpl() {
65         nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
66     }
67
68     public ETSIServiceImpl(final NonManoConfiguration nonManoConfiguration) {
69         this.nonManoConfiguration = nonManoConfiguration;
70     }
71
72     @Override
73     public boolean isSol004WithToscaMetaDirectory(FileContentHandler handler) throws IOException {
74         final Map<String, byte[]> templates = handler.getFiles();
75         return isMetaFilePresent(templates) && hasMetaMandatoryEntries(getMetadata(handler));
76     }
77
78     @Override
79     public Optional<Map<String, Path>> moveNonManoFileToArtifactFolder(final FileContentHandler handler) throws IOException {
80         final Manifest manifest;
81         try {
82             manifest = getManifest(handler);
83         } catch (final IOException ex) {
84             if (LOGGER.isErrorEnabled()) {
85                 LOGGER.error("An error occurred while getting the manifest file", ex);
86             }
87             throw ex;
88         }
89         final Path originalManifestPath;
90         try {
91             originalManifestPath = getOriginalManifestPath(handler);
92         } catch (final IOException ex) {
93             if (LOGGER.isErrorEnabled()) {
94                 LOGGER.error("An error occurred while getting the original manifest path", ex);
95             }
96             throw ex;
97         }
98         final Map<String, Path> fromToPathMap = new HashMap<>();
99         final Map<String, NonManoFolderType> nonManoKeyFolderMapping = nonManoConfiguration.getNonManoKeyFolderMapping();
100         manifest.getNonManoSources().entrySet().stream()
101             .filter(manifestNonManoSourceEntry -> nonManoKeyFolderMapping.containsKey(manifestNonManoSourceEntry.getKey()))
102             .forEach(manifestNonManoSourceEntry -> {
103                 final NonManoFolderType nonManoFolderType = nonManoKeyFolderMapping.get(manifestNonManoSourceEntry.getKey());
104                 final List<String> nonManoFileList = manifestNonManoSourceEntry.getValue();
105                 final Map<String, Path> actualFromToPathMap = nonManoFileList.stream()
106                     .map(nonManoFilePath -> {
107                         final Path normalizedFilePath = resolveNonManoFilePath(originalManifestPath, nonManoFilePath);
108                         final Optional<Path> changedPath = updateNonManoPathInHandler(handler, nonManoFolderType, normalizedFilePath);
109                         if (changedPath.isPresent()) {
110                             final Map<String, Path> fromAndToPathMap = new HashMap<>();
111                             fromAndToPathMap.put(nonManoFilePath, Paths.get(ARTIFACTS_FOLDER).resolve(changedPath.get()));
112                             return fromAndToPathMap;
113                         }
114                         return null;
115                     })
116                     .filter(Objects::nonNull)
117                     .collect(Collectors.toMap(
118                         fromToPathEntry -> fromToPathEntry.keySet().iterator().next(),
119                         fromToPathEntry -> fromToPathEntry.values().iterator().next()
120                     ));
121                 fromToPathMap.putAll(actualFromToPathMap);
122             });
123
124         return MapUtils.isEmpty(fromToPathMap) ? Optional.empty() : Optional.of(fromToPathMap);
125     }
126
127     /**
128      * Resolves the non mano file path based on the original manifest path of the onboarded package.
129      *
130      * @param originalManifestPath The original path from the onboarded package manifest
131      * @param nonManoFilePath The non mano file path defined in the manifest
132      * @return The resolved and normalized non mano path.
133      */
134     private Path resolveNonManoFilePath(final Path originalManifestPath, final String nonManoFilePath) {
135         return originalManifestPath.resolve(Paths.get(nonManoFilePath)).normalize();
136     }
137
138     /**
139      * Updates the non mano file path in the package file handler based on the non mano type.
140      *
141      * @param handler The package file handler
142      * @param nonManoFolderType The Non Mano type of the file to update
143      * @param nonManoOriginalFilePath The Non Mano file original path
144      * @return The new file path if it was updated in the package file handler, otherwise empty.
145      */
146     private Optional<Path> updateNonManoPathInHandler(final FileContentHandler handler, final NonManoFolderType nonManoFolderType,
147                                                       final Path nonManoOriginalFilePath) {
148         final Path fixedSourcePath = fixNonManoPath(nonManoOriginalFilePath);
149         if (handler.containsFile(fixedSourcePath.toString())) {
150             final Path newNonManoPath = Paths.get(nonManoFolderType.getType(), nonManoFolderType.getLocation()
151                 , fixedSourcePath.getFileName().toString());
152             if (!handler.containsFile(newNonManoPath.toString())) {
153                 handler.addFile(newNonManoPath.toString(), handler.remove(fixedSourcePath.toString()));
154                 return Optional.of(newNonManoPath);
155             }
156         }
157
158         return Optional.empty();
159     }
160
161     /**
162      * Fix the original non mano file path to the ONAP package file path.
163      *
164      * Non mano artifacts that were inside the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} path
165      * are not moved when parsed to ONAP package, but the Manifest declaration can still have the {@link
166      * org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} reference in it. If so, that reference is removed.
167      *
168      * @param nonManoOriginalFilePath The original non mano file path
169      * @return The non mano fixed path to ONAP package structure.
170      */
171     private Path fixNonManoPath(final Path nonManoOriginalFilePath) {
172         final Path rootArtifactsPath = Paths.get("/", ARTIFACTS_FOLDER);
173         if (nonManoOriginalFilePath.startsWith(rootArtifactsPath)) {
174             return rootArtifactsPath.relativize(nonManoOriginalFilePath);
175         }
176         final Path relativeArtifactsPath = Paths.get(ARTIFACTS_FOLDER);
177         if (nonManoOriginalFilePath.startsWith(relativeArtifactsPath)) {
178             return relativeArtifactsPath.relativize(nonManoOriginalFilePath);
179         }
180
181         return nonManoOriginalFilePath;
182     }
183
184     @Override
185     public void updateMainDescriptorPaths(final ToscaServiceModel toscaServiceModel,
186                                           final Map<String, Path> fromToMovedArtifactMap) {
187         final ServiceTemplate entryDefinition = toscaServiceModel.getServiceTemplates()
188             .get(toscaServiceModel.getEntryDefinitionServiceTemplate());
189         final YamlUtil yamlUtil = new YamlUtil();
190         final String[] entryDefinitionYaml = {yamlUtil.objectToYaml(entryDefinition)};
191         fromToMovedArtifactMap.forEach((fromPath, toPath) -> entryDefinitionYaml[0] = entryDefinitionYaml[0]
192             .replaceAll(fromPath, toPath.toString()));
193
194         toscaServiceModel.addServiceTemplate(toscaServiceModel.getEntryDefinitionServiceTemplate()
195             , yamlUtil.yamlToObject(entryDefinitionYaml[0], ServiceTemplate.class));
196     }
197
198     private boolean hasMetaMandatoryEntries(final ToscaMetadata toscaMetadata) {
199         final Map<String, String> metaDataEntries = toscaMetadata.getMetaEntries();
200         return metaDataEntries.containsKey(ENTRY_DEFINITIONS.getName()) && metaDataEntries
201             .containsKey(ETSI_ENTRY_MANIFEST.getName())
202             && metaDataEntries.containsKey(ETSI_ENTRY_CHANGE_LOG.getName());
203     }
204
205     private boolean isMetaFilePresent(Map<String, byte[]> handler) {
206         return handler.containsKey(TOSCA_META_PATH_FILE_NAME) || handler.containsKey(TOSCA_META_ORIG_PATH_FILE_NAME);
207     }
208
209     public ResourceTypeEnum getResourceType(FileContentHandler handler) throws IOException {
210         ToscaMetadata metadata = getMetadata(handler);
211         Manifest manifest = getManifest(handler, metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()));
212         return getResourceType(manifest);
213     }
214
215     public ResourceTypeEnum getResourceType(Manifest manifest) {
216         // Valid manifest should contain whether vnf or pnf related metadata data exclusively in SOL004 standard,
217         // validation of manifest done during package upload stage
218         if (manifest != null && !manifest.getMetadata().isEmpty()
219             && MANIFEST_PNF_METADATA.stream().anyMatch(e -> manifest.getMetadata().containsKey(e))) {
220             return ResourceTypeEnum.PNF;
221         }
222         // VNF is default resource type
223         return ResourceTypeEnum.VF;
224     }
225
226     public Manifest getManifest(FileContentHandler handler) throws IOException {
227         ToscaMetadata metadata = getMetadata(handler);
228         return getManifest(handler, metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()));
229     }
230
231     private Manifest getManifest(FileContentHandler handler, String manifestLocation) throws IOException {
232         try (InputStream manifestInputStream = getManifestInputStream(handler, manifestLocation)) {
233             Manifest onboardingManifest = new SOL004ManifestOnboarding();
234             onboardingManifest.parse(manifestInputStream);
235             return onboardingManifest;
236         }
237     }
238
239     public Path getOriginalManifestPath(final FileContentHandler handler) throws IOException {
240         final ToscaMetadata metadata = getOriginalMetadata(handler);
241         final String originalMetadataPath = metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName());
242         final Path path = Paths.get(originalMetadataPath);
243         return path.getParent() == null ? Paths.get("") : path.getParent();
244     }
245
246     private ToscaMetadata getMetadata(FileContentHandler handler) throws IOException {
247         ToscaMetadata metadata;
248         if (handler.containsFile(TOSCA_META_PATH_FILE_NAME)) {
249             metadata = OnboardingToscaMetadata
250                 .parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
251         } else if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
252             metadata = OnboardingToscaMetadata
253                 .parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
254         } else {
255             throw new IOException("TOSCA.meta file not found!");
256         }
257         return metadata;
258     }
259
260     private ToscaMetadata getOriginalMetadata(final FileContentHandler handler) throws IOException {
261         if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
262             return OnboardingToscaMetadata
263                 .parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
264         } else {
265             throw new IOException(String.format("%s file not found", TOSCA_META_ORIG_PATH_FILE_NAME));
266         }
267     }
268
269     private InputStream getManifestInputStream(FileContentHandler handler, String manifestLocation) throws IOException {
270         InputStream io;
271         if (manifestLocation == null || !handler.containsFile(manifestLocation)) {
272             io = handler.getFileContentAsStream(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME);
273         } else {
274             io = handler.getFileContentAsStream(manifestLocation);
275         }
276
277         if (io == null) {
278             throw new IOException("Manifest file not found!");
279         }
280         return io;
281     }
282
283     public NonManoConfiguration getConfiguration() {
284         return nonManoConfiguration;
285     }
286 }