2  * ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2019 Nordix Foundation.
 
   4  * ================================================================================
 
   5  *  Modifications Copyright (c) 2019 Samsung
 
   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.
 
  19  * SPDX-License-Identifier: Apache-2.0
 
  20  * ============LICENSE_END=========================================================
 
  23 package org.onap.so.adapters.vnfmadapter.extclients;
 
  25 import static com.google.common.base.Splitter.on;
 
  26 import static com.google.common.collect.Iterables.filter;
 
  27 import static com.google.common.io.ByteStreams.toByteArray;
 
  28 import static java.lang.String.format;
 
  29 import static org.apache.http.HttpHeaders.ACCEPT;
 
  30 import static org.apache.http.HttpHeaders.AUTHORIZATION;
 
  31 import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.abortOperation;
 
  32 import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.child;
 
  33 import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.childElement;
 
  34 import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.children;
 
  35 import static org.slf4j.LoggerFactory.getLogger;
 
  36 import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
 
  37 import com.google.common.io.ByteStreams;
 
  38 import com.google.gson.Gson;
 
  39 import com.google.gson.JsonObject;
 
  40 import java.io.ByteArrayInputStream;
 
  41 import java.io.ByteArrayOutputStream;
 
  42 import java.io.IOException;
 
  43 import java.io.InputStream;
 
  44 import java.nio.charset.StandardCharsets;
 
  45 import java.util.HashSet;
 
  46 import java.util.Iterator;
 
  47 import java.util.List;
 
  48 import java.util.NoSuchElementException;
 
  50 import java.util.zip.ZipEntry;
 
  51 import java.util.zip.ZipInputStream;
 
  52 import org.apache.commons.codec.binary.Base64;
 
  53 import org.apache.http.HttpEntity;
 
  54 import org.apache.http.client.methods.CloseableHttpResponse;
 
  55 import org.apache.http.client.methods.HttpGet;
 
  56 import org.apache.http.impl.client.CloseableHttpClient;
 
  57 import org.apache.http.impl.client.HttpClients;
 
  58 import org.onap.so.utils.CryptoUtils;
 
  59 import org.slf4j.Logger;
 
  60 import org.springframework.beans.factory.annotation.Value;
 
  61 import org.springframework.stereotype.Component;
 
  62 import org.yaml.snakeyaml.Yaml;
 
  65 public class SdcPackageProvider {
 
  66     private static final String GET_PACKAGE_URL = "%s/sdc/v1/catalog/resources/%s/toscaModel";
 
  67     @Value("${sdc.toscametapath:TOSCA-Metadata/TOSCA.meta}")
 
  68     private List<String> toscaMetaPaths;
 
  69     private static final String TOSCA_VNFD_KEY = "Entry-Definitions";
 
  70     private static Logger logger = getLogger(SdcPackageProvider.class);
 
  72     @Value("${sdc.username}")
 
  73     private String sdcUsername;
 
  74     @Value("${sdc.password}")
 
  75     private String sdcPassword;
 
  77     private String sdcKey;
 
  78     @Value("${sdc.endpoint}")
 
  79     private String baseUrl;
 
  81     public String getVnfdId(final String csarId) {
 
  82         return getVnfNodeProperty(csarId, "descriptor_id");
 
  85     private String getVnfNodeProperty(final String csarId, final String propertyName) {
 
  86         logger.debug("Getting " + propertyName + " from " + csarId);
 
  87         final byte[] onapPackage = getPackage(csarId);
 
  90             final String vnfdLocation = getVnfdLocation(new ByteArrayInputStream(onapPackage));
 
  91             final String onapVnfdContent = getFileInZip(new ByteArrayInputStream(onapPackage), vnfdLocation).toString();
 
  92             final JsonObject root = new Gson().toJsonTree(new Yaml().load(onapVnfdContent)).getAsJsonObject();
 
  94             final JsonObject topologyTemplates = child(root, "topology_template");
 
  95             final JsonObject nodeTemplates = child(topologyTemplates, "node_templates");
 
  96             for (final JsonObject child : children(nodeTemplates)) {
 
  97                 final String type = childElement(child, "type").getAsString();
 
  98                 String propertyValue = null;
 
  99                 if ("tosca.nodes.nfv.VNF".equals(type)) {
 
 100                     final JsonObject properties = child(child, "properties");
 
 101                     logger.debug("properties: " + properties.toString());
 
 103                     propertyValue = properties.get(propertyName).getAsJsonPrimitive().getAsString();
 
 105                 if (propertyValue == null) {
 
 106                     propertyValue = getValueFromNodeTypeDefinition(root, type, propertyName);
 
 108                 return propertyValue;
 
 111         } catch (final Exception e) {
 
 112             throw new IllegalArgumentException("Unable to extract " + propertyName + " from ONAP package", e);
 
 114         throw new IllegalArgumentException("Unable to extract " + propertyName + " from ONAP package");
 
 117     private String getValueFromNodeTypeDefinition(final JsonObject root, final String nodeTypeName,
 
 118             final String propertyName) {
 
 119         final JsonObject nodeTypes = child(root, "node_types");
 
 120         final JsonObject nodeType = child(nodeTypes, nodeTypeName);
 
 122         if ("tosca.nodes.nfv.VNF".equals(childElement(nodeType, "derived_from").getAsString())) {
 
 123             final JsonObject properties = child(nodeType, "properties");
 
 124             logger.debug("properties: " + properties.toString());
 
 125             final JsonObject property = child(properties, propertyName);
 
 126             logger.debug("property: " + property.toString());
 
 127             logger.debug("property default: " + childElement(property, "default").toString());
 
 128             return childElement(property, "default").getAsJsonPrimitive().getAsString();
 
 133     private byte[] getPackage(final String csarId) {
 
 134         final String SERVICE_NAME = "vnfm-adapter";
 
 135         try (CloseableHttpClient client = HttpClients.createDefault()) {
 
 136             final HttpGet httpget = new HttpGet(format(GET_PACKAGE_URL, baseUrl, csarId));
 
 137             httpget.setHeader(ACCEPT, APPLICATION_OCTET_STREAM_VALUE);
 
 138             httpget.setHeader("X-ECOMP-InstanceID", SERVICE_NAME);
 
 139             httpget.setHeader("X-FromAppId", SERVICE_NAME);
 
 140             final String auth = sdcUsername + ":" + CryptoUtils.decrypt(sdcPassword, sdcKey);
 
 141             final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
 
 142             final String authHeader = "Basic " + new String(encodedAuth);
 
 143             httpget.setHeader(AUTHORIZATION, authHeader);
 
 144             logger.debug("Fetching from SDC: " + httpget);
 
 145             final CloseableHttpResponse response = client.execute(httpget);
 
 146             final HttpEntity entity = response.getEntity();
 
 147             final InputStream is = entity.getContent();
 
 148             return toByteArray(is);
 
 149         } catch (final Exception e) {
 
 150             throw abortOperation("Unable to download " + csarId + " package from SDC", e);
 
 154     private String getVnfdLocation(final InputStream stream) throws IOException {
 
 155         final Iterator<String> pathIterator = toscaMetaPaths.iterator();
 
 156         while (pathIterator.hasNext()) {
 
 157             final String toscaMetadata = new String(getFileInZip(stream, pathIterator.next()).toByteArray());
 
 158             if (!toscaMetadata.isEmpty()) {
 
 159                 final String toscaVnfdLine =
 
 160                         filter(on("\n").split(toscaMetadata), line -> line.contains(TOSCA_VNFD_KEY)).iterator().next();
 
 161                 return toscaVnfdLine.replace(TOSCA_VNFD_KEY + ":", "").trim();
 
 164         throw abortOperation("Unable to find valid Tosca Path");
 
 167     private static ByteArrayOutputStream getFileInZip(final InputStream zip, final String path) throws IOException {
 
 168         final ZipInputStream zipInputStream = new ZipInputStream(zip);
 
 169         final ByteArrayOutputStream fileContent = getFileInZip(zipInputStream, path);
 
 170         zipInputStream.close();
 
 174     private static ByteArrayOutputStream getFileInZip(final ZipInputStream zipInputStream, final String path)
 
 177         final Set<String> items = new HashSet<>();
 
 178         while ((zipEntry = zipInputStream.getNextEntry()) != null) {
 
 179             items.add(zipEntry.getName());
 
 180             if (zipEntry.getName().matches(path)) {
 
 181                 final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 
 182                 ByteStreams.copy(zipInputStream, byteArrayOutputStream);
 
 183                 return byteArrayOutputStream;
 
 186         logger.error("Unable to find the {} in archive found: {}", path, items);
 
 187         throw new NoSuchElementException("Unable to find the " + path + " in archive found: " + items);
 
 190     public String getFlavourId(final String csarId) {
 
 191         return getVnfNodeProperty(csarId, "flavour_id");