From 7d2b19e9b65c045675381b5f352e67650bdd068d Mon Sep 17 00:00:00 2001 From: "waqas.ikram" Date: Wed, 25 Jan 2023 11:47:41 +0000 Subject: Adding support for registration of kubernetes clusters and fixing code smells Change-Id: I2d10c263e255ca8644539de9c47c9a4fed04997f Issue-ID: SO-4050 Signed-off-by: waqas.ikram --- .../DefaultToShortClassNameBeanNameGenerator.java | 9 ++- .../KubeConfigFileNotFoundException.java | 39 +++++++++ .../exceptions/KubeConfigFileUploadException.java | 39 +++++++++ .../sdc/SdcClientConfigurationProvider.java | 24 ++---- .../flows/extclients/sdc/SdcCsarPackageParser.java | 6 +- .../lcm/bpmn/flows/service/JobExecutorService.java | 39 +++++---- .../lcm/bpmn/flows/service/KubConfigProvider.java | 39 +++++++++ .../bpmn/flows/service/KubConfigProviderImpl.java | 92 ++++++++++++++++++++++ .../bpmn/flows/service/WorkflowQueryService.java | 14 ++-- .../so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java | 8 +- .../flows/utils/PropertiesToYamlConverter.java | 1 - .../cnfm/lcm/rest/CloudKubeConfigController.java | 73 +++++++++++++++++ .../lcm/rest/CloudKubeConfigControllerTest.java | 54 +++++++++++++ 13 files changed, 382 insertions(+), 55 deletions(-) create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileNotFoundException.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileUploadException.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProvider.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProviderImpl.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigController.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigControllerTest.java diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-application/src/main/java/org/onap/so/cnfm/lcm/app/DefaultToShortClassNameBeanNameGenerator.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-application/src/main/java/org/onap/so/cnfm/lcm/app/DefaultToShortClassNameBeanNameGenerator.java index dbf5e02..2683b03 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-application/src/main/java/org/onap/so/cnfm/lcm/app/DefaultToShortClassNameBeanNameGenerator.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-application/src/main/java/org/onap/so/cnfm/lcm/app/DefaultToShortClassNameBeanNameGenerator.java @@ -19,6 +19,8 @@ */ package org.onap.so.cnfm.lcm.app; +import static org.slf4j.LoggerFactory.getLogger; +import org.slf4j.Logger; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.util.ClassUtils; @@ -28,9 +30,14 @@ import org.springframework.util.ClassUtils; * */ public class DefaultToShortClassNameBeanNameGenerator extends AnnotationBeanNameGenerator { + private static final Logger logger = getLogger(DefaultToShortClassNameBeanNameGenerator.class); @Override protected String buildDefaultBeanName(final BeanDefinition definition) { - return ClassUtils.getShortName(definition.getBeanClassName()); + if (definition.getBeanClassName() != null) { + return ClassUtils.getShortName(definition.getBeanClassName()); + } + logger.warn("Bean class name is not specified..."); + return null; } } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileNotFoundException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileNotFoundException.java new file mode 100644 index 0000000..24eb8b1 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileNotFoundException.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.exceptions; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class KubeConfigFileNotFoundException extends Exception { + + private static final long serialVersionUID = -7347276762841623563L; + + public KubeConfigFileNotFoundException(final String message) { + super(message); + } + + public KubeConfigFileNotFoundException(final String message, final Throwable cause) { + super(message, cause); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileUploadException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileUploadException.java new file mode 100644 index 0000000..caee609 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileUploadException.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.exceptions; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class KubeConfigFileUploadException extends RuntimeException { + + private static final long serialVersionUID = -7347276762841623563L; + + public KubeConfigFileUploadException(final String message) { + super(message); + } + + public KubeConfigFileUploadException(final String message, final Throwable cause) { + super(message, cause); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java index 4ae1d43..dd47bad 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java @@ -24,8 +24,6 @@ import java.security.GeneralSecurityException; import org.apache.commons.codec.binary.Base64; import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.BasicAuthConfigException; import org.onap.so.utils.CryptoUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -36,8 +34,6 @@ import org.springframework.context.annotation.Configuration; @Configuration public class SdcClientConfigurationProvider { - private static final Logger logger = LoggerFactory.getLogger(SdcClientConfigurationProvider.class); - @Value("${sdc.username:mso}") private String sdcUsername; @@ -52,20 +48,14 @@ public class SdcClientConfigurationProvider { private static String basicAuth = null; - - public String getBasicAuth() { + public synchronized String getBasicAuth() { if (basicAuth == null) { - synchronized (this) { - if (basicAuth == null) { - try { - final String auth = sdcUsername + ":" + CryptoUtils.decrypt(sdcPassword, sdcKey); - final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1)); - basicAuth = "Basic " + new String(encodedAuth); - } catch (final GeneralSecurityException exception) { - logger.error("Unable to process basic auth information", exception); - throw new BasicAuthConfigException("Unable to process basic auth information", exception); - } - } + try { + final String auth = sdcUsername + ":" + CryptoUtils.decrypt(sdcPassword, sdcKey); + final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1)); + basicAuth = "Basic " + new String(encodedAuth); + } catch (final GeneralSecurityException exception) { + throw new BasicAuthConfigException("Unable to process basic auth information", exception); } } return basicAuth; diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java index 0ade7bf..c06d42f 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java @@ -82,7 +82,7 @@ public class SdcCsarPackageParser { final String type = childElement(child, "type").getAsString(); if ("tosca.nodes.asd".equals(type)) { final JsonObject properties = child(child, "properties"); - logger.debug("properties: {}", properties.toString()); + logger.debug("properties: {}", properties); final Map propertiesValues = new HashMap<>(); propertiesValues.put(DESCRIPTOR_ID_PARAM_NAME, getStringValue(properties, DESCRIPTOR_ID_PARAM_NAME)); @@ -134,9 +134,9 @@ public class SdcCsarPackageParser { private List getLifecycleParameters(final JsonObject artifactsProperties) { final JsonArray lcParameters = childElement(artifactsProperties, "lifecycle_parameters").getAsJsonArray(); final List lifecycleParameters = new ArrayList<>(); - if(lcParameters != null) { + if (lcParameters != null) { final Iterator it = lcParameters.iterator(); - while(it.hasNext()){ + while (it.hasNext()) { lifecycleParameters.add(it.next().getAsString()); } } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java index c4bd210..0f6e8d0 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java @@ -39,6 +39,7 @@ import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.tuple.ImmutablePair; import org.onap.so.cnfm.lcm.bpmn.flows.GsonProvider; @@ -61,7 +62,6 @@ import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; /** @@ -73,8 +73,7 @@ public class JobExecutorService { private static final Logger logger = getLogger(JobExecutorService.class); - private static final ImmutableSet JOB_FINISHED_STATES = - ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR); + private static final Set JOB_FINISHED_STATES = Set.of(FINISHED, ERROR, FINISHED_WITH_ERROR); private static final int SLEEP_TIME_IN_SECONDS = 5; @@ -103,7 +102,7 @@ public class JobExecutorService { .status(JobStatusEnum.STARTING); databaseServiceProvider.addJob(newJob); - logger.info("New job created in database :\n{}", newJob); + logger.info("New job created in database for CreateAs:\n{}", newJob); workflowExecutorService.executeWorkflow(newJob.getJobId(), CREATE_AS_WORKFLOW_NAME, getVariables(newJob.getJobId(), createAsRequest)); @@ -130,8 +129,8 @@ public class JobExecutorService { throw new AsRequestProcessingException(message, errorDetails); } - final String message = "Received unexpected Job Status: " + finalJobStatus - + " Failed to Create AS for request: \n" + createAsRequest; + final String message = "Create AS request failed. Received unexpected Job Status: " + finalJobStatus + + " Create As request: \n" + createAsRequest; logger.error(message); throw new AsRequestProcessingException(message); } @@ -151,7 +150,7 @@ public class JobExecutorService { final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.INSTANTIATE) .resourceId(asInstanceId).status(JobStatusEnum.STARTING); databaseServiceProvider.addJob(newJob); - logger.info("New job created in database :\n{}", newJob); + logger.info("New job created in database for InstantiateAs :\n{}", newJob); final LocalDateTime currentDateTime = LocalDateTime.now(); final AsLcmOpOcc newAsLcmOpOcc = new AsLcmOpOcc().id(asInstanceId).operation(AsLcmOpType.INSTANTIATE) @@ -164,8 +163,7 @@ public class JobExecutorService { workflowExecutorService.executeWorkflow(newJob.getJobId(), INSTANTIATE_AS_WORKFLOW_NAME, getVariables(asInstanceId, newJob.getJobId(), newAsLcmOpOcc.getId(), instantiateAsRequest)); - final ImmutableSet jobFinishedStates = - ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); + final Set jobFinishedStates = Set.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); final ImmutablePair immutablePair = waitForJobToFinish(newJob.getJobId(), jobFinishedStates); @@ -181,8 +179,8 @@ public class JobExecutorService { return newAsLcmOpOcc.getId(); } - final String message = "Received unexpected Job Status: " + finalJobStatus - + " Failed to instantiate AS for request: \n" + instantiateAsRequest; + final String message = "Instantiate AS request failed. Received unexpected Job Status: " + finalJobStatus + + " Instantiate AS request: \n" + instantiateAsRequest; logger.error(message); throw new AsRequestProcessingException(message); } @@ -193,7 +191,7 @@ public class JobExecutorService { final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.TERMINATE) .resourceId(asInstanceId).status(JobStatusEnum.STARTING); databaseServiceProvider.addJob(newJob); - logger.info("New job created in database :\n{}", newJob); + logger.info("New job created in database for TerminateAs :\n{}", newJob); final LocalDateTime currentDateTime = LocalDateTime.now(); final AsLcmOpOcc newAsLcmOpOcc = new AsLcmOpOcc().id(asInstanceId).operation(AsLcmOpType.TERMINATE) @@ -206,8 +204,7 @@ public class JobExecutorService { workflowExecutorService.executeWorkflow(newJob.getJobId(), TERMINATE_AS_WORKFLOW_NAME, getVariables(asInstanceId, newJob.getJobId(), newAsLcmOpOcc.getId(), terminateAsRequest)); - final ImmutableSet jobFinishedStates = - ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); + final Set jobFinishedStates = Set.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); final ImmutablePair immutablePair = waitForJobToFinish(newJob.getJobId(), jobFinishedStates); @@ -225,8 +222,8 @@ public class JobExecutorService { return newAsLcmOpOcc.getId(); } - final String message = "Received unexpected Job Status: " + finalJobStatus + " Failed to Terminate AS with id: " - + asInstanceId + " for request: \n" + terminateAsRequest; + final String message = "Terminate AS request failed. Received unexpected Job Status: " + finalJobStatus + + " id: " + asInstanceId + " Terminate AS request: \n" + terminateAsRequest; logger.error(message); throw new AsRequestProcessingException(message); } @@ -235,7 +232,7 @@ public class JobExecutorService { final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.DELETE) .resourceId(asInstanceId).status(JobStatusEnum.STARTING); databaseServiceProvider.addJob(newJob); - logger.info("New job created in database :\n{}", newJob); + logger.info("New job created in database for DeleteAs :\n{}", newJob); workflowExecutorService.executeWorkflow(newJob.getJobId(), DELETE_AS_WORKFLOW_NAME, getVariables(asInstanceId, newJob.getJobId())); @@ -264,8 +261,8 @@ public class JobExecutorService { throw new AsRequestProcessingException(message, errorDetails); } - final String message = "Received unexpected Job Status: " + finalJobStatus - + " Failed to Delete AS with id: " + asInstanceId; + final String message = "Delete AS request failed. Received unexpected Job Status: " + finalJobStatus + + " Delete AS with id: " + asInstanceId; logger.error(message); throw new AsRequestProcessingException(message); } @@ -286,12 +283,12 @@ public class JobExecutorService { } private ImmutablePair waitForJobToFinish(final String jobId, - final ImmutableSet jobFinishedStates) { + final Set jobFinishedStates) { try { final long startTimeInMillis = System.currentTimeMillis(); final long timeOutTime = startTimeInMillis + TimeUnit.SECONDS.toMillis(timeOutInSeconds); - logger.info("Will wait till {} for {} job to finish", Instant.ofEpochMilli(timeOutTime).toString(), jobId); + logger.info("Will wait till {} for {} job to finish", Instant.ofEpochMilli(timeOutTime), jobId); JobStatusEnum currentJobStatus = null; while (timeOutTime > System.currentTimeMillis()) { diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProvider.java new file mode 100644 index 0000000..87e0c29 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProvider.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.service; + +import java.nio.file.Path; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileNotFoundException; +import org.springframework.web.multipart.MultipartFile; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface KubConfigProvider { + + Path getKubeConfigFile(final String cloudOwner, final String cloudRegion, final String tenantId) + throws KubeConfigFileNotFoundException; + + void addKubeConfigFile(final MultipartFile file, final String cloudOwner, final String cloudRegion, + final String tenantId); + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProviderImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProviderImpl.java new file mode 100644 index 0000000..9f42038 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/KubConfigProviderImpl.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.service; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileNotFoundException; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileUploadException; +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.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class KubConfigProviderImpl implements KubConfigProvider { + private static final Logger logger = LoggerFactory.getLogger(KubConfigProviderImpl.class); + + private final Path kubeConfigsDirPath; + + @Autowired + public KubConfigProviderImpl(@Value("${cnfm.kube-configs-dir:/app/kube-configs}") final String kubeConfigsDir) { + this.kubeConfigsDirPath = Paths.get(kubeConfigsDir).toAbsolutePath().normalize(); + } + + @Override + public Path getKubeConfigFile(final String cloudOwner, final String cloudRegion, final String tenantId) + throws KubeConfigFileNotFoundException { + final String filename = getFilename(cloudOwner, cloudRegion, tenantId); + final Path targetLocation = this.kubeConfigsDirPath.resolve(filename); + logger.debug("Looking for kube-config file at location {}", targetLocation); + + if (Files.exists(targetLocation)) { + logger.debug("Found kube-config file at location {}", targetLocation); + if (Files.isReadable(targetLocation)) { + return targetLocation; + } + throw new KubeConfigFileNotFoundException("kube-config file at " + targetLocation + " is not readable"); + } + + throw new KubeConfigFileNotFoundException("Unable to find kube-config file at " + targetLocation); + } + + @Override + public void addKubeConfigFile(final MultipartFile file, final String cloudOwner, final String cloudRegion, + final String tenantId) { + final String filename = getFilename(cloudOwner, cloudRegion, tenantId); + final Path targetLocation = this.kubeConfigsDirPath.resolve(filename); + + try (final InputStream inputStream = file.getInputStream()) { + logger.debug("Storing kube-config to location {} ", targetLocation); + Files.copy(inputStream, targetLocation, StandardCopyOption.REPLACE_EXISTING); + } catch (final IOException ex) { + throw new KubeConfigFileUploadException( + "Could not store kube-config file " + filename + " to location " + targetLocation, ex); + } + + } + + private String getFilename(final String cloudOwner, final String cloudRegion, final String tenantId) { + return String.join("-", Arrays.asList(cloudOwner, cloudRegion, tenantId)); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java index b6dbd77..f017e08 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java @@ -43,6 +43,9 @@ public class WorkflowQueryService { private static final Logger logger = getLogger(WorkflowQueryService.class); + private static final String PROCESS_INSTANCE_ID_NOT_FOUND_ERROR_MESSAGE = + "Unable to find {} variable using processInstanceId: {}"; + private final HistoryService camundaHistoryService; @Autowired @@ -71,11 +74,10 @@ public class WorkflowQueryService { historicVariableInstance.getValue() != null ? variableValue.getClass() : null, variableValue); } } catch (final ProcessEngineException processEngineException) { - logger.error("Unable to find {} variable using processInstanceId: {}", CREATE_AS_RESPONSE_PARAM_NAME, - processInstanceId, processEngineException); + logger.error(PROCESS_INSTANCE_ID_NOT_FOUND_ERROR_MESSAGE, CREATE_AS_RESPONSE_PARAM_NAME, processInstanceId, + processEngineException); } - logger.error("Unable to find {} variable using processInstanceId: {}", CREATE_AS_RESPONSE_PARAM_NAME, - processInstanceId); + logger.error(PROCESS_INSTANCE_ID_NOT_FOUND_ERROR_MESSAGE, CREATE_AS_RESPONSE_PARAM_NAME, processInstanceId); return Optional.empty(); } @@ -96,8 +98,8 @@ public class WorkflowQueryService { } logger.error("Unable to retrieve HistoricVariableInstance value was null"); } catch (final ProcessEngineException processEngineException) { - logger.error("Unable to find {} variable using processInstanceId: {}", - AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, processInstanceId, processEngineException); + logger.error(PROCESS_INSTANCE_ID_NOT_FOUND_ERROR_MESSAGE, AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, + processInstanceId, processEngineException); } return Optional.empty(); } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java index 85af369..6e2b489 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java @@ -79,7 +79,6 @@ public class CreateAsTask extends AbstractServiceTask { private final SdcPackageProvider sdcPackageProvider; private final SdcCsarPackageParser sdcParser; - @Autowired public CreateAsTask(final DatabaseServiceProvider databaseServiceProvider, final AaiServiceProvider aaiServiceProvider, final SdcPackageProvider sdcPackageProvider, @@ -154,11 +153,8 @@ public class CreateAsTask extends AbstractServiceTask { execution.setVariable(DOES_AS_INSTANCE_EXISTS_PARAM_NAME, exists); if (exists) { - final Optional optional = - databaseServiceProvider.getAsInstByName(createAsRequest.getAsInstanceName()); - final AsInst asInst = optional.get(); - execution.setVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, - new ErrorDetails().detail("As Instance already exists in database : " + asInst.toString())); + execution.setVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, new ErrorDetails() + .detail("As Instance already exists in database for : " + createAsRequest.getAsInstanceName())); } logger.info("Finished executing doesAsInstanceExistsInDb ..."); diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java index 4cc1f8a..b675c38 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java @@ -49,7 +49,6 @@ public class PropertiesToYamlConverter { final Map subMap = new TreeMap<>(); local.put(currentKey, subMap); local = subMap; - continue; } else { local = (Map) local.get(currentKey); } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigController.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigController.java new file mode 100644 index 0000000..e3c0aaf --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigController.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.rest; + +import static org.onap.so.cnfm.lcm.Constants.BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import javax.ws.rs.core.MediaType; +import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Sagar Shetty (sagar.shetty@est.tech) + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +@Controller +@RequestMapping(value = BASE_URL) +public class CloudKubeConfigController { + + private static final Logger logger = getLogger(CloudKubeConfigController.class); + private final KubConfigProvider kubConfigProvider; + + @Autowired + public CloudKubeConfigController(final KubConfigProvider kubConfigProvider) { + this.kubConfigProvider = kubConfigProvider; + } + + @PutMapping(value = "/kube-config/cloudOwner/{cloudOwner}/cloudRegion/{cloudRegion}/tenantId/{tenantId}/upload", + produces = {MediaType.APPLICATION_JSON}, + consumes = {MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_OCTET_STREAM}) + public ResponseEntity uploadKubeConfig( + @PathVariable(name = "cloudOwner", required = true) final String cloudOwner, + @PathVariable(name = "cloudRegion", required = true) final String cloudRegion, + @PathVariable(name = "tenantId", required = true) final String tenantId, + @RequestParam(name = "file", required = true) final MultipartFile file) { + try { + kubConfigProvider.addKubeConfigFile(file, cloudOwner, cloudRegion, tenantId); + logger.info( + "Successfully retrieved kube-config file for cloud Owner: {}, " + "cloud region: {}, tenant Id: {}", + cloudOwner, cloudRegion, tenantId); + return ResponseEntity.accepted().build(); + } catch (final Exception e) { + logger.error("Error while saving kube-config file due to: {} for cloud Owner: {}, " + + "cloud region: {}, tenant Id: {}", e.getMessage(), cloudOwner, cloudRegion, tenantId); + return ResponseEntity.unprocessableEntity().body(e.getMessage()); + } + + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigControllerTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigControllerTest.java new file mode 100644 index 0000000..3157f84 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/CloudKubeConfigControllerTest.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.rest; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Sagar Shetty (sagar.shetty@est.tech) + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +@RunWith(MockitoJUnitRunner.class) +public class CloudKubeConfigControllerTest { + + @Mock + private KubConfigProvider objUnderTest; + + @InjectMocks + private CloudKubeConfigController controller; + + @Test + public void uploadKubeConfigTest() throws Exception { + final MultipartFile file = Mockito.mock(MultipartFile.class); + final ResponseEntity response = controller.uploadKubeConfig("owner", "athlone", "1234", file); + assertEquals(202, response.getStatusCode().value()); + Mockito.verify(objUnderTest, Mockito.times(1)).addKubeConfigFile(file, "owner", "athlone", "1234"); + } + +} -- cgit 1.2.3-korg