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