2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2020 Nordix Foundation.
 
   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.parser;
 
  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.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.nsd.FileEntry;
 
  35 import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.nsd.NetworkServiceDescriptor;
 
  36 import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.nsd.ToscaMetadata;
 
  37 import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.nsd.VirtualNetworkFunction;
 
  38 import org.slf4j.Logger;
 
  39 import org.slf4j.LoggerFactory;
 
  40 import org.springframework.beans.factory.annotation.Autowired;
 
  41 import org.springframework.stereotype.Service;
 
  44  * @author Waqas Ikram (waqas.ikram@est.tech)
 
  48 public class NetworkServiceDescriptorParser {
 
  49     public static final String NS_NODE_TYPE = "tosca.nodes.nfv.NS";
 
  50     private static final String NODE_TYPE = "node_type";
 
  51     private static final String SUBSTITUTION_MAPPINGS = "substitution_mappings";
 
  52     private static final Logger logger = LoggerFactory.getLogger(NetworkServiceDescriptorParser.class);
 
  53     private static final String VNF_TYPE = "tosca.nodes.nfv.VNF";
 
  54     private static final String PROPERTIES = "properties";
 
  55     private static final String TYPE = "type";
 
  56     private static final String NODE_TEMPLATES = "node_templates";
 
  57     private static final String TOPOLOGY_TEMPLATE = "topology_template";
 
  58     private static final String ENTRY_DEFINITIONS = "Entry-Definitions";
 
  59     private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta";
 
  60     private final ToscaMetadataParser toscaMetadataParser;
 
  61     private final FileParser fileParser;
 
  64     public NetworkServiceDescriptorParser(final ToscaMetadataParser toscaMetadataParser, final FileParser fileParser) {
 
  65         this.toscaMetadataParser = toscaMetadataParser;
 
  66         this.fileParser = fileParser;
 
  69     public Optional<NetworkServiceDescriptor> parse(final byte[] zipBytes) {
 
  71             final Map<String, FileEntry> files = getZipContent(zipBytes);
 
  72             if (isMetaFilePresent(files)) {
 
  73                 final Optional<ToscaMetadata> optional =
 
  74                         toscaMetadataParser.parse(files.get(TOSCA_META_PATH_FILE_NAME));
 
  75                 if (optional.isPresent()) {
 
  76                     final ToscaMetadata toscaMetadata = optional.get();
 
  77                     logger.info("Parsed ToscaMetadata {}", toscaMetadata);
 
  78                     final String entryDefinitionFile = toscaMetadata.getEntry(ENTRY_DEFINITIONS);
 
  79                     if (entryDefinitionFile != null && files.containsKey(entryDefinitionFile)) {
 
  80                         final Map<String, Object> fileContent =
 
  81                                 fileParser.getFileContent(files.get(entryDefinitionFile));
 
  82                         final Map<String, Object> topologyTemplates = getTopologyTemplates(fileContent);
 
  83                         final Map<String, Object> nodeTemplates = getNodeTemplates(topologyTemplates);
 
  85                         final Optional<NetworkServiceDescriptor> nsdOptional =
 
  86                                 getNetworkServiceDescriptor(topologyTemplates);
 
  87                         if (nsdOptional.isPresent()) {
 
  88                             final NetworkServiceDescriptor networkServiceDescriptor = nsdOptional.get();
 
  89                             networkServiceDescriptor.setVnfs(getVirtualNetworkFunctions(nodeTemplates));
 
  90                             return Optional.of(networkServiceDescriptor);
 
  98             logger.error("Unable to find {} file in {}", TOSCA_META_PATH_FILE_NAME, files);
 
  99         } catch (final Exception exception) {
 
 100             logger.error("Unable to parse nsd zip content", exception);
 
 102         return Optional.empty();
 
 105     @SuppressWarnings("unchecked")
 
 106     private Optional<NetworkServiceDescriptor> getNetworkServiceDescriptor(
 
 107             final Map<String, Object> topologyTemplates) {
 
 108         final Map<String, Object> substitutionMappings =
 
 109                 (Map<String, Object>) topologyTemplates.get(SUBSTITUTION_MAPPINGS);
 
 110         final Object nodeType = substitutionMappings.get(NODE_TYPE);
 
 111         if (substitutionMappings != null && NS_NODE_TYPE.equals(nodeType)) {
 
 112             final NetworkServiceDescriptor networkServiceDescriptor = new NetworkServiceDescriptor();
 
 113             networkServiceDescriptor.setType(nodeType.toString());
 
 114             networkServiceDescriptor.setProperties((Map<String, Object>) substitutionMappings.get(PROPERTIES));
 
 115             return Optional.of(networkServiceDescriptor);
 
 117         logger.error("No {} found in fileContent: {}", SUBSTITUTION_MAPPINGS, topologyTemplates);
 
 119         return Optional.empty();
 
 122     private List<VirtualNetworkFunction> getVirtualNetworkFunctions(final Map<String, Object> nodeTemplates) {
 
 123         final List<VirtualNetworkFunction> vnfs = new ArrayList<>();
 
 124         for (final Entry<String, Object> entry : nodeTemplates.entrySet()) {
 
 125             @SuppressWarnings("unchecked")
 
 126             final Map<String, Object> entryValue = (Map<String, Object>) entry.getValue();
 
 127             final Object type = entryValue.get(TYPE);
 
 128             if (type != null && type.equals(VNF_TYPE)) {
 
 129                 @SuppressWarnings("unchecked")
 
 130                 final Map<String, Object> vnfProperties = (Map<String, Object>) entryValue.get(PROPERTIES);
 
 131                 final VirtualNetworkFunction vnf = new VirtualNetworkFunction();
 
 132                 vnf.setVnfName(entry.getKey());
 
 134                 if (vnfProperties != null && !vnfProperties.isEmpty()) {
 
 135                     final Object vnfDescriptorId = vnfProperties.get("descriptor_id");
 
 136                     @SuppressWarnings("unchecked")
 
 137                     final List<String> vnfmInfoList = (List<String>) vnfProperties.get("vnfm_info");
 
 138                     if (vnfDescriptorId != null && vnfmInfoList != null) {
 
 139                         vnf.setVnfmInfoList(vnfmInfoList);
 
 140                         vnf.setVnfdId(vnfDescriptorId.toString());
 
 141                         vnf.setProperties(vnfProperties);
 
 144                         logger.warn("descriptor_id missing {}", entryValue);
 
 153     private Map<String, Object> getNodeTemplates(final Map<String, Object> topologyTemplates) {
 
 154         @SuppressWarnings("unchecked")
 
 155         final Map<String, Object> nodeTemplates = (Map<String, Object>) topologyTemplates.get(NODE_TEMPLATES);
 
 156         if (nodeTemplates != null) {
 
 157             logger.debug("Found nodeTemplates: {}", topologyTemplates);
 
 158             return nodeTemplates;
 
 160         logger.error("No {} found in fileContent: {}", NODE_TEMPLATES, topologyTemplates);
 
 161         return Collections.emptyMap();
 
 164     private Map<String, Object> getTopologyTemplates(final Map<String, Object> fileContent) {
 
 165         @SuppressWarnings("unchecked")
 
 166         final Map<String, Object> topologyTemplates = (Map<String, Object>) fileContent.get(TOPOLOGY_TEMPLATE);
 
 167         if (topologyTemplates != null) {
 
 168             logger.debug("Found {}: {}", TOPOLOGY_TEMPLATE, topologyTemplates);
 
 170             return topologyTemplates;
 
 172         logger.error("No {} found in fileContent: {}", TOPOLOGY_TEMPLATE, fileContent);
 
 173         return Collections.emptyMap();
 
 176     private boolean isMetaFilePresent(final Map<String, FileEntry> files) {
 
 177         return files.containsKey(TOSCA_META_PATH_FILE_NAME);
 
 180     private Map<String, FileEntry> getZipContent(final byte[] zipBytes) {
 
 181         final Map<String, FileEntry> files = new HashMap<>();
 
 182         try (final ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(zipBytes));) {
 
 184             while ((zipEntry = inputZipStream.getNextEntry()) != null) {
 
 185                 logger.info("{} : {}", zipEntry.getName(), zipEntry.isDirectory());
 
 186                 if (files.get(zipEntry.getName()) != null) {
 
 187                     logger.warn("{} File entry already exists ...", zipEntry.getName());
 
 189                     final FileEntry fileEntry = new FileEntry().filePath(zipEntry.getName())
 
 190                             .fileContent(getBytes(inputZipStream)).isDirectory(zipEntry.isDirectory());
 
 191                     files.put(zipEntry.getName(), fileEntry);
 
 197         } catch (final Exception exception) {
 
 198             logger.error("Unable to parse nsd zip content", exception);
 
 199             return Collections.emptyMap();
 
 203     private byte[] getBytes(final ZipInputStream inputZipStream) throws IOException {
 
 205             return IOUtils.toByteArray(inputZipStream);
 
 206         } catch (final IOException exception) {
 
 207             logger.error("Could not read bytes from file", exception);