5bcd3d3a39300c7e0b87272688a9de72c30f1009
[sdc.git] /
1 /*
2  * Copyright 2017 Huawei Technologies Co., Ltd.
3  * Modifications Copyright 2018 European Support Limited
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
18 package org.openecomp.sdcrests.vsp.rest.services;
19
20 import static javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION;
21 import static org.openecomp.core.utilities.file.FileUtils.getFileExtension;
22 import static org.openecomp.core.utilities.file.FileUtils.getNetworkPackageName;
23
24 import java.net.URI;
25 import java.nio.ByteBuffer;
26 import java.nio.charset.StandardCharsets;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.Optional;
31 import javax.inject.Named;
32 import javax.net.ssl.HostnameVerifier;
33 import javax.net.ssl.SSLContext;
34 import javax.ws.rs.client.Client;
35 import javax.ws.rs.client.ClientBuilder;
36 import javax.ws.rs.client.Invocation;
37 import javax.ws.rs.client.WebTarget;
38 import javax.ws.rs.core.Link;
39 import javax.ws.rs.core.Response;
40 import javax.ws.rs.core.UriBuilder;
41 import org.onap.config.api.ConfigurationManager;
42 import org.openecomp.sdc.common.errors.CoreException;
43 import org.openecomp.sdc.common.errors.ErrorCode;
44 import org.openecomp.sdc.common.errors.ErrorCodeAndMessage;
45 import org.openecomp.sdc.common.errors.GeneralErrorBuilder;
46 import org.openecomp.sdc.logging.api.Logger;
47 import org.openecomp.sdc.logging.api.LoggerFactory;
48 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
49 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
50 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
51 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
52 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
53 import org.openecomp.sdc.versioning.VersioningManager;
54 import org.openecomp.sdc.versioning.VersioningManagerFactory;
55 import org.openecomp.sdc.versioning.dao.types.Version;
56 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
57 import org.openecomp.sdcrests.vsp.rest.VnfPackageRepository;
58 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
59 import org.springframework.context.annotation.Scope;
60 import org.springframework.stereotype.Service;
61
62 /**
63  * Enables integration API interface with VNF Repository (VNFSDK).
64  * <ol>
65  *     <li>Get all the VNF Package Meta-data.</li>
66  *     <li>Download a VNF Package.</li>
67  *     <li>Import a VNF package to SDC catalog (Download & validate).</li>
68  * </ol>
69  *
70  * @version Amsterdam release (ONAP 1.0)
71  */
72 @Named
73 @Service("vnfPackageRepository")
74 @Scope(value = "prototype")
75 public class VnfPackageRepositoryImpl implements VnfPackageRepository {
76
77     private static final Logger LOGGER = LoggerFactory.getLogger(VnfPackageRepositoryImpl.class);
78
79     private final Configuration config;
80
81     public VnfPackageRepositoryImpl(Configuration config) {
82         this.config = config;
83     }
84
85     public VnfPackageRepositoryImpl() {
86         this(new FileConfiguration());
87     }
88
89     @Override
90     public Response getVnfPackages(String vspId, String versionId, String user) {
91
92         LOGGER.debug("Get VNF Packages from Repository: {}", vspId);
93
94         Client client = new SharedClient();
95
96         final String getVnfPackageUri = config.getGetUri();
97
98         try {
99
100             Response remoteResponse = client.target(getVnfPackageUri).request().get();
101             if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
102                 return handleUnexpectedStatus("querying VNF package metadata", getVnfPackageUri, remoteResponse);
103             }
104
105             LOGGER.debug("Response from VNF Repository: {}", remoteResponse);
106             return Response.ok(remoteResponse.readEntity(String.class)).build();
107
108         } finally {
109             client.close();
110         }
111     }
112
113     @Override
114     public Response importVnfPackage(String vspId, String versionId, String csarId, String user) {
115
116         LOGGER.debug("Import VNF Packages from Repository: {}", csarId);
117
118         final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
119
120         Client client = new SharedClient();
121
122         try {
123
124             Response remoteResponse = client.target(downloadPackageUri).request().get();
125             if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
126                 return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
127             }
128
129             LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
130             byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
131             return uploadVnfPackage(vspId, versionId, csarId, payload);
132
133         } finally {
134             client.close();
135         }
136     }
137
138     private Response uploadVnfPackage(final String vspId, final String versionId,
139                                       final String csarId, final byte[] payload) {
140         try {
141             final OrchestrationTemplateCandidateManager candidateManager =
142                     OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
143             final String filename = formatFilename(csarId);
144             final OnboardPackageInfo onboardPackageInfo = new OnboardPackageInfo(getNetworkPackageName(filename),
145                 getFileExtension(filename), ByteBuffer.wrap(payload));
146             final VspDetails vspDetails = new VspDetails(vspId, getVersion(vspId, versionId));
147             final UploadFileResponse response = candidateManager.upload(vspDetails, onboardPackageInfo);
148             final UploadFileResponseDto uploadFileResponse =
149                 new MapUploadFileResponseToUploadFileResponseDto()
150                     .applyMapping(response, UploadFileResponseDto.class);
151
152             return Response.ok(uploadFileResponse).build();
153
154         } catch (final Exception e) {
155             ErrorCode error = new GeneralErrorBuilder().build();
156             LOGGER.error("Exception while uploading package received from VNF Repository", new CoreException(error, e));
157             return generateInternalServerError(error);
158         }
159     }
160
161     @Override
162     public Response downloadVnfPackage(String vspId, String versionId, String csarId, String user) {
163
164         LOGGER.debug("Download VNF package from repository: csarId={}", csarId);
165
166         final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
167
168         Client client = new SharedClient();
169
170         try {
171
172             Response remoteResponse = client.target(downloadPackageUri).request().get();
173             if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
174                 return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
175             }
176
177             byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
178             Response.ResponseBuilder response = Response.ok(payload);
179             response.header(CONTENT_DISPOSITION, "attachment; filename=" + formatFilename(csarId));
180
181             LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
182             return response.build();
183
184         } finally {
185             client.close();
186         }
187     }
188
189     private Version getVersion(String vspId, String versionId) {
190         VersioningManager versioningManager = VersioningManagerFactory.getInstance().createInterface();
191         return findVersion(versioningManager.list(vspId), versionId).orElse(new Version(versionId));
192     }
193
194     Optional<Version> findVersion(List<Version> versions, String requestedVersion) {
195         return versions.stream().filter(ver -> Objects.equals(ver.getId(), requestedVersion)).findAny();
196     }
197
198     private static Response handleUnexpectedStatus(String action, String uri, Response response) {
199
200         ErrorCode error = new GeneralErrorBuilder().build();
201
202         if (LOGGER.isErrorEnabled()) {
203             String body = response.hasEntity() ? response.readEntity(String.class) : "";
204             LOGGER.error("Unexpected response status while {}: URI={}, status={}, body={}", action, uri,
205                     response.getStatus(), body, new CoreException(error));
206         }
207
208         return generateInternalServerError(error);
209     }
210
211     private static Response generateInternalServerError(ErrorCode error) {
212         ErrorCodeAndMessage payload = new ErrorCodeAndMessage(Response.Status.INTERNAL_SERVER_ERROR, error);
213         return Response.serverError().entity(payload).build();
214     }
215
216     private static String formatFilename(String csarId) {
217         return "temp_" + csarId + ".csar";
218     }
219
220     interface Configuration {
221
222         String getGetUri();
223
224         String getDownloadUri();
225     }
226
227     private static class SharedClient implements Client {
228
229         private static final Client CLIENT = ClientBuilder.newClient();
230
231         @Override
232         public void close() {
233             // do not close the shared client
234         }
235
236         @Override
237         public WebTarget target(String uri) {
238             return CLIENT.target(uri);
239         }
240
241         @Override
242         public WebTarget target(URI uri) {
243             return CLIENT.target(uri);
244         }
245
246         @Override
247         public WebTarget target(UriBuilder uriBuilder) {
248             return CLIENT.target(uriBuilder);
249         }
250
251         @Override
252         public WebTarget target(Link link) {
253             return CLIENT.target(link);
254         }
255
256         @Override
257         public Invocation.Builder invocation(Link link) {
258             return CLIENT.invocation(link);
259         }
260
261         @Override
262         public SSLContext getSslContext() {
263             return CLIENT.getSslContext();
264         }
265
266         @Override
267         public HostnameVerifier getHostnameVerifier() {
268             return CLIENT.getHostnameVerifier();
269         }
270
271         @Override
272         public javax.ws.rs.core.Configuration getConfiguration() {
273             return CLIENT.getConfiguration();
274         }
275
276         @Override
277         public Client property(String name, Object value) {
278             return CLIENT.property(name, value);
279         }
280
281         @Override
282         public Client register(Class<?> componentClass) {
283             return CLIENT.register(componentClass);
284         }
285
286         @Override
287         public Client register(Class<?> componentClass, int priority) {
288             return CLIENT.register(componentClass, priority);
289         }
290
291         @Override
292         public Client register(Class<?> componentClass, Class<?>... contracts) {
293             return CLIENT.register(componentClass, contracts);
294         }
295
296         @Override
297         public Client register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
298             return CLIENT.register(componentClass, contracts);
299         }
300
301         @Override
302         public Client register(Object component) {
303             return CLIENT.register(component);
304         }
305
306         @Override
307         public Client register(Object component, int priority) {
308             return CLIENT.register(component, priority);
309         }
310
311         @Override
312         public Client register(Object component, Class<?>... contracts) {
313             return CLIENT.register(component, contracts);
314         }
315
316         @Override
317         public Client register(Object component, Map<Class<?>, Integer> contracts) {
318             return CLIENT.register(component, contracts);
319         }
320     }
321
322     static class FileConfiguration implements Configuration {
323
324         @Override
325         public String getGetUri() {
326             return LazyFileConfiguration.INSTANCE.getGetUri();
327         }
328
329         @Override
330         public String getDownloadUri() {
331             return LazyFileConfiguration.INSTANCE.getDownloadUri();
332         }
333
334         private static class LazyFileConfiguration implements Configuration {
335
336             private static final String CONFIG_NAMESPACE = "vnfrepo";
337
338             private static final String DEFAULT_HOST = "localhost";
339             private static final String DEFAULT_PORT = "8702";
340
341             private static final String DEFAULT_URI_PREFIX = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars";
342             private static final String DEFAULT_LIST_URI = DEFAULT_URI_PREFIX + "/";
343             private static final String DEFAULT_DOWNLOAD_URI = DEFAULT_URI_PREFIX + "/%s/files";
344
345             private static final LazyFileConfiguration INSTANCE = new LazyFileConfiguration();
346
347             private final String getUri;
348             private final String downloadUri;
349
350             private LazyFileConfiguration() {
351                 org.onap.config.api.Configuration config = ConfigurationManager.lookup();
352                 String host = readConfig(config, "vnfRepoHost", DEFAULT_HOST);
353                 String port = readConfig(config, "vnfRepoPort", DEFAULT_PORT);
354                 String listPackagesUri = readConfig(config, "getVnfUri", DEFAULT_LIST_URI);
355                 String downloadPackageUri = readConfig(config, "downloadVnfUri", DEFAULT_DOWNLOAD_URI);
356                 this.getUri = formatUri(host, port, listPackagesUri);
357                 this.downloadUri = formatUri(host, port, downloadPackageUri);
358             }
359
360             private String readConfig(org.onap.config.api.Configuration config, String key, String defaultValue) {
361
362                 try {
363                     String value = config.getAsString(CONFIG_NAMESPACE, key);
364                     return (value == null) ? defaultValue : value;
365                 } catch (Exception e) {
366                     LOGGER.error(
367                             "Failed to read VNF repository configuration key '{}', default value '{}' will be used",
368                             key, defaultValue, e);
369                     return defaultValue;
370                 }
371             }
372
373             private static String formatUri(String host, String port, String path) {
374                 return "http://" + host + ":" + port + (path.startsWith("/") ? path : "/" + path);
375             }
376
377             public String getGetUri() {
378                 return getUri;
379             }
380
381             public String getDownloadUri() {
382                 return downloadUri;
383             }
384         }
385     }
386 }