2 * Copyright © 2019 Bell Canada
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.ccsdk.cds.sdclistener.service;
19 import com.google.protobuf.ByteString;
20 import io.grpc.ManagedChannel;
21 import org.apache.commons.io.FileUtils;
22 import org.apache.commons.io.IOUtils;
23 import org.onap.ccsdk.cds.controllerblueprints.common.api.ActionIdentifiers;
24 import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader;
25 import org.onap.ccsdk.cds.controllerblueprints.common.api.Status;
26 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput;
27 import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk;
28 import org.onap.ccsdk.cds.controllerblueprints.management.api.UploadAction;
29 import org.onap.ccsdk.cds.sdclistener.client.SdcListenerAuthClientInterceptor;
30 import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto;
31 import org.onap.ccsdk.cds.sdclistener.handler.BluePrintProcesssorHandler;
32 import org.onap.ccsdk.cds.sdclistener.status.SdcListenerStatus;
33 import org.onap.ccsdk.cds.sdclistener.util.FileUtil;
34 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.beans.factory.annotation.Value;
39 import org.springframework.boot.context.properties.ConfigurationProperties;
40 import org.springframework.stereotype.Component;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.OutputStream;
47 import java.nio.file.Files;
48 import java.nio.file.Path;
49 import java.nio.file.Paths;
50 import java.util.Enumeration;
51 import java.util.List;
52 import java.util.UUID;
53 import java.util.regex.Pattern;
54 import java.util.zip.ZipEntry;
55 import java.util.zip.ZipFile;
57 import static java.lang.String.format;
58 import static org.onap.ccsdk.cds.sdclistener.status.SdcListenerStatus.NotificationType.SDC_LISTENER_COMPONENT;
59 import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_ERROR;
60 import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_OK;
63 @ConfigurationProperties("listenerservice")
64 public class ListenerServiceImpl implements ListenerService {
67 private BluePrintProcesssorHandler bluePrintProcesssorHandler;
70 private SdcListenerAuthClientInterceptor sdcListenerAuthClientInterceptor;
73 private SdcListenerStatus listenerStatus;
76 private SdcListenerDto sdcListenerDto;
78 @Value("${listenerservice.config.grpcAddress}")
79 private String grpcAddress;
81 @Value("${listenerservice.config.grpcPort}")
84 private static final String CBA_ZIP_PATH =
85 "Artifacts/[a-zA-Z0-9-_.]+/Deployment/CONTROLLER_BLUEPRINT_ARCHIVE/[a-zA-Z0-9-_.()]+[.]zip";
86 private static final int SUCCESS_CODE = 200;
87 private static final Logger LOGGER = LoggerFactory.getLogger(ListenerServiceImpl.class);
90 public void extractBluePrint(String csarArchivePath, String cbaArchivePath) {
91 int validPathCount = 0;
92 final String distributionId = getDistributionId();
93 final String artifactUrl = getArtifactUrl();
94 Path cbaStorageDir = getStorageDirectory(cbaArchivePath);
95 try (ZipFile zipFile = new ZipFile(csarArchivePath)) {
96 Enumeration<? extends ZipEntry> entries = zipFile.entries();
97 while (entries.hasMoreElements()) {
98 ZipEntry entry = entries.nextElement();
99 String fileName = entry.getName();
100 if (Pattern.matches(CBA_ZIP_PATH, fileName)) {
102 final String cbaArchiveName = Paths.get(fileName).getFileName().toString();
103 LOGGER.info("Storing the CBA archive {}", cbaArchiveName);
104 storeBluePrint(zipFile, cbaArchiveName, cbaStorageDir, entry);
108 if (validPathCount == 0) {
110 "CBA archive doesn't exist in the CSAR Package or it doesn't exist as per the given path {}",
112 listenerStatus.sendResponseBackToSdc(distributionId, COMPONENT_DONE_OK, null, artifactUrl,
113 SDC_LISTENER_COMPONENT);
116 } catch (Exception e) {
117 final String errorMessage = format("Failed to extract blueprint %s", e.getMessage());
118 listenerStatus.sendResponseBackToSdc(distributionId, COMPONENT_DONE_ERROR, errorMessage, artifactUrl,
119 SDC_LISTENER_COMPONENT);
120 LOGGER.error(errorMessage);
124 private void storeBluePrint(ZipFile zipFile, String fileName, Path cbaArchivePath, ZipEntry entry) {
125 Path targetLocation = cbaArchivePath.resolve(fileName);
126 LOGGER.info("The target location for zip file is {}", targetLocation);
127 File targetZipFile = new File(targetLocation.toString());
130 if (!targetZipFile.createNewFile()) {
131 LOGGER.warn("Overwriting zip file {}", targetLocation);
133 } catch (IOException e) {
134 LOGGER.error("Could not able to create file {}", targetZipFile, e);
137 try (InputStream inputStream = zipFile.getInputStream(entry);
138 OutputStream out = new FileOutputStream(targetZipFile)) {
139 IOUtils.copy(inputStream, out);
140 LOGGER.info("Successfully store the CBA archive {} at this location", targetZipFile);
141 } catch (Exception e) {
142 LOGGER.error("Failed to put zip file into target location {}, {}", targetLocation, e);
147 public void saveBluePrintToCdsDatabase(Path cbaArchivePath, ManagedChannel channel) {
148 List<File> zipFiles = FileUtil.getFilesFromDisk(cbaArchivePath);
149 if (!zipFiles.isEmpty()) {
150 prepareRequestForCdsBackend(zipFiles, channel, cbaArchivePath.toString());
155 public void extractCsarAndStore(IDistributionClientDownloadResult result, Path csarArchivePath) {
157 // Create CSAR storage directory
158 Path csarStorageDir = getStorageDirectory(csarArchivePath.toString());
159 byte[] payload = result.getArtifactPayload();
160 String csarFileName = result.getArtifactFilename();
161 Path targetLocation = csarStorageDir.resolve(csarFileName);
163 LOGGER.info("The target location for the CSAR file is {}", targetLocation);
165 File targetCsarFile = new File(targetLocation.toString());
167 try (FileOutputStream outFile = new FileOutputStream(targetCsarFile)) {
168 outFile.write(payload, 0, payload.length);
169 if (!csarArchivePath.toFile().exists()) {
170 LOGGER.error("Could not able to store the CSAR at this location {}", csarArchivePath);
172 } catch (Exception e) {
173 LOGGER.error("Fail to write the data into FileOutputStream {}, {}", targetLocation, e);
177 private Path getStorageDirectory(String path) {
178 Path fileStorageLocation = Paths.get(path).toAbsolutePath().normalize();
180 if (!fileStorageLocation.toFile().exists()) {
182 return Files.createDirectories(fileStorageLocation);
183 } catch (IOException e) {
184 LOGGER.error("Fail to create directory {}, {}", e, fileStorageLocation);
187 return fileStorageLocation;
190 private void prepareRequestForCdsBackend(List<File> files, ManagedChannel managedChannel, String path) {
191 final String distributionId = getDistributionId();
192 final String artifactUrl = getArtifactUrl();
194 files.forEach(zipFile -> {
196 final BluePrintUploadInput request = generateBluePrintUploadInputBuilder(zipFile, path);
198 // Send request to CDS Backend.
199 final Status responseStatus = bluePrintProcesssorHandler.sendRequest(request, managedChannel);
201 if (responseStatus.getCode() != SUCCESS_CODE) {
202 final String errorMessage = format("Failed to store the CBA archive into CDS DB due to %s",
203 responseStatus.getErrorMessage());
204 listenerStatus.sendResponseBackToSdc(distributionId, COMPONENT_DONE_ERROR, errorMessage,
205 artifactUrl, SDC_LISTENER_COMPONENT);
206 LOGGER.error(errorMessage);
208 LOGGER.info(responseStatus.getMessage());
209 listenerStatus.sendResponseBackToSdc(distributionId, COMPONENT_DONE_OK, null, artifactUrl,
210 SDC_LISTENER_COMPONENT);
213 } catch (Exception e) {
214 final String errorMessage = format("Failure due to %s", e.getMessage());
215 listenerStatus.sendResponseBackToSdc(distributionId, COMPONENT_DONE_ERROR, errorMessage, artifactUrl,
216 SDC_LISTENER_COMPONENT);
217 LOGGER.error(errorMessage);
222 private BluePrintUploadInput generateBluePrintUploadInputBuilder(File file, String path) throws IOException {
223 byte[] bytes = FileUtils.readFileToByteArray(file);
224 FileChunk fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(bytes)).build();
225 FileUtil.deleteFile(file, path);
226 return BluePrintUploadInput.newBuilder()
227 .setCommonHeader(CommonHeader.newBuilder().setRequestId(UUID.randomUUID().toString())
228 .setSubRequestId(UUID.randomUUID().toString()).setOriginatorId("SDC-LISTENER").build())
229 .setActionIdentifiers(
230 ActionIdentifiers.newBuilder().setActionName(UploadAction.PUBLISH.toString()).build())
231 .setFileChunk(fileChunk).build();
234 private String getDistributionId() {
235 return sdcListenerDto.getDistributionId();
238 private String getArtifactUrl() {
239 return sdcListenerDto.getArtifactUrl();