From baebe989f102c10d5077fb24a6948893284a236d Mon Sep 17 00:00:00 2001 From: Murali-P Date: Mon, 16 Oct 2017 15:07:16 +0530 Subject: Integrate VNF Repository with SDC Add Browse VNF packages feature Change-Id: I0c721829efdac8ad6f72c4ac9d25ec96e091f7ca Issue-ID: VNFSDK-82 Signed-off-by: Michael Lando Signed-off-by: Murali-P --- .../onboarding-rest-war/pom.xml | 5 + .../src/main/webapp/WEB-INF/beans-services.xml | 1 + .../vendor-software-products-rest/pom.xml | 1 + .../vnf-repository-rest-services/pom.xml | 104 +++++++++ .../sdcrests/vsp/rest/VnfPackageRepository.java | 71 +++++++ .../rest/services/VnfPackageRepositoryImpl.java | 232 +++++++++++++++++++++ 6 files changed, 414 insertions(+) create mode 100644 openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/pom.xml create mode 100644 openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VnfPackageRepository.java create mode 100644 openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImpl.java (limited to 'openecomp-be/api') diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/pom.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/pom.xml index 9808d76a9c..ee1b9b3d65 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/pom.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/pom.xml @@ -30,6 +30,11 @@ vendor-software-products-rest-services ${project.version} + + org.openecomp.sdc.onboarding + vnf-repository-rest-services + ${project.version} + org.openecomp.sdc.onboarding validation-rest-services diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml index 126f7814d7..fb2db2b362 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml @@ -76,6 +76,7 @@ + diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/pom.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/pom.xml index eb7fe70691..e311a7ca1e 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/pom.xml +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/pom.xml @@ -17,5 +17,6 @@ /vendor-software-products-rest-services /vendor-software-products-rest-types + /vnf-repository-rest-services diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/pom.xml b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/pom.xml new file mode 100644 index 0000000000..47ed01d2d9 --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + vnf-repository-rest-services + + + org.openecomp.sdc.onboarding + vendor-software-products-rest + 1.1.0-SNAPSHOT + + + + + org.springframework + spring-core + ${spring.framework.version} + + + org.springframework + spring-context + ${spring.framework.version} + + + org.springframework + spring-context-support + ${spring.framework.version} + + + org.springframework + spring-web + ${spring.framework.version} + + + org.springframework + spring-beans + ${spring.framework.version} + + + + + org.apache.cxf + cxf-rt-frontend-jaxrs + ${cxf.version} + + + org.apache.httpcomponents + httpclient + ${http.client.version} + + + + + + javax.inject + javax.inject + ${javax.inject.version} + provided + + + org.openecomp.sdc + openecomp-sdc-common-rest + ${project.version} + + + org.openecomp.sdc + common-app-api + ${project.version} + + + org.openecomp.sdc.common + openecomp-configuration-management-api + ${project.version} + + + org.openecomp.sdc.common + openecomp-configuration-management-core + ${project.version} + runtime + + + org.openecomp.sdc.onboarding + vendor-software-products-rest-services + ${project.version} + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + test/core/unittest/offline/** + + + + + + + diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VnfPackageRepository.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VnfPackageRepository.java new file mode 100644 index 0000000000..1d922a63e8 --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VnfPackageRepository.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openecomp.sdcrests.vsp.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.File; +import static org.openecomp.sdcrests.common.RestConstants.USER_ID_HEADER_PARAM; +import static org.openecomp.sdcrests.common.RestConstants.USER_MISSING_ERROR_MSG; + +@Path("/v1.0/vendor-software-products/{vspId}/versions/{versionId}/vnfrepository") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Api(value = "VNF Repository packages") +@Validated +public interface VnfPackageRepository extends VspEntities { + + @GET + @Path("/vnfpackages") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Get VNF packages from VNF Repository", notes = "Call VNF Repostory to get VNF package details", response = File.class) + Response getVnfPackages(@PathParam("vspId") String vspId, + @ApiParam(value = "Version Id") @PathParam("versionId") String versionId, + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user) throws Exception; + + @GET + @Path("/vnfpackage/{csarId}/download") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @ApiOperation(value = "Download VNF package from VNF Repository", notes = "Download VNF package from VNF repository and send to client", response = File.class) + Response downloadVnfPackage(@PathParam("vspId") String vspId, + @ApiParam(value = "Version Id") @PathParam("versionId") String versionId, + @PathParam("csarId") String csarId, + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user) throws Exception; + + @POST + @Path("/vnfpackage/{csarId}/import") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Import VNF package from VNF Repository", notes = "Call VNF Repostory to download VNF package, validate it and send the response", response = UploadFileResponseDto.class) + Response importVnfPackage(@PathParam("vspId") String vspId, + @ApiParam(value = "Version Id") @PathParam("versionId") String versionId, + @PathParam("csarId") String csarId, + @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user) throws Exception; + +} diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImpl.java new file mode 100644 index 0000000000..acbfb328f1 --- /dev/null +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImpl.java @@ -0,0 +1,232 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openecomp.sdcrests.vsp.rest.services; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.logging.messages.AuditMessages; +import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager; +import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory; +import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse; +import org.openecomp.sdc.versioning.types.VersionableEntityAction; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto; +import org.openecomp.sdcrests.vsp.rest.VnfPackageRepository; +import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; +import org.openecomp.sdc.common.rest.api.IRestClient; +import org.openecomp.sdc.common.rest.api.RestConfigurationInfo; +import org.openecomp.sdc.common.rest.api.RestResponse; +import org.openecomp.sdc.common.rest.impl.RestClientServiceFactory; +import org.openecomp.config.api.Configuration; +import org.openecomp.config.api.ConfigurationManager; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import javax.inject.Named; +import javax.ws.rs.core.Response; + +import static org.openecomp.core.utilities.file.FileUtils.getFileExtension; +import static org.openecomp.core.utilities.file.FileUtils.getNetworkPackageName; + +/** + * + * The class implements the API interface with VNF Repository (VNFSDK) such as + * i) Get all the VNF Package Meta-data ii) Download the VNF Package iii) Import + * VNF package to SDC catalog (Download & validate) + * + * @version Amsterdam release (ONAP 1.0) + * + */ +@Named +@Service("vnfPackageRepository") +@Scope(value = "prototype") +public class VnfPackageRepositoryImpl implements VnfPackageRepository { + + private static final Logger LOGGER = LoggerFactory.getLogger(VnfPackageRepositoryImpl.class); + private static IRestClient iRestClnt = null; + private static boolean initFlag = false; + + // Default VNF Repository configuration + private static final String CONFIG_NAMESPACE = "vnfsdk"; + + // Default address for VNF repository docker + private static final String DEF_DOCKER_COMPOSE_ADDR = "172.18.0.1"; + private static String ipAddress = DEF_DOCKER_COMPOSE_ADDR; + + // Default Download package URI and Get VNF package meta-data URI - + // configurable + private static String getVnfPkgUri = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars"; + private static String downldPkgUri = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars/%s/files"; + + // Default port for VNF Repository + private static String port = "8702"; + + @Override + public Response getVnfPackages(String vspId, String versionId, String user) throws Exception { + + LOGGER.audit(AuditMessages.AUDIT_MSG, "Get VNF Packages from Repository:{}", vspId); + + // Step 1: Create REST client and configuration and prepare URI + init(); + + // Step 2: Build URI based on the IP address and port allocated + RestResponse rsp = iRestClnt.doGET(getVnfPkgUri, null); + if (HttpStatus.SC_OK != rsp.getHttpStatusCode()) { + LOGGER.error("Failed to query VNF package metadata:uri={}, Response={}", getVnfPkgUri, rsp); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + + // Step 3: Send the response to the client + LOGGER.debug("Response from VNF Repository: {}", rsp.getResponse()); + + return Response.ok(rsp.getResponse()).build(); + } + + @Override + public Response importVnfPackage(String vspId, String versionId, String csarId, String user) throws Exception { + + LOGGER.audit(AuditMessages.AUDIT_MSG, "Import VNF Packages from Repository:{}", csarId); + + // Step 1: Create REST client and configuration and prepare URI + init(); + + // Step 2: Build URI based on the IP address and port allocated + String uri = String.format(downldPkgUri, csarId); + RestResponse rsp = iRestClnt.doGET(getVnfPkgUri, null); + if (HttpStatus.SC_OK != rsp.getHttpStatusCode()) { + LOGGER.error("Failed to download package from VNF Repository:uri={}, Response={}", uri, rsp); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + LOGGER.debug(AuditMessages.AUDIT_MSG, "Response from VNF Repository for download package is success "); + + // Step 3: Import the file to SDC and validate and send the response + try (InputStream fileStream = new BufferedInputStream( + new ByteArrayInputStream(rsp.getResponse().getBytes(StandardCharsets.ISO_8859_1)))) { + + String filename = "temp_" + csarId + ".csar"; + OrchestrationTemplateCandidateManager candidateManager = OrchestrationTemplateCandidateManagerFactory + .getInstance().createInterface(); + UploadFileResponse uploadFileResponse = candidateManager.upload(vspId, + resolveVspVersion(vspId, null, user, VersionableEntityAction.Write), fileStream, user, + getFileExtension(filename), getNetworkPackageName(filename)); + + UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto() + .applyMapping(uploadFileResponse, UploadFileResponseDto.class); + + return Response.ok(uploadFileResponseDto).build(); + } catch (IOException e) { + // Exception while uploading file + LOGGER.error("Exception while uploading VNF package received from VNF Repository:", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + } + + @Override + public Response downloadVnfPackage(String vspId, String versionId, String csarId, String user) throws Exception { + + LOGGER.audit(AuditMessages.AUDIT_MSG + "Download VNF Packages from Repository:csarId={}", csarId); + + // Step 1: Create REST client and configuration and prepare URI + init(); + + // Step 2: Build URI based on the IP address and port allocated + String uri = String.format(downldPkgUri, csarId); + RestResponse rsp = iRestClnt.doGET(uri, null); + if (HttpStatus.SC_OK != rsp.getHttpStatusCode()) { + LOGGER.error("Failed to download package from VNF Repository:uri={}, Response={}", uri, rsp); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + + // Step 3:Send response to the client + String filename = "temp_" + csarId + ".csar"; + Response.ResponseBuilder response = Response.ok(rsp.getResponse().getBytes(StandardCharsets.ISO_8859_1)); + response.header("Content-Disposition", "attachment; filename=" + filename); + + LOGGER.debug(AuditMessages.AUDIT_MSG, "Response from VNF Repository for download package is success "); + + return response.build(); + } + + private static void setRestClient() { + + if (null == iRestClnt) { + RestConfigurationInfo restInfo = new RestConfigurationInfo(); + iRestClnt = RestClientServiceFactory.createRestClientService(restInfo); + if (null == iRestClnt) { + return; + } + } + } + + private static void setVnfRepoConfig() { + + try { + // Step 1: Fetch the on-boarding configuration + Configuration config = ConfigurationManager.lookup(); + + String vnfRepoHost = config.getAsString(CONFIG_NAMESPACE, "vnfRepoHost"); + if (null != vnfRepoHost) { + ipAddress = vnfRepoHost; + } + + String vnfRepoPort = config.getAsString(CONFIG_NAMESPACE, "vnfRepoPort"); + if (null != vnfRepoPort) { + port = vnfRepoPort; + } + + String getVnfUri = config.getAsString(CONFIG_NAMESPACE, "getVnfUri"); + if (null != getVnfUri) { + getVnfPkgUri = getVnfUri; + } + + String downloadVnfUri = config.getAsString(CONFIG_NAMESPACE, "downloadVnfUri"); + if (null != downloadVnfUri) { + downldPkgUri = downloadVnfUri; + } + + } catch (Exception e) { + LOGGER.error("Failed to load configuration, Exception caught, using default configuration", e); + } + + getVnfPkgUri = new StringBuilder("http://").append(ipAddress).append(":").append(port).append(getVnfPkgUri) + .toString(); + + downldPkgUri = new StringBuilder("http://").append(ipAddress).append(":").append(port).append(downldPkgUri) + .toString(); + } + + private static synchronized void init() throws Exception { + if (!initFlag) { + // Step 1: Initialize configuration + setVnfRepoConfig(); + + // Step 2: Initialize rest client + setRestClient(); + if (null == iRestClnt) { + LOGGER.error("REST initialization error, Rest client is null"); + throw new Exception("Rest Initializer error, Rest client is null"); + } + + initFlag = true; + } + } +} -- cgit