2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2020 Ericsson. All rights reserved.
 
   4  * ================================================================================
 
   5  * Licensed under the Apache License, Version 2.0 (the "License");
 
   6  * you may not use this file except in compliance with the License.
 
   7  * You may obtain a copy of the License at
 
   9  *      http://www.apache.org/licenses/LICENSE-2.0
 
  11  * Unless required by applicable law or agreed to in writing, software
 
  12  * distributed under the License is distributed on an "AS IS" BASIS,
 
  13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  * See the License for the specific language governing permissions and
 
  15  * limitations under the License.
 
  17  * SPDX-License-Identifier: Apache-2.0
 
  18  * ============LICENSE_END=========================================================
 
  20 package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.nsd;
 
  22 import java.io.ByteArrayInputStream;
 
  23 import java.io.IOException;
 
  24 import java.util.ArrayList;
 
  25 import java.util.Collections;
 
  26 import java.util.HashMap;
 
  27 import java.util.List;
 
  29 import java.util.Map.Entry;
 
  30 import java.util.Optional;
 
  31 import java.util.zip.ZipEntry;
 
  32 import java.util.zip.ZipInputStream;
 
  33 import org.apache.commons.io.IOUtils;
 
  34 import org.slf4j.Logger;
 
  35 import org.slf4j.LoggerFactory;
 
  36 import org.springframework.beans.factory.annotation.Autowired;
 
  37 import org.springframework.stereotype.Service;
 
  40  * @author Waqas Ikram (waqas.ikram@est.tech)
 
  44 public class NetworkServiceDescriptorParser {
 
  45     public static final String NS_NODE_TYPE = "tosca.nodes.nfv.NS";
 
  46     private static final String NODE_TYPE = "node_type";
 
  47     private static final String SUBSTITUTION_MAPPINGS = "substitution_mappings";
 
  48     private static final Logger logger = LoggerFactory.getLogger(NetworkServiceDescriptorParser.class);
 
  49     private static final String VNF_TYPE = "tosca.nodes.nfv.VNF";
 
  50     private static final String PROPERTIES = "properties";
 
  51     private static final String TYPE = "type";
 
  52     private static final String NODE_TEMPLATES = "node_templates";
 
  53     private static final String TOPOLOGY_TEMPLATE = "topology_template";
 
  54     private static final String ENTRY_DEFINITIONS = "Entry-Definitions";
 
  55     private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta";
 
  56     private final ToscaMetadataParser toscaMetadataParser;
 
  57     private final FileParser fileParser;
 
  60     public NetworkServiceDescriptorParser(final ToscaMetadataParser toscaMetadataParser, final FileParser fileParser) {
 
  61         this.toscaMetadataParser = toscaMetadataParser;
 
  62         this.fileParser = fileParser;
 
  65     public Optional<NetworkServiceDescriptor> parser(final byte[] zipBytes) {
 
  67             final Map<String, FileEntry> files = getZipContent(zipBytes);
 
  68             if (isMetaFilePresent(files)) {
 
  69                 final Optional<ToscaMetadata> optional =
 
  70                         toscaMetadataParser.parse(files.get(TOSCA_META_PATH_FILE_NAME));
 
  71                 if (optional.isPresent()) {
 
  72                     final ToscaMetadata toscaMetadata = optional.get();
 
  73                     logger.info("Parsed ToscaMetadata {}", toscaMetadata);
 
  74                     final String entryDefinitionFile = toscaMetadata.getEntry(ENTRY_DEFINITIONS);
 
  75                     if (entryDefinitionFile != null && files.containsKey(entryDefinitionFile)) {
 
  76                         final Map<String, Object> fileContent =
 
  77                                 fileParser.getFileContent(files.get(entryDefinitionFile));
 
  78                         final Map<String, Object> topologyTemplates = getTopologyTemplates(fileContent);
 
  79                         final Map<String, Object> nodeTemplates = getNodeTemplates(topologyTemplates);
 
  81                         final Optional<NetworkServiceDescriptor> nsdOptional =
 
  82                                 getNetworkServiceDescriptor(topologyTemplates);;
 
  83                         if (nsdOptional.isPresent()) {
 
  84                             final NetworkServiceDescriptor networkServiceDescriptor = nsdOptional.get();
 
  85                             networkServiceDescriptor.setVnfs(getVirtualNetworkFunctions(nodeTemplates));
 
  86                             return Optional.of(networkServiceDescriptor);
 
  94         } catch (final Exception exception) {
 
  95             logger.error("Unable to parser nsd zip content", exception);
 
  97         logger.error("Unable to parser nsd zip content");
 
  98         return Optional.empty();
 
 101     @SuppressWarnings("unchecked")
 
 102     private Optional<NetworkServiceDescriptor> getNetworkServiceDescriptor(
 
 103             final Map<String, Object> topologyTemplates) {
 
 104         final Map<String, Object> substitutionMappings =
 
 105                 (Map<String, Object>) topologyTemplates.get(SUBSTITUTION_MAPPINGS);
 
 106         final Object nodeType = substitutionMappings.get(NODE_TYPE);
 
 107         if (substitutionMappings != null && nodeType != null && NS_NODE_TYPE.equals(nodeType)) {
 
 108             final NetworkServiceDescriptor networkServiceDescriptor = new NetworkServiceDescriptor();
 
 109             networkServiceDescriptor.setType(nodeType.toString());
 
 110             networkServiceDescriptor.setProperties((Map<String, Object>) substitutionMappings.get(PROPERTIES));
 
 111             return Optional.of(networkServiceDescriptor);
 
 113         logger.error("No {} found in fileContent: {}", SUBSTITUTION_MAPPINGS, topologyTemplates);
 
 115         return Optional.empty();
 
 118     private List<VirtualNetworkFunction> getVirtualNetworkFunctions(final Map<String, Object> nodeTemplates) {
 
 119         final List<VirtualNetworkFunction> vnfs = new ArrayList<>();
 
 120         for (final Entry<String, Object> entry : nodeTemplates.entrySet()) {
 
 121             @SuppressWarnings("unchecked")
 
 122             final Map<String, Object> entryValue = (Map<String, Object>) entry.getValue();
 
 123             final Object type = entryValue.get(TYPE);
 
 124             if (type != null && type.equals(VNF_TYPE)) {
 
 125                 @SuppressWarnings("unchecked")
 
 126                 final Map<String, Object> vnfProperties = (Map<String, Object>) entryValue.get(PROPERTIES);
 
 127                 final VirtualNetworkFunction vnf = new VirtualNetworkFunction();
 
 128                 vnf.setVnfName(entry.getKey());
 
 130                 if (vnfProperties != null && !vnfProperties.isEmpty()) {
 
 131                     final Object vnfDescriptorId = vnfProperties.get("descriptor_id");
 
 132                     @SuppressWarnings("unchecked")
 
 133                     final List<String> vnfmInfoList = (List<String>) vnfProperties.get("vnfm_info");
 
 134                     if (vnfDescriptorId != null && vnfmInfoList != null) {
 
 135                         vnf.setVnfmInfoList(vnfmInfoList);
 
 136                         vnf.setVnfdId(vnfDescriptorId.toString());
 
 137                         vnf.setProperties(vnfProperties);
 
 140                         logger.warn("descriptor_id missing {}", entryValue);
 
 149     private Map<String, Object> getNodeTemplates(final Map<String, Object> topologyTemplates) {
 
 150         @SuppressWarnings("unchecked")
 
 151         final Map<String, Object> nodeTemplates = (Map<String, Object>) topologyTemplates.get(NODE_TEMPLATES);
 
 152         if (nodeTemplates != null) {
 
 153             logger.debug("Found nodeTemplates: {}", topologyTemplates);
 
 154             return nodeTemplates;
 
 156         logger.error("No {} found in fileContent: {}", NODE_TEMPLATES, topologyTemplates);
 
 157         return Collections.emptyMap();
 
 160     private Map<String, Object> getTopologyTemplates(final Map<String, Object> fileContent) {
 
 161         @SuppressWarnings("unchecked")
 
 162         final Map<String, Object> topologyTemplates = (Map<String, Object>) fileContent.get(TOPOLOGY_TEMPLATE);
 
 163         if (topologyTemplates != null) {
 
 164             logger.debug("Found {}: {}", TOPOLOGY_TEMPLATE, topologyTemplates);
 
 166             return topologyTemplates;
 
 168         logger.error("No {} found in fileContent: {}", TOPOLOGY_TEMPLATE, fileContent);
 
 169         return Collections.emptyMap();
 
 172     private boolean isMetaFilePresent(final Map<String, FileEntry> files) {
 
 173         return files.containsKey(TOSCA_META_PATH_FILE_NAME);
 
 176     private Map<String, FileEntry> getZipContent(final byte[] zipBytes) {
 
 177         final Map<String, FileEntry> files = new HashMap<>();
 
 178         try (final ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(zipBytes));) {
 
 180             while ((zipEntry = inputZipStream.getNextEntry()) != null) {
 
 181                 logger.info("{} : {}", zipEntry.getName(), zipEntry.isDirectory());
 
 182                 if (files.get(zipEntry.getName()) != null) {
 
 183                     logger.warn("{} File entry already exists ...", zipEntry.getName());
 
 185                     final FileEntry fileEntry = new FileEntry().filePath(zipEntry.getName())
 
 186                             .fileContent(getBytes(inputZipStream)).isDirectory(zipEntry.isDirectory());
 
 187                     files.put(zipEntry.getName(), fileEntry);
 
 193         } catch (final Exception exception) {
 
 194             logger.error("Unable to parser nsd zip content", exception);
 
 195             return Collections.emptyMap();
 
 199     private byte[] getBytes(final ZipInputStream inputZipStream) throws IOException {
 
 201             return IOUtils.toByteArray(inputZipStream);
 
 202         } catch (final IOException exception) {
 
 203             logger.error("Could not read bytes from file", exception);