Adding AS Instantiaion support 52/133052/1
authorwaqas.ikram <waqas.ikram@est.tech>
Fri, 27 Jan 2023 13:59:55 +0000 (13:59 +0000)
committerwaqas.ikram <waqas.ikram@est.tech>
Fri, 27 Jan 2023 14:03:05 +0000 (14:03 +0000)
Change-Id: Ieeb0b8febe392bf8a4c770335cd5b9d302c15347
Issue-ID: SO-4052
Signed-off-by: waqas.ikram <waqas.ikram@est.tech>
27 files changed:
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateAs.bpmn [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/InstantiateDeploymentItem.bpmn [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/MonitorHelmInstallStatus.bpmn [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
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 with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json [deleted file]

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 (file)
index 0000000..ca40a8f
--- /dev/null
@@ -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 (file)
index 0000000..f054414
--- /dev/null
@@ -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 (file)
index 0000000..dae6a79
--- /dev/null
@@ -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 (file)
index 0000000..9e7f8eb
--- /dev/null
@@ -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 (file)
index 0000000..db5d092
--- /dev/null
@@ -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 (file)
index 0000000..ffce0ad
--- /dev/null
@@ -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 (file)
index 0000000..685cb3b
--- /dev/null
@@ -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 (file)
index 0000000..d4a3425
--- /dev/null
@@ -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 (file)
index 0000000..4731c24
--- /dev/null
@@ -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 (file)
index 0000000..4b487f9
--- /dev/null
@@ -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 (file)
index 0000000..f8837a9
--- /dev/null
@@ -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 (file)
index 0000000..b32fd65
--- /dev/null
@@ -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 (file)
index 0000000..789f1be
--- /dev/null
@@ -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 (file)
index 0000000..b7b8598
--- /dev/null
@@ -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 (file)
index 0000000..a2cf976
--- /dev/null
@@ -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 (file)
index 0000000..4462829
--- /dev/null
@@ -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 (file)
index 0000000..8e00a8b
--- /dev/null
@@ -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&#10;&#10;" sourceRef="Gateway_06foddt" targetRef="Activity_1n3b4tw">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{isAsInstantiationSuccessful}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:sequenceFlow id="Flow_11d2dsb" name="No&#10;&#10;" 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 (file)
index 0000000..ede1341
--- /dev/null
@@ -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 (file)
index 0000000..92b8ee2
--- /dev/null
@@ -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="&#10;Is Resource Ready&#10;" 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="&#10;Time Out Log Failure&#10;" 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="&#10;Check if operation was successful&#10;" 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>
index 9920ab9..2bf2f30 100644 (file)
@@ -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 {
index 7de9bdc..8374faa 100644 (file)
@@ -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 (file)
index 0000000..1c41894
--- /dev/null
@@ -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 (file)
index 0000000..e2f0cce
--- /dev/null
@@ -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 (file)
index 0000000..1f80cc7
--- /dev/null
@@ -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 (file)
index 0000000..4788023
--- /dev/null
@@ -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 (file)
index 0000000..b9da6f7
--- /dev/null
@@ -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 (file)
index 042247f..0000000
+++ /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