diff options
author | 2023-01-27 13:59:55 +0000 | |
---|---|---|
committer | 2023-01-27 14:03:05 +0000 | |
commit | 7142578a39982381c16b06a901fbbfd23c1e1c03 (patch) | |
tree | 0c72e6da3d29ea18f68b3920cb88cd751df5604b /so-cnfm | |
parent | 5789cdb2073db0a01fce9474affdb58230c71c46 (diff) |
Adding AS Instantiaion support
Change-Id: Ieeb0b8febe392bf8a4c770335cd5b9d302c15347
Issue-ID: SO-4052
Signed-off-by: waqas.ikram <waqas.ikram@est.tech>
Diffstat (limited to 'so-cnfm')
27 files changed, 4633 insertions, 43 deletions
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/HelmClientExecuteException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/HelmClientExecuteException.java new file mode 100644 index 0000000..ca40a8f --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/HelmClientExecuteException.java @@ -0,0 +1,37 @@ +/*- + * ============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 HelmClientExecuteException extends RuntimeException { + private static final long serialVersionUID = -5810465476055222463L; + + public HelmClientExecuteException(final String message) { + super(message); + } + + public HelmClientExecuteException(final String message, final Exception originalException) { + super(message, originalException); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileProcessingException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileProcessingException.java new file mode 100644 index 0000000..f054414 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubeConfigFileProcessingException.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 KubeConfigFileProcessingException extends RuntimeException { + + private static final long serialVersionUID = -1898963426949862968L; + + public KubeConfigFileProcessingException(final String message) { + super(message); + } + + public KubeConfigFileProcessingException(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/KubernetesRequestProcessingException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubernetesRequestProcessingException.java new file mode 100644 index 0000000..dae6a79 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubernetesRequestProcessingException.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 KubernetesRequestProcessingException extends RuntimeException { + + private static final long serialVersionUID = -7914311498846116528L; + + public KubernetesRequestProcessingException(final String message) { + super(message); + } + + public KubernetesRequestProcessingException(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/KubernetesRequestTimeOut.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubernetesRequestTimeOut.java new file mode 100644 index 0000000..9e7f8eb --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/KubernetesRequestTimeOut.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 KubernetesRequestTimeOut extends RuntimeException { + + private static final long serialVersionUID = 743034172959845332L; + + public KubernetesRequestTimeOut(final String message) { + super(message); + } + + public KubernetesRequestTimeOut(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/helm/HelmClient.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/HelmClient.java new file mode 100644 index 0000000..db5d092 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/HelmClient.java @@ -0,0 +1,48 @@ +/*- + * ============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.extclients.helm; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.HelmClientExecuteException; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface HelmClient { + + void runHelmChartInstallWithDryRunFlag(final String releaseName, final Path kubeconfig, final Path helmChart) + throws HelmClientExecuteException; + + List<String> getKubeKinds(final String releaseName, final Path kubeconfig, final Path helmChart) + throws HelmClientExecuteException; + + List<String> getKubeKindsUsingManifestCommand(final String releaseName, final Path kubeconfig) + throws HelmClientExecuteException; + + void installHelmChart(final String releaseName, final Path kubeconfig, final Path helmChart, + final Map<String, String> lifeCycleParams) throws HelmClientExecuteException; + + void unInstallHelmChart(final String releaseName, final Path kubeConfigFilePath) throws HelmClientExecuteException; +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/HelmClientImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/HelmClientImpl.java new file mode 100644 index 0000000..ffce0ad --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/HelmClientImpl.java @@ -0,0 +1,288 @@ +/*- + * ============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.extclients.helm; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DAEMON_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DEPLOYMENT; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_JOB; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_POD; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_REPLICA_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_SERVICE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_STATEFUL_SET; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.jvnet.jaxb2_commons.lang.StringUtils; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.HelmClientExecuteException; +import org.onap.so.cnfm.lcm.bpmn.flows.utils.PropertiesToYamlConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class HelmClientImpl implements HelmClient { + private static final String KIND_KEY = "kind: "; + private static final String ANY_UNICODE_NEWLINE = "\\R"; + private static final Logger logger = LoggerFactory.getLogger(HelmClientImpl.class); + private final PropertiesToYamlConverter propertiesToYamlConverter; + + @Autowired + public HelmClientImpl(final PropertiesToYamlConverter propertiesToYamlConverter) { + this.propertiesToYamlConverter = propertiesToYamlConverter; + } + + private static final Set<String> SUPPORTED_KINDS = Set.of(KIND_JOB, KIND_POD, KIND_SERVICE, KIND_DEPLOYMENT, + KIND_REPLICA_SET, KIND_DAEMON_SET, KIND_STATEFUL_SET); + + /** + * Execute a helm install dry run + * + * @param releaseName Name of the release given to helm install + * @param kubeconfig kubernetes configuration file path + * @param helmChart path of the helm chart to install + * + * @throws HelmClientExecuteException when exception occurs on executing command + */ + @Override + public void runHelmChartInstallWithDryRunFlag(final String releaseName, final Path kubeconfig, final Path helmChart) + throws HelmClientExecuteException { + logger.info("Running dry-run on {} to cluster {} using releaseName: {}", helmChart, kubeconfig, releaseName); + final ProcessBuilder processBuilder = prepareDryRunCommand(releaseName, kubeconfig, helmChart); + executeCommand(processBuilder); + logger.info("Successfully ran dry for Chart {}", helmChart); + + } + + /** + * + * @param releaseName Name of the release given to helm install + * @param kubeconfig kubernetes configuration file path + * @param helmChart path of the helm chart to install + * + * @return Resources for helmChart as a List of strings + */ + @Override + public List<String> getKubeKinds(final String releaseName, final Path kubeconfig, final Path helmChart) { + logger.info("Retrieving kinds from chart {} using releaseName {}", helmChart, releaseName); + final ProcessBuilder processBuilder = prepareKubeKindCommand(releaseName, kubeconfig, helmChart); + final String response = executeCommand(processBuilder); + if (StringUtils.isEmpty(response)) { + logger.warn("Response is empty: {}", response); + return Collections.emptyList(); + } + final List<String> kinds = processKinds(response); + + logger.debug("Found kinds: {}", kinds); + return kinds; + } + + + @Override + public List<String> getKubeKindsUsingManifestCommand(final String releaseName, final Path kubeConfig) + throws HelmClientExecuteException { + logger.info("Retrieving kinds from helm release history using releaseName {}", releaseName); + + final ProcessBuilder processBuilder = prepareGetKubeKindCommand(releaseName, kubeConfig); + final String response = executeCommand(processBuilder); + if (StringUtils.isEmpty(response)) { + logger.warn("Response is empty: {}", response); + return Collections.emptyList(); + } + final List<String> kinds = processKinds(response); + + logger.debug("Kinds found from the helm release history: {}", kinds); + return kinds; + } + + + /** + * + * @param releaseName Name of the release given to helm install + * @param kubeconfig kubernetes configuration file path + * @param helmChart path of the helm chart to install + * @throws HelmClientExecuteException when exception occurs on executing command + */ + @Override + public void installHelmChart(final String releaseName, final Path kubeconfig, final Path helmChart, + final Map<String, String> lifeCycleParams) throws HelmClientExecuteException { + logger.info("Installing {} to cluster {} using releaseName: {}", helmChart, kubeconfig, releaseName); + final ProcessBuilder processBuilder = + prepareInstallCommand(releaseName, kubeconfig, helmChart, lifeCycleParams); + executeCommand(processBuilder); + logger.info("Chart {} installed successfully", helmChart); + + } + + /** + * @param releaseName Name of the release given to helm install + * @param kubeConfigFilePath kubernetes configuration file path + * @throws HelmClientExecuteException when exception occurs on executing command + */ + @Override + public void unInstallHelmChart(final String releaseName, final Path kubeConfigFilePath) + throws HelmClientExecuteException { + logger.info("uninstalling the release {} from cluster {}", releaseName, kubeConfigFilePath); + final ProcessBuilder processBuilder = prepareUnInstallCommand(releaseName, kubeConfigFilePath); + final String commandResponse = executeCommand(processBuilder); + if (!StringUtils.isEmpty(commandResponse)) { + if (commandResponse.contains("Release not loaded")) { + throw new HelmClientExecuteException( + "Unable to find the installed Helm chart by using releaseName: " + releaseName); + } + } + + logger.info("Release {} uninstalled successfully", releaseName); + } + + private ProcessBuilder prepareDryRunCommand(final String releaseName, final Path kubeconfig, final Path helmChart) { + final List<String> helmArguments = List.of("helm", "install", releaseName, "-n", "default", + helmChart.toString(), "--dry-run", "--kubeconfig", kubeconfig.toString()); + return new ProcessBuilder().command(helmArguments); + } + + private ProcessBuilder prepareInstallCommand(final String releaseName, final Path kubeconfig, final Path helmChart, + final Map<String, String> lifeCycleParams) { + final List<String> commands = new ArrayList<String>(List.of("helm", "install", releaseName, "-n", "default", + helmChart.toString(), "--kubeconfig", kubeconfig.toString())); + + if (lifeCycleParams != null && !lifeCycleParams.isEmpty()) { + final String fileName = helmChart.getParent().resolve("values.yaml").toString(); + createYamlFile(fileName, lifeCycleParams); + commands.add("-f ".concat(fileName)); + } + final List<String> helmArguments = List.of("sh", "-c", toString(commands)); + return new ProcessBuilder().command(helmArguments); + } + + private void createYamlFile(final String fileName, final Map<String, String> lifeCycleParams) { + logger.debug("Will create the runtime values.yaml file."); + final String yamlContent = propertiesToYamlConverter.getValuesYamlFileContent(lifeCycleParams); + logger.debug("Yaml file content : {}", yamlContent); + try { + Files.write(Paths.get(fileName), yamlContent.getBytes()); + } catch (final IOException e) { + logger.error("Failed to create the run time life cycle yaml file: {} " + e.getMessage()); + throw new HelmClientExecuteException( + "Failed to create the run time life cycle yaml file: {} " + e.getMessage()); + } + } + + private ProcessBuilder prepareUnInstallCommand(final String releaseName, final Path kubeConfig) { + logger.debug("Will remove tis log after checking ubeconfig path: {}", kubeConfig.toFile().getName()); + final List<String> helmArguments = new ArrayList<>( + List.of("helm", "uninstall", releaseName, "-n", "default", "--kubeconfig", kubeConfig.toString())); + return new ProcessBuilder().command(helmArguments); + } + + private ProcessBuilder prepareKubeKindCommand(final String releaseName, final Path kubeconfig, + final Path helmChart) { + final List<String> commands = List.of("helm", "template", releaseName, "-n", "default", helmChart.toString(), + "--dry-run", "--kubeconfig", kubeconfig.toString(), "--skip-tests", "| grep kind | uniq"); + final List<String> helmArguments = List.of("sh", "-c", toString(commands)); + return new ProcessBuilder().command(helmArguments); + } + + private ProcessBuilder prepareGetKubeKindCommand(final String releaseName, final Path kubeconfig) { + final List<String> commands = List.of("helm", "get", "manifest", releaseName, "-n", "default", "--kubeconfig", + kubeconfig.toString(), "| grep kind | uniq"); + final List<String> helmArguments = List.of("sh", "-c", toString(commands)); + return new ProcessBuilder().command(helmArguments); + } + + private String executeCommand(final ProcessBuilder processBuilder) throws HelmClientExecuteException { + final String commandStr = toString(processBuilder); + + try { + logger.debug("Executing cmd: {}", commandStr); + final Process process = processBuilder.start(); + + final InputStreamConsumer errors = new InputStreamConsumer(process.getErrorStream()); + final InputStreamConsumer output = new InputStreamConsumer(process.getInputStream()); + + final Thread errorsConsumer = new Thread(errors); + final Thread outputConsumer = new Thread(output); + errorsConsumer.start(); + outputConsumer.start(); + + process.waitFor(); + + errorsConsumer.join(); + outputConsumer.join(); + + final int exitValue = process.exitValue(); + if (exitValue != 0) { + final String stderr = errors.getContent(); + if (!stderr.isEmpty()) { + throw new HelmClientExecuteException("Command execution failed: " + commandStr + " " + stderr); + } + } + + final String stdout = output.getContent(); + logger.debug("Command <{}> execution, output: {}", commandStr, stdout); + return stdout; + + } catch (final InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + throw new HelmClientExecuteException( + "Failed to execute the Command: " + commandStr + ", the command was interrupted", + interruptedException); + } catch (final Exception exception) { + throw new HelmClientExecuteException("Failed to execute the Command: " + commandStr, exception); + } + } + + private List<String> processKinds(final String response) { + + logger.debug("Processing kube kinds"); + + final List<String> kinds = new ArrayList<>(); + for (final String entry : response.split(ANY_UNICODE_NEWLINE)) { + if (entry != null) { + final String line = entry.trim(); + if (!line.isBlank()) { + final String kind = line.replace(KIND_KEY, "").trim(); + if (SUPPORTED_KINDS.contains(kind)) { + logger.debug("Found Supported kind: {}", kind); + kinds.add(kind); + } else { + logger.warn("kind: {} is not currently supported", kind); + } + } + } + } + return kinds; + } + + private String toString(final ProcessBuilder processBuilder) { + return String.join(" ", processBuilder.command()); + } + + private String toString(final List<String> commands) { + return String.join(" ", commands); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/InputStreamConsumer.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/InputStreamConsumer.java new file mode 100644 index 0000000..685cb3b --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/helm/InputStreamConsumer.java @@ -0,0 +1,81 @@ +/*- + * ============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.extclients.helm; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.concurrent.atomic.AtomicBoolean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class InputStreamConsumer implements Runnable { + private static final Logger logger = LoggerFactory.getLogger(InputStreamConsumer.class); + + private final InputStream inputStream; + private final StringBuilder builder = new StringBuilder(); + private final Object lock = new Object(); + private final AtomicBoolean isStopped = new AtomicBoolean(false); + + public InputStreamConsumer(final InputStream inputStream) { + this.inputStream = inputStream; + } + + @Override + public void run() { + logger.debug("Starting InputStreamConsumer Thread ..."); + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(this.inputStream));) { + String line; + while ((line = reader.readLine()) != null) { + this.builder.append(line).append("\n"); + } + } catch (final IOException ioException) { + logger.error("Failed while gobbling the input stream: ", ioException); + } finally { + this.isStopped.set(true); + synchronized (lock) { + lock.notifyAll(); + } + } + logger.debug("InputStreamConsumer Thread Finished ..."); + + } + + public String getContent() { + if (!this.isStopped.get()) { + try { + synchronized (lock) { + logger.debug("Waiting for Thread to finish reading the input stream ... "); + lock.wait(); + } + } catch (final InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + } + return this.builder.toString(); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClient.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClient.java new file mode 100644 index 0000000..d4a3425 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClient.java @@ -0,0 +1,55 @@ +/*- + * ============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.extclients.kubernetes; + +import java.util.List; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubernetesRequestProcessingException; +import io.kubernetes.client.openapi.ApiClient; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface KubernetesClient extends KubernetesResourceStatusCheck { + + List<KubernetesResource> getJobResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getDeploymentResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getPodResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getServiceResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getReplicaSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getDaemonSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + List<KubernetesResource> getStatefulSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientImpl.java new file mode 100644 index 0000000..4731c24 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientImpl.java @@ -0,0 +1,1067 @@ +/*- + * ============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.extclients.kubernetes; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DAEMON_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DEPLOYMENT; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_JOB; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_POD; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_REPLICA_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_SERVICE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_STATEFUL_SET; +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubernetesRequestProcessingException; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubernetesRequestTimeOut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import com.google.gson.reflect.TypeToken; +import io.kubernetes.client.apimachinery.GroupVersion; +import io.kubernetes.client.common.KubernetesListObject; +import io.kubernetes.client.common.KubernetesObject; +import io.kubernetes.client.custom.IntOrString; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.AppsV1Api; +import io.kubernetes.client.openapi.apis.BatchV1Api; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1DaemonSet; +import io.kubernetes.client.openapi.models.V1DaemonSetList; +import io.kubernetes.client.openapi.models.V1DaemonSetSpec; +import io.kubernetes.client.openapi.models.V1DaemonSetStatus; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1DeploymentList; +import io.kubernetes.client.openapi.models.V1DeploymentSpec; +import io.kubernetes.client.openapi.models.V1DeploymentStatus; +import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1JobCondition; +import io.kubernetes.client.openapi.models.V1JobList; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1Pod; +import io.kubernetes.client.openapi.models.V1PodCondition; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.openapi.models.V1ReplicaSet; +import io.kubernetes.client.openapi.models.V1ReplicaSetList; +import io.kubernetes.client.openapi.models.V1ReplicaSetSpec; +import io.kubernetes.client.openapi.models.V1ReplicaSetStatus; +import io.kubernetes.client.openapi.models.V1RollingUpdateStatefulSetStrategy; +import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServiceList; +import io.kubernetes.client.openapi.models.V1StatefulSet; +import io.kubernetes.client.openapi.models.V1StatefulSetList; +import io.kubernetes.client.openapi.models.V1StatefulSetSpec; +import io.kubernetes.client.openapi.models.V1StatefulSetStatus; +import io.kubernetes.client.openapi.models.V1StatefulSetUpdateStrategy; +import io.kubernetes.client.util.Watch; +import io.kubernetes.client.util.Watch.Response; +import okhttp3.Call; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class KubernetesClientImpl implements KubernetesClient { + private static final String ROLLING_UPDATE = "RollingUpdate"; + private static final String EVENT_TYPE_ERROR = "ERROR"; + private static final String EVENT_TYPE_DELETED = "DELETED"; + private static final String EVENT_TYPE_MODIFIED = "MODIFIED"; + private static final String EVENT_TYPE_ADDED = "ADDED"; + private static final String TRUE_STRING = Boolean.TRUE.toString(); + private static final String JOB_FAILED = "Failed"; + private static final String JOB_COMPLETE = "Complete"; + private static final boolean DISABLE_WATCH = false; + private static final boolean ENABLE_WATCH = true; + private static final String POD_READY = "Ready"; + + private static final Logger logger = LoggerFactory.getLogger(KubernetesClientImpl.class); + + /** + * Event Listener timeout in seconds Note: this should be less then the timeout camunda task execution + */ + @Value("${kubernetes.client.http-request.timeoutSeconds:5}") + private Integer timeoutSeconds; + + @Override + public boolean isJobReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if Job is ready using labelSelector: {}", labelSelector); + try { + final BatchV1Api batchV1Api = new BatchV1Api(apiClient); + final Call call = batchV1Api.listJobForAllNamespacesCall(null, null, null, labelSelector, null, null, null, + null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1Job, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1Job>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1Job, String>> jobNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isJobReady)) + .collect(Collectors.toList()); + + if (jobNotReadyList.isEmpty()) { + logger.debug("JobList is ready ..."); + return true; + } + logger.debug("JobList is not yet Ready: {}", jobNotReadyList); + return false; + + } + + logger.warn("No items found in jobList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_JOB, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_JOB, labelSelector, runtimeException); + } + logger.debug("Returning false as Job is not ready ..."); + return false; + } + + @Override + public boolean isPodReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if Pod is ready using labelSelector: {}", labelSelector); + try { + final CoreV1Api coreV1Api = new CoreV1Api(apiClient); + final Call call = coreV1Api.listPodForAllNamespacesCall(null, null, null, labelSelector, null, null, null, + null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1Pod, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1Pod>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1Pod, String>> podNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isPodReady)) + .collect(Collectors.toList()); + + if (podNotReadyList.isEmpty()) { + logger.debug("PodList is ready ..."); + return true; + } + logger.debug("PodList is not yet Ready: {}", podNotReadyList); + return false; + + } + + logger.warn("No items found in podList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_POD, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_POD, labelSelector, runtimeException); + } + + logger.debug("Returning false as Pod is not ready ..."); + + return false; + } + + @Override + public boolean isServiceReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if Service is ready using labelSelector: {}", labelSelector); + try { + final CoreV1Api api = new CoreV1Api(apiClient); + final Call call = api.listServiceForAllNamespacesCall(null, null, null, labelSelector, null, null, null, + null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1Service, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1Service>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1Service, String>> serviceNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isServiceReady)) + .collect(Collectors.toList()); + + if (serviceNotReadyList.isEmpty()) { + logger.debug("ServiceList is ready ..."); + return true; + } + logger.debug("ServiceList is not yet Ready: {}", serviceNotReadyList); + return false; + + } + + logger.warn("No items found in serviceList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_SERVICE, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_SERVICE, labelSelector, runtimeException); + } + + logger.debug("Returning false as Service is not ready ..."); + return false; + } + + @Override + public boolean isDeploymentReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if Deployment is ready using labelSelector: {}", labelSelector); + + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final Call call = appsV1Api.listDeploymentForAllNamespacesCall(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1Deployment, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1Deployment>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1Deployment, String>> deploymentNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isDeploymentReady)) + .collect(Collectors.toList()); + + if (deploymentNotReadyList.isEmpty()) { + logger.debug("DeploymentList is ready ..."); + return true; + } + logger.debug("DeploymentList is not yet Ready: {}", deploymentNotReadyList); + return false; + + } + + logger.warn("No items found in deploymentList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_DEPLOYMENT, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_DEPLOYMENT, labelSelector, runtimeException); + } + + logger.debug("Returning false as Deployment is not ready ..."); + return false; + } + + @Override + public boolean isReplicaSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if ReplicaSet is ready using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final Call call = appsV1Api.listReplicaSetForAllNamespacesCall(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1ReplicaSet, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1ReplicaSet>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1ReplicaSet, String>> replicaSet = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isReplicaSetReady)) + .collect(Collectors.toList()); + + if (replicaSet.isEmpty()) { + logger.debug("ReplicaSetList is ready ..."); + return true; + } + logger.debug("ReplicaSetList is not yet Ready: {}", replicaSet); + return false; + + } + + logger.warn("No items found in replicaSetList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_REPLICA_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_REPLICA_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as ReplicaSet is not ready ..."); + return false; + } + + @Override + public boolean isDaemonSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if DaemonSet is ready using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final Call call = appsV1Api.listDaemonSetForAllNamespacesCall(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1DaemonSet, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1DaemonSet>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1DaemonSet, String>> daemonSetNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isDaemonSetReady)) + .collect(Collectors.toList()); + + if (daemonSetNotReadyList.isEmpty()) { + logger.debug("DaemonSetList is ready ..."); + return true; + } + logger.debug("DaemonSetList is not yet Ready: {}", daemonSetNotReadyList); + return false; + + } + + logger.warn("No items found in daemonSetList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_DAEMON_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_DAEMON_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as DaemonSet is not ready ..."); + return false; + } + + @Override + public boolean isStatefulSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Will check if StatefulSet is ready using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final Call call = appsV1Api.listStatefulSetForAllNamespacesCall(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, ENABLE_WATCH, null); + + final Map<V1StatefulSet, String> readyResources = + getReadyResources(apiClient, call, new TypeToken<Response<V1StatefulSet>>() {}.getType()); + + if (!readyResources.isEmpty()) { + final List<Entry<V1StatefulSet, String>> statefulSetNotReadyList = readyResources.entrySet().stream() + .filter(entry -> !isResourceReady(entry.getKey(), entry.getValue(), this::isStatefulSetReady)) + .collect(Collectors.toList()); + + if (statefulSetNotReadyList.isEmpty()) { + logger.debug("StatefulSetList is ready ..."); + return true; + } + logger.debug("StatefulSetList is not yet Ready: {}", statefulSetNotReadyList); + return false; + + } + + logger.warn("No items found in statefulSetList : {}", readyResources); + return false; + + } catch (final ApiException exception) { + handleApiException(KIND_STATEFUL_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_STATEFUL_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as StatefulSet is not ready ..."); + return false; + } + + @Override + public boolean isServiceDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is Service deleted by using labelSelector: {}", labelSelector); + try { + final CoreV1Api coreV1Api = new CoreV1Api(apiClient); + final V1ServiceList v1ServiceList = coreV1Api.listServiceForAllNamespaces(null, null, null, labelSelector, + null, null, null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list service for all Namespaces: {}", v1ServiceList); + return v1ServiceList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_SERVICE, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_SERVICE, labelSelector, runtimeException); + } + logger.debug("Returning false as Service is not Deleted ..."); + return false; + } + + @Override + public boolean isPodDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is Pod deleted by using labelSelector: {}", labelSelector); + try { + final CoreV1Api coreV1Api = new CoreV1Api(apiClient); + final V1PodList v1PodList = coreV1Api.listPodForAllNamespaces(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list Pod for all Namespaces: {}", v1PodList); + return v1PodList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_POD, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_POD, labelSelector, runtimeException); + } + logger.debug("Returning false as Pod is not Deleted ..."); + return false; + } + + @Override + public boolean isJobDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is Job deleted by using labelSelector: {}", labelSelector); + try { + final BatchV1Api batchV1Api = new BatchV1Api(apiClient); + final V1JobList v1JobList = batchV1Api.listJobForAllNamespaces(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list Job for all Namespaces: {}", v1JobList); + return v1JobList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_JOB, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_JOB, labelSelector, runtimeException); + } + logger.debug("Returning false as Job is not Deleted ..."); + return false; + } + + @Override + public boolean isDeploymentDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is Deployment deleted by using labelSelector: {}", labelSelector); + try { + final AppsV1Api batchV1Api = new AppsV1Api(apiClient); + final V1DeploymentList v1DeploymentList = batchV1Api.listDeploymentForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list Deployment for all Namespaces: {}", v1DeploymentList); + return v1DeploymentList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_DEPLOYMENT, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_DEPLOYMENT, labelSelector, runtimeException); + } + logger.debug("Returning false as Deployment is not Deleted ..."); + return false; + } + + @Override + public boolean isReplicaSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is ReplicaSet deleted by using labelSelector: {}", labelSelector); + try { + final AppsV1Api batchV1Api = new AppsV1Api(apiClient); + final V1ReplicaSetList v1ReplicaSetList = batchV1Api.listReplicaSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list ReplicaSet for all Namespaces: {}", v1ReplicaSetList); + return v1ReplicaSetList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_REPLICA_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_REPLICA_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as ReplicaSet is not Deleted ..."); + return false; + } + + @Override + public boolean isDaemonSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is DaemonSet deleted by using labelSelector: {}", labelSelector); + try { + final AppsV1Api batchV1Api = new AppsV1Api(apiClient); + final V1DaemonSetList v1DaemonSetList = batchV1Api.listDaemonSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list DaemonSet for all Namespaces: {}", v1DaemonSetList); + return v1DaemonSetList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_DAEMON_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_DAEMON_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as DaemonSet is not Deleted ..."); + return false; + } + + @Override + public boolean isStatefulSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Check is StatefulSet deleted by using labelSelector: {}", labelSelector); + try { + final AppsV1Api batchV1Api = new AppsV1Api(apiClient); + final V1StatefulSetList v1StatefulSetList = batchV1Api.listStatefulSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + logger.debug("Response from list StatefulSet for all Namespaces: {}", v1StatefulSetList); + return v1StatefulSetList.getItems().isEmpty(); + } catch (final ApiException exception) { + logger.debug("Return false because of exception occurred: {}", exception.getMessage()); + handleApiException(KIND_STATEFUL_SET, labelSelector, exception); + } catch (final RuntimeException runtimeException) { + logger.debug("Return false because of Runtime exception occurred: {}", runtimeException.getMessage()); + handleRuntimeException(KIND_STATEFUL_SET, labelSelector, runtimeException); + } + logger.debug("Returning false as StatefulSet is not Deleted ..."); + return false; + } + + + @Override + public List<KubernetesResource> getJobResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving Jobs using labelSelector: {}", labelSelector); + try { + final BatchV1Api batchV1Api = new BatchV1Api(apiClient); + final V1JobList jobList = batchV1Api.listJobForAllNamespaces(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received Jobs: {}", jobList); + return getKubernetesResource(jobList); + + } catch (final ApiException exception) { + handleApiException(KIND_JOB, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_JOB, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_JOB, labelSelector, runtimeException); + } + + logger.error("Unable to find any job resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getDeploymentResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving Deployment using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final V1DeploymentList deploymentList = appsV1Api.listDeploymentForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received Deployments: {}", deploymentList); + return getKubernetesResource(deploymentList); + + } catch (final ApiException exception) { + handleApiException(KIND_DEPLOYMENT, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_DEPLOYMENT, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_DEPLOYMENT, labelSelector, runtimeException); + } + + logger.error("Unable to find any Deployment resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getPodResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving Pod using labelSelector: {}", labelSelector); + try { + final CoreV1Api coreV1Api = new CoreV1Api(apiClient); + final V1PodList podList = coreV1Api.listPodForAllNamespaces(null, null, null, labelSelector, null, null, + null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received Pods: {}", podList); + return getKubernetesResource(podList); + + } catch (final ApiException exception) { + handleApiException(KIND_POD, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_POD, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_POD, labelSelector, runtimeException); + } + + logger.error("Unable to find any Pod resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getServiceResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving Service using labelSelector: {}", labelSelector); + try { + final CoreV1Api coreV1Api = new CoreV1Api(apiClient); + final V1ServiceList serviceList = coreV1Api.listServiceForAllNamespaces(null, null, null, labelSelector, + null, null, null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received Services: {}", serviceList); + return getKubernetesResource(serviceList); + + } catch (final ApiException exception) { + handleApiException(KIND_SERVICE, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_SERVICE, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_SERVICE, labelSelector, runtimeException); + } + + logger.error("Unable to find any Service resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getReplicaSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving ReplicaSet using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + final V1ReplicaSetList replicaSetList = appsV1Api.listReplicaSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received ReplicaSets: {}", replicaSetList); + return getKubernetesResource(replicaSetList); + + } catch (final ApiException exception) { + handleApiException(KIND_REPLICA_SET, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_REPLICA_SET, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_REPLICA_SET, labelSelector, runtimeException); + } + + logger.error("Unable to find any ReplicaSet resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getDaemonSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving DaemonSet using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + + final V1DaemonSetList daemonSetList = appsV1Api.listDaemonSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received DaemonSets: {}", daemonSetList); + return getKubernetesResource(daemonSetList); + + } catch (final ApiException exception) { + handleApiException(KIND_DAEMON_SET, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_DAEMON_SET, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_DAEMON_SET, labelSelector, runtimeException); + } + + logger.error("Unable to find any DaemonSet resources ..."); + return Collections.emptyList(); + } + + @Override + public List<KubernetesResource> getStatefulSetResources(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException { + logger.debug("Retrieving StatefulSet using labelSelector: {}", labelSelector); + try { + final AppsV1Api appsV1Api = new AppsV1Api(apiClient); + + final V1StatefulSetList statefulSetList = appsV1Api.listStatefulSetForAllNamespaces(null, null, null, + labelSelector, null, null, null, null, timeoutSeconds, DISABLE_WATCH); + + logger.debug("Received StatefulSets: {}", statefulSetList); + return getKubernetesResource(statefulSetList); + + } catch (final ApiException exception) { + handleApiException(KIND_STATEFUL_SET, labelSelector, exception); + } catch (final IllegalArgumentException illegalArgumentException) { + handleIllegalArgumentException(KIND_STATEFUL_SET, labelSelector, illegalArgumentException); + } catch (final RuntimeException runtimeException) { + handleRuntimeException(KIND_STATEFUL_SET, labelSelector, runtimeException); + } + + logger.error("Unable to find any StatefulSet resources ..."); + return Collections.emptyList(); + + } + + private List<KubernetesResource> getKubernetesResource(final KubernetesListObject kubernetesListObject) { + if (kubernetesListObject != null && kubernetesListObject.getItems() != null) { + final List<KubernetesResource> kubernetesResources = new ArrayList<>(); + final List<? extends KubernetesObject> items = kubernetesListObject.getItems(); + items.forEach(item -> { + final String apiVersion = + item.getApiVersion() != null ? item.getApiVersion() : kubernetesListObject.getApiVersion(); + final String kind = item.getKind() != null ? item.getKind() : kubernetesListObject.getKind(); + kubernetesResources.add(getKubernetesResource(apiVersion, kind, item.getMetadata())); + }); + logger.debug("KubernetesResources found: {}", kubernetesResources); + return kubernetesResources; + } + logger.error("kubernetesListObject or items is null {}", kubernetesListObject); + return Collections.emptyList(); + } + + private KubernetesResource getKubernetesResource(final String apiVersion, final String kind, + final V1ObjectMeta metadata) { + final GroupVersion groupVersion = GroupVersion.parse(apiVersion); + final KubernetesResource resource = + new KubernetesResource().id(metadata.getUid()).name(metadata.getName()).group(groupVersion.getGroup()) + .version(groupVersion.getVersion()).kind(kind).resourceVersion(metadata.getResourceVersion()) + .namespace(metadata.getNamespace() != null ? metadata.getNamespace() : "") + .labels(getLabels(metadata.getLabels())); + return resource; + } + + private List<String> getLabels(final Map<String, String> labels) { + if (labels != null) { + final List<String> result = new ArrayList<>(); + labels.entrySet().forEach(entry -> { + result.add(entry.getKey() + "=" + entry.getValue()); + }); + return result; + } + return Collections.emptyList(); + + } + + private boolean isJobReady(final V1Job job) { + if (job.getStatus() != null && job.getStatus().getConditions() != null) { + logger.debug("Received Job with conditions .."); + for (final V1JobCondition condition : job.getStatus().getConditions()) { + if (JOB_COMPLETE.equalsIgnoreCase(condition.getType()) + && TRUE_STRING.equalsIgnoreCase(condition.getStatus())) { + logger.debug("Job completed successfully ..."); + return true; + } + if (JOB_FAILED.equalsIgnoreCase(condition.getType()) + && TRUE_STRING.equalsIgnoreCase(condition.getStatus())) { + final String message = "Job failed with reason: " + condition.getReason(); + logger.error(message); + throw new KubernetesRequestProcessingException(message); + + } + } + } + + logger.debug("Job is not ready ..."); + return false; + } + + private boolean isPodReady(final V1Pod pod) { + final Optional<V1PodCondition> optional = getPodReadyCondition(pod); + if (optional.isPresent()) { + final V1PodCondition condition = optional.get(); + if (TRUE_STRING.equalsIgnoreCase(condition.getStatus())) { + logger.debug("Pod is Ready..."); + return true; + } + + } + + logger.debug("Pod is not ready ..."); + return false; + } + + private boolean isServiceReady(final V1Service service) { + logger.debug("V1Service is Ready ..."); + return true; + } + + private boolean isDeploymentReady(final V1Deployment deployment) { + final V1DeploymentSpec spec = deployment.getSpec(); + final V1DeploymentStatus status = deployment.getStatus(); + + if (status != null && status.getReplicas() != null && status.getAvailableReplicas() != null && spec != null + && spec.getReplicas() != null) { + if (spec.getReplicas().intValue() == status.getReplicas().intValue() + && status.getAvailableReplicas().intValue() <= spec.getReplicas().intValue()) { + logger.debug("Deployment is Ready..."); + return true; + } + } + + logger.debug("Deployment is not ready ..."); + return false; + } + + private boolean isReplicaSetReady(final V1ReplicaSet replicaSet) { + final V1ReplicaSetSpec spec = replicaSet.getSpec(); + final V1ReplicaSetStatus status = replicaSet.getStatus(); + + if (status != null && status.getReadyReplicas() != null && spec != null && spec.getReplicas() != null) { + if (spec.getReplicas().intValue() == status.getReadyReplicas().intValue()) { + logger.debug("ReplicaSet is Ready..."); + return true; + } + } + + logger.debug("ReplicaSet is not ready ..."); + return false; + } + + private boolean isDaemonSetReady(final V1DaemonSet daemonSet) { + + final V1DaemonSetSpec spec = daemonSet.getSpec(); + final V1DaemonSetStatus status = daemonSet.getStatus(); + + if (status == null || spec == null) { + logger.debug("Found null status/spec \n DaemonSet: {}", daemonSet); + return false; + } + + if (spec.getUpdateStrategy() != null && spec.getUpdateStrategy().getType() != null) { + if (!ROLLING_UPDATE.equalsIgnoreCase(spec.getUpdateStrategy().getType())) { + logger.debug("Type is {} returning true", spec.getUpdateStrategy().getType()); + return true; + } + } + + if (status.getDesiredNumberScheduled() != null && status.getUpdatedNumberScheduled() != null) { + if (status.getUpdatedNumberScheduled().intValue() != status.getDesiredNumberScheduled().intValue()) { + logger.debug("DaemonSet is not ready {} out of {} expected pods have been scheduled", + status.getUpdatedNumberScheduled(), status.getDesiredNumberScheduled()); + return false; + } + + if (spec.getUpdateStrategy() != null && spec.getUpdateStrategy().getRollingUpdate() != null + && status.getNumberReady() != null) { + + final Integer maxUnavailable = + getMaxUnavailable(spec.getUpdateStrategy().getRollingUpdate().getMaxUnavailable(), + status.getDesiredNumberScheduled()); + + final int expectedReady = status.getDesiredNumberScheduled().intValue() - maxUnavailable.intValue(); + final int numberReady = status.getNumberReady().intValue(); + if (!(numberReady >= expectedReady)) { + logger.debug("DaemonSet is not ready {} out of {} expected pods are ready", numberReady, + expectedReady); + return false; + } + logger.debug("DaemonSet is ready {} out of {} expected pods are ready", numberReady, expectedReady); + logger.debug("DaemonSet is Ready..."); + return true; + } + + } + + logger.debug("DaemonSet is not ready ..."); + return false; + } + + private boolean isStatefulSetReady(final V1StatefulSet statefulSet) { + final V1StatefulSetSpec spec = statefulSet.getSpec(); + final V1StatefulSetStatus status = statefulSet.getStatus(); + + if (status == null || spec == null) { + logger.debug("Found null status/spec \n StatefulSet: {}", statefulSet); + return false; + } + + final V1StatefulSetUpdateStrategy updateStrategy = spec.getUpdateStrategy(); + if (updateStrategy != null && updateStrategy.getType() != null) { + if (!ROLLING_UPDATE.equalsIgnoreCase(updateStrategy.getType())) { + logger.debug("Type is {} returning true", updateStrategy.getType()); + return true; + } + + // Dereference all the pointers because StatefulSets like them + int partition = 0; + // 1 is the default for replicas if not set + int replicas = 1; + final V1RollingUpdateStatefulSetStrategy rollingUpdate = updateStrategy.getRollingUpdate(); + if (rollingUpdate != null && rollingUpdate.getPartition() != null) { + partition = updateStrategy.getRollingUpdate().getPartition().intValue(); + } + + if (spec.getReplicas() != null) { + replicas = spec.getReplicas().intValue(); + } + + final int expectedReplicas = replicas - partition; + + if (status.getUpdatedReplicas() != null && status.getUpdatedReplicas().intValue() < expectedReplicas) { + logger.debug("StatefulSet is not ready. {} out of {} expected pods have been scheduled", + status.getUpdatedReplicas(), expectedReplicas); + return false; + } + + if (status.getReadyReplicas() != null && status.getReadyReplicas().intValue() != replicas) { + logger.debug("StatefulSet is not ready. {} out of {} expected pods are ready", + status.getReadyReplicas(), replicas); + return false; + } + + logger.debug("{} out of {} expected pods are ready", status.getReadyReplicas(), replicas); + logger.debug("StatefulSet is Ready..."); + return true; + } + + logger.debug("StatefulSet is not ready ..."); + return false; + } + + private Integer getMaxUnavailable(final IntOrString maxUnavailable, final Integer desiredNumberScheduled) { + if (maxUnavailable == null) { + logger.debug("maxUnavailable value is {}", maxUnavailable); + return desiredNumberScheduled; + } + + if (maxUnavailable.isInteger()) { + logger.debug("maxUnavailable is Integer: {}", maxUnavailable); + return maxUnavailable.getIntValue(); + } + + if (!maxUnavailable.isInteger()) { + final Integer maxUnavailableIntValue = getIntegerValue(maxUnavailable); + if (maxUnavailableIntValue != null) { + return (maxUnavailableIntValue.intValue() * desiredNumberScheduled.intValue()) / 100; + } + + logger.debug("maxUnavailableIntValue is null {}", maxUnavailableIntValue); + } + logger.debug("Returning desiredNumberScheduled: {}", desiredNumberScheduled); + return desiredNumberScheduled; + } + + private Integer getIntegerValue(final IntOrString maxUnavailable) { + try { + final String strValue = maxUnavailable.getStrValue(); + if (strValue != null && strValue.length() > 1) { + if (strValue.contains("%")) { + final String val = strValue.trim().replace("%", ""); + return Integer.valueOf(val); + } + logger.debug("maxUnavailable is not a percentage"); + } + } catch (final Exception exception) { + logger.error("Unable to parse maxUnavailable value: {}", maxUnavailable); + } + return null; + } + + private void closeWatchSilently(final Watch<?> watch) { + try { + watch.close(); + } catch (final IOException exception) { + logger.warn("Unexpected IOException while closing watch suppressing exception"); + } + } + + private void handleRuntimeException(final String resourceType, final String labelSelector, + final RuntimeException runtimeException) { + if (runtimeException.getCause() instanceof SocketTimeoutException) { + final Throwable cause = runtimeException.getCause(); + final String message = "Unexpected SocketTimeoutException occurred while getting " + resourceType + + " status using labelSelector: " + labelSelector + " message: " + cause.getMessage(); + logger.error(message, cause); + throw new KubernetesRequestTimeOut(message, cause); + } + final String message = "Unexpected RuntimeException occurred while getting " + resourceType + + " status using labelSelector: " + labelSelector; + logger.error(message, runtimeException); + throw new KubernetesRequestProcessingException(message, runtimeException); + } + + private void handleApiException(final String resourceType, final String labelSelector, + final ApiException exception) { + final String message = "Unexpected ApiException occurred while getting " + resourceType + + " status using labelSelector: " + labelSelector + " \n response code: " + exception.getCode() + + " \n response body: " + exception.getResponseBody(); + logger.error(message, exception); + throw new KubernetesRequestProcessingException(message, exception); + } + + private void handleIllegalArgumentException(final String resourceType, final String labelSelector, + final IllegalArgumentException illegalArgumentException) { + final String message = "Unexpected IllegalArgumentException occurred while getting " + resourceType + + " resource using labelSelector: " + labelSelector; + logger.error(message, illegalArgumentException); + throw new KubernetesRequestProcessingException(message, illegalArgumentException); + } + + private Optional<V1PodCondition> getPodReadyCondition(final V1Pod pod) { + if (pod.getStatus() != null && pod.getStatus().getConditions() != null) { + final List<V1PodCondition> conditions = pod.getStatus().getConditions(); + return conditions.stream().filter(condition -> POD_READY.equals(condition.getType())) + .peek(condition -> logger.debug("Found {}", condition)).findFirst(); + + } + logger.warn("Unable to find a {} condition {}", POD_READY, pod.getStatus()); + return Optional.empty(); + } + + /** + * Capturing resource events and objects + * + * @param <T> + * @param apiClient + * @param call + * @param type + * @return + * @throws ApiException + */ + private <T> Map<T, String> getReadyResources(final ApiClient apiClient, final Call call, final Type type) + throws ApiException { + final Watch<T> watch = Watch.createWatch(apiClient, call, type); + logger.debug("Listening for {} events ....", type.getTypeName()); + + final Map<T, String> resources = new HashMap<>(); + try { + while (watch.hasNext()) { + final Response<T> next = watch.next(); + final T object = next.object; + logger.debug("Received object: {}", object); + final String event = next.type; + logger.debug("Received Event: {}", event); + resources.put(object, event); + } + + } finally { + closeWatchSilently(watch); + } + logger.debug("Finished Listening for {} events ....", type.getTypeName()); + return resources; + + } + + private static <T> boolean isResourceReady(final T object, final String eventType, final Predicate<T> predicate) { + + switch (eventType) { + case EVENT_TYPE_ADDED: + case EVENT_TYPE_MODIFIED: + return predicate.test(object); + case EVENT_TYPE_DELETED: + logger.debug("{} event received marking it as successfully", EVENT_TYPE_DELETED); + return true; + case EVENT_TYPE_ERROR: + final String message = "Error event received for " + (object != null ? object.getClass() : "null"); + logger.error(message); + logger.debug("{} received: {}", (object != null ? object.getClass() : "null"), object); + throw new KubernetesRequestProcessingException(message); + + default: + logger.warn("Unhandled event received ... "); + return false; + } + + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProvider.java new file mode 100644 index 0000000..4b487f9 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProvider.java @@ -0,0 +1,35 @@ +/*- + * ============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.extclients.kubernetes; + +import io.kubernetes.client.openapi.ApiClient; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface KubernetesClientProvider { + + ApiClient getApiClient(final String kubeConfigFile); + + void closeApiClient(final String kubeConfigFile); + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProviderImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProviderImpl.java new file mode 100644 index 0000000..f8837a9 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesClientProviderImpl.java @@ -0,0 +1,85 @@ +/*- + * ============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.extclients.kubernetes; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.Reader; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileProcessingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.util.ClientBuilder; +import io.kubernetes.client.util.KubeConfig; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class KubernetesClientProviderImpl implements KubernetesClientProvider { + private static final Logger logger = LoggerFactory.getLogger(KubernetesClientProviderImpl.class); + private static final Map<String, ApiClient> INSTANCES = new ConcurrentHashMap<>(); + + @Override + public ApiClient getApiClient(final String kubeConfigPath) { + + ApiClient client = INSTANCES.get(kubeConfigPath.toString()); + if (client == null) { + synchronized (this) { + try (final Reader input = new FileReader(kubeConfigPath);) { + logger.debug("{} Loading kube-config file", kubeConfigPath); + final KubeConfig kubeConfig = KubeConfig.loadKubeConfig(input); + logger.debug("{} kube-config loaded successfully", kubeConfigPath); + client = ClientBuilder.kubeconfig(kubeConfig).build(); + logger.debug("ApiClient created successfully"); + INSTANCES.put(kubeConfigPath, client); + } catch (final FileNotFoundException fileNotFoundException) { + logger.error("{} KubeConfig not found", kubeConfigPath, fileNotFoundException); + throw new KubeConfigFileProcessingException(kubeConfigPath + " kube-config file not found", + fileNotFoundException); + } catch (final Exception exception) { + final String message = "Unexpected exception while processing kube-config file"; + logger.error(message, exception); + throw new KubeConfigFileProcessingException(message, exception); + } + } + } + logger.debug("Found ApiClient for {}", kubeConfigPath); + return client; + } + + @Override + public void closeApiClient(final String kubeConfigFile) { + final ApiClient client = INSTANCES.get(kubeConfigFile); + if (client != null) { + logger.debug("Closing ApiClient and removing it from local cache for {}", kubeConfigFile); + INSTANCES.remove(kubeConfigFile); + } + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesResourceStatusCheck.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesResourceStatusCheck.java new file mode 100644 index 0000000..b32fd65 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesResourceStatusCheck.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.bpmn.flows.extclients.kubernetes; + +import io.kubernetes.client.openapi.ApiClient; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubernetesRequestProcessingException; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface KubernetesResourceStatusCheck { + boolean isJobReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isPodReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isServiceReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isDeploymentReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isReplicaSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isDaemonSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isStatefulSetReady(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isServiceDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isPodDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isJobDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isDeploymentDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isReplicaSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isDaemonSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; + + boolean isStatefulSetDeleted(final ApiClient apiClient, final String labelSelector) + throws KubernetesRequestProcessingException; +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTask.java new file mode 100644 index 0000000..789f1be --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTask.java @@ -0,0 +1,408 @@ +/*- + * ============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.tasks; + +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.INSTANTIATE_AS_REQUEST_PARAM_NAME; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.FINISHED; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.IN_PROGRESS; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.STARTED; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.zip.ZipInputStream; +import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.util.Strings; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileNotFoundException; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.SdcPackageRequestFailureException; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPackageParser; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcPackageProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider; +import org.onap.so.cnfm.lcm.database.beans.AsDeploymentItem; +import org.onap.so.cnfm.lcm.database.beans.AsInst; +import org.onap.so.cnfm.lcm.database.beans.AsLifecycleParam; +import org.onap.so.cnfm.lcm.database.beans.State; +import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider; +import org.onap.so.cnfm.lcm.model.AsInfoModificationRequestDeploymentItems; +import org.onap.so.cnfm.lcm.model.InstantiateAsRequest; +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.Component; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +public class InstantiateAsTask extends AbstractServiceTask { + private static final String KUBE_CONFIG_FILE_PARAM_NAME = "kubeConfigFile"; + private static final String DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME = + "asDeploymentItemInstIdToHelmFileMapping"; + private static final String IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME = "isAsInstantiationSuccessful"; + + private static final Logger logger = LoggerFactory.getLogger(InstantiateAsTask.class); + + private final String csarDir; + + private final SdcPackageProvider sdcPackageProvider; + + private final SdcCsarPackageParser sdcParser; + private final KubConfigProvider kubConfigProvider; + + @Autowired + public InstantiateAsTask(final DatabaseServiceProvider databaseServiceProvider, + final SdcPackageProvider sdcPackageProvider, final SdcCsarPackageParser sdcParser, + final KubConfigProvider kubConfigProvider, @Value("${cnfm.csar.dir:/app/csar}") final String csarDir) { + super(databaseServiceProvider); + this.sdcPackageProvider = sdcPackageProvider; + this.sdcParser = sdcParser; + this.kubConfigProvider = kubConfigProvider; + this.csarDir = csarDir; + } + + public void setJobStatusToStarted(final DelegateExecution execution) { + setJobStatus(execution, STARTED, "Instantiate AS workflow process started"); + } + + public void setJobStatusToFinished(final DelegateExecution execution) { + setJobStatus(execution, FINISHED, "Instantiate AS workflow process finished"); + } + + public void updateAsInstanceStatusToInstantiating(final DelegateExecution execution) { + logger.info("Executing updateAsInstanceStatusToInstantiating"); + setJobStatus(execution, IN_PROGRESS, "Updating AsInst Status to " + State.INSTANTIATING); + updateAsInstanceStatus(execution, State.INSTANTIATING); + + logger.info("Finished executing updateNsInstanceStatusToInstantiating ..."); + } + + public void updateAsInstanceStatusToInstantiated(final DelegateExecution execution) { + logger.info("Executing updateAsInstanceStatusToInstantiated"); + + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + setJobStatus(execution, FINISHED, "Successfully " + State.INSTANTIATED + " AS: " + asInstId); + + updateAsInstanceStatus(execution, State.INSTANTIATED); + logger.info("Finished executing updateAsInstanceStatusToInstantiated ..."); + } + + public void downloadHelmPackagesFromSdc(final DelegateExecution execution) { + logger.info("Executing downloadHelmPackages ..."); + setJobStatus(execution, IN_PROGRESS, "Downloading helm packages"); + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + + final AsInst asInst = getAsInst(execution); + final Optional<byte[]> optional = getSdcResourcePackage(execution, asInst.getAsdId()); + + if (optional.isEmpty()) { + final String message = "Unable to find ASD package using asdId: " + asInst.getAsdId(); + logger.error(message); + abortOperation(execution, message); + } + + final List<AsDeploymentItem> asDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId); + + final File dir = mkdirIfnotExists(csarDir, asInstId); + + final Map<String, String> asDeploymentItemInstIdToHelmFileMapping = new HashMap<>(); + + asDeploymentItems.forEach(asDeploymentItem -> { + try (final ByteArrayInputStream stream = new ByteArrayInputStream(optional.get()); + final ZipInputStream zipInputStream = new ZipInputStream(stream);) { + + final String artifactFilePath = asDeploymentItem.getArtifactFilePath(); + final String asDeploymentItemInstId = asDeploymentItem.getAsDeploymentItemInstId(); + try (final ByteArrayOutputStream helmByteArrayOutputStream = + sdcParser.getFileInZip(zipInputStream, artifactFilePath);) { + + final Path artifactPath = Paths.get(artifactFilePath); + final Path path = dir.toPath().resolve(asDeploymentItem.getAsDeploymentItemInstId()) + .resolve(artifactPath.getFileName()); + + if (!Files.exists(path.getParent())) { + final File parentDir = path.getParent().toFile(); + logger.debug("Creating sub directories to download helm chart file {}", parentDir.toString()); + parentDir.mkdirs(); + } + + if (Files.exists(path)) { + logger.debug("{} file already exists will remove it", path); + Files.delete(path); + } + + try (final OutputStream outputStream = new FileOutputStream(path.toString())) { + helmByteArrayOutputStream.writeTo(outputStream); + } + + asDeploymentItemInstIdToHelmFileMapping.put(asDeploymentItemInstId, path.toString()); + + } + } catch (final IOException ioException) { + final String message = "Unexpected exception occured while processing CSAR " + asInst.getAsdId(); + logger.error(message, ioException); + abortOperation(execution, message); + } catch (final NoSuchElementException noSuchElementException) { + final String message = "Unable to find artifact " + asDeploymentItem.getArtifactFilePath(); + logger.error(message, noSuchElementException); + abortOperation(execution, message); + } catch (final Exception exception) { + final String message = "Unexpected exception occured while downloading helm packages"; + logger.error(message, exception); + abortOperation(execution, message); + } + }); + + logger.info("asDeploymentItemInstIdToHelmFileMapping: {}", asDeploymentItemInstIdToHelmFileMapping); + execution.setVariable(DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME, + asDeploymentItemInstIdToHelmFileMapping); + + logger.info("Finished executing downloadHelmPackages ..."); + } + + private Optional<byte[]> getSdcResourcePackage(final DelegateExecution execution, final String asdId) { + try { + return sdcPackageProvider.getSdcResourcePackage(asdId); + } catch (final SdcPackageRequestFailureException exception) { + final String message = "Unexpected exception occured while getting asd package using asdId: " + asdId; + logger.error(message); + abortOperation(execution, message); + } + return Optional.empty(); + } + + public void prepareInstantiateDeploymentItemRequests(final DelegateExecution execution) { + logger.info("Executing prepareInstantiateDeploymentItemRequests ..."); + setJobStatus(execution, IN_PROGRESS, "Preparing InstantiateDeploymentItemRequest requests"); + + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + final InstantiateAsRequest instantiateAsRequest = + (InstantiateAsRequest) execution.getVariable(INSTANTIATE_AS_REQUEST_PARAM_NAME); + + @SuppressWarnings("unchecked") + final Map<String, String> asDeploymentItemInstIdToHelmFileMapping = + (Map<String, String>) execution.getVariable(DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME); + + final String kubeConfigFile = (String) execution.getVariable(KUBE_CONFIG_FILE_PARAM_NAME); + + final List<AsDeploymentItem> asDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId); + + final Set<InstantiateDeploymentItemRequest> requests = new TreeSet<>(); + final Map<String, Object> lifeCycleParamMap = instantiateAsRequest.getDeploymentItems().stream() + .collect(Collectors.toMap(AsInfoModificationRequestDeploymentItems::getDeploymentItemsId, + AsInfoModificationRequestDeploymentItems::getLifecycleParameterKeyValues)); + asDeploymentItems.forEach(asDeploymentItem -> { + + final String asDeploymentItemInstId = asDeploymentItem.getAsDeploymentItemInstId(); + final String artifactFilePath = asDeploymentItemInstIdToHelmFileMapping.get(asDeploymentItemInstId); + final String releaseName = asDeploymentItem.getReleaseName(); + + if (Strings.isEmpty(artifactFilePath)) { + final String message = + "Unable to find helm artifact for asDeploymentItemInstId: " + asDeploymentItemInstId; + abortOperation(execution, message); + } + + + @SuppressWarnings("unchecked") + final Map<String, String> lifeCycleParams = + (Map<String, String>) lifeCycleParamMap.get(asDeploymentItem.getItemId()); + + final List<AsLifecycleParam> requiredParams = asDeploymentItem.getAsLifecycleParams(); + + checkForLifecycleParametersAbort(execution, lifeCycleParams, requiredParams); + requests.add(new InstantiateDeploymentItemRequest().asInstId(asInstId) + .asDeploymentItemInstId(asDeploymentItemInstId).asDeploymentItemName(asDeploymentItem.getName()) + .helmArtifactFilePath(artifactFilePath).deploymentOrder(asDeploymentItem.getDeploymentOrder()) + .kubeConfigFile(kubeConfigFile).lifeCycleParameters(lifeCycleParams).releaseName((releaseName))); + + }); + + execution.setVariable(DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS, requests); + + logger.info("Finished executing prepareInstantiateDeploymentItemRequests ..."); + + } + + private void checkForLifecycleParametersAbort(final DelegateExecution execution, + final Map<String, String> lifeCycleParams, final List<AsLifecycleParam> requiredParams) { + if (!requiredParams.isEmpty()) { + if (isNullOrEmptyMap(lifeCycleParams)) { + abortOnLifecycleParams(execution, "no lifecycle parameters in request"); + } + final Iterator<AsLifecycleParam> it = requiredParams.iterator(); + while (it.hasNext()) { + final String next = it.next().getLifecycleParam(); + if (!lifeCycleParams.containsKey(next)) { + abortOnLifecycleParams(execution, "parameter missing: " + next); + } + } + } + } + + private void abortOnLifecycleParams(final DelegateExecution execution, final String reason) { + final String message = "Lifecycle parameter error, " + reason; + abortOperation(execution, message); + } + + public void checkIfDeploymentItemsInstantiationWasSuccessful(final DelegateExecution execution) { + logger.info("Executing checkIfDeploymentItemsInstantiationWasSuccessful"); + + @SuppressWarnings("unchecked") + final Set<InstantiateDeploymentItemRequest> requests = + (Set<InstantiateDeploymentItemRequest>) execution.getVariable(DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS); + + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + final List<AsDeploymentItem> asDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId); + + + if (asDeploymentItems == null || asDeploymentItems.isEmpty()) { + final String message = "Found empty asDeploymentItems"; + abortOperation(execution, message); + } + + if (requests.size() != asDeploymentItems.size()) { + final String message = "Missing asDeploymentItems. Request triggered has: " + requests.size() + + " asDeploymentItems but database has: " + asDeploymentItems.size(); + abortOperation(execution, message); + } + + execution.setVariable(IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME, true); + + asDeploymentItems.stream().forEach(asDeploymentItem -> { + logger.info("Checking if AsDeploymentItem {} was successfull Status: {}", + asDeploymentItem.getAsDeploymentItemInstId(), asDeploymentItem.getStatus()); + if (!State.INSTANTIATED.equals(asDeploymentItem.getStatus())) { + logger.error("AsDeploymentItem : {} {} instantiation failed", + asDeploymentItem.getAsDeploymentItemInstId(), asDeploymentItem.getName()); + execution.setVariable(IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME, false); + } else { + cleanUpDeploymentItemDirectory(asInstId, asDeploymentItem.getAsDeploymentItemInstId()); + } + }); + + cleanUpInstanceIdDirectory(asInstId); + logger.info("Finished executing checkIfDeploymentItemsInstantiationWasSuccessful ..."); + } + + private void cleanUpDeploymentItemDirectory(final String asInstId, final String deploymentItemInstId) { + logger.info("Executing Cleaning up Deployment Item Directory {}", deploymentItemInstId); + final Path helmChartDirPath = Paths.get(csarDir, asInstId).resolve(deploymentItemInstId); + if (Files.exists(helmChartDirPath)) { + logger.debug("Will clean up the directory {}", helmChartDirPath); + try { + FileUtils.deleteDirectory(helmChartDirPath.toFile()); + } catch (final IOException e) { + logger.debug("Error deleting the directory {}", helmChartDirPath); + } + } + } + + private void cleanUpInstanceIdDirectory(final String asInstId) { + logger.debug("Executing Cleaning up Instance Id Directory {}", asInstId); + final Path dirPath = Paths.get(csarDir, asInstId); + if (Files.exists(dirPath) && (dirPath.toFile().list().length == 0)) { + logger.debug("Will clean up the instance id directory {}", dirPath); + try { + Files.delete(dirPath); + } catch (final IOException e) { + logger.debug("Error deleting the instance id directory {}", dirPath); + } + } else { + logger.debug("Will not clean up the instance id directory. {} is not Empty", dirPath); + } + } + + public void checkifKubConfigFileAvailable(final DelegateExecution execution) { + logger.info("Executing checkifKubConfigFileAvailable"); + try { + final AsInst asInst = getAsInst(execution); + + final Path kubeConfigFile = kubConfigProvider.getKubeConfigFile(asInst.getCloudOwner(), + asInst.getCloudRegion(), asInst.getTenantId()); + + execution.setVariable(KUBE_CONFIG_FILE_PARAM_NAME, kubeConfigFile.toString()); + + } catch (final KubeConfigFileNotFoundException exception) { + final String message = "Unable to find kube-config file on filesystem"; + logger.error(message, exception); + abortOperation(execution, message); + + } + + logger.info("Finished executing checkifKubConfigFileAvailable ..."); + + } + + public void logTimeOut(final DelegateExecution execution) { + logger.error("Deployment items instantiation timedOut ..."); + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + final List<AsDeploymentItem> asDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId); + if (asDeploymentItems != null) { + asDeploymentItems.stream().forEach(asDeploymentItem -> { + logger.info("Current status {} of asDeploymentItem: {}", asDeploymentItem.getStatus(), + asDeploymentItem.getName()); + }); + } + } + + public void setJobStatusToError(final DelegateExecution execution) { + setJobStatusToError(execution, "Instantiate AS workflow process failed"); + } + + private File mkdirIfnotExists(final String parentDir, final String dirname) { + final Path dirPath = Paths.get(parentDir, dirname); + final File dir = dirPath.toFile(); + if (!dir.exists()) { + logger.debug("Creating directory to download helm chart file {}", dir.toString()); + dir.mkdir(); + } + return dir; + } + + public static boolean isNullOrEmptyMap(final Map<?, ?> map) { + return (map == null || map.isEmpty()); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemRequest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemRequest.java new file mode 100644 index 0000000..b7b8598 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemRequest.java @@ -0,0 +1,193 @@ +/*- + * ============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.tasks; + +import static org.onap.so.cnfm.lcm.database.beans.utils.Utils.toIndentedString; +import java.io.Serializable; +import java.util.Comparator; +import java.util.Map; +import java.util.Objects; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class InstantiateDeploymentItemRequest implements Serializable, Comparable<InstantiateDeploymentItemRequest> { + private static final long serialVersionUID = 6972854424933379019L; + + private String asInstId; + private String asDeploymentItemInstId; + private String asDeploymentItemName; + private String helmArtifactFilePath; + private String kubeConfigFile; + private Integer deploymentOrder; + private Map<String, String> lifeCycleParameters; + private String releaseName; + + private static final Comparator<Integer> COMPARATOR = Comparator.nullsFirst(Integer::compare); + + public String getAsInstId() { + return asInstId; + } + + public void setAsInstId(final String asInstId) { + this.asInstId = asInstId; + } + + public InstantiateDeploymentItemRequest asInstId(final String asInstId) { + this.asInstId = asInstId; + return this; + } + + public String getAsDeploymentItemInstId() { + return asDeploymentItemInstId; + } + + public void setAsDeploymentItemInstId(final String asDeploymentItemInstId) { + this.asDeploymentItemInstId = asDeploymentItemInstId; + } + + public InstantiateDeploymentItemRequest asDeploymentItemInstId(final String asDeploymentItemInstId) { + this.asDeploymentItemInstId = asDeploymentItemInstId; + return this; + } + + public String getAsDeploymentItemName() { + return asDeploymentItemName; + } + + public void setAsDeploymentItemName(final String asDeploymentItemName) { + this.asDeploymentItemName = asDeploymentItemName; + } + + public InstantiateDeploymentItemRequest asDeploymentItemName(final String asDeploymentItemName) { + this.asDeploymentItemName = asDeploymentItemName; + return this; + } + + public String getHelmArtifactFilePath() { + return helmArtifactFilePath; + } + + public void setHelmArtifactFilePath(final String helmArtifactFilePath) { + this.helmArtifactFilePath = helmArtifactFilePath; + } + + public InstantiateDeploymentItemRequest helmArtifactFilePath(final String helmArtifactFilePath) { + this.helmArtifactFilePath = helmArtifactFilePath; + return this; + } + + public Integer getDeploymentOrder() { + return deploymentOrder; + } + + public void setDeploymentOrder(final Integer deploymentOrder) { + this.deploymentOrder = deploymentOrder; + } + + public InstantiateDeploymentItemRequest deploymentOrder(final Integer deploymentOrder) { + this.deploymentOrder = deploymentOrder; + return this; + } + + public String getReleaseName() { + return releaseName; + } + + public void setReleaseName(final String releaseName) { + this.releaseName = releaseName; + } + + public InstantiateDeploymentItemRequest releaseName(final String releaseName) { + this.releaseName = releaseName; + return this; + } + + public String getKubeConfigFile() { + return kubeConfigFile; + } + + public void setKubeConfigFile(final String kubeConfigFile) { + this.kubeConfigFile = kubeConfigFile; + } + + public InstantiateDeploymentItemRequest kubeConfigFile(final String kubeConfigFile) { + this.kubeConfigFile = kubeConfigFile; + return this; + } + + public Map<String, String> getLifeCycleParameters() { + return lifeCycleParameters; + } + + public void setLifeCycleParameters(final Map<String, String> lifeCycleParameters) { + this.lifeCycleParameters = lifeCycleParameters; + } + + public InstantiateDeploymentItemRequest lifeCycleParameters(final Map<String, String> lifeCycleParameters) { + this.lifeCycleParameters = lifeCycleParameters; + return this; + } + + @Override + public int hashCode() { + return Objects.hash(asInstId, asDeploymentItemInstId, asDeploymentItemName, helmArtifactFilePath, + deploymentOrder, kubeConfigFile, lifeCycleParameters, releaseName); + } + + @Override + public int compareTo(final InstantiateDeploymentItemRequest other) { + return COMPARATOR.compare(this.getDeploymentOrder(), other.getDeploymentOrder()); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof InstantiateDeploymentItemRequest) { + final InstantiateDeploymentItemRequest other = (InstantiateDeploymentItemRequest) obj; + return Objects.equals(asInstId, other.asInstId) + && Objects.equals(asDeploymentItemInstId, other.asDeploymentItemInstId) + && Objects.equals(asDeploymentItemName, other.asDeploymentItemName) + && Objects.equals(helmArtifactFilePath, other.helmArtifactFilePath) + && Objects.equals(deploymentOrder, other.deploymentOrder) + && Objects.equals(kubeConfigFile, other.kubeConfigFile) + && Objects.equals(lifeCycleParameters, other.lifeCycleParameters) + && Objects.equals(releaseName, other.releaseName); + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("class InstantiateDeploymentItemRequest {\n"); + sb.append(" asInstId: ").append(toIndentedString(asInstId)).append("\n"); + sb.append(" asDeploymentItemInstId: ").append(toIndentedString(asDeploymentItemInstId)).append("\n"); + sb.append(" asDeploymentItemName: ").append(toIndentedString(asDeploymentItemName)).append("\n"); + sb.append(" helmArtifactFilePath: ").append(toIndentedString(helmArtifactFilePath)).append("\n"); + sb.append(" deploymentOrder: ").append(toIndentedString(deploymentOrder)).append("\n"); + sb.append(" kubeConfigFile: ").append(toIndentedString(kubeConfigFile)).append("\n"); + sb.append(" LifeCycleParameters: ").append(toIndentedString(lifeCycleParameters)).append("\n"); + sb.append(" releaseName: ").append(toIndentedString(releaseName)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemTask.java new file mode 100644 index 0000000..a2cf976 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateDeploymentItemTask.java @@ -0,0 +1,406 @@ +/*- + * ============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.tasks; + +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KUBE_CONFIG_FILE_PATH_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KUBE_KINDS_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KUBE_KINDS_RESULT_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.RELEASE_NAME_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DAEMON_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DEPLOYMENT; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_JOB; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_POD; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_REPLICA_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_SERVICE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_STATEFUL_SET; + +import io.kubernetes.client.openapi.ApiClient; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.camunda.bpm.engine.delegate.BpmnError; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.onap.aai.domain.yang.K8SResource; +import org.onap.aai.domain.yang.VfModule; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.aai.AaiServiceProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.helm.HelmClient; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClient; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClientProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesResource; +import org.onap.so.cnfm.lcm.database.beans.AsDeploymentItem; +import org.onap.so.cnfm.lcm.database.beans.AsInst; +import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum; +import org.onap.so.cnfm.lcm.database.beans.State; +import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ + +@Component +public class InstantiateDeploymentItemTask extends AbstractServiceTask { + + private static final Logger logger = LoggerFactory.getLogger(InstantiateDeploymentItemTask.class); + + private static final String KUBERNETES_RESOURCES_PARAM_NAME = "kubernetesResources"; + + private static final String IS_SUCCESSFUL_PARAM_NAME = "isSuccessful"; + private static final String INSTANTIATE_REQUEST_PARAM_NAME = "request"; + + private final AaiServiceProvider aaiServiceProvider; + private final HelmClient helmClient; + private final KubernetesClientProvider kubernetesClientProvider; + private final KubernetesClient kubernetesClient; + + @Autowired + protected InstantiateDeploymentItemTask(final DatabaseServiceProvider databaseServiceProvider, + final AaiServiceProvider aaiServiceProvider, final HelmClient helmClient, + final KubernetesClientProvider kubernetesClientProvider, final KubernetesClient kubernetesClient) { + super(databaseServiceProvider); + this.aaiServiceProvider = aaiServiceProvider; + this.helmClient = helmClient; + this.kubernetesClientProvider = kubernetesClientProvider; + this.kubernetesClient = kubernetesClient; + } + + public void checkIfDeploymentItemExistsInDb(final DelegateExecution execution) { + logger.info("Executing checkIfDeploymentItemExistsInDb"); + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + logger.info("Instantiate request: {}", request); + + final String asDeploymentItemInstId = request.getAsDeploymentItemInstId(); + addJobStatus(execution, JobStatusEnum.IN_PROGRESS, + "Checking if Deployment item record exists in database for asDeploymentItemInstId: " + + asDeploymentItemInstId); + + if (!databaseServiceProvider.isAsDeploymentItemExists(request.getAsDeploymentItemInstId())) { + abortOperation(execution, "Deployment Item does not exists in database for asDeploymentItemInstId: " + + asDeploymentItemInstId); + } + + logger.info("Finished executing checkIfDeploymentItemExistsInDb ..."); + + } + + public void createVfModuleInAai(final DelegateExecution execution) { + logger.info("Executing createVfModuleInAai ..."); + try { + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + + setJobStatus(execution, JobStatusEnum.IN_PROGRESS, + "Creating Vf Module Instance in AAI for " + request.getAsDeploymentItemInstId()); + + final String asDeploymentItemInstId = request.getAsDeploymentItemInstId(); + + final VfModule vfModule = new VfModule(); + vfModule.setVfModuleId(asDeploymentItemInstId); + vfModule.setVfModuleName(request.getAsDeploymentItemName()); + vfModule.setIsBaseVfModule(true); + vfModule.setAutomatedAssignment(true); + vfModule.setOrchestrationStatus("Created"); + + aaiServiceProvider.createVfModule(request.getAsInstId(), asDeploymentItemInstId, vfModule); + + } catch (final Exception exception) { + final String message = "Unable to Create Vf Module Instance in AAI"; + logger.error(message, exception); + abortOperation(execution, message); + } + logger.info("Finished executing createVfModuleInAai ..."); + + } + + public void updateDeploymentItemStatusToInstantiated(final DelegateExecution execution) { + logger.info("Executing updateDeploymentItemStatusToInstantiated"); + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + + updateDeploymentItemStatus(execution, request.getAsDeploymentItemInstId(), State.INSTANTIATED); + + addJobStatus(execution, JobStatusEnum.FINISHED, "Successfully Instantiated Deployment Item: " + + request.getAsDeploymentItemName() + " will set status to " + State.INSTANTIATED); + + logger.info("Finished executing updateDeploymentItemStatusToInstantiated ..."); + + } + + + public void runHelmInstallDryRun(final DelegateExecution execution) { + logger.info("Executing runHelmInstallDryRun"); + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + + final String releaseName = request.getReleaseName(); + + try { + final Path kubeConfigFilePath = Paths.get(request.getKubeConfigFile()); + final Path helmChartPath = Paths.get(request.getHelmArtifactFilePath()); + + logger.debug("Running helm install with dry run flag"); + helmClient.runHelmChartInstallWithDryRunFlag(releaseName, kubeConfigFilePath, helmChartPath); + } catch (final Exception exception) { + final String message = "Unable to run helm install with dry run flag"; + logger.error(message, exception); + abortOperation(execution, message); + } + logger.info("Finished executing runHelmInstallDryRun ..."); + + } + + public void retrieveKubeKinds(final DelegateExecution execution) { + logger.info("Executing retrieveKubeKinds"); + + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + + try { + final Path kubeConfigFilePath = Paths.get(request.getKubeConfigFile()); + final Path helmChartPath = Paths.get(request.getHelmArtifactFilePath()); + final String releaseName = request.getReleaseName(); + final List<String> kubeKinds = helmClient.getKubeKinds(releaseName, kubeConfigFilePath, helmChartPath); + + if (kubeKinds.isEmpty()) { + abortOperation(execution, + "Unable to retrieve kinds from chart / charts doesn't contains kinds: " + helmChartPath); + } + + execution.setVariable(AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME, request.getAsDeploymentItemInstId()); + execution.setVariable(KUBE_CONFIG_FILE_PATH_PARAM_NAME, request.getKubeConfigFile()); + execution.setVariable(KUBE_KINDS_PARAM_NAME, kubeKinds); + + final Map<String, Boolean> result = new HashMap<>(); + kubeKinds.forEach(kind -> { + result.put(kind, false); + }); + + execution.setVariable(KUBE_KINDS_RESULT_PARAM_NAME, result); + } catch (final BpmnError bpmnError) { + throw bpmnError; + } catch (final Exception exception) { + final String message = "Unable to retrieve kube kinds"; + logger.error(message, exception); + abortOperation(execution, message); + } + logger.info("Finished executing retrieveKubeKinds ..."); + + } + + public void instantiateHelmChart(final DelegateExecution execution) { + logger.info("Executing instantiateHelmChart"); + + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + final String releaseName = request.getReleaseName(); + execution.setVariable(RELEASE_NAME_PARAM_NAME, releaseName); + try { + final Path kubeConfigFilePath = Paths.get(request.getKubeConfigFile()); + final Path helmChartPath = Paths.get(request.getHelmArtifactFilePath()); + final Map<String, String> lifeCycleParams = request.getLifeCycleParameters(); + + helmClient.installHelmChart(releaseName, kubeConfigFilePath, helmChartPath, lifeCycleParams); + } catch (final Exception exception) { + final String message = "Unable to install helm chart: " + request.getHelmArtifactFilePath() + + " using kube-config file: " + request.getKubeConfigFile(); + logger.error(message, exception); + abortOperation(execution, message); + } + logger.info("Finished executing instantiateHelmChart ..."); + + } + + public void checkIfHelmInstallWasSuccessful(final DelegateExecution execution) { + logger.info("Executing checkIfHelmInstallWasSuccessful"); + + @SuppressWarnings("unchecked") + final Map<String, Boolean> kubeKindResult = + (Map<String, Boolean>) execution.getVariable(KUBE_KINDS_RESULT_PARAM_NAME); + + execution.setVariable(IS_SUCCESSFUL_PARAM_NAME, true); + + kubeKindResult.entrySet().forEach(entry -> { + logger.info("Checking if resource type {} was successfull Status: {}", entry.getKey(), entry.getValue()); + + if (Boolean.FALSE.equals(entry.getValue())) { + logger.error("resource type {} failed", entry.getKey()); + execution.setVariable(IS_SUCCESSFUL_PARAM_NAME, false); + } + }); + + final String kubeConfigFile = (String) execution.getVariable(KUBE_CONFIG_FILE_PATH_PARAM_NAME); + kubernetesClientProvider.closeApiClient(kubeConfigFile); + + logger.info("Finished executing checkIfHelmInstallWasSuccessful ..."); + + } + + public void retrieveKubernetesResources(final DelegateExecution execution) { + logger.info("Executing retrieveKubernetesResources"); + final String releaseName = (String) execution.getVariable(RELEASE_NAME_PARAM_NAME); + final String kubeConfigFile = (String) execution.getVariable(KUBE_CONFIG_FILE_PATH_PARAM_NAME); + @SuppressWarnings("unchecked") + final List<String> kubeKinds = (List<String>) execution.getVariable(KUBE_KINDS_PARAM_NAME); + + final String labelSelector = "app.kubernetes.io/instance=" + releaseName; + + if (kubeKinds != null) { + final List<KubernetesResource> resources = new ArrayList<>(); + kubeKinds.forEach(kind -> { + try { + final ApiClient apiClient = kubernetesClientProvider.getApiClient(kubeConfigFile); + logger.debug("Will check if resource type: {} is ready using labelSelector: {}", kind, + labelSelector); + switch (kind) { + case KIND_JOB: + resources.addAll(kubernetesClient.getJobResources(apiClient, labelSelector)); + break; + case KIND_POD: + resources.addAll(kubernetesClient.getPodResources(apiClient, labelSelector)); + break; + case KIND_SERVICE: + resources.addAll(kubernetesClient.getServiceResources(apiClient, labelSelector)); + break; + case KIND_DEPLOYMENT: + resources.addAll(kubernetesClient.getDeploymentResources(apiClient, labelSelector)); + break; + case KIND_REPLICA_SET: + resources.addAll(kubernetesClient.getReplicaSetResources(apiClient, labelSelector)); + break; + case KIND_DAEMON_SET: + resources.addAll(kubernetesClient.getDaemonSetResources(apiClient, labelSelector)); + break; + case KIND_STATEFUL_SET: + resources.addAll(kubernetesClient.getStatefulSetResources(apiClient, labelSelector)); + break; + default: + logger.warn("Unknown resource type {} setting {} skipping it", kind); + break; + } + } catch (final Exception exception) { + final String message = "Unable to query kubernetes for resource " + kind; + logger.error(message, exception); + abortOperation(execution, message); + } + }); + logger.debug("Found resources : {}", resources); + + execution.setVariable(KUBERNETES_RESOURCES_PARAM_NAME, resources); + + } + + logger.info("Finished executing retrieveKubernetesResources ..."); + + } + + public void createK8sResourcesInAai(final DelegateExecution execution) { + logger.info("Executing createK8sResourcesInAai"); + @SuppressWarnings("unchecked") + final List<KubernetesResource> resources = + (List<KubernetesResource>) execution.getVariable(KUBERNETES_RESOURCES_PARAM_NAME); + if (resources == null) { + abortOperation(execution, "resources cannot be null"); + } + final InstantiateDeploymentItemRequest request = + (InstantiateDeploymentItemRequest) execution.getVariable(INSTANTIATE_REQUEST_PARAM_NAME); + + setJobStatus(execution, JobStatusEnum.IN_PROGRESS, + "Creating K8s Resource in AAI for " + request.getAsDeploymentItemInstId()); + + final AsInst asInst = getAsInst(execution); + + resources.forEach(kubernetesResource -> { + try { + final K8SResource k8sResource = new K8SResource(); + k8sResource.setId(kubernetesResource.getId()); + k8sResource.setName(kubernetesResource.getName()); + k8sResource.setGroup(kubernetesResource.getGroup()); + k8sResource.setVersion(kubernetesResource.getVersion()); + k8sResource.setKind(kubernetesResource.getKind()); + k8sResource.setNamespace(kubernetesResource.getNamespace()); + k8sResource.setDataSourceVersion(kubernetesResource.getResourceVersion()); + + k8sResource.getLabels().addAll(kubernetesResource.getLabels()); + + k8sResource.setDataOwner("so-cnfm"); + k8sResource.setDataSource("kubernetes"); + k8sResource.setSelflink("http://so-cnfm-lcm.onap:9888/query/"); + + aaiServiceProvider.createK8sResource(kubernetesResource.getId(), asInst.getCloudOwner(), + asInst.getCloudRegion(), asInst.getTenantId(), k8sResource); + + aaiServiceProvider.connectK8sResourceToVfModule(kubernetesResource.getId(), asInst.getCloudOwner(), + asInst.getCloudRegion(), asInst.getTenantId(), request.getAsInstId(), + request.getAsDeploymentItemInstId()); + + aaiServiceProvider.connectK8sResourceToGenericVnf(kubernetesResource.getId(), asInst.getCloudOwner(), + asInst.getCloudRegion(), asInst.getTenantId(), request.getAsInstId()); + + + } catch (final Exception exception) { + final String message = "Unable to Create K8s Resource in AAI for " + kubernetesResource; + logger.error(message, exception); + abortOperation(execution, message); + } + }); + + + logger.info("Finished executing createK8sResourcesInAai ..."); + + } + + public void logTimeOut(final DelegateExecution execution) { + logger.error("Checking helm install status timedOut ..."); + + @SuppressWarnings("unchecked") + final Map<String, Boolean> kubeKindResult = + (Map<String, Boolean>) execution.getVariable(KUBE_KINDS_RESULT_PARAM_NAME); + + if (kubeKindResult != null) { + kubeKindResult.entrySet().forEach(entry -> { + logger.info("Current status {} of resource type: {}", entry.getValue(), entry.getKey()); + }); + } + + + final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME); + final List<AsDeploymentItem> asDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId); + if (asDeploymentItems != null) { + asDeploymentItems.stream().forEach(asDeploymentItem -> { + logger.info("Current status {} of asDeploymentItem: {}", asDeploymentItem.getStatus(), + asDeploymentItem.getName()); + }); + } + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MonitorHelmInstallStatusTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MonitorHelmInstallStatusTask.java new file mode 100644 index 0000000..4462829 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MonitorHelmInstallStatusTask.java @@ -0,0 +1,185 @@ +/*- + * ============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.tasks; + +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KIND_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KUBE_CONFIG_FILE_PATH_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.KUBE_KINDS_RESULT_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.RELEASE_NAME_PARAM_NAME; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DAEMON_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DEPLOYMENT; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_JOB; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_POD; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_REPLICA_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_SERVICE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_STATEFUL_SET; + +import io.kubernetes.client.openapi.ApiClient; +import java.util.Map; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubernetesRequestTimeOut; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClient; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClientProvider; +import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum; +import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +public class MonitorHelmInstallStatusTask extends AbstractServiceTask { + + + private static final int MAX_RETRIES = 10; + private static final String RETRY_COUNTER_PARAM_NAME = "retryCounter"; + private static final String IS_RESOURCE_READY_PARAM_NAME = "isResourceReady"; + private static final Logger logger = LoggerFactory.getLogger(MonitorHelmInstallStatusTask.class); + private final KubernetesClientProvider kubernetesClientProvider; + private final KubernetesClient kubernetesClient; + + @Autowired + protected MonitorHelmInstallStatusTask(final DatabaseServiceProvider databaseServiceProvider, + final KubernetesClientProvider kubernetesClientProvider, final KubernetesClient kubernetesClient) { + super(databaseServiceProvider); + this.kubernetesClientProvider = kubernetesClientProvider; + this.kubernetesClient = kubernetesClient; + } + + public void updateJobStatus(final DelegateExecution execution) { + logger.info("Executing updateJobStatus "); + final String kind = (String) execution.getVariable(KIND_PARAM_NAME); + final String asDeploymentItemInstId = (String) execution.getVariable(AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME); + + addJobStatus(execution, JobStatusEnum.IN_PROGRESS, + "Checking if resource " + kind + " is ready for asDeploymentItemInstId: " + asDeploymentItemInstId); + + execution.setVariable(RETRY_COUNTER_PARAM_NAME, 0); + + logger.info("Finished updateJobStatus ..."); + } + + public void isResourceReady(final DelegateExecution execution) { + logger.info("Executing isResourceReady "); + final String kind = (String) execution.getVariable(KIND_PARAM_NAME); + final String releaseName = (String) execution.getVariable(RELEASE_NAME_PARAM_NAME); + final String kubeConfigFile = (String) execution.getVariable(KUBE_CONFIG_FILE_PATH_PARAM_NAME); + final String labelSelector = "app.kubernetes.io/instance=" + releaseName; + try { + final ApiClient apiClient = kubernetesClientProvider.getApiClient(kubeConfigFile); + boolean isReady = false; + logger.debug("Will check if resource type: {} is ready using labelSelector: {}", kind, labelSelector); + switch (kind) { + case KIND_JOB: + isReady = kubernetesClient.isJobReady(apiClient, labelSelector); + break; + case KIND_POD: + isReady = kubernetesClient.isPodReady(apiClient, labelSelector); + break; + case KIND_SERVICE: + isReady = kubernetesClient.isServiceReady(apiClient, labelSelector); + break; + case KIND_DEPLOYMENT: + isReady = kubernetesClient.isDeploymentReady(apiClient, labelSelector); + break; + case KIND_REPLICA_SET: + isReady = kubernetesClient.isReplicaSetReady(apiClient, labelSelector); + break; + case KIND_DAEMON_SET: + isReady = kubernetesClient.isDaemonSetReady(apiClient, labelSelector); + break; + case KIND_STATEFUL_SET: + isReady = kubernetesClient.isStatefulSetReady(apiClient, labelSelector); + break; + + default: + logger.warn("Unknown resource type {} setting {} flag to true", kind, IS_RESOURCE_READY_PARAM_NAME); + isReady = true; + break; + } + + logger.debug("isReady: {}", isReady); + execution.setVariable(IS_RESOURCE_READY_PARAM_NAME, isReady); + + } catch (final KubernetesRequestTimeOut kubernetesRequestTimeOut) { + final Integer counter = (Integer) execution.getVariable(RETRY_COUNTER_PARAM_NAME); + if (counter > MAX_RETRIES) { + final String message = "Retries max out for resource: " + kind; + logger.error(message); + abortOperation(execution, message); + } + logger.debug("Current retries counter: {} will increament and try again", counter); + execution.setVariable(RETRY_COUNTER_PARAM_NAME, counter + 1); + execution.setVariable(IS_RESOURCE_READY_PARAM_NAME, false); + + } catch (final Exception exception) { + final String message = "Unable to preform status check for resource " + kind; + logger.error(message, exception); + abortOperation(execution, message); + } + logger.info("Finished isResourceReady ..."); + + } + + public void checkIfOperationWasSuccessful(final DelegateExecution execution) { + logger.info("Executing checkIfOperationWasSuccessful "); + + final String kind = (String) execution.getVariable(KIND_PARAM_NAME); + + @SuppressWarnings("unchecked") + final Map<String, Boolean> kubeKindResult = + (Map<String, Boolean>) execution.getVariable(KUBE_KINDS_RESULT_PARAM_NAME); + + final boolean isReady = (boolean) execution.getVariable(IS_RESOURCE_READY_PARAM_NAME); + logger.debug("{} status {}", kind, isReady ? "Successful" : "failed"); + kubeKindResult.put(kind, isReady); + + execution.setVariable(KUBE_KINDS_RESULT_PARAM_NAME, kubeKindResult); + + if (!isReady) { + final String message = "Status check failed for resource: {}" + kind; + logger.error(message); + abortOperation(execution, message); + } + + final String asDeploymentItemInstId = (String) execution.getVariable(AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME); + addJobStatus(execution, JobStatusEnum.IN_PROGRESS, + "Resource " + kind + " is ready for asDeploymentItemInstId: " + asDeploymentItemInstId); + logger.info("Finished checkIfOperationWasSuccessful ..."); + } + + public void timeOutLogFailue(final DelegateExecution execution) { + logger.info("Executing timeOutLogFailue "); + final String message = "Is Resource ready operation timed out"; + logger.error(message); + abortOperation(execution, message); + logger.info("Finished timeOutLogFailue ..."); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateAs.bpmn b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateAs.bpmn new file mode 100644 index 0000000..8e00a8b --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateAs.bpmn @@ -0,0 +1,350 @@ +<?xml version="1.0" encoding="UTF-8"?> +<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_0z4cnke" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.0.0"> + <bpmn:process id="InstantiateAs" name="InstantiateAs" isExecutable="true"> + <bpmn:startEvent id="StartEvent_1"> + <bpmn:outgoing>Flow_1sxgter</bpmn:outgoing> + </bpmn:startEvent> + <bpmn:serviceTask id="Activity_1795atc" name="Set Job Status to STARTED" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.setJobStatusToStarted(execution)}"> + <bpmn:incoming>Flow_1sxgter</bpmn:incoming> + <bpmn:outgoing>Flow_0tq8t7y</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:serviceTask id="Activity_0hucgqb" name="Update AS Instance status to INSTANTIATING" camunda:expression="${InstantiateAsTask.updateAsInstanceStatusToInstantiating(execution)}"> + <bpmn:incoming>Flow_0tq8t7y</bpmn:incoming> + <bpmn:outgoing>Flow_17dvp3y</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0tq8t7y" sourceRef="Activity_1795atc" targetRef="Activity_0hucgqb" /> + <bpmn:sequenceFlow id="Flow_1sxgter" sourceRef="StartEvent_1" targetRef="Activity_1795atc" /> + <bpmn:endEvent id="Event_1oro0qa"> + <bpmn:incoming>Flow_1sxbcxh</bpmn:incoming> + </bpmn:endEvent> + <bpmn:sequenceFlow id="Flow_17dvp3y" sourceRef="Activity_0hucgqb" targetRef="Activity_0wlcizw" /> + <bpmn:subProcess id="Activity_0q2xhus" name="Error Handling" triggeredByEvent="true"> + <bpmn:startEvent id="Event_0yregoc" name="error"> + <bpmn:outgoing>Flow_14unlim</bpmn:outgoing> + <bpmn:errorEventDefinition id="ErrorEventDefinition_1p86pwa" /> + </bpmn:startEvent> + <bpmn:endEvent id="Event_0chtf5u" name="end"> + <bpmn:incoming>Flow_040m09j</bpmn:incoming> + </bpmn:endEvent> + <bpmn:serviceTask id="Activity_0120hwd" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.setJobStatusToError(execution)}"> + <bpmn:incoming>Flow_143iui6</bpmn:incoming> + <bpmn:outgoing>Flow_040m09j</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:serviceTask id="Activity_1wlkvmw" name="Update AsLcmOpOcc operation status to FAILED" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.updateAsLcmOpOccStatusToFailed(execution)}"> + <bpmn:incoming>Flow_14unlim</bpmn:incoming> + <bpmn:outgoing>Flow_0wgvjyh</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0wgvjyh" sourceRef="Activity_1wlkvmw" targetRef="Activity_1hopv4t" /> + <bpmn:sequenceFlow id="Flow_14unlim" sourceRef="Event_0yregoc" targetRef="Activity_1wlkvmw" /> + <bpmn:sequenceFlow id="Flow_040m09j" sourceRef="Activity_0120hwd" targetRef="Event_0chtf5u" /> + <bpmn:serviceTask id="Activity_1hopv4t" name="Update AS Instance status to FAILED" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.setAsInstanceStatusToFailed(execution)}"> + <bpmn:incoming>Flow_0wgvjyh</bpmn:incoming> + <bpmn:outgoing>Flow_143iui6</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_143iui6" sourceRef="Activity_1hopv4t" targetRef="Activity_0120hwd" /> + </bpmn:subProcess> + <bpmn:subProcess id="Activity_1frrsch" name="Java Exception Handling" triggeredByEvent="true"> + <bpmn:startEvent id="Event_097n1bq" name="error"> + <bpmn:outgoing>Flow_0ta9hkf</bpmn:outgoing> + <bpmn:errorEventDefinition id="ErrorEventDefinition_0lcz3oo" errorRef="Error_0t56zia" camunda:errorCodeVariable="BPMN_javaExpCode" camunda:errorMessageVariable="BPMN_javaExpMsg" /> + </bpmn:startEvent> + <bpmn:endEvent id="Event_1i8yr4f"> + <bpmn:incoming>Flow_17s9t7i</bpmn:incoming> + </bpmn:endEvent> + <bpmn:serviceTask id="Activity_06i1xfx" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.setJobStatusToError(execution)}"> + <bpmn:incoming>Flow_1uv2624</bpmn:incoming> + <bpmn:outgoing>Flow_17s9t7i</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:serviceTask id="Activity_1lz6wg9" name="Update AsLcmOpOcc operation status to FAILED" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.updateAsLcmOpOccStatusToFailed(execution)}"> + <bpmn:incoming>Flow_0ta9hkf</bpmn:incoming> + <bpmn:outgoing>Flow_04bdbeu</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_04bdbeu" sourceRef="Activity_1lz6wg9" targetRef="Activity_17o23mj" /> + <bpmn:sequenceFlow id="Flow_0ta9hkf" sourceRef="Event_097n1bq" targetRef="Activity_1lz6wg9" /> + <bpmn:sequenceFlow id="Flow_17s9t7i" sourceRef="Activity_06i1xfx" targetRef="Event_1i8yr4f" /> + <bpmn:serviceTask id="Activity_17o23mj" name="Update AS Instance status to FAILED" camunda:asyncBefore="true" camunda:expression="${InstantiateAsTask.setAsInstanceStatusToFailed(execution)}"> + <bpmn:incoming>Flow_04bdbeu</bpmn:incoming> + <bpmn:outgoing>Flow_1uv2624</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_1uv2624" sourceRef="Activity_17o23mj" targetRef="Activity_06i1xfx" /> + </bpmn:subProcess> + <bpmn:serviceTask id="Activity_00mubx8" name="Download helm packages from SDC" camunda:expression="${InstantiateAsTask.downloadHelmPackagesFromSdc(execution)}"> + <bpmn:incoming>Flow_0scutoj</bpmn:incoming> + <bpmn:outgoing>Flow_0isluk8</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0isluk8" sourceRef="Activity_00mubx8" targetRef="Activity_1wkdqgz" /> + <bpmn:serviceTask id="Activity_1wkdqgz" name="Prepare Instantiate Deployment Item requests" camunda:expression="${InstantiateAsTask.prepareInstantiateDeploymentItemRequests(execution)}"> + <bpmn:incoming>Flow_0isluk8</bpmn:incoming> + <bpmn:outgoing>Flow_00adm9l</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_00adm9l" sourceRef="Activity_1wkdqgz" targetRef="Activity_1mj5zfc" /> + <bpmn:callActivity id="Activity_1mj5zfc" name="Instantiate each Deployment Item" calledElement="InstantiateDeploymentItem"> + <bpmn:extensionElements> + <camunda:in source="request" target="request" /> + <camunda:in source="jobId" target="jobId" /> + <camunda:in source="AsInstanceId" target="AsInstanceId" /> + </bpmn:extensionElements> + <bpmn:incoming>Flow_00adm9l</bpmn:incoming> + <bpmn:outgoing>Flow_132rxn7</bpmn:outgoing> + <bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:asyncAfter="true" camunda:collection="${deploymentItemInstantiateRequests}" camunda:elementVariable="request" /> + </bpmn:callActivity> + <bpmn:boundaryEvent id="Event_056xxf3" name="Overall Wait" attachedToRef="Activity_1mj5zfc"> + <bpmn:outgoing>Flow_1qbt795</bpmn:outgoing> + <bpmn:timerEventDefinition id="TimerEventDefinition_11u0ekp"> + <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT3H</bpmn:timeDuration> + </bpmn:timerEventDefinition> + </bpmn:boundaryEvent> + <bpmn:serviceTask id="Activity_1jts0xn" name="Log TimeOut" camunda:expression="${InstantiateAsTask.logTimeOut(execution)}"> + <bpmn:incoming>Flow_1qbt795</bpmn:incoming> + <bpmn:outgoing>Flow_1idswft</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_1qbt795" sourceRef="Event_056xxf3" targetRef="Activity_1jts0xn" /> + <bpmn:endEvent id="Event_0iz85ln"> + <bpmn:incoming>Flow_1idswft</bpmn:incoming> + <bpmn:incoming>Flow_11d2dsb</bpmn:incoming> + <bpmn:errorEventDefinition id="ErrorEventDefinition_0uqpvyg" errorRef="Error_0t56zia" /> + </bpmn:endEvent> + <bpmn:sequenceFlow id="Flow_1idswft" sourceRef="Activity_1jts0xn" targetRef="Event_0iz85ln" /> + <bpmn:serviceTask id="Activity_1ied5nc" name="Check if Deployment Items Instantiation was Successful" camunda:expression="${InstantiateAsTask.checkIfDeploymentItemsInstantiationWasSuccessful(execution)}"> + <bpmn:incoming>Flow_132rxn7</bpmn:incoming> + <bpmn:outgoing>Flow_02em5qs</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_02em5qs" sourceRef="Activity_1ied5nc" targetRef="Gateway_06foddt" /> + <bpmn:exclusiveGateway id="Gateway_06foddt" name="is Successful?"> + <bpmn:incoming>Flow_02em5qs</bpmn:incoming> + <bpmn:outgoing>Flow_0y5o040</bpmn:outgoing> + <bpmn:outgoing>Flow_11d2dsb</bpmn:outgoing> + </bpmn:exclusiveGateway> + <bpmn:sequenceFlow id="Flow_0y5o040" name="Yes " sourceRef="Gateway_06foddt" targetRef="Activity_1n3b4tw"> + <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{isAsInstantiationSuccessful}</bpmn:conditionExpression> + </bpmn:sequenceFlow> + <bpmn:sequenceFlow id="Flow_11d2dsb" name="No " sourceRef="Gateway_06foddt" targetRef="Event_0iz85ln"> + <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{not isAsInstantiationSuccessful}</bpmn:conditionExpression> + </bpmn:sequenceFlow> + <bpmn:sequenceFlow id="Flow_132rxn7" sourceRef="Activity_1mj5zfc" targetRef="Activity_1ied5nc" /> + <bpmn:serviceTask id="Activity_1n3b4tw" name="Update NS Instance status to INSTANTIATED" camunda:expression="${InstantiateAsTask.updateAsInstanceStatusToInstantiated(execution)}"> + <bpmn:incoming>Flow_0y5o040</bpmn:incoming> + <bpmn:outgoing>Flow_0vsf68v</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0vsf68v" sourceRef="Activity_1n3b4tw" targetRef="Activity_1twfzif" /> + <bpmn:serviceTask id="Activity_1twfzif" name="Update AsLcmOpOcc operation status to COMPLETED" camunda:expression="${InstantiateAsTask.updateAsLcmOpOccStatusToCompleted(execution)}"> + <bpmn:incoming>Flow_0vsf68v</bpmn:incoming> + <bpmn:outgoing>Flow_05p6kb1</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_05p6kb1" sourceRef="Activity_1twfzif" targetRef="Activity_010av23" /> + <bpmn:serviceTask id="Activity_010av23" name="Set Job Status to FINISHED" camunda:expression="${InstantiateAsTask.setJobStatusToFinished(execution)}"> + <bpmn:incoming>Flow_05p6kb1</bpmn:incoming> + <bpmn:outgoing>Flow_1sxbcxh</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_1sxbcxh" sourceRef="Activity_010av23" targetRef="Event_1oro0qa" /> + <bpmn:serviceTask id="Activity_0wlcizw" name="Check if Kube Config file available on filesystem" camunda:expression="${InstantiateAsTask.checkifKubConfigFileAvailable(execution)}"> + <bpmn:incoming>Flow_17dvp3y</bpmn:incoming> + <bpmn:outgoing>Flow_0scutoj</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0scutoj" sourceRef="Activity_0wlcizw" targetRef="Activity_00mubx8" /> + </bpmn:process> + <bpmn:error id="Error_17q9mss" name="NsWorkflowProcessingException" errorCode="INSTANTIATE_NS_WORKFLOW_PROCESSING_EXCEPTION" /> + <bpmn:error id="Error_0t56zia" name="AsWorkflowProcessingException" errorCode="INSTANTIATE_AS_WORKFLOW_PROCESSING_EXCEPTION" /> + <bpmndi:BPMNDiagram id="BPMNDiagram_1"> + <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="InstantiateAs"> + <bpmndi:BPMNEdge id="Flow_0scutoj_di" bpmnElement="Flow_0scutoj"> + <di:waypoint x="600" y="97" /> + <di:waypoint x="660" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1sxbcxh_di" bpmnElement="Flow_1sxbcxh"> + <di:waypoint x="1780" y="97" /> + <di:waypoint x="1822" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_05p6kb1_di" bpmnElement="Flow_05p6kb1"> + <di:waypoint x="1650" y="97" /> + <di:waypoint x="1680" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0vsf68v_di" bpmnElement="Flow_0vsf68v"> + <di:waypoint x="1520" y="97" /> + <di:waypoint x="1550" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_132rxn7_di" bpmnElement="Flow_132rxn7"> + <di:waypoint x="1060" y="97" /> + <di:waypoint x="1140" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_11d2dsb_di" bpmnElement="Flow_11d2dsb"> + <di:waypoint x="1330" y="122" /> + <di:waypoint x="1330" y="222" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1338" y="142" width="14" height="40" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0y5o040_di" bpmnElement="Flow_0y5o040"> + <di:waypoint x="1355" y="97" /> + <di:waypoint x="1420" y="97" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1397" y="79" width="19" height="40" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_02em5qs_di" bpmnElement="Flow_02em5qs"> + <di:waypoint x="1240" y="97" /> + <di:waypoint x="1305" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1idswft_di" bpmnElement="Flow_1idswft"> + <di:waypoint x="1240" y="240" /> + <di:waypoint x="1312" y="240" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1qbt795_di" bpmnElement="Flow_1qbt795"> + <di:waypoint x="1040" y="155" /> + <di:waypoint x="1040" y="240" /> + <di:waypoint x="1140" y="240" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_00adm9l_di" bpmnElement="Flow_00adm9l"> + <di:waypoint x="900" y="97" /> + <di:waypoint x="960" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0isluk8_di" bpmnElement="Flow_0isluk8"> + <di:waypoint x="760" y="97" /> + <di:waypoint x="800" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_17dvp3y_di" bpmnElement="Flow_17dvp3y"> + <di:waypoint x="460" y="97" /> + <di:waypoint x="500" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1sxgter_di" bpmnElement="Flow_1sxgter"> + <di:waypoint x="188" y="97" /> + <di:waypoint x="230" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0tq8t7y_di" bpmnElement="Flow_0tq8t7y"> + <di:waypoint x="330" y="97" /> + <di:waypoint x="360" y="97" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> + <dc:Bounds x="152" y="79" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1795atc_di" bpmnElement="Activity_1795atc"> + <dc:Bounds x="230" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0hucgqb_di" bpmnElement="Activity_0hucgqb"> + <dc:Bounds x="360" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_1oro0qa_di" bpmnElement="Event_1oro0qa"> + <dc:Bounds x="1822" y="79" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0q2xhus_di" bpmnElement="Activity_0q2xhus" isExpanded="true"> + <dc:Bounds x="315" y="260" width="665" height="200" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNEdge id="Flow_040m09j_di" bpmnElement="Flow_040m09j"> + <di:waypoint x="859" y="323" /> + <di:waypoint x="921" y="323" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_14unlim_di" bpmnElement="Flow_14unlim"> + <di:waypoint x="373" y="323" /> + <di:waypoint x="435" y="323" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0wgvjyh_di" bpmnElement="Flow_0wgvjyh"> + <di:waypoint x="535" y="323" /> + <di:waypoint x="600" y="323" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_143iui6_di" bpmnElement="Flow_143iui6"> + <di:waypoint x="700" y="323" /> + <di:waypoint x="759" y="323" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="Event_0yregoc_di" bpmnElement="Event_0yregoc"> + <dc:Bounds x="337" y="305" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="343" y="348" width="24" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_0chtf5u_di" bpmnElement="Event_0chtf5u"> + <dc:Bounds x="921" y="305" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="931" y="347" width="19" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0120hwd_di" bpmnElement="Activity_0120hwd"> + <dc:Bounds x="759" y="283" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1wlkvmw_di" bpmnElement="Activity_1wlkvmw"> + <dc:Bounds x="435" y="283" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1hopv4t_di" bpmnElement="Activity_1hopv4t"> + <dc:Bounds x="600" y="283" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1frrsch_di" bpmnElement="Activity_1frrsch" isExpanded="true"> + <dc:Bounds x="315" y="420" width="665" height="130" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNEdge id="Flow_17s9t7i_di" bpmnElement="Flow_17s9t7i"> + <di:waypoint x="859" y="483" /> + <di:waypoint x="921" y="483" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0ta9hkf_di" bpmnElement="Flow_0ta9hkf"> + <di:waypoint x="373" y="483" /> + <di:waypoint x="435" y="483" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_04bdbeu_di" bpmnElement="Flow_04bdbeu"> + <di:waypoint x="535" y="483" /> + <di:waypoint x="600" y="483" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1uv2624_di" bpmnElement="Flow_1uv2624"> + <di:waypoint x="700" y="483" /> + <di:waypoint x="759" y="483" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="Event_097n1bq_di" bpmnElement="Event_097n1bq"> + <dc:Bounds x="337" y="465" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="344" y="508" width="24" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_1i8yr4f_di" bpmnElement="Event_1i8yr4f"> + <dc:Bounds x="921" y="465" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_06i1xfx_di" bpmnElement="Activity_06i1xfx"> + <dc:Bounds x="759" y="443" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1lz6wg9_di" bpmnElement="Activity_1lz6wg9"> + <dc:Bounds x="435" y="443" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_17o23mj_di" bpmnElement="Activity_17o23mj"> + <dc:Bounds x="600" y="443" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_00mubx8_di" bpmnElement="Activity_00mubx8"> + <dc:Bounds x="660" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1wkdqgz_di" bpmnElement="Activity_1wkdqgz"> + <dc:Bounds x="800" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1mj5zfc_di" bpmnElement="Activity_1mj5zfc"> + <dc:Bounds x="960" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1jts0xn_di" bpmnElement="Activity_1jts0xn"> + <dc:Bounds x="1140" y="200" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_0iz85ln_di" bpmnElement="Event_0iz85ln"> + <dc:Bounds x="1312" y="222" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1ied5nc_di" bpmnElement="Activity_1ied5nc"> + <dc:Bounds x="1140" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Gateway_06foddt_di" bpmnElement="Gateway_06foddt" isMarkerVisible="true"> + <dc:Bounds x="1305" y="72" width="50" height="50" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1300" y="42" width="71" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1n3b4tw_di" bpmnElement="Activity_1n3b4tw"> + <dc:Bounds x="1420" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1twfzif_di" bpmnElement="Activity_1twfzif"> + <dc:Bounds x="1550" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_010av23_di" bpmnElement="Activity_010av23"> + <dc:Bounds x="1680" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0wlcizw_di" bpmnElement="Activity_0wlcizw"> + <dc:Bounds x="500" y="57" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_056xxf3_di" bpmnElement="Event_056xxf3"> + <dc:Bounds x="1022" y="119" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="970" y="159" width="60" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + </bpmndi:BPMNPlane> + </bpmndi:BPMNDiagram> +</bpmn:definitions> diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateDeploymentItem.bpmn b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateDeploymentItem.bpmn new file mode 100644 index 0000000..ede1341 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateDeploymentItem.bpmn @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="UTF-8"?> +<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_0do535p" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.12.0"> + <bpmn:process id="InstantiateDeploymentItem" name="InstantiateDeploymentItem" isExecutable="true"> + <bpmn:startEvent id="StartEvent_1"> + <bpmn:outgoing>Flow_0ghkhbe</bpmn:outgoing> + </bpmn:startEvent> + <bpmn:sequenceFlow id="Flow_0ghkhbe" sourceRef="StartEvent_1" targetRef="Activity_1mxlyu9" /> + <bpmn:serviceTask id="Activity_1mxlyu9" name="Check If Deployment Item exists in DB" camunda:expression="${InstantiateDeploymentItemTask.checkIfDeploymentItemExistsInDb(execution)}"> + <bpmn:incoming>Flow_0ghkhbe</bpmn:incoming> + <bpmn:outgoing>Flow_0pmmai4</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0pmmai4" sourceRef="Activity_1mxlyu9" targetRef="Activity_146igl2" /> + <bpmn:serviceTask id="Activity_0v0l862" name="Update Deployment Item Status to INSTANTIATED" camunda:expression="${InstantiateDeploymentItemTask.updateDeploymentItemStatusToInstantiated(execution)}"> + <bpmn:incoming>Flow_18206u4</bpmn:incoming> + <bpmn:outgoing>Flow_1lom9jz</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0vn456y" sourceRef="Activity_146igl2" targetRef="Activity_109vs6j" /> + <bpmn:serviceTask id="Activity_146igl2" name="Create VF Module in AAI" camunda:expression="${InstantiateDeploymentItemTask.createVfModuleInAai(execution)}"> + <bpmn:incoming>Flow_0pmmai4</bpmn:incoming> + <bpmn:outgoing>Flow_0vn456y</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:serviceTask id="Activity_109vs6j" name="Run Helm install dry run cmd" camunda:expression="${InstantiateDeploymentItemTask.runHelmInstallDryRun(execution)}"> + <bpmn:incoming>Flow_0vn456y</bpmn:incoming> + <bpmn:outgoing>Flow_0q2g71k</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0q2g71k" sourceRef="Activity_109vs6j" targetRef="Activity_059s0fc" /> + <bpmn:serviceTask id="Activity_1fz4blq" name="Instantiate Helm Chart Using install cmd" camunda:expression="${InstantiateDeploymentItemTask.instantiateHelmChart(execution)}"> + <bpmn:incoming>Flow_1ozvp5a</bpmn:incoming> + <bpmn:outgoing>Flow_0drw9oj</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0drw9oj" sourceRef="Activity_1fz4blq" targetRef="Activity_0vf33qo" /> + <bpmn:serviceTask id="Activity_059s0fc" name="Retrieve Kubes Kinds" camunda:expression="${InstantiateDeploymentItemTask.retrieveKubeKinds(execution)}"> + <bpmn:incoming>Flow_0q2g71k</bpmn:incoming> + <bpmn:outgoing>Flow_1ozvp5a</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_1ozvp5a" sourceRef="Activity_059s0fc" targetRef="Activity_1fz4blq" /> + <bpmn:callActivity id="Activity_0vf33qo" name="Monitor Helm Install Status" calledElement="MonitorHelmInstallStatus"> + <bpmn:extensionElements> + <camunda:in source="kind" target="kind" /> + <camunda:in source="jobId" target="jobId" /> + <camunda:in source="asDeploymentItemInstId" target="asDeploymentItemInstId" /> + <camunda:in source="kubeKindsResult" target="kubeKindsResult" /> + <camunda:out source="kubeKindsResult" target="kubeKindsResult" /> + <camunda:in source="releaseName" target="releaseName" /> + <camunda:in source="kubeConfigFilePath" target="kubeConfigFilePath" /> + </bpmn:extensionElements> + <bpmn:incoming>Flow_0drw9oj</bpmn:incoming> + <bpmn:outgoing>Flow_01sku2c</bpmn:outgoing> + <bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:asyncAfter="true" camunda:collection="${kubeKinds}" camunda:elementVariable="kind" /> + </bpmn:callActivity> + <bpmn:sequenceFlow id="Flow_01sku2c" sourceRef="Activity_0vf33qo" targetRef="Activity_1627673" /> + <bpmn:serviceTask id="Activity_1627673" name="Check if Helm install was Successful" camunda:expression="${InstantiateDeploymentItemTask.checkIfHelmInstallWasSuccessful(execution)}"> + <bpmn:incoming>Flow_01sku2c</bpmn:incoming> + <bpmn:outgoing>Flow_0tyfwuy</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:exclusiveGateway id="Gateway_1uu753x"> + <bpmn:incoming>Flow_0tyfwuy</bpmn:incoming> + <bpmn:outgoing>Flow_1diujxx</bpmn:outgoing> + <bpmn:outgoing>Flow_0zeyvx5</bpmn:outgoing> + </bpmn:exclusiveGateway> + <bpmn:sequenceFlow id="Flow_0tyfwuy" sourceRef="Activity_1627673" targetRef="Gateway_1uu753x" /> + <bpmn:sequenceFlow id="Flow_1diujxx" name="Yes" sourceRef="Gateway_1uu753x" targetRef="Activity_0woatnu"> + <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{isSuccessful}</bpmn:conditionExpression> + </bpmn:sequenceFlow> + <bpmn:endEvent id="Event_09xnu7v"> + <bpmn:incoming>Flow_1lom9jz</bpmn:incoming> + </bpmn:endEvent> + <bpmn:sequenceFlow id="Flow_1lom9jz" sourceRef="Activity_0v0l862" targetRef="Event_09xnu7v" /> + <bpmn:serviceTask id="Activity_03vf5tr" name="Log TimeOut" camunda:expression="${InstantiateDeploymentItemTask.logTimeOut(execution)}"> + <bpmn:incoming>Flow_1dhihe0</bpmn:incoming> + <bpmn:outgoing>Flow_0e5lbb0</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:endEvent id="Event_04754lw"> + <bpmn:incoming>Flow_0e5lbb0</bpmn:incoming> + <bpmn:incoming>Flow_0zeyvx5</bpmn:incoming> + <bpmn:errorEventDefinition id="ErrorEventDefinition_0u4gfai" errorRef="Error_04z28em" /> + </bpmn:endEvent> + <bpmn:sequenceFlow id="Flow_1dhihe0" sourceRef="Event_0brrq9d" targetRef="Activity_03vf5tr" /> + <bpmn:sequenceFlow id="Flow_0e5lbb0" sourceRef="Activity_03vf5tr" targetRef="Event_04754lw" /> + <bpmn:boundaryEvent id="Event_0brrq9d" name="Overall Wait" attachedToRef="Activity_0vf33qo"> + <bpmn:outgoing>Flow_1dhihe0</bpmn:outgoing> + <bpmn:timerEventDefinition id="TimerEventDefinition_0fbjp7r"> + <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT1H</bpmn:timeDuration> + </bpmn:timerEventDefinition> + </bpmn:boundaryEvent> + <bpmn:sequenceFlow id="Flow_0zeyvx5" name="No" sourceRef="Gateway_1uu753x" targetRef="Event_04754lw"> + <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{not isSuccessful}</bpmn:conditionExpression> + </bpmn:sequenceFlow> + <bpmn:serviceTask id="Activity_0woatnu" name="Retrieve kubernetes resources" camunda:expression="${InstantiateDeploymentItemTask.retrieveKubernetesResources(execution)}"> + <bpmn:incoming>Flow_1diujxx</bpmn:incoming> + <bpmn:outgoing>Flow_0ozzvzk</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0ozzvzk" sourceRef="Activity_0woatnu" targetRef="Activity_021tzex" /> + <bpmn:serviceTask id="Activity_021tzex" name="Create K8s Resources in AAI" camunda:expression="${InstantiateDeploymentItemTask.createK8sResourcesInAai(execution)}"> + <bpmn:incoming>Flow_0ozzvzk</bpmn:incoming> + <bpmn:outgoing>Flow_18206u4</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_18206u4" sourceRef="Activity_021tzex" targetRef="Activity_0v0l862" /> + <bpmn:textAnnotation id="TextAnnotation_13aqexc"> + <bpmn:text>Create and Connect to VF Module and Generic Vnf</bpmn:text> + </bpmn:textAnnotation> + <bpmn:association id="Association_1x6eub9" sourceRef="Activity_021tzex" targetRef="TextAnnotation_13aqexc" /> + </bpmn:process> + <bpmn:error id="Error_04z28em" name="AsWorkflowProcessingException" errorCode="INSTANTIATE_AS_WORKFLOW_PROCESSING_EXCEPTION" /> + <bpmndi:BPMNDiagram id="BPMNDiagram_1"> + <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="InstantiateDeploymentItem"> + <bpmndi:BPMNEdge id="Flow_18206u4_di" bpmnElement="Flow_18206u4"> + <di:waypoint x="1710" y="200" /> + <di:waypoint x="1770" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0ozzvzk_di" bpmnElement="Flow_0ozzvzk"> + <di:waypoint x="1540" y="200" /> + <di:waypoint x="1610" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0zeyvx5_di" bpmnElement="Flow_0zeyvx5"> + <di:waypoint x="1340" y="225" /> + <di:waypoint x="1340" y="342" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1348" y="281" width="15" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0e5lbb0_di" bpmnElement="Flow_0e5lbb0"> + <di:waypoint x="1260" y="360" /> + <di:waypoint x="1322" y="360" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1dhihe0_di" bpmnElement="Flow_1dhihe0"> + <di:waypoint x="1090" y="258" /> + <di:waypoint x="1090" y="360" /> + <di:waypoint x="1160" y="360" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1lom9jz_di" bpmnElement="Flow_1lom9jz"> + <di:waypoint x="1870" y="200" /> + <di:waypoint x="1942" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1diujxx_di" bpmnElement="Flow_1diujxx"> + <di:waypoint x="1365" y="200" /> + <di:waypoint x="1440" y="200" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1401" y="184" width="18" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0tyfwuy_di" bpmnElement="Flow_0tyfwuy"> + <di:waypoint x="1260" y="200" /> + <di:waypoint x="1315" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_01sku2c_di" bpmnElement="Flow_01sku2c"> + <di:waypoint x="1110" y="200" /> + <di:waypoint x="1160" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1ozvp5a_di" bpmnElement="Flow_1ozvp5a"> + <di:waypoint x="800" y="200" /> + <di:waypoint x="860" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0drw9oj_di" bpmnElement="Flow_0drw9oj"> + <di:waypoint x="960" y="200" /> + <di:waypoint x="1010" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0q2g71k_di" bpmnElement="Flow_0q2g71k"> + <di:waypoint x="650" y="200" /> + <di:waypoint x="700" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0vn456y_di" bpmnElement="Flow_0vn456y"> + <di:waypoint x="480" y="200" /> + <di:waypoint x="550" y="200" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0pmmai4_di" bpmnElement="Flow_0pmmai4"> + <di:waypoint x="330" y="197" /> + <di:waypoint x="380" y="197" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0ghkhbe_di" bpmnElement="Flow_0ghkhbe"> + <di:waypoint x="188" y="197" /> + <di:waypoint x="230" y="197" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"> + <dc:Bounds x="152" y="179" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1mxlyu9_di" bpmnElement="Activity_1mxlyu9"> + <dc:Bounds x="230" y="157" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0v0l862_di" bpmnElement="Activity_0v0l862"> + <dc:Bounds x="1770" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_146igl2_di" bpmnElement="Activity_146igl2"> + <dc:Bounds x="380" y="157" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_109vs6j_di" bpmnElement="Activity_109vs6j"> + <dc:Bounds x="550" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1fz4blq_di" bpmnElement="Activity_1fz4blq"> + <dc:Bounds x="860" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_059s0fc_di" bpmnElement="Activity_059s0fc"> + <dc:Bounds x="700" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0vf33qo_di" bpmnElement="Activity_0vf33qo"> + <dc:Bounds x="1010" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1x946to_di" bpmnElement="Activity_1627673"> + <dc:Bounds x="1160" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Gateway_1uu753x_di" bpmnElement="Gateway_1uu753x" isMarkerVisible="true"> + <dc:Bounds x="1315" y="175" width="50" height="50" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_09xnu7v_di" bpmnElement="Event_09xnu7v"> + <dc:Bounds x="1942" y="182" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_03vf5tr_di" bpmnElement="Activity_03vf5tr"> + <dc:Bounds x="1160" y="320" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_04754lw_di" bpmnElement="Event_04754lw"> + <dc:Bounds x="1322" y="342" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0woatnu_di" bpmnElement="Activity_0woatnu"> + <dc:Bounds x="1440" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_021tzex_di" bpmnElement="Activity_021tzex"> + <dc:Bounds x="1610" y="160" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="TextAnnotation_13aqexc_di" bpmnElement="TextAnnotation_13aqexc"> + <dc:Bounds x="1710" y="80" width="247" height="40" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_08y244c_di" bpmnElement="Event_0brrq9d"> + <dc:Bounds x="1072" y="222" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1020" y="262" width="60" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNEdge id="Association_1x6eub9_di" bpmnElement="Association_1x6eub9"> + <di:waypoint x="1698" y="160" /> + <di:waypoint x="1736" y="120" /> + </bpmndi:BPMNEdge> + </bpmndi:BPMNPlane> + </bpmndi:BPMNDiagram> +</bpmn:definitions> diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/MonitorHelmInstallStatus.bpmn b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/MonitorHelmInstallStatus.bpmn new file mode 100644 index 0000000..92b8ee2 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/MonitorHelmInstallStatus.bpmn @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8"?> +<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_07q5pn8" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.0.0"> + <bpmn:process id="MonitorHelmInstallStatus" name="MonitorHelmInstallStatus" isExecutable="true"> + <bpmn:endEvent id="Event_0v9a531"> + <bpmn:incoming>Flow_1f87oz7</bpmn:incoming> + </bpmn:endEvent> + <bpmn:subProcess id="Activity_1exvnm9" name="${kind}"> + <bpmn:incoming>Flow_0f5dibe</bpmn:incoming> + <bpmn:outgoing>Flow_1kpnioc</bpmn:outgoing> + <bpmn:startEvent id="Event_1m6vi78"> + <bpmn:outgoing>Flow_1kekeh7</bpmn:outgoing> + </bpmn:startEvent> + <bpmn:exclusiveGateway id="Gateway_0neju2q" default="Flow_1g3xchu"> + <bpmn:incoming>Flow_0kdhub4</bpmn:incoming> + <bpmn:outgoing>Flow_0n6qu57</bpmn:outgoing> + <bpmn:outgoing>Flow_1g3xchu</bpmn:outgoing> + </bpmn:exclusiveGateway> + <bpmn:intermediateCatchEvent id="Event_0lx9pd7" name="Wait between checks" camunda:asyncAfter="true"> + <bpmn:incoming>Flow_1g3xchu</bpmn:incoming> + <bpmn:outgoing>Flow_0tqwb9b</bpmn:outgoing> + <bpmn:timerEventDefinition id="TimerEventDefinition_1icke43"> + <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT15S</bpmn:timeDuration> + </bpmn:timerEventDefinition> + </bpmn:intermediateCatchEvent> + <bpmn:endEvent id="Event_1pka4w4"> + <bpmn:incoming>Flow_0n6qu57</bpmn:incoming> + </bpmn:endEvent> + <bpmn:serviceTask id="Activity_0rxj50o" name=" Is Resource Ready " camunda:asyncAfter="true" camunda:expression="${MonitorHelmInstallStatusTask.isResourceReady(execution)}"> + <bpmn:incoming>Flow_0tqwb9b</bpmn:incoming> + <bpmn:incoming>Flow_11mzqci</bpmn:incoming> + <bpmn:outgoing>Flow_0kdhub4</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_0kdhub4" sourceRef="Activity_0rxj50o" targetRef="Gateway_0neju2q" /> + <bpmn:sequenceFlow id="Flow_0n6qu57" sourceRef="Gateway_0neju2q" targetRef="Event_1pka4w4"> + <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{isResourceReady}</bpmn:conditionExpression> + </bpmn:sequenceFlow> + <bpmn:sequenceFlow id="Flow_1g3xchu" sourceRef="Gateway_0neju2q" targetRef="Event_0lx9pd7" /> + <bpmn:sequenceFlow id="Flow_0tqwb9b" sourceRef="Event_0lx9pd7" targetRef="Activity_0rxj50o" /> + <bpmn:sequenceFlow id="Flow_1kekeh7" sourceRef="Event_1m6vi78" targetRef="Activity_1cc0pq6" /> + <bpmn:serviceTask id="Activity_1cc0pq6" name="Update Job Status" camunda:expression="${MonitorHelmInstallStatusTask.updateJobStatus(execution)}"> + <bpmn:incoming>Flow_1kekeh7</bpmn:incoming> + <bpmn:outgoing>Flow_11mzqci</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:sequenceFlow id="Flow_11mzqci" sourceRef="Activity_1cc0pq6" targetRef="Activity_0rxj50o" /> + </bpmn:subProcess> + <bpmn:endEvent id="Event_119znxi" name="Timeout Exception"> + <bpmn:incoming>Flow_0qm63h0</bpmn:incoming> + <bpmn:terminateEventDefinition id="TerminateEventDefinition_14qywzg" /> + </bpmn:endEvent> + <bpmn:serviceTask id="Activity_09s0jak" name=" Time Out Log Failure " camunda:asyncAfter="true" camunda:expression="${MonitorHelmInstallStatusTask.timeOutLogFailue(execution)}"> + <bpmn:incoming>Flow_1719q6v</bpmn:incoming> + <bpmn:outgoing>Flow_0qm63h0</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:serviceTask id="Activity_0a4jpkd" name=" Check if operation was successful " camunda:asyncAfter="true" camunda:expression="${MonitorHelmInstallStatusTask.checkIfOperationWasSuccessful(execution)}"> + <bpmn:incoming>Flow_1kpnioc</bpmn:incoming> + <bpmn:outgoing>Flow_1f87oz7</bpmn:outgoing> + </bpmn:serviceTask> + <bpmn:boundaryEvent id="Event_0cfcuv3" name="Overall Wait" attachedToRef="Activity_1exvnm9"> + <bpmn:outgoing>Flow_1719q6v</bpmn:outgoing> + <bpmn:timerEventDefinition id="TimerEventDefinition_1258pyb"> + <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT20M</bpmn:timeDuration> + </bpmn:timerEventDefinition> + </bpmn:boundaryEvent> + <bpmn:sequenceFlow id="Flow_1f87oz7" sourceRef="Activity_0a4jpkd" targetRef="Event_0v9a531" /> + <bpmn:sequenceFlow id="Flow_1kpnioc" sourceRef="Activity_1exvnm9" targetRef="Activity_0a4jpkd" /> + <bpmn:sequenceFlow id="Flow_0qm63h0" sourceRef="Activity_09s0jak" targetRef="Event_119znxi" /> + <bpmn:sequenceFlow id="Flow_1719q6v" sourceRef="Event_0cfcuv3" targetRef="Activity_09s0jak" /> + <bpmn:startEvent id="Event_1kp76of"> + <bpmn:outgoing>Flow_0f5dibe</bpmn:outgoing> + </bpmn:startEvent> + <bpmn:sequenceFlow id="Flow_0f5dibe" sourceRef="Event_1kp76of" targetRef="Activity_1exvnm9" /> + </bpmn:process> + <bpmndi:BPMNDiagram id="BPMNDiagram_1"> + <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="MonitorHelmInstallStatus"> + <bpmndi:BPMNEdge id="Flow_0f5dibe_di" bpmnElement="Flow_0f5dibe"> + <di:waypoint x="188" y="350" /> + <di:waypoint x="270" y="350" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1719q6v_di" bpmnElement="Flow_1719q6v"> + <di:waypoint x="963" y="342" /> + <di:waypoint x="1044" y="342" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0qm63h0_di" bpmnElement="Flow_0qm63h0"> + <di:waypoint x="1144" y="342" /> + <di:waypoint x="1223" y="342" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1kpnioc_di" bpmnElement="Flow_1kpnioc"> + <di:waypoint x="684" y="240" /> + <di:waypoint x="684" y="120" /> + <di:waypoint x="1044" y="120" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1f87oz7_di" bpmnElement="Flow_1f87oz7"> + <di:waypoint x="1144" y="120" /> + <di:waypoint x="1223" y="120" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="Event_0v9a531_di" bpmnElement="Event_0v9a531"> + <dc:Bounds x="1223" y="102" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_1exvnm9_di" bpmnElement="Activity_1exvnm9" isExpanded="true"> + <dc:Bounds x="270" y="240" width="675" height="220" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNEdge id="Flow_11mzqci_di" bpmnElement="Flow_11mzqci"> + <di:waypoint x="490" y="326" /> + <di:waypoint x="546" y="326" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1kekeh7_di" bpmnElement="Flow_1kekeh7"> + <di:waypoint x="338" y="326" /> + <di:waypoint x="390" y="326" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0tqwb9b_di" bpmnElement="Flow_0tqwb9b"> + <di:waypoint x="671" y="398" /> + <di:waypoint x="607" y="398" /> + <di:waypoint x="607" y="369" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_1g3xchu_di" bpmnElement="Flow_1g3xchu"> + <di:waypoint x="755" y="351" /> + <di:waypoint x="755" y="398" /> + <di:waypoint x="707" y="398" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0n6qu57_di" bpmnElement="Flow_0n6qu57"> + <di:waypoint x="780" y="326" /> + <di:waypoint x="843" y="326" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_0kdhub4_di" bpmnElement="Flow_0kdhub4"> + <di:waypoint x="646" y="326" /> + <di:waypoint x="730" y="326" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNShape id="Event_1m6vi78_di" bpmnElement="Event_1m6vi78"> + <dc:Bounds x="302" y="308" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Gateway_0neju2q_di" bpmnElement="Gateway_0neju2q" isMarkerVisible="true"> + <dc:Bounds x="730" y="301" width="50" height="50" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_0lx9pd7_di" bpmnElement="Event_0lx9pd7"> + <dc:Bounds x="671" y="380" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="658" y="423" width="67" height="27" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_1pka4w4_di" bpmnElement="Event_1pka4w4"> + <dc:Bounds x="843" y="308" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0rxj50o_di" bpmnElement="Activity_0rxj50o"> + <dc:Bounds x="546" y="286" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_153w092_di" bpmnElement="Activity_1cc0pq6"> + <dc:Bounds x="390" y="286" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_119znxi_di" bpmnElement="Event_119znxi"> + <dc:Bounds x="1223" y="324" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="1216" y="284" width="49" height="27" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_09s0jak_di" bpmnElement="Activity_09s0jak"> + <dc:Bounds x="1044" y="302" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Activity_0a4jpkd_di" bpmnElement="Activity_0a4jpkd"> + <dc:Bounds x="1044" y="80" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_1kp76of_di" bpmnElement="Event_1kp76of"> + <dc:Bounds x="152" y="332" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="Event_0cfcuv3_di" bpmnElement="Event_0cfcuv3"> + <dc:Bounds x="927" y="324" width="36" height="36" /> + <bpmndi:BPMNLabel> + <dc:Bounds x="916" y="363" width="60" height="14" /> + </bpmndi:BPMNLabel> + </bpmndi:BPMNShape> + </bpmndi:BPMNPlane> + </bpmndi:BPMNDiagram> +</bpmn:definitions> diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java index 9920ab9..2bf2f30 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java @@ -22,8 +22,6 @@ package org.onap.so.cnfm.lcm.bpmn.flows; import static org.camunda.bpm.engine.history.HistoricProcessInstance.STATE_ACTIVE; import static org.slf4j.LoggerFactory.getLogger; - -import com.github.tomakehurst.wiremock.WireMockServer; import java.io.IOException; import java.nio.file.Path; import java.time.LocalDateTime; @@ -38,9 +36,9 @@ import org.camunda.bpm.engine.history.HistoricProcessInstance; import org.camunda.bpm.engine.history.HistoricVariableInstance; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.junit.runner.RunWith; -//import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider; -//import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedHelmClientConfiguration; -//import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedKubernetesClientProviderConfiguration; +import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedHelmClientConfiguration; +import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedKubernetesClientProviderConfiguration; import org.onap.so.cnfm.lcm.database.beans.AsInst; import org.onap.so.cnfm.lcm.database.beans.Job; import org.onap.so.cnfm.lcm.database.beans.JobAction; @@ -50,12 +48,13 @@ import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; -//import org.springframework.context.annotation.Import; -//import org.springframework.mock.web.MockMultipartFile; +import org.springframework.context.annotation.Import; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.FileSystemUtils; +import com.github.tomakehurst.wiremock.WireMockServer; /** * @author Waqas Ikram (waqas.ikram@est.tech) @@ -66,12 +65,12 @@ import org.springframework.util.FileSystemUtils; @ActiveProfiles("test") @ContextConfiguration @AutoConfigureWireMock(port = 0) -//@Import({MockedHelmClientConfiguration.class, MockedKubernetesClientProviderConfiguration.class}) +@Import({MockedHelmClientConfiguration.class, MockedKubernetesClientProviderConfiguration.class}) public abstract class BaseTest { protected static final String SERVICE_INSTANCE_ID = UUID.randomUUID().toString(); protected static final String SERVICE_INSTANCE_NAME = "ServiceName"; -// private static final String KUBE_CONFIG_EMPTY_FILE_NAME = "kube-config-empty-file"; -// private static final String EMPTY = ""; + private static final String KUBE_CONFIG_EMPTY_FILE_NAME = "kube-config-empty-file"; + private static final String EMPTY = ""; protected static final String UUID_REGEX = "[0-9a-zA-Z]{8}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{12}"; @@ -87,8 +86,8 @@ public abstract class BaseTest { @Autowired private RuntimeService runtimeService; -// @Autowired -// private KubConfigProvider kubConfigProvider; + @Autowired + private KubConfigProvider kubConfigProvider; @Autowired protected DatabaseServiceProvider databaseServiceProvider; @@ -169,9 +168,9 @@ public abstract class BaseTest { } public void createKubeConfigFile(final AsInst asInst) throws IOException { -// final MockMultipartFile file = new MockMultipartFile(KUBE_CONFIG_EMPTY_FILE_NAME, EMPTY.getBytes()); -// kubConfigProvider.addKubeConfigFile(file, asInst.getCloudOwner(), asInst.getCloudRegion(), -// asInst.getTenantId()); + final MockMultipartFile file = new MockMultipartFile(KUBE_CONFIG_EMPTY_FILE_NAME, EMPTY.getBytes()); + kubConfigProvider.addKubeConfigFile(file, asInst.getCloudOwner(), asInst.getCloudRegion(), + asInst.getTenantId()); } public void deleteFoldersAndFiles(final Path path) throws IOException { diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java index 7de9bdc..8374faa 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java @@ -21,7 +21,6 @@ package org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.APPLICATION_NAME_PARAM_NAME; import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_ID_PARAM_NAME; import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_INVARIANT_ID_PARAM_NAME; @@ -61,9 +60,9 @@ public class SdcCsarPackageParserTest { final List<DeploymentItem> items = (List<DeploymentItem>) properties.get(SdcCsarPropertiesConstants.DEPLOYMENT_ITEMS_PARAM_NAME); assertNotNull(items); - assertTrue(items.size() == 2); + assertEquals(2, items.size()); - DeploymentItem deploymentItem = items.get(0); + final DeploymentItem deploymentItem = items.get(0); assertEquals("sampleapp-db", deploymentItem.getName()); assertEquals("1", deploymentItem.getItemId()); assertEquals("1", deploymentItem.getDeploymentOrder()); diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTaskTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTaskTest.java new file mode 100644 index 0000000..1c41894 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/InstantiateAsTaskTest.java @@ -0,0 +1,527 @@ +/*- + * ============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.tasks; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.notFound; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.onap.aaiclient.client.aai.AAIVersion.V19; +import static org.springframework.http.HttpHeaders.ACCEPT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import org.camunda.bpm.engine.history.HistoricProcessInstance; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onap.so.cnfm.lcm.bpmn.flows.BaseTest; +import org.onap.so.cnfm.lcm.bpmn.flows.GsonProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.AsRequestProcessingException; +import org.onap.so.cnfm.lcm.bpmn.flows.service.JobExecutorService; +import org.onap.so.cnfm.lcm.database.beans.AsDeploymentItem; +import org.onap.so.cnfm.lcm.database.beans.AsInst; +import org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc; +import org.onap.so.cnfm.lcm.database.beans.AsLifecycleParam; +import org.onap.so.cnfm.lcm.database.beans.Job; +import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum; +import org.onap.so.cnfm.lcm.database.beans.OperationStateEnum; +import org.onap.so.cnfm.lcm.database.beans.State; +import org.onap.so.cnfm.lcm.model.AsInfoModificationRequestDeploymentItems; +import org.onap.so.cnfm.lcm.model.InstantiateAsRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.Gson; +import io.kubernetes.client.custom.IntOrString; +import io.kubernetes.client.openapi.models.V1DaemonSet; +import io.kubernetes.client.openapi.models.V1DaemonSetList; +import io.kubernetes.client.openapi.models.V1DaemonSetSpec; +import io.kubernetes.client.openapi.models.V1DaemonSetStatus; +import io.kubernetes.client.openapi.models.V1DaemonSetUpdateStrategy; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1DeploymentList; +import io.kubernetes.client.openapi.models.V1DeploymentSpec; +import io.kubernetes.client.openapi.models.V1DeploymentStatus; +import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1JobCondition; +import io.kubernetes.client.openapi.models.V1JobList; +import io.kubernetes.client.openapi.models.V1JobStatus; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1Pod; +import io.kubernetes.client.openapi.models.V1PodCondition; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.openapi.models.V1PodStatus; +import io.kubernetes.client.openapi.models.V1ReplicaSet; +import io.kubernetes.client.openapi.models.V1ReplicaSetList; +import io.kubernetes.client.openapi.models.V1ReplicaSetSpec; +import io.kubernetes.client.openapi.models.V1ReplicaSetStatus; +import io.kubernetes.client.openapi.models.V1RollingUpdateDaemonSet; +import io.kubernetes.client.openapi.models.V1RollingUpdateStatefulSetStrategy; +import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServiceList; +import io.kubernetes.client.openapi.models.V1StatefulSet; +import io.kubernetes.client.openapi.models.V1StatefulSetList; +import io.kubernetes.client.openapi.models.V1StatefulSetSpec; +import io.kubernetes.client.openapi.models.V1StatefulSetStatus; +import io.kubernetes.client.openapi.models.V1StatefulSetUpdateStrategy; +import io.kubernetes.client.util.Watch; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +public class InstantiateAsTaskTest extends BaseTest { + private static final String DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_1 = ".Values.primary.service.ports.mysql"; + private static final String DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_2 = ".Values.primary.service.nodePorts.mysql"; + + private static final String DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_1 = ".Values.service.ports.http"; + private static final String DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_2 = ".Values.service.ports.https"; + private static final String DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_3 = ".Values.service.nodePorts"; + + private static final String DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE = "dummy"; + private static final String RANDOM_UUID = UUID.randomUUID().toString(); + private static final String SERVICE_INSTANCE_ID = UUID.randomUUID().toString(); + private static final String AS_INST_ID = SERVICE_INSTANCE_ID; + + private static final String SERVICE_INSTANCE_ID2 = UUID.randomUUID().toString(); + private static final String AS_INST_ID2 = SERVICE_INSTANCE_ID2; + private static final String ASD_NAME = "InstantiateCnfService"; + private static final String AS_INST_NAME = ASD_NAME + "-" + System.currentTimeMillis(); + private static final String ASD_ID = AS_INST_ID; + private static final String SRC_TEST_DIR = "src/test/resources"; + + private static final String SDC_GET_RESOURCE_URL = "/sdc/v1/catalog/resources/" + ASD_ID + "/toscaModel"; + private static final String RESOURCE_ASD_PACKAGE_CSAR_PATH = + SRC_TEST_DIR + "/resource-Generatedasdpackage-csar.csar"; + + private static final String AS_DEPLOYMENT_ITEM_1_INST_ID = UUID.randomUUID().toString(); + private static final String AS_DEPLOYMENT_ITEM_2_INST_ID = UUID.randomUUID().toString(); + private static final String AS_DEPLOYMENT_ITEM_1_INST_ID2 = UUID.randomUUID().toString(); + private static final String AS_DEPLOYMENT_ITEM_2_INST_ID2 = UUID.randomUUID().toString(); + + @Value("${cnfm.csar.dir}") + private String dir; + + @Value("${cnfm.kube-configs-dir}") + private String kubeConfigsDir; + + @Autowired + private JobExecutorService objUnderTest; + + @Autowired + private MockedHelmClient mockedHelmClient; + + @Autowired + private MockedKubernetesClientProvider kubernetesClientProvider; + + @Autowired + private GsonProvider gsonProvider; + private Gson gson; + + @Before + public void before() { + wireMockServer.resetAll(); + try { + deleteFoldersAndFiles(Paths.get(kubeConfigsDir)); + Files.createDirectory(Paths.get(kubeConfigsDir)); + } catch (final IOException ioException) { + throw new RuntimeException( + "Failed to create/Delete Directory in InstantiateAsTaskTest due to: " + ioException.getMessage()); + } + kubernetesClientProvider.setWireMockServer(wireMockServer); + + gson = gsonProvider.getGson(); + } + + @After + public void after() { + wireMockServer.resetAll(); + final Path path = Paths.get(dir, AS_INST_ID); + try { + deleteFoldersAndFiles(path); + deleteFoldersAndFiles(Paths.get(kubeConfigsDir)); + } catch (final IOException ioException) { + logger.debug("Exception occurred while deleting folder and files: {}", ioException.getMessage()); + } + } + + @Test + public void testInstantiateAsWorkflow_JustUpdateStatus_SuccessfullCase() throws InterruptedException, IOException { + + mockKubernetesClientEndpoint(); + + mockAAIEndpoints(); + + wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL) + .willReturn(aResponse().withBody(getFileContent(getAbsolutePath(RESOURCE_ASD_PACKAGE_CSAR_PATH))) + .withHeader(ACCEPT, APPLICATION_OCTET_STREAM_VALUE))); + + final AsInst asInst = createAsInst(AS_INST_ID, AS_DEPLOYMENT_ITEM_1_INST_ID, AS_DEPLOYMENT_ITEM_2_INST_ID); + + databaseServiceProvider.saveAsInst(asInst); + + createKubeConfigFile(asInst); + + final String asLcmOpOccId = objUnderTest.runInstantiateAsJob(asInst.getAsInstId(), getInstantiateAsRequest()); + + final Optional<Job> optional = getJobByResourceId(asInst.getAsInstId()); + assertTrue(optional.isPresent()); + final Job job = optional.get(); + + + assertTrue(waitForProcessInstanceToFinish(job.getProcessInstanceId())); + + final HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance(job.getProcessInstanceId()); + assertNotNull(historicProcessInstance); + assertEquals(HistoricProcessInstance.STATE_COMPLETED, historicProcessInstance.getState()); + + final Optional<AsInst> asInstOptional = databaseServiceProvider.getAsInst(asInst.getAsInstId()); + final AsInst actualAsInst = asInstOptional.get(); + assertEquals(State.INSTANTIATED, actualAsInst.getStatus()); + + final Optional<AsLcmOpOcc> asLcmOpOccOptional = databaseServiceProvider.getAsLcmOpOcc(asLcmOpOccId); + assertTrue(asLcmOpOccOptional.isPresent()); + assertEquals(OperationStateEnum.COMPLETED, asLcmOpOccOptional.get().getOperationState()); + + final List<AsDeploymentItem> actualAsDeploymentItems = + databaseServiceProvider.getAsDeploymentItemByAsInstId(actualAsInst.getAsInstId()); + assertEquals(2, actualAsDeploymentItems.size()); + + actualAsDeploymentItems.forEach(asDeploymentItem -> { + assertEquals(State.INSTANTIATED, asDeploymentItem.getStatus()); + }); + + final Map<String, Integer> counter = mockedHelmClient.getCounter(); + assertEquals(2, counter.size()); + assertEquals(Integer.valueOf(3), counter.get(asInst.getAsdeploymentItems().get(0).getReleaseName())); + assertEquals(Integer.valueOf(3), counter.get(asInst.getAsdeploymentItems().get(1).getReleaseName())); + + + } + + @Test(expected = AsRequestProcessingException.class) + public void testInstantiateAsWorkflow_LifecycleParametersMissing_Fail() throws InterruptedException, IOException { + + wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL) + .willReturn(aResponse().withBody(getFileContent(getAbsolutePath(RESOURCE_ASD_PACKAGE_CSAR_PATH))) + .withHeader(ACCEPT, APPLICATION_OCTET_STREAM_VALUE))); + + final AsLifecycleParam lcp3 = new AsLifecycleParam().asLifecycleParam(".Values.extra.missing"); + final AsInst asInst1 = createAsInst(AS_INST_ID2, AS_DEPLOYMENT_ITEM_1_INST_ID2, AS_DEPLOYMENT_ITEM_2_INST_ID2); + asInst1.getAsdeploymentItems().get(0).asLifecycleParams(lcp3); + + databaseServiceProvider.saveAsInst(asInst1); + + createKubeConfigFile(asInst1); + + objUnderTest.runInstantiateAsJob(asInst1.getAsInstId(), getInstantiateAsRequest()); + + } + + @Test + public void testInstantiateAsWorkflow_UpdateAsInstState_ExceptionCase() { + + final AsInst asInst = new AsInst().asInstId(UUID.randomUUID().toString()).name(AS_INST_NAME).asdId(ASD_ID) + .asdInvariantId(AS_INST_ID).status(State.NOT_INSTANTIATED).statusUpdatedTime(LocalDateTime.now()) + .asApplicationName("asApplicationName").asApplicationVersion("asApplicationVersion") + .asProvider("asProvider").serviceInstanceId(SERVICE_INSTANCE_ID) + .serviceInstanceName("serviceInstanceName").cloudOwner("cloudOwner").cloudRegion("cloudRegion") + .tenantId("tenantId"); + + databaseServiceProvider.saveAsInst(asInst); + + assertThrows(AsRequestProcessingException.class, + () -> objUnderTest.runInstantiateAsJob(asInst.getAsInstId(), getInstantiateAsRequest())); + + final Optional<Job> optional = getJobByResourceId(asInst.getAsInstId()); + final Job job = optional.get(); + + final Optional<AsInst> asInstOptional = databaseServiceProvider.getAsInst(asInst.getAsInstId()); + + assertEquals(JobStatusEnum.ERROR, job.getStatus()); + assertEquals(State.FAILED, asInstOptional.get().getStatus()); + } + + + private void mockKubernetesClientEndpoint() { + wireMockServer.stubFor(get(urlMatching("/apis/batch/v1/jobs\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getJobResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/apis/batch/v1/jobs\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getJobList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/api/v1/pods\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getPodResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/api/v1/pods\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getPodList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/api/v1/services\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getServiceResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/api/v1/services\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getServiceList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/deployments\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getDeploymentResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/deployments\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getDeploymentList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/replicasets\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getReplicaSetResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/replicasets\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getReplicaSetList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/daemonsets\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getDaemonSetResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/daemonsets\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getDaemonSetList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/statefulsets\\?labelSelector.*&watch=true")) + .willReturn(aResponse().withBody(getStatefulSetResponse()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + wireMockServer.stubFor(get(urlMatching("/apis/apps/v1/statefulsets\\?labelSelector.*&watch=false")) + .willReturn(aResponse().withBody(getStatefulSetList()).withHeader(ACCEPT, APPLICATION_JSON_VALUE))); + } + + private String getStatefulSetResponse() { + return gson.toJson(new Watch.Response<V1StatefulSet>("ADDED", getStatefulSet())); + } + + private String getStatefulSetList() { + final V1StatefulSetList v1StatefulSetList = new V1StatefulSetList(); + v1StatefulSetList.addItemsItem(getStatefulSet()); + return gson.toJson(v1StatefulSetList); + } + + private V1StatefulSet getStatefulSet() { + return new V1StatefulSet() + .apiVersion( + "apps/v1") + .metadata(getV1ObjectMeta()) + .spec(new V1StatefulSetSpec() + .updateStrategy(new V1StatefulSetUpdateStrategy().type("RollingUpdate") + .rollingUpdate(new V1RollingUpdateStatefulSetStrategy().partition(Integer.valueOf(0)))) + .replicas(Integer.valueOf(2))) + .status(new V1StatefulSetStatus().updatedReplicas(Integer.valueOf(2)) + .readyReplicas(Integer.valueOf(2))); + } + + private String getDaemonSetResponse() { + return gson.toJson(new Watch.Response<V1DaemonSet>("ADDED", getDaemonSet())); + } + + private String getDaemonSetList() { + final V1DaemonSetList v1DaemonSetList = new V1DaemonSetList(); + v1DaemonSetList.addItemsItem(getDaemonSet()); + return gson.toJson(v1DaemonSetList); + } + + private V1DaemonSet getDaemonSet() { + return new V1DaemonSet().apiVersion("apps/v1").metadata(getV1ObjectMeta()) + .spec(new V1DaemonSetSpec().updateStrategy(new V1DaemonSetUpdateStrategy().type("RollingUpdate") + .rollingUpdate(new V1RollingUpdateDaemonSet().maxUnavailable(new IntOrString("50%"))))) + .status(new V1DaemonSetStatus().desiredNumberScheduled(Integer.valueOf(2)) + .numberReady(Integer.valueOf(2)).updatedNumberScheduled(Integer.valueOf(2))); + } + + private String getReplicaSetResponse() { + return gson.toJson(new Watch.Response<V1ReplicaSet>("ADDED", getReplicaSet())); + } + + private String getReplicaSetList() { + final V1ReplicaSetList v1ReplicaSetList = new V1ReplicaSetList(); + v1ReplicaSetList.addItemsItem(getReplicaSet()); + return gson.toJson(v1ReplicaSetList); + } + + private V1ReplicaSet getReplicaSet() { + return new V1ReplicaSet().apiVersion("apps/v1").metadata(getV1ObjectMeta()) + .status(new V1ReplicaSetStatus().readyReplicas(Integer.valueOf(1))) + .spec(new V1ReplicaSetSpec().replicas(Integer.valueOf(1))); + } + + private V1ObjectMeta getV1ObjectMeta() { + return new V1ObjectMeta().name("job-name").namespace("job-namespace").uid(RANDOM_UUID) + .resourceVersion(RANDOM_UUID).labels(Map.of("label-key", "label-value")); + } + + private String getDeploymentResponse() { + return gson.toJson(new Watch.Response<V1Deployment>("ADDED", getDeployment())); + } + + private String getDeploymentList() { + final V1DeploymentList v1DeploymentList = new V1DeploymentList(); + v1DeploymentList.addItemsItem(getDeployment()); + return gson.toJson(v1DeploymentList); + } + + private V1Deployment getDeployment() { + return new V1Deployment().apiVersion("apps/v1").metadata(getV1ObjectMeta()) + .status(new V1DeploymentStatus().replicas(Integer.valueOf(1)).availableReplicas(Integer.valueOf(1))) + .spec(new V1DeploymentSpec().replicas(Integer.valueOf(1))); + } + + private String getServiceResponse() { + return gson.toJson(new Watch.Response<V1Service>("ADDED", getService())); + + } + + private String getServiceList() { + final V1ServiceList v1ServiceList = new V1ServiceList(); + v1ServiceList.addItemsItem(getService()); + return gson.toJson(v1ServiceList); + } + + private V1Service getService() { + return new V1Service().apiVersion("v1").metadata(getV1ObjectMeta()); + } + + private String getPodList() { + final V1PodList v1Podlist = new V1PodList(); + v1Podlist.addItemsItem(getPod()); + return gson.toJson(v1Podlist); + } + + private String getPodResponse() { + return gson.toJson(new Watch.Response<V1Pod>("ADDED", getPod())); + } + + private V1Pod getPod() { + return new V1Pod().apiVersion("v1").metadata(getV1ObjectMeta()).status(new V1PodStatus() + .addConditionsItem(new V1PodCondition().type("Ready").status(Boolean.TRUE.toString()))); + } + + private String getJobResponse() { + return gson.toJson(new Watch.Response<V1Job>("ADDED", getJob())); + } + + private String getJobList() { + final V1JobList v1JobList = new V1JobList(); + v1JobList.addItemsItem(getJob()); + return gson.toJson(v1JobList); + } + + private V1Job getJob() { + return new V1Job().apiVersion("batch/v1").metadata(getV1ObjectMeta()).status(new V1JobStatus() + .addConditionsItem(new V1JobCondition().type("Complete").status(Boolean.TRUE.toString()))); + } + + private void mockAAIEndpoints() throws JsonProcessingException { + final String vfModule1EndPoint = "/aai/" + V19 + "/network/generic-vnfs/generic-vnf/" + AS_INST_ID + + "/vf-modules/vf-module/" + AS_DEPLOYMENT_ITEM_1_INST_ID; + + wireMockServer.stubFor(get(urlMatching(vfModule1EndPoint + "\\?resultIndex=0&resultSize=1&format=count")) + .willReturn(notFound())); + + final String vfModule2EndPoint = "/aai/" + V19 + "/network/generic-vnfs/generic-vnf/" + AS_INST_ID + + "/vf-modules/vf-module/" + AS_DEPLOYMENT_ITEM_2_INST_ID; + + wireMockServer.stubFor(get(urlMatching(vfModule2EndPoint + "\\?resultIndex=0&resultSize=1&format=count")) + .willReturn(notFound())); + + wireMockServer.stubFor(put(urlMatching(vfModule1EndPoint)).willReturn(ok())); + wireMockServer.stubFor(put(urlMatching(vfModule2EndPoint)).willReturn(ok())); + + final String k8sResourcesEndpoint = "/aai/" + V19 + + "/cloud-infrastructure/cloud-regions/cloud-region/cloudOwner/cloudRegion/tenants/tenant/tenantId/" + + "k8s-resources/.*"; + wireMockServer.stubFor(get(urlMatching(k8sResourcesEndpoint)).willReturn(notFound())); + wireMockServer.stubFor(put(urlMatching(k8sResourcesEndpoint)).willReturn(ok())); + wireMockServer + .stubFor(put(urlMatching(k8sResourcesEndpoint + "/relationship-list/relationship")).willReturn(ok())); + + + } + + private AsInst createAsInst(final String as_inst_id, final String as_deployment_item_1_id, + final String as_deployment_item_2_id) { + final AsInst asInst = new AsInst().asInstId(as_inst_id).name(AS_INST_NAME).asdId(ASD_ID) + .asdInvariantId(as_inst_id).status(State.NOT_INSTANTIATED).statusUpdatedTime(LocalDateTime.now()) + .asApplicationName("asApplicationName").asApplicationVersion("asApplicationVersion") + .asProvider("asProvider").serviceInstanceId(as_inst_id).serviceInstanceName("serviceInstanceName") + .cloudOwner("cloudOwner").cloudRegion("cloudRegion").tenantId("tenantId"); + + final String helmFile1 = "Artifacts/Deployment/HELM/sampleapp-db-operator-helm.tgz"; + final AsLifecycleParam lcp1 = new AsLifecycleParam().asLifecycleParam(DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_1); + final AsLifecycleParam lcp2 = new AsLifecycleParam().asLifecycleParam(DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_2); + + final AsDeploymentItem item1 = new AsDeploymentItem().asDeploymentItemInstId(as_deployment_item_1_id) + .asInst(asInst).status(State.NOT_INSTANTIATED).name("sampleapp-db").itemId("1").deploymentOrder(1) + .artifactFilePath(helmFile1).createTime(LocalDateTime.now()).lastUpdateTime(LocalDateTime.now()) + .releaseName("testOne").asLifecycleParams(lcp1).asLifecycleParams(lcp2); + + final String helmFile2 = "Artifacts/Deployment/HELM/sampleapp-services-helm.tgz"; + final AsLifecycleParam lcpitem2_1 = + new AsLifecycleParam().asLifecycleParam(DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_1); + final AsLifecycleParam lcpitem2_2 = + new AsLifecycleParam().asLifecycleParam(DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_2); + final AsLifecycleParam lcpitem2_3 = + new AsLifecycleParam().asLifecycleParam(DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_3); + + final AsDeploymentItem item2 = new AsDeploymentItem().asDeploymentItemInstId(as_deployment_item_2_id) + .asInst(asInst).status(State.NOT_INSTANTIATED).name("sampleapp-services").itemId("2").deploymentOrder(2) + .artifactFilePath(helmFile2).createTime(LocalDateTime.now()).lastUpdateTime(LocalDateTime.now()) + .releaseName("testTwo").asLifecycleParams(lcpitem2_1).asLifecycleParams(lcpitem2_2) + .asLifecycleParams(lcpitem2_3); + + asInst.asdeploymentItems(item1); + asInst.asdeploymentItems(item2); + return asInst; + } + + private InstantiateAsRequest getInstantiateAsRequest() { + final AsInfoModificationRequestDeploymentItems lifecycleParams_1 = + new AsInfoModificationRequestDeploymentItems().deploymentItemsId("1").lifecycleParameterKeyValues( + Map.of(DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_1, DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE, + DEPLOYMENT_ITEM_1_LIFECYCLE_PARAM_2, DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE)); + + final AsInfoModificationRequestDeploymentItems lifecycleParams_2 = + new AsInfoModificationRequestDeploymentItems().deploymentItemsId("2").lifecycleParameterKeyValues( + Map.of(DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_1, DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE, + DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_2, DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE, + DEPLOYMENT_ITEM_2_LIFECYCLE_PARAM_3, DEPLOYMENT_ITEM_LIFECYCLE_PARAM_VALUE)); + + return new InstantiateAsRequest().addDeploymentItemsItem(lifecycleParams_1) + .addDeploymentItemsItem(lifecycleParams_2); + } + + private Path getAbsolutePath(final String path) { + final File file = new File(path); + return file.toPath(); + } + + private byte[] getFileContent(final Path path) throws IOException { + return Files.readAllBytes(path); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClient.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClient.java new file mode 100644 index 0000000..e2f0cce --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClient.java @@ -0,0 +1,108 @@ +/*- + * ============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.tasks; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.HelmClientExecuteException; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.helm.HelmClient; +import org.springframework.stereotype.Service; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class MockedHelmClient implements HelmClient { + + private final Map<String, Integer> counter = new ConcurrentHashMap<>(); + private final Map<String, Integer> unInstallCounter = new ConcurrentHashMap<>(); + private final List<String> kubeKinds; + + public MockedHelmClient(final List<String> kubeKinds) { + this.kubeKinds = kubeKinds; + } + + @Override + public void runHelmChartInstallWithDryRunFlag(final String releaseName, final Path kubeconfig, + final Path helmChart) { + + Integer count = counter.get(releaseName); + if (count == null) { + count = 0; + } + counter.put(releaseName, ++count); + + } + + @Override + public List<String> getKubeKinds(final String releaseName, final Path kubeconfig, final Path helmChart) { + Integer count = counter.get(releaseName); + if (count == null) { + count = 0; + } + counter.put(releaseName, ++count); + return kubeKinds; + } + + @Override + public List<String> getKubeKindsUsingManifestCommand(final String releaseName, final Path kubeconfig) { + Integer count = unInstallCounter.get(releaseName); + if (count == null) { + count = 0; + } + unInstallCounter.put(releaseName, ++count); + return kubeKinds; + } + + @Override + public void installHelmChart(final String releaseName, final Path kubeconfig, final Path helmChart, + final Map<String, String> lifeCycleParams) { + Integer count = counter.get(releaseName); + if (count == null) { + count = 0; + } + counter.put(releaseName, ++count); + } + + @Override + public void unInstallHelmChart(final String releaseName, final Path kubeConfigFilePath) + throws HelmClientExecuteException { + Integer count = unInstallCounter.get(releaseName); + if (count == null) { + count = 0; + } + unInstallCounter.put(releaseName, ++count); + } + + public Map<String, Integer> getCounter() { + return counter; + } + + public Map<String, Integer> getUnInstallCounter() { + return unInstallCounter; + } + + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClientConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClientConfiguration.java new file mode 100644 index 0000000..1f80cc7 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedHelmClientConfiguration.java @@ -0,0 +1,50 @@ +/*- + * ============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.tasks; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DAEMON_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_DEPLOYMENT; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_JOB; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_POD; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_REPLICA_SET; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_SERVICE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.KIND_STATEFUL_SET; + +import java.util.List; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.helm.HelmClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class MockedHelmClientConfiguration { + @Bean + @Primary + public HelmClient helmClient() { + return new MockedHelmClient(List.of(KIND_JOB, KIND_POD, KIND_SERVICE, KIND_DEPLOYMENT, KIND_REPLICA_SET, + KIND_DAEMON_SET, KIND_STATEFUL_SET)); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProvider.java new file mode 100644 index 0000000..4788023 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProvider.java @@ -0,0 +1,58 @@ +/*- + * ============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.tasks; + +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClientProvider; +import org.springframework.stereotype.Component; +import com.github.tomakehurst.wiremock.WireMockServer; +import io.kubernetes.client.openapi.ApiClient; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +public class MockedKubernetesClientProvider implements KubernetesClientProvider { + + private WireMockServer wireMockServer; + + @Override + public ApiClient getApiClient(final String kubeConfigFile) { + if (wireMockServer != null) { + final ApiClient client = new ApiClient(); + client.setBasePath("http://localhost:" + wireMockServer.port()); + return client; + } + return null; + } + + @Override + public void closeApiClient(final String kubeConfigFile) { + + } + + public void setWireMockServer(final WireMockServer wireMockServer) { + this.wireMockServer = wireMockServer; + } + + + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProviderConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProviderConfiguration.java new file mode 100644 index 0000000..b9da6f7 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/MockedKubernetesClientProviderConfiguration.java @@ -0,0 +1,40 @@ +/*- + * ============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.tasks; + +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesClientProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class MockedKubernetesClientProviderConfiguration { + @Bean + @Primary + public KubernetesClientProvider kubernetesClientProvider() { + return new MockedKubernetesClientProvider(); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json deleted file mode 100644 index 042247f..0000000 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "deploymentItems": [ - { - "deploymentItemsId": "1", - "lifecycleParameterKeyValues": { - ".Values.primary.service.ports.mysql": "dummy", - ".Values.primary.service.nodePorts.mysql": "dummy" - } - }, - { - "deploymentItemsId": "2", - "lifecycleParameterKeyValues": { - - } - } - ], - "asdExtCpdInputParams": { - "extCpdId": null, - "loadbalanceIP": null, - "externalIPs": [], - "nadNames": [], - "nadNamespace": null - }, - "additionalParams": {} -}
\ No newline at end of file |