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