From d5339481d3c3f24dd5faccb44dccd4addfd58499 Mon Sep 17 00:00:00 2001 From: Oleg Mitsura Date: Mon, 22 Apr 2019 17:47:33 -0400 Subject: SDC Listner Docker touchup 1.Reworked Dockerization of SDC Listener to follow application/distribution+parent style; 2.Renamed CDS-SDClistener to just SDCListener Issue-ID: CCSDK-1145 Change-Id: I007373d3a48fb8eb7042150bdbb37fc7fec346b3 Signed-off-by: Oleg Mitsura --- .../cds/sdclistener/SdcListenerApplication.java | 28 +++ .../cds/sdclistener/SdcListenerConfiguration.java | 143 +++++++++++++++ .../SdcListenerNotificationCallback.java | 129 +++++++++++++ .../client/SdcListenerAuthClientInterceptor.java | 54 ++++++ .../cds/sdclistener/client/SdcListenerClient.java | 95 ++++++++++ .../cds/sdclistener/controller/HealthCheck.java | 35 ++++ .../ccsdk/cds/sdclistener/dto/SdcListenerDto.java | 70 +++++++ .../exceptions/SdcListenerException.java | 34 ++++ .../handler/BluePrintProcesssorHandler.java | 64 +++++++ .../cds/sdclistener/service/ListenerService.java | 47 +++++ .../sdclistener/service/ListenerServiceImpl.java | 202 +++++++++++++++++++++ .../status/DistributionStatusMessage.java | 55 ++++++ .../cds/sdclistener/status/SdcListenerStatus.java | 82 +++++++++ .../ccsdk/cds/sdclistener/util/BuilderUtil.java | 33 ++++ .../onap/ccsdk/cds/sdclistener/util/FileUtil.java | 61 +++++++ .../application/src/main/resources/application.yml | 27 +++ .../application/src/main/resources/logback.xml | 33 ++++ .../cds/sdclistener/SdcListenerClientTest.java | 80 ++++++++ .../sdclistener/SdcListenerConfigurationTest.java | 48 +++++ .../handler/BluePrintProcessorHandlerTest.java | 112 ++++++++++++ .../service/ListenerServiceImplTest.java | 126 +++++++++++++ .../src/test/resources/service-Testsvc140.csar | Bin 0 -> 116298 bytes .../application/src/test/resources/testcba.zip | Bin 0 -> 15123 bytes 23 files changed, 1558 insertions(+) create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerApplication.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfiguration.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerNotificationCallback.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerAuthClientInterceptor.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerClient.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/controller/HealthCheck.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/dto/SdcListenerDto.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/exceptions/SdcListenerException.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcesssorHandler.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerService.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImpl.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/DistributionStatusMessage.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/SdcListenerStatus.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/BuilderUtil.java create mode 100644 ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/FileUtil.java create mode 100644 ms/sdclistener/application/src/main/resources/application.yml create mode 100644 ms/sdclistener/application/src/main/resources/logback.xml create mode 100644 ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerClientTest.java create mode 100644 ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java create mode 100644 ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcessorHandlerTest.java create mode 100644 ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImplTest.java create mode 100644 ms/sdclistener/application/src/test/resources/service-Testsvc140.csar create mode 100644 ms/sdclistener/application/src/test/resources/testcba.zip (limited to 'ms/sdclistener/application/src') diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerApplication.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerApplication.java new file mode 100644 index 000000000..253b576d2 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@EnableConfigurationProperties(SdcListenerConfiguration.class) +public class SdcListenerApplication { + public static void main(String[] args) { + SpringApplication.run(SdcListenerApplication.class, args); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfiguration.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfiguration.java new file mode 100644 index 000000000..06e2a0342 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfiguration.java @@ -0,0 +1,143 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener; + +import java.util.List; +import org.onap.sdc.api.consumer.IConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * In order to initiate a SDC distribution client we need to supply some pre-configuration values that + * distribution client needs. + */ +@ConfigurationProperties("listenerservice") +public class SdcListenerConfiguration implements IConfiguration { + + public static final String TOSCA_CSAR = "TOSCA_CSAR"; + + @Value("${listenerservice.config.asdcAddress}") + private String asdcAddress; + + @Value("${listenerservice.config.messageBusAddress}") + private List messageBusAddress; + + @Value("${listenerservice.config.user}") + private String user; + + @Value("${listenerservice.config.password}") + private String password; + + @Value("${listenerservice.config.pollingTimeout}") + private int pollingTimeout; + + @Value("${listenerservice.config.pollingInterval}") + private int pollingInterval; + + @Value("${listenerservice.config.relevantArtifactTypes}") + private List relevantArtifactTypes; + + @Value("${listenerservice.config.consumerGroup}") + private String consumerGroup; + + @Value("${listenerservice.config.environmentName}") + private String envName; + + @Value("${listenerservice.config.consumerId}") + private String consumerId; + + @Value("${listenerservice.config.activateServerTLSAuth}") + private boolean activateServerTLSAuth; + + @Value("${listenerservice.config.isUseHttpsWithDmaap}") + private boolean isUseHttpsWithDmaap; + + @Override + public String getAsdcAddress() { + return asdcAddress; + } + + @Override + public List getMsgBusAddress() { + return messageBusAddress; + } + + @Override + public String getUser() { + return user; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public int getPollingInterval() { + return pollingInterval; + } + + @Override + public int getPollingTimeout() { + return pollingTimeout; + } + + @Override + public List getRelevantArtifactTypes() { + return relevantArtifactTypes; + } + + @Override + public String getConsumerGroup() { + return consumerGroup; + } + + @Override + public String getEnvironmentName() { + return envName; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public String getKeyStorePath() { + return null; + } + + @Override + public String getKeyStorePassword() { + return null; + } + + @Override + public boolean activateServerTLSAuth() { + return activateServerTLSAuth; + } + + @Override + public boolean isFilterInEmptyResources() { + return false; + } + + @Override + public Boolean isUseHttpsWithDmaap() { + return isUseHttpsWithDmaap; + } +} + diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerNotificationCallback.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerNotificationCallback.java new file mode 100644 index 000000000..eb339aef7 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/SdcListenerNotificationCallback.java @@ -0,0 +1,129 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener; + +import static org.onap.sdc.utils.DistributionActionResultEnum.SUCCESS; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.service.ListenerService; +import org.onap.ccsdk.cds.sdclistener.status.SdcListenerStatus; +import org.onap.ccsdk.cds.sdclistener.util.FileUtil; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.consumer.INotificationCallback; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; + +@ConfigurationProperties("listenerservice") +@Component +@ComponentScan("org.onap.ccsdk.cds.cdssdclistener.dto") +public class SdcListenerNotificationCallback implements INotificationCallback { + + @Autowired + private SdcListenerDto sdcListenerDto; + + @Autowired + private ListenerService listenerService; + + @Value("${listenerservice.config.archivePath}") + private String pathToStoreArchives; + + @Autowired + private SdcListenerStatus listenerStatus; + + private static final Logger LOGGER = LoggerFactory.getLogger(SdcListenerNotificationCallback.class); + + @Override + public void activateCallback(INotificationData notificationData) { + final String distributionId = notificationData.getDistributionID(); + sdcListenerDto.setDistributionId(distributionId); + LOGGER.info("Received service distribution from SDC with the id {}", distributionId); + processNotification(notificationData); + } + + private void processNotification(INotificationData notificationData) { + final IDistributionClient distributionClient = sdcListenerDto.getDistributionClient(); + notificationData.getServiceArtifacts() + .forEach(artifactInfo -> downloadCsarArtifacts(artifactInfo, distributionClient)); + } + + /** + * Download the TOSCA CSAR artifact and process it. + * + * @param info - Artifact information + * @param distributionClient - SDC distribution client + */ + private void downloadCsarArtifacts(IArtifactInfo info, IDistributionClient distributionClient) { + final String url = info.getArtifactURL(); + final String id = info.getArtifactUUID(); + + if (Objects.equals(info.getArtifactType(), SdcListenerConfiguration.TOSCA_CSAR)) { + LOGGER.info("Trying to download the artifact from : {} and UUID is {} ", url, id); + + // Download the artifact + IDistributionClientDownloadResult result = distributionClient.download(info); + + if (!Objects.equals(result.getDistributionActionResult(), SUCCESS)) { + String errorMessage = String.format("Failed to download the artifact from : %s due to %s ", url, + result.getDistributionActionResult()); + listenerStatus.sendResponseStatusBackToSDC(sdcListenerDto.getDistributionId(), + DistributionStatusEnum.COMPONENT_DONE_ERROR, errorMessage); + LOGGER.error(errorMessage); + } else { + LOGGER.info("Trying to write CSAR artifact to file with URL {} and UUID {}", url, id); + processCsarArtifact(result); + } + } + } + + public void processCsarArtifact(IDistributionClientDownloadResult result) { + Path cbaArchivePath = Paths.get(pathToStoreArchives, "cba-archive"); + Path csarArchivePath = Paths.get(pathToStoreArchives, "csar-archive"); + + // Extract and store the CSAR archive into local disk. + listenerService.extractCsarAndStore(result, csarArchivePath.toString()); + + Optional> csarFiles = FileUtil.getFilesFromDisk(csarArchivePath); + + if (csarFiles.isPresent()) { + //Extract CBA archive from CSAR package and store it into local disk. + List files = csarFiles.get(); + + if (!files.isEmpty()) { + final String archivePath = cbaArchivePath.toString(); + files.forEach(file -> listenerService.extractBluePrint(file.getAbsolutePath(), archivePath)); + files.forEach(file -> FileUtil.deleteFile(file, archivePath)); + } else { + LOGGER.error("The CSAR file is not present at this location {}", csarArchivePath); + } + } + + listenerService.saveBluePrintToCdsDatabase(cbaArchivePath, sdcListenerDto.getManagedChannelForGrpc()); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerAuthClientInterceptor.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerAuthClientInterceptor.java new file mode 100644 index 000000000..6f782d10a --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerAuthClientInterceptor.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.client; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.Metadata.Key; +import io.grpc.MethodDescriptor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * To provide authentication with GRPC server. + */ +@ConfigurationProperties("listenerservice") +@Component +public class SdcListenerAuthClientInterceptor implements ClientInterceptor { + + @Value("${listenerservice.config.authHeader}") + private String basicAuth; + + @Override + public ClientCall interceptCall(MethodDescriptor methodDescriptor, + CallOptions callOptions, Channel channel) { + Key authHeader = Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER); + return new ForwardingClientCall.SimpleForwardingClientCall( + channel.newCall(methodDescriptor, callOptions)) { + @Override + public void start(Listener responseListener, Metadata headers) { + headers.put(authHeader, basicAuth); + super.start(responseListener, headers); + } + }; + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerClient.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerClient.java new file mode 100644 index 000000000..973f950bc --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/client/SdcListenerClient.java @@ -0,0 +1,95 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.client; + +import java.util.Optional; +import org.onap.ccsdk.cds.sdclistener.SdcListenerConfiguration; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.SdcListenerNotificationCallback; +import org.onap.ccsdk.cds.sdclistener.exceptions.SdcListenerException; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientFactory; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@ComponentScan("org.onap.ccsdk.cds.cdssdclistener.dto") +public class SdcListenerClient { + + private static Logger LOG = LoggerFactory.getLogger(SdcListenerClient.class); + + @Autowired + private SdcListenerConfiguration configuration; + + @Autowired + private SdcListenerNotificationCallback notification; + + @Autowired + private SdcListenerDto listenerDto; + + private IDistributionClient distributionClient; + + /** + * This method initializes the SDC Distribution client. + */ + @EventListener(ApplicationReadyEvent.class) + public void initSdcClient() throws SdcListenerException { + LOG.info("Initialize the SDC distribution client"); + + distributionClient = Optional.of(DistributionClientFactory.createDistributionClient()) + .orElseThrow(() -> new SdcListenerException("Could not able to create SDC Distribution client")); + + listenerDto.setManagedChannelForGrpc(); + + listenerDto.setDistributionClient(distributionClient); + + IDistributionClientResult result = distributionClient.init(configuration, notification); + startSdcClientBasedOnTheResult(result); + } + + private void startSdcClientBasedOnTheResult(IDistributionClientResult result) throws SdcListenerException { + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + throw new SdcListenerException( + "SDC distribution client init failed with reason:" + result.getDistributionMessageResult()); + } + + LOG.info("Initialization of the SDC distribution client is complete"); + + // Start the client. + result = this.distributionClient.start(); + + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + throw new SdcListenerException( + "Startup of the SDC distribution client failed with reason: " + result.getDistributionMessageResult()); + } + } + + private void closeSdcDistributionclient() throws SdcListenerException { + LOG.info("Closing SDC distribution client"); + IDistributionClientResult status = this.distributionClient.stop(); + if (status.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + throw new SdcListenerException( + "Failed to close the SDC distribution client due to : " + status.getDistributionMessageResult()); + } + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/controller/HealthCheck.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/controller/HealthCheck.java new file mode 100644 index 000000000..a9e51ac12 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/controller/HealthCheck.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.controller; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/api/v1/sdclistener") +public class HealthCheck { + + @RequestMapping(path = "/healthcheck", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + Mono ping() { + return Mono.just("{\"status\":\"UP\"}"); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/dto/SdcListenerDto.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/dto/SdcListenerDto.java new file mode 100644 index 000000000..c7c3d4829 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/dto/SdcListenerDto.java @@ -0,0 +1,70 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.dto; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import org.onap.ccsdk.cds.sdclistener.client.SdcListenerAuthClientInterceptor; +import org.onap.sdc.api.IDistributionClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("listenerservice") +public class SdcListenerDto { + + @Value("${listenerservice.config.grpcAddress}") + private String grpcAddress; + + @Value("${listenerservice.config.grpcPort}") + private int grpcPort; + + @Autowired + private SdcListenerAuthClientInterceptor sdcListenerAuthClientInterceptor; + + private IDistributionClient distributionClient; + private ManagedChannel managedChannel; + private String distributionId; + + public IDistributionClient getDistributionClient() { + return distributionClient; + } + + public void setDistributionClient(IDistributionClient distributionClient) { + this.distributionClient = distributionClient; + } + + public void setDistributionId(String id) { + this.distributionId = id; + } + + public String getDistributionId() { + return distributionId; + } + + public void setManagedChannelForGrpc() { + managedChannel = ManagedChannelBuilder.forAddress(grpcAddress, grpcPort) + .usePlaintext() + .intercept(sdcListenerAuthClientInterceptor) + .build(); + } + + public ManagedChannel getManagedChannelForGrpc() { + return managedChannel; + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/exceptions/SdcListenerException.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/exceptions/SdcListenerException.java new file mode 100644 index 000000000..23f669f1e --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/exceptions/SdcListenerException.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.exceptions; + +public class SdcListenerException extends Exception { + + /** + * @param message The message to dump + */ + public SdcListenerException(final String message) { + super(message); + } + + /** + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcListenerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcesssorHandler.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcesssorHandler.java new file mode 100644 index 000000000..96b2ff081 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcesssorHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.handler; + +import io.grpc.ManagedChannel; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc.BluePrintManagementServiceBlockingStub; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties("listenerservice") +@Component +public class BluePrintProcesssorHandler implements AutoCloseable { + + private static final Logger LOGGER = LoggerFactory.getLogger(BluePrintProcesssorHandler.class); + + private ManagedChannel channel; + + /** + * Sending CBA archive to CDS backend to store into its Database. + * + * @param request BluePrintManagementInput object holds CBA archive, its version and blueprints. + * @param managedChannel - ManagedChannel object helps to access the server or application end point. + * @return A response object + */ + public Status sendRequest(BluePrintUploadInput request, ManagedChannel managedChannel) { + LOGGER.info("Sending request to blueprint processor"); + + this.channel = managedChannel; + + final BluePrintManagementServiceBlockingStub syncStub = BluePrintManagementServiceGrpc.newBlockingStub(channel); + + // Send the request to CDS backend. + final BluePrintManagementOutput response = syncStub.uploadBlueprint(request); + + return response.getStatus(); + } + + @Override + public void close() { + if (channel != null) { + channel.shutdown(); + } + LOGGER.info("Stopping GRPC connection to CDS backend"); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerService.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerService.java new file mode 100644 index 000000000..446c3e621 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerService.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.service; + +import io.grpc.ManagedChannel; +import java.nio.file.Path; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; + +public interface ListenerService { + + /** + * Get the controller blueprint archive from CSAR package. + * + * @param csarArchivePath The path where CSAR archive is stored. + * @param cbaArchivePath The destination path where CBA will be stored. + */ + void extractBluePrint(String csarArchivePath, String cbaArchivePath); + + /** + * Store the Zip file into CDS database. + * + * @param path path where zip file exists. + * @param managedChannel To access the blueprint processor application end point + */ + void saveBluePrintToCdsDatabase(Path path, ManagedChannel managedChannel); + + /** + * Extract and store the csar package to local disk. + * + * @param result - IDistributionClientDownloadResult contains payload. + * @param csarArchivePath The destination path where CSAR will be stored. + */ + void extractCsarAndStore(IDistributionClientDownloadResult result, String csarArchivePath); +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImpl.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImpl.java new file mode 100644 index 000000000..9a6ae8779 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImpl.java @@ -0,0 +1,202 @@ +/* + * Copyright © 2017-2019 AT&T, Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.service; + +import static java.nio.file.Files.walk; +import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_ERROR; +import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_OK; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannel; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.apache.commons.io.FileUtils; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.onap.ccsdk.cds.sdclistener.client.SdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.handler.BluePrintProcesssorHandler; +import org.onap.ccsdk.cds.sdclistener.status.SdcListenerStatus; +import org.onap.ccsdk.cds.sdclistener.util.FileUtil; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("listenerservice") +public class ListenerServiceImpl implements ListenerService { + + @Autowired + private BluePrintProcesssorHandler bluePrintProcesssorHandler; + + @Autowired + private SdcListenerAuthClientInterceptor sdcListenerAuthClientInterceptor; + + @Autowired + private SdcListenerStatus listenerStatus; + + @Autowired + private SdcListenerDto sdcListenerDto; + + @Value("${listenerservice.config.grpcAddress}") + private String grpcAddress; + + @Value("${listenerservice.config.grpcPort}") + private int grpcPort; + + private static final String CBA_ZIP_PATH = "Artifacts/Resources/[a-zA-Z0-9-_]+/Deployment/CONTROLLER_BLUEPRINT_ARCHIVE/[a-zA-Z0-9-_]+[.]zip"; + private static final int SUCCESS_CODE = 200; + private static final Logger LOGGER = LoggerFactory.getLogger(ListenerServiceImpl.class); + + @Override + public void extractBluePrint(String csarArchivePath, String cbaArchivePath) { + Path cbaStorageDir = getStorageDirectory(cbaArchivePath); + try (ZipFile zipFile = new ZipFile(csarArchivePath)) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + String fileName = entry.getName(); + if (Pattern.matches(CBA_ZIP_PATH, fileName)) { + final String cbaArchiveName = Paths.get(fileName).getFileName().toString(); + LOGGER.info("Storing the CBA archive {}", cbaArchiveName); + storeBluePrint(zipFile, cbaArchiveName, cbaStorageDir, entry); + } + } + + } catch (Exception e) { + LOGGER.error("Failed to extract blueprint {}", e); + } + } + + private void storeBluePrint(ZipFile zipFile, String fileName, Path cbaArchivePath, ZipEntry entry) { + Path targetLocation = cbaArchivePath.resolve(fileName); + LOGGER.info("The target location for zip file is {}", targetLocation); + File targetZipFile = new File(targetLocation.toString()); + + try { + targetZipFile.createNewFile(); + } catch (IOException e) { + LOGGER.error("Could not able to create file {}", targetZipFile, e); + } + + try (InputStream inputStream = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream( + targetZipFile)) { + IOUtils.copy(inputStream, out); + LOGGER.info("Successfully store the CBA archive {} at this location", targetZipFile); + } catch (Exception e) { + LOGGER.error("Failed to put zip file into target location {}, {}", targetLocation, e); + } + } + + @Override + public void saveBluePrintToCdsDatabase(Path cbaArchivePath, ManagedChannel channel) { + Optional> zipFiles = FileUtil.getFilesFromDisk(cbaArchivePath); + zipFiles.ifPresent(files -> prepareRequestForCdsBackend(files, channel, cbaArchivePath.toString())); + } + + @Override + public void extractCsarAndStore(IDistributionClientDownloadResult result, String csarArchivePath) { + + // Create CSAR storage directory + Path csarStorageDir = getStorageDirectory(csarArchivePath); + byte[] payload = result.getArtifactPayload(); + String csarFileName = result.getArtifactFilename(); + Path targetLocation = csarStorageDir.resolve(csarFileName); + + LOGGER.info("The target location for the CSAR file is {}", targetLocation); + + File targetCsarFile = new File(targetLocation.toString()); + + try (FileOutputStream outFile = new FileOutputStream(targetCsarFile)) { + outFile.write(payload, 0, payload.length); + } catch (Exception e) { + LOGGER.error("Failed to put CSAR file into target location {}, {}", targetLocation, e); + } + } + + private Path getStorageDirectory(String path) { + Path fileStorageLocation = Paths.get(path).toAbsolutePath().normalize(); + + if (!fileStorageLocation.toFile().exists()) { + try { + return Files.createDirectories(fileStorageLocation); + } catch (IOException e) { + LOGGER.error("Fail to create directory {}, {}", e, fileStorageLocation); + } + } + return fileStorageLocation; + } + + private void prepareRequestForCdsBackend(List files, ManagedChannel managedChannel, String path) { + final String distributionId = sdcListenerDto.getDistributionId(); + + files.forEach(zipFile -> { + try { + final BluePrintUploadInput request = generateBluePrintUploadInputBuilder(zipFile); + + // Send request to CDS Backend. + final Status responseStatus = bluePrintProcesssorHandler.sendRequest(request, managedChannel); + + if (responseStatus.getCode() != SUCCESS_CODE) { + final String errorMessage = String.format("Failed to store the CBA archive into CDS DB due to %s", + responseStatus.getErrorMessage()); + listenerStatus.sendResponseStatusBackToSDC(distributionId, + COMPONENT_DONE_ERROR, errorMessage); + LOGGER.error(errorMessage); + + } else { + LOGGER.info(responseStatus.getMessage()); + listenerStatus.sendResponseStatusBackToSDC(distributionId, + COMPONENT_DONE_OK, null); + } + + } catch (Exception e) { + final String errorMessage = String.format("Failure due to %s", e.getMessage()); + listenerStatus.sendResponseStatusBackToSDC(distributionId, COMPONENT_DONE_ERROR, errorMessage); + LOGGER.error("Failure due to {}", e); + } finally { + FileUtil.deleteFile(zipFile, path); + } + }); + } + + private BluePrintUploadInput generateBluePrintUploadInputBuilder(File file) throws IOException { + byte[] bytes = FileUtils.readFileToByteArray(file); + FileChunk fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(bytes)).build(); + + return BluePrintUploadInput.newBuilder() + .setFileChunk(fileChunk) + .build(); + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/DistributionStatusMessage.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/DistributionStatusMessage.java new file mode 100644 index 000000000..60463762b --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/DistributionStatusMessage.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.status; + +import org.onap.sdc.api.consumer.IFinalDistrStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + +public class DistributionStatusMessage implements IFinalDistrStatusMessage { + + public String componentName; + + public String consumerID; + + public String distributionID; + + public DistributionStatusEnum status; + + @Override + public String getDistributionID() { + return distributionID; + } + + @Override + public long getTimestamp() { + return 0; + } + + @Override + public DistributionStatusEnum getStatus() { + return status; + } + + @Override + public String getConsumerID() { + return consumerID; + } + + @Override + public String getComponentName() { + return componentName; + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/SdcListenerStatus.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/SdcListenerStatus.java new file mode 100644 index 000000000..ff64c0d0c --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/status/SdcListenerStatus.java @@ -0,0 +1,82 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.status; + +import static org.onap.sdc.utils.DistributionActionResultEnum.SUCCESS; +import java.util.Objects; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.util.BuilderUtil; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.consumer.IFinalDistrStatusMessage; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.utils.DistributionStatusEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties("listenerservice") +@ComponentScan("org.onap.ccsdk.cds.cdssdclistener.dto") +public class SdcListenerStatus { + + private static final Logger LOGGER = LoggerFactory.getLogger(SdcListenerStatus.class); + private static final String COMPONENT_NAME = "cds"; + + @Value("${listenerservice.config.consumerId}") + private String consumerId; + + @Autowired + private SdcListenerDto sdcListenerDto; + + /** + * Send the response back to SDC. + * + * @param distributionID SDC Distribution ID + * @param status Distribution status + * @param errorReason Reason of failure + */ + public void sendResponseStatusBackToSDC(String distributionID, DistributionStatusEnum status, String errorReason) { + + final IDistributionClient distributionClient = sdcListenerDto.getDistributionClient(); + + IFinalDistrStatusMessage finalDistribution = new BuilderUtil<>(new DistributionStatusMessage()) + .build(builder -> { + builder.distributionID = distributionID; + builder.status = status; + builder.consumerID = consumerId; + builder.componentName = COMPONENT_NAME; + }).create(); + + if (errorReason == null) { + checkResponseStatusFromSdc(distributionClient.sendFinalDistrStatus(finalDistribution)); + } else { + checkResponseStatusFromSdc(distributionClient.sendFinalDistrStatus(finalDistribution, errorReason)); + } + } + + private void checkResponseStatusFromSdc(IDistributionClientResult result) { + if (!Objects.equals(result.getDistributionActionResult(), SUCCESS)) { + LOGGER.error("SDC failed to receive the response from cds-sdc listener due to {}", + result.getDistributionMessageResult()); + } else { + LOGGER.info("SDC successfully received the response"); + } + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/BuilderUtil.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/BuilderUtil.java new file mode 100644 index 000000000..1f546d107 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/BuilderUtil.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Bell Canada. All rights reserved. + * + * NOTICE: All the intellectual and technical concepts contained herein are + * proprietary to Bell Canada and are protected by trade secret or copyright law. + * Unauthorized copying of this file, via any medium is strictly prohibited. + */ +package org.onap.ccsdk.cds.sdclistener.util; + +import java.util.function.Consumer; + +/** + * A generic builder for constructing an object. + * + * @param - Any object + */ +public class BuilderUtil { + + private final T object; + + public BuilderUtil(T instance) { + this.object = instance; + } + + public BuilderUtil build(Consumer consumer) { + consumer.accept(object); + return this; + } + + public T create() { + return object; + } +} diff --git a/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/FileUtil.java b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/FileUtil.java new file mode 100644 index 000000000..967e854d7 --- /dev/null +++ b/ms/sdclistener/application/src/main/java/org/onap/ccsdk/cds/sdclistener/util/FileUtil.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 Bell Canada. All rights reserved. + * + * NOTICE: All the intellectual and technical concepts contained herein are + * proprietary to Bell Canada and are protected by trade secret or copyright law. + * Unauthorized copying of this file, via any medium is strictly prohibited. + */ + +package org.onap.ccsdk.cds.sdclistener.util; + +import static java.nio.file.Files.walk; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class FileUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class); + + private FileUtil() { + + } + + /** + * Delete the file. + * + * @param file - Given file + * @param path - Given path + */ + public static void deleteFile(File file, String path) { + boolean value = file.delete(); + if (!value) { + LOGGER.error("Failed to delete the file {} at the location {}", file, path); + } + } + + /** + * Extract files from the given path + * + * @param path where files reside. + * @return list of files. + */ + public static Optional> getFilesFromDisk(Path path) { + try (Stream fileTree = walk(path)) { + // Get the list of files from the path + return Optional.of(fileTree.filter(Files::isRegularFile) + .map(Path::toFile) + .collect(Collectors.toList())); + } catch (IOException e) { + LOGGER.error("Failed to find the file due to", e); + } + return Optional.empty(); + } +} diff --git a/ms/sdclistener/application/src/main/resources/application.yml b/ms/sdclistener/application/src/main/resources/application.yml new file mode 100644 index 000000000..b3f8443eb --- /dev/null +++ b/ms/sdclistener/application/src/main/resources/application.yml @@ -0,0 +1,27 @@ +listenerservice: + config: + asdcAddress: ${asdcAddress:localhost:8443} + messageBusAddress: ${messageBusAddress:localhost} + user: ${sdcusername:vid} + password: ${password:Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U} + pollingInterval: ${pollingInterval:15} + pollingTimeout: ${pollingTimeout:60} + relevantArtifactTypes: ${relevantArtifactTypes:TOSCA_CSAR} + consumerGroup: ${consumerGroup:cds-id-local} + environmentName: ${environmentName:AUTO} + consumerId: ${consumerId:cds-id-local} + keyStorePassword: ${keyStorePassword} + keyStorePath: ${keyStorePath} + activateServerTLSAuth : ${activateServerTLSAuth:false} + isUseHttpsWithDmaap: ${isUseHttpsWithDmaap:false} + archivePath: ${archivePath:/opt/app/onap/cds-sdc-listener/} + grpcAddress: ${grpcAddress:localhost} + grpcPort: ${grpcPort:9111} + authHeader: ${authHeader:Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==} +#port needed by Liveness probe +server: + port: ${healthcheckPort:9000} +#set spring.main.web-environment=false if you want to NOT to open a port for healthcheck. +spring: + main: + web-environment: ${sprintWebListenerEnabled:true} diff --git a/ms/sdclistener/application/src/main/resources/logback.xml b/ms/sdclistener/application/src/main/resources/logback.xml new file mode 100644 index 000000000..b26cbcbe4 --- /dev/null +++ b/ms/sdclistener/application/src/main/resources/logback.xml @@ -0,0 +1,33 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + + + + + + diff --git a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerClientTest.java b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerClientTest.java new file mode 100644 index 000000000..c9f2c5a39 --- /dev/null +++ b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerClientTest.java @@ -0,0 +1,80 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener; + +import mockit.Expectations; +import mockit.Injectable; +import mockit.Mock; +import mockit.MockUp; +import mockit.Tested; +import mockit.VerificationsInOrder; +import mockit.integration.junit4.JMockit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.sdclistener.client.SdcListenerClient; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.exceptions.SdcListenerException; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientFactory; +import org.onap.sdc.impl.DistributionClientResultImpl; +import org.onap.sdc.utils.DistributionActionResultEnum; + +@RunWith(JMockit.class) +public class SdcListenerClientTest { + + @Tested + private SdcListenerClient sdcListenerClient; + + @Test + public void testInitCdsClientSuccesfully(@Injectable IDistributionClient distributionClient, + @Injectable SdcListenerConfiguration configuration, + @Injectable SdcListenerNotificationCallback notification, + @Injectable SdcListenerDto sdcListenerDto) throws SdcListenerException { + + //Arrange + new MockUp() { + @Mock + public IDistributionClient createDistributionClient() { + return distributionClient; + } + }; + + new Expectations() {{ + distributionClient.init(configuration, notification); + result = getResult(); + }}; + + new Expectations() {{ + distributionClient.start(); + result = getResult(); + }}; + + // Act + sdcListenerClient.initSdcClient(); + + // Verify + new VerificationsInOrder() {{ + distributionClient.init(configuration, notification); + distributionClient.start(); + }}; + } + + public IDistributionClientResult getResult() { + return new DistributionClientResultImpl(DistributionActionResultEnum.SUCCESS, + DistributionActionResultEnum.SUCCESS.name()); + } +} diff --git a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java new file mode 100644 index 000000000..01ffe1ba9 --- /dev/null +++ b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@EnableConfigurationProperties(SdcListenerConfiguration.class) +@SpringBootTest(classes = {SdcListenerConfigurationTest.class}) +public class SdcListenerConfigurationTest { + + @Autowired + private SdcListenerConfiguration listenerConfiguration; + + @Test + public void testCdsSdcListenerConfiguration() { + assertEquals(listenerConfiguration.getAsdcAddress(), "localhost:8443"); + assertEquals(listenerConfiguration.getMsgBusAddress().stream().findFirst().get(), "localhost"); + assertEquals(listenerConfiguration.getUser(), "vid"); + assertEquals(listenerConfiguration.getPassword(), "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"); + assertEquals(listenerConfiguration.getPollingInterval(), 15); + assertEquals(listenerConfiguration.getPollingTimeout(), 60); + assertEquals(listenerConfiguration.getRelevantArtifactTypes().stream().findFirst().get(), "TOSCA_CSAR"); + assertEquals(listenerConfiguration.getConsumerGroup(), "cds-id-local"); + assertEquals(listenerConfiguration.getEnvironmentName(), "AUTO"); + assertEquals(listenerConfiguration.getConsumerID(), "cds-id-local"); + assertEquals(listenerConfiguration.activateServerTLSAuth(), false); + } +} diff --git a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcessorHandlerTest.java b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcessorHandlerTest.java new file mode 100644 index 000000000..ee20f8771 --- /dev/null +++ b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/handler/BluePrintProcessorHandlerTest.java @@ -0,0 +1,112 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannel; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.sdclistener.client.SdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@EnableConfigurationProperties({BluePrintProcesssorHandler.class, SdcListenerAuthClientInterceptor.class}) +@SpringBootTest(classes = {BluePrintProcessorHandlerTest.class}) +public class BluePrintProcessorHandlerTest { + + @Autowired + private BluePrintProcesssorHandler bluePrintProcesssorHandler; + + @Autowired + private SdcListenerAuthClientInterceptor sdcListenerAuthClientInterceptor; + + @Rule + public GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + private static final String CBA_ARCHIVE = "src/test/resources/testcba.zip"; + private static final String SUCCESS_MSG = "Successfully uploaded CBA"; + private static final int SUCCESS_CODE = 200; + private ManagedChannel channel; + + @Before + public void setUp() throws IOException { + final BluePrintManagementServiceImplBase serviceImplBase = new BluePrintManagementServiceImplBase() { + @Override + public void uploadBlueprint(BluePrintUploadInput request, + StreamObserver responseObserver) { + responseObserver.onNext(getBluePrintManagementOutput()); + responseObserver.onCompleted(); + } + }; + + // Generate server name. + String serverName = InProcessServerBuilder.generateName(); + + // Create a server, add service, start, and register. + grpcCleanup.register( + InProcessServerBuilder.forName(serverName).addService(serviceImplBase).directExecutor().build().start()); + + // Create a client channel. + channel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build()); + } + + @Test + public void testApplicationEndPointSucess() throws IOException { + // Arrange + BluePrintUploadInput request = generateRequest(); + + // Act + Status output = bluePrintProcesssorHandler.sendRequest(request, channel); + + // Verify + assertEquals(SUCCESS_CODE, output.getCode()); + assertTrue(output.getMessage().contains(SUCCESS_MSG)); + } + + private BluePrintUploadInput generateRequest() throws IOException { + File file = Paths.get(CBA_ARCHIVE).toFile(); + byte[] bytes = FileUtils.readFileToByteArray(file); + FileChunk fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(bytes)).build(); + + return BluePrintUploadInput.newBuilder().setFileChunk(fileChunk).build(); + } + + private BluePrintManagementOutput getBluePrintManagementOutput() { + return BluePrintManagementOutput.newBuilder() + .setStatus(Status.newBuilder().setMessage(SUCCESS_MSG).setCode(200).build()) + .build(); + } +} diff --git a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImplTest.java b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImplTest.java new file mode 100644 index 000000000..f5ff2bdb8 --- /dev/null +++ b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/service/ListenerServiceImplTest.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2019 Bell Canada + * + * 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.onap.ccsdk.cds.sdclistener.service; + +import static junit.framework.TestCase.assertTrue; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.sdclistener.SdcListenerConfiguration; +import org.onap.ccsdk.cds.sdclistener.client.SdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.sdclistener.dto.SdcListenerDto; +import org.onap.ccsdk.cds.sdclistener.handler.BluePrintProcesssorHandler; +import org.onap.ccsdk.cds.sdclistener.status.SdcListenerStatus; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.impl.mock.DistributionClientResultStubImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@EnableConfigurationProperties({SdcListenerAuthClientInterceptor.class, + BluePrintProcesssorHandler.class, SdcListenerDto.class, ListenerServiceImpl.class, SdcListenerStatus.class, + SdcListenerConfiguration.class}) +@SpringBootTest(classes = {ListenerServiceImplTest.class}) +public class ListenerServiceImplTest { + + private static final String CSAR_SAMPLE = "src/test/resources/service-Testsvc140.csar"; + private static final String ZIP_FILE = ".zip"; + private static final String CSAR_FILE = ".csar"; + private String csarArchivePath; + private Path tempDirectoryPath; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Autowired + private ListenerServiceImpl listenerService; + + @Before + public void setup() { + csarArchivePath = folder.getRoot().toString(); + tempDirectoryPath = Paths.get(csarArchivePath, "cds-sdc-listener-test"); + } + @Test + public void extractBluePrintSuccessfully() throws IOException { + // Act + listenerService.extractBluePrint(CSAR_SAMPLE, tempDirectoryPath.toString()); + + // Verify + String result = checkFileExists(tempDirectoryPath); + assertTrue(result.contains(ZIP_FILE)); + } + + @Test + public void storeCsarArtifactToFileSuccessfully() throws IOException { + // Arrange + DistributionClientDownloadResultStubImpl resultStub = new DistributionClientDownloadResultStubImpl(); + + // Act + listenerService.extractCsarAndStore(resultStub, tempDirectoryPath.toString()); + + // Verify + String result = checkFileExists(tempDirectoryPath); + assertTrue(result.contains(CSAR_FILE)); + } + + private String checkFileExists(Path path) throws IOException { + return Files.walk(path) + .filter(Files::isRegularFile) + .map(Path::toFile) + .findAny() + .get() + .getName(); + } + + public byte[] convertFileToByteArray(File file) { + try { + return FileUtils.readFileToByteArray(file); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public class DistributionClientDownloadResultStubImpl extends DistributionClientResultStubImpl implements + IDistributionClientDownloadResult { + + public DistributionClientDownloadResultStubImpl() { + } + + public byte[] getArtifactPayload() { + File file = Paths.get(CSAR_SAMPLE).toFile(); + return convertFileToByteArray(file); + } + + public String getArtifactName() { + return "MackArtifactName"; + } + + public String getArtifactFilename() { + return "MackArtifactName.csar"; + } + } +} diff --git a/ms/sdclistener/application/src/test/resources/service-Testsvc140.csar b/ms/sdclistener/application/src/test/resources/service-Testsvc140.csar new file mode 100644 index 000000000..4aa0de72b Binary files /dev/null and b/ms/sdclistener/application/src/test/resources/service-Testsvc140.csar differ diff --git a/ms/sdclistener/application/src/test/resources/testcba.zip b/ms/sdclistener/application/src/test/resources/testcba.zip new file mode 100644 index 000000000..c886fe6bc Binary files /dev/null and b/ms/sdclistener/application/src/test/resources/testcba.zip differ -- cgit 1.2.3-korg