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