0993c6eeec90baa7c4624767d599bdba9588ea33
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / main / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / vnfm / CatalogManager.java
1 /*
2  * Copyright 2016-2017, Nokia Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;
18
19 import com.google.common.base.Charsets;
20 import com.google.common.io.ByteStreams;
21 import com.nokia.cbam.catalog.v1.api.DefaultApi;
22 import com.nokia.cbam.catalog.v1.model.CatalogAdapterVnfpackage;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.util.HashSet;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30 import java.util.zip.ZipEntry;
31 import java.util.zip.ZipInputStream;
32 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.IPackageProvider;
33 import org.slf4j.Logger;
34
35 import static com.google.common.base.Splitter.on;
36 import static com.google.common.collect.Iterables.filter;
37 import static okhttp3.MediaType.parse;
38 import static okhttp3.RequestBody.create;
39 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.buildFatalFailure;
40 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.LifecycleManager.ETSI_CONFIG;
41 import static org.slf4j.LoggerFactory.getLogger;
42 import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
43
44
45 /**
46  * Responsible for handling the CBAM catalog
47  * - the VNF package is uploaded as part of the instantiation
48  * - the VNF package is not deleted after VNF deletion
49  */
50 public class CatalogManager {
51     /**
52      * The location of the CBAM package within the ONAP package
53      */
54     public static final String CBAM_PACKAGE_NAME_IN_ZIP = "Artifacts/Deployment/OTHER/cbam.package.zip";
55     public static final String ETSI_CONFIG_NAME_IN_ZIP = "Artifacts/Deployment/OTHER/" + ETSI_CONFIG +".json";
56
57     private static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta";
58     private static final String TOSCA_VNFD_KEY = "Entry-Definitions";
59     private static Logger logger = getLogger(CatalogManager.class);
60     private final CbamRestApiProvider cbamRestApiProvider;
61     private final IPackageProvider packageProvider;
62
63     CatalogManager(CbamRestApiProvider cbamRestApiProvider, IPackageProvider packageProvider) {
64         this.cbamRestApiProvider = cbamRestApiProvider;
65         this.packageProvider = packageProvider;
66     }
67
68     /**
69      * @param zip  the zip
70      * @param path the path of the file to be returned
71      * @return the file in the zip
72      */
73     public static ByteArrayOutputStream getFileInZip(InputStream zip, String path) throws IOException {
74         ZipInputStream zipInputStream = new ZipInputStream(zip);
75         ByteArrayOutputStream fileContent = getFileInZip(zipInputStream, path);
76         zipInputStream.close();
77         return fileContent;
78     }
79
80     /**
81      * @param stream the CBAM VNF package
82      * @return the location of the VNFD within the CBAM package
83      */
84     public static String getVnfdLocation(InputStream stream) throws IOException {
85         String toscaMetadata = new String(getFileInZip(stream, TOSCA_META_PATH).toByteArray());
86         String toscaVnfdLine = filter(on("\n").split(toscaMetadata), line -> line.contains(TOSCA_VNFD_KEY)).iterator().next();
87         return toscaVnfdLine.replace(TOSCA_VNFD_KEY + ":", "").trim();
88     }
89
90     private static ByteArrayOutputStream getFileInZip(ZipInputStream zipInputStream, String path) throws IOException {
91         ZipEntry zipEntry;
92         Set<String> items = new HashSet<>();
93         while ((zipEntry = zipInputStream.getNextEntry()) != null) {
94             items.add(zipEntry.getName());
95             if (zipEntry.getName().matches(path)) {
96                 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
97                 ByteStreams.copy(zipInputStream, byteArrayOutputStream);
98                 return byteArrayOutputStream;
99             }
100         }
101         logger.error("Unable to find the {} in archive found: {}", path, items);
102         throw new NoSuchElementException("Unable to find the " + path + " in archive found: " + items);
103     }
104
105     /**
106      * Prepare the VNF package in CBAM. If the package is not available in the catalog it is uploaded.
107      *
108      * @param vnfmId the identifier of the VNFM
109      * @param csarId the CSAR identifier of the package in ONAP catalog
110      * @return the package in CBAM catalog
111      */
112     public CatalogAdapterVnfpackage preparePackageInCbam(String vnfmId, String csarId) {
113         String cbamVnfdId = packageProvider.getCbamVnfdId(csarId);
114         DefaultApi cbamCatalogApi = cbamRestApiProvider.getCbamCatalogApi(vnfmId);
115             if (!isPackageReplicated(cbamVnfdId, cbamCatalogApi)) {
116             try {
117                 ByteArrayOutputStream cbamPackage = getFileInZip(new ByteArrayInputStream(packageProvider.getPackage(csarId)), CBAM_PACKAGE_NAME_IN_ZIP);
118                 return cbamCatalogApi.create(create(parse(APPLICATION_OCTET_STREAM.toString()), cbamPackage.toByteArray())).blockingFirst();
119             } catch (Exception e) {
120                 logger.debug("Probably concurrent package uploads", e);
121                 //retest if the VNF package exists in CBAM. It might happen that an other operation
122                 //triggered the replication making this API fail. The replication is considered to be
123                 //successful if the package exist in CBAM even if the current package transfer failed
124                 if (isPackageReplicated(cbamVnfdId, cbamCatalogApi)) {
125                     return queryPackageFromCBAM(cbamVnfdId, cbamCatalogApi);
126                 } else {
127                     throw buildFatalFailure(logger, "Unable to create VNF with " + csarId + " CSAR identifier in package in CBAM", e);
128                 }
129             }
130         }
131         return queryPackageFromCBAM(cbamVnfdId, cbamCatalogApi);
132     }
133
134     /**
135      * Download the ETSI configuration of the VNF
136      * @param csarId the CSAR identifier of the package in ONAP catalog
137      * @return the content of the ETSI configuration
138      */
139     public String getEtsiConfiguration(String csarId){
140         try {
141             ByteArrayOutputStream etsiConfig = getFileInZip(new ByteArrayInputStream(packageProvider.getPackage(csarId)), ETSI_CONFIG_NAME_IN_ZIP);
142             return new String(etsiConfig.toByteArray(), Charsets.UTF_8);
143         }
144         catch (Exception e){
145             throw buildFatalFailure(logger, "Unable to download the ETSI configuration file");
146         }
147     }
148
149     /**
150      * Gets the content of the VNFD from the CBAM package uploaded to CBAM
151      *
152      * @param vnfmId the identifier of the VNFM
153      * @param vnfdId the identifier of the VNFD
154      * @return the content of the CBAM VNFD
155      */
156     public String getCbamVnfdContent(String vnfmId, String vnfdId) {
157         try {
158             byte[] vnfdContent = cbamRestApiProvider.getCbamCatalogApi(vnfmId).content(vnfdId).blockingFirst().bytes();
159             String vnfdPath = getVnfdLocation(new ByteArrayInputStream(vnfdContent));
160             return new String(getFileInZip(new ByteArrayInputStream(vnfdContent), vnfdPath).toByteArray());
161         } catch (Exception e) {
162             throw buildFatalFailure(logger, "Unable to get package with (" + vnfdId + ")", e);
163         }
164     }
165
166     private boolean isPackageReplicated(String cbamVnfdId, DefaultApi cbamCatalogApi) {
167         try {
168             return isPackageReplicatedToCbam(cbamVnfdId, cbamCatalogApi);
169         } catch (Exception e) {
170             throw buildFatalFailure(logger, "Unable to determine if the VNF package has been replicated in CBAM", e);
171         }
172     }
173
174     private CatalogAdapterVnfpackage queryPackageFromCBAM(String cbamVnfdId, DefaultApi cbamCatalogApi) {
175         try {
176             return cbamCatalogApi.getById(cbamVnfdId).blockingFirst();
177         } catch (Exception e) {
178             throw buildFatalFailure(logger, "Unable to query VNF package with " + cbamVnfdId + " from CBAM", e);
179         }
180     }
181
182     private boolean isPackageReplicatedToCbam(String cbamVnfdId, DefaultApi cbamCatalogApi) {
183         for (CatalogAdapterVnfpackage vnfPackage : cbamCatalogApi.list().blockingFirst()) {
184             if (vnfPackage.getVnfdId().equals(cbamVnfdId)) {
185                 return true;
186             }
187         }
188         return false;
189     }
190 }