2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.etsi;
22 import static org.openecomp.sdc.tosca.csar.CSARConstants.ARTIFACTS_FOLDER;
23 import static org.openecomp.sdc.tosca.csar.CSARConstants.ETSI_VERSION_2_6_1;
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.ManifestTokenType.COMPATIBLE_SPECIFICATION_VERSIONS;
28 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ENTRY_DEFINITIONS;
29 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_CHANGE_LOG;
30 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_MANIFEST;
31 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_PATH_FILE_NAME;
33 import com.vdurmont.semver4j.Semver;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.nio.file.Path;
37 import java.nio.file.Paths;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.List;
42 import java.util.Objects;
43 import java.util.Optional;
44 import java.util.stream.Collectors;
45 import org.apache.commons.collections.MapUtils;
46 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
47 import org.onap.sdc.tosca.services.YamlUtil;
48 import org.openecomp.core.utilities.file.FileContentHandler;
49 import org.openecomp.sdc.be.config.NonManoArtifactType;
50 import org.openecomp.sdc.be.config.NonManoConfiguration;
51 import org.openecomp.sdc.be.config.NonManoConfigurationManager;
52 import org.openecomp.sdc.be.config.NonManoFolderType;
53 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
54 import org.openecomp.sdc.logging.api.Logger;
55 import org.openecomp.sdc.logging.api.LoggerFactory;
56 import org.openecomp.sdc.tosca.csar.Manifest;
57 import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata;
58 import org.openecomp.sdc.tosca.csar.SOL004ManifestOnboarding;
59 import org.openecomp.sdc.tosca.csar.ToscaMetadata;
60 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
62 public class ETSIServiceImpl implements ETSIService {
64 private static final Logger LOGGER = LoggerFactory.getLogger(ETSIServiceImpl.class);
65 private final NonManoConfiguration nonManoConfiguration;
67 public ETSIServiceImpl() {
68 nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
71 public ETSIServiceImpl(final NonManoConfiguration nonManoConfiguration) {
72 this.nonManoConfiguration = nonManoConfiguration;
76 public boolean isSol004WithToscaMetaDirectory(FileContentHandler handler) throws IOException {
77 final Map<String, byte[]> templates = handler.getFiles();
78 return isMetaFilePresent(templates) && hasMetaMandatoryEntries(getMetadata(handler));
82 public Optional<Map<String, Path>> moveNonManoFileToArtifactFolder(final FileContentHandler handler) throws IOException {
83 final Manifest manifest = loadManifest(handler);
84 final Path originalManifestPath;
86 originalManifestPath = getOriginalManifestPath(handler);
87 } catch (final IOException ex) {
88 if (LOGGER.isErrorEnabled()) {
89 LOGGER.error("An error occurred while getting the original manifest path", ex);
93 final Map<String, Path> fromToPathMap = new HashMap<>();
94 final Map<String, NonManoFolderType> nonManoKeyFolderMapping = nonManoConfiguration.getNonManoKeyFolderMapping();
95 manifest.getNonManoSources().entrySet().stream()
96 .filter(manifestNonManoSourceEntry -> nonManoKeyFolderMapping.containsKey(manifestNonManoSourceEntry.getKey()))
97 .forEach(manifestNonManoSourceEntry -> {
98 final NonManoFolderType nonManoFolderType = nonManoKeyFolderMapping.get(manifestNonManoSourceEntry.getKey());
99 final List<String> nonManoFileList = manifestNonManoSourceEntry.getValue();
100 final Map<String, Path> actualFromToPathMap = nonManoFileList.stream().map(nonManoFilePath -> {
101 final Path normalizedFilePath = resolveNonManoFilePath(originalManifestPath, nonManoFilePath);
102 final Optional<Path> changedPath = updateNonManoPathInHandler(handler, nonManoFolderType, normalizedFilePath);
103 if (changedPath.isPresent()) {
104 final Map<String, Path> fromAndToPathMap = new HashMap<>();
105 fromAndToPathMap.put(nonManoFilePath, Paths.get(ARTIFACTS_FOLDER).resolve(changedPath.get()));
106 return fromAndToPathMap;
109 }).filter(Objects::nonNull).collect(Collectors.toMap(fromToPathEntry -> fromToPathEntry.keySet().iterator().next(),
110 fromToPathEntry -> fromToPathEntry.values().iterator().next()));
111 fromToPathMap.putAll(actualFromToPathMap);
113 return MapUtils.isEmpty(fromToPathMap) ? Optional.empty() : Optional.of(fromToPathMap);
117 * Resolves the non mano file path based on the original manifest path of the onboarded package.
119 * @param originalManifestPath The original path from the onboarded package manifest
120 * @param nonManoFilePath The non mano file path defined in the manifest
121 * @return The resolved and normalized non mano path.
123 private Path resolveNonManoFilePath(final Path originalManifestPath, final String nonManoFilePath) {
124 return originalManifestPath.resolve(Paths.get(nonManoFilePath)).normalize();
128 * Updates the non mano file path in the package file handler based on the non mano type.
130 * @param handler The package file handler
131 * @param nonManoFolderType The Non Mano type of the file to update
132 * @param nonManoOriginalFilePath The Non Mano file original path
133 * @return The new file path if it was updated in the package file handler, otherwise empty.
135 private Optional<Path> updateNonManoPathInHandler(final FileContentHandler handler, final NonManoFolderType nonManoFolderType,
136 final Path nonManoOriginalFilePath) {
137 final Path fixedSourcePath = fixNonManoPath(nonManoOriginalFilePath);
138 if (handler.containsFile(fixedSourcePath.toString())) {
139 final Path newNonManoPath = Paths
140 .get(nonManoFolderType.getType(), nonManoFolderType.getLocation(), fixedSourcePath.getFileName().toString());
141 if (!handler.containsFile(newNonManoPath.toString())) {
142 handler.addFile(newNonManoPath.toString(), handler.remove(fixedSourcePath.toString()));
143 return Optional.of(newNonManoPath);
146 return Optional.empty();
150 * Fix the original non mano file path to the ONAP package file path.
152 * Non mano artifacts that were inside the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} path are not moved when parsed to
153 * ONAP package, but the Manifest declaration can still have the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} reference in
154 * it. If so, that reference is removed.
156 * @param nonManoOriginalFilePath The original non mano file path
157 * @return The non mano fixed path to ONAP package structure.
159 private Path fixNonManoPath(final Path nonManoOriginalFilePath) {
160 final Path rootArtifactsPath = Paths.get("/", ARTIFACTS_FOLDER);
161 if (nonManoOriginalFilePath.startsWith(rootArtifactsPath)) {
162 return rootArtifactsPath.relativize(nonManoOriginalFilePath);
164 final Path relativeArtifactsPath = Paths.get(ARTIFACTS_FOLDER);
165 if (nonManoOriginalFilePath.startsWith(relativeArtifactsPath)) {
166 return relativeArtifactsPath.relativize(nonManoOriginalFilePath);
168 return nonManoOriginalFilePath;
172 public void updateMainDescriptorPaths(final ToscaServiceModel toscaServiceModel, final Map<String, Path> fromToMovedArtifactMap) {
173 final ServiceTemplate entryDefinition = toscaServiceModel.getServiceTemplates().get(toscaServiceModel.getEntryDefinitionServiceTemplate());
174 final YamlUtil yamlUtil = new YamlUtil();
175 final String[] entryDefinitionYaml = {yamlUtil.objectToYaml(entryDefinition)};
176 fromToMovedArtifactMap.forEach((fromPath, toPath) -> entryDefinitionYaml[0] = entryDefinitionYaml[0].replaceAll(fromPath, toPath.toString()));
177 toscaServiceModel.addServiceTemplate(toscaServiceModel.getEntryDefinitionServiceTemplate(),
178 yamlUtil.yamlToObject(entryDefinitionYaml[0], ServiceTemplate.class));
181 private boolean hasMetaMandatoryEntries(final ToscaMetadata toscaMetadata) {
182 final Map<String, String> metaDataEntries = toscaMetadata.getMetaEntries();
183 return metaDataEntries.containsKey(ENTRY_DEFINITIONS.getName()) && metaDataEntries.containsKey(ETSI_ENTRY_MANIFEST.getName())
184 && metaDataEntries.containsKey(ETSI_ENTRY_CHANGE_LOG.getName());
188 public Semver getHighestCompatibleSpecificationVersion(final FileContentHandler handler) {
190 Map<String, String> metadata = getManifest(handler).getMetadata();
191 if (metadata.containsKey(COMPATIBLE_SPECIFICATION_VERSIONS.getToken())) {
192 return Arrays.asList(metadata.get(COMPATIBLE_SPECIFICATION_VERSIONS.getToken()).split(",")).stream().map(Semver::new)
193 .max((v1, v2) -> v1.compareTo(v2)).orElse(new Semver(ETSI_VERSION_2_6_1));
195 } catch (Exception ex) {
196 LOGGER.error("An error occurred while getting highest compatible version from manifest file", ex);
198 return new Semver(ETSI_VERSION_2_6_1);
202 public boolean hasCnfEnhancements(final FileContentHandler fileContentHandler) throws IOException {
203 final Manifest manifest = loadManifest(fileContentHandler);
204 return manifest.getNonManoSources().entrySet().stream()
205 .filter(manifestNonManoSourceEntry -> NonManoArtifactType.ONAP_CNF_HELM.getType().equalsIgnoreCase(manifestNonManoSourceEntry.getKey()))
206 .findFirst().isPresent();
209 private Manifest loadManifest(final FileContentHandler handler) throws IOException {
210 final Manifest manifest;
212 manifest = getManifest(handler);
213 } catch (final IOException ex) {
214 if (LOGGER.isErrorEnabled()) {
215 LOGGER.error("An error occurred while getting the manifest file", ex);
222 private boolean isMetaFilePresent(Map<String, byte[]> handler) {
223 return handler.containsKey(TOSCA_META_PATH_FILE_NAME) || handler.containsKey(TOSCA_META_ORIG_PATH_FILE_NAME);
226 public ResourceTypeEnum getResourceType(FileContentHandler handler) throws IOException {
227 ToscaMetadata metadata = getMetadata(handler);
228 Manifest manifest = getManifest(handler, metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()));
229 return getResourceType(manifest);
232 public ResourceTypeEnum getResourceType(Manifest manifest) {
233 // Valid manifest should contain whether vnf or pnf related metadata data exclusively in SOL004 standard,
235 // validation of manifest done during package upload stage
236 if (manifest != null && !manifest.getMetadata().isEmpty() && MANIFEST_PNF_METADATA.stream()
237 .anyMatch(e -> manifest.getMetadata().containsKey(e))) {
238 return ResourceTypeEnum.PNF;
240 // VNF is default resource type
241 return ResourceTypeEnum.VF;
244 public Manifest getManifest(FileContentHandler handler) throws IOException {
245 ToscaMetadata metadata = getMetadata(handler);
246 return getManifest(handler, metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()));
249 private Manifest getManifest(FileContentHandler handler, String manifestLocation) throws IOException {
250 try (InputStream manifestInputStream = getManifestInputStream(handler, manifestLocation)) {
251 Manifest onboardingManifest = new SOL004ManifestOnboarding();
252 onboardingManifest.parse(manifestInputStream);
253 return onboardingManifest;
257 public Path getOriginalManifestPath(final FileContentHandler handler) throws IOException {
258 final ToscaMetadata metadata = getOriginalMetadata(handler);
259 final String originalMetadataPath = metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName());
260 final Path path = Paths.get(originalMetadataPath);
261 return path.getParent() == null ? Paths.get("") : path.getParent();
264 private ToscaMetadata getMetadata(FileContentHandler handler) throws IOException {
265 ToscaMetadata metadata;
266 if (handler.containsFile(TOSCA_META_PATH_FILE_NAME)) {
267 metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
268 } else if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
269 metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
271 throw new IOException("TOSCA.meta file not found!");
276 private ToscaMetadata getOriginalMetadata(final FileContentHandler handler) throws IOException {
277 if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
278 return OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
280 throw new IOException(String.format("%s file not found", TOSCA_META_ORIG_PATH_FILE_NAME));
284 private InputStream getManifestInputStream(FileContentHandler handler, String manifestLocation) throws IOException {
286 if (manifestLocation == null || !handler.containsFile(manifestLocation)) {
287 io = handler.getFileContentAsStream(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME);
289 io = handler.getFileContentAsStream(manifestLocation);
292 throw new IOException("Manifest file not found!");
297 public NonManoConfiguration getConfiguration() {
298 return nonManoConfiguration;