2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2023 Nordix Foundation.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.so.cnfm.lcm.bpmn.flows.tasks;
23 import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME;
24 import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS;
25 import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.INSTANTIATE_AS_REQUEST_PARAM_NAME;
26 import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.FINISHED;
27 import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.IN_PROGRESS;
28 import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.STARTED;
30 import java.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.nio.file.Paths;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
43 import java.util.NoSuchElementException;
44 import java.util.Optional;
46 import java.util.TreeSet;
47 import java.util.stream.Collectors;
48 import java.util.zip.ZipInputStream;
49 import org.apache.commons.io.FileUtils;
50 import org.apache.logging.log4j.util.Strings;
51 import org.camunda.bpm.engine.delegate.DelegateExecution;
52 import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.KubeConfigFileNotFoundException;
53 import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.SdcPackageRequestFailureException;
54 import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPackageParser;
55 import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcPackageProvider;
56 import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider;
57 import org.onap.so.cnfm.lcm.database.beans.AsDeploymentItem;
58 import org.onap.so.cnfm.lcm.database.beans.AsInst;
59 import org.onap.so.cnfm.lcm.database.beans.AsLifecycleParam;
60 import org.onap.so.cnfm.lcm.database.beans.State;
61 import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
62 import org.onap.so.cnfm.lcm.model.AsInfoModificationRequestDeploymentItems;
63 import org.onap.so.cnfm.lcm.model.InstantiateAsRequest;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.beans.factory.annotation.Value;
68 import org.springframework.stereotype.Component;
72 * @author Waqas Ikram (waqas.ikram@est.tech)
76 public class InstantiateAsTask extends AbstractServiceTask {
77 private static final String KUBE_CONFIG_FILE_PARAM_NAME = "kubeConfigFile";
78 private static final String DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME =
79 "asDeploymentItemInstIdToHelmFileMapping";
80 private static final String IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME = "isAsInstantiationSuccessful";
82 private static final Logger logger = LoggerFactory.getLogger(InstantiateAsTask.class);
84 private final String csarDir;
86 private final SdcPackageProvider sdcPackageProvider;
88 private final SdcCsarPackageParser sdcParser;
89 private final KubConfigProvider kubConfigProvider;
92 public InstantiateAsTask(final DatabaseServiceProvider databaseServiceProvider,
93 final SdcPackageProvider sdcPackageProvider, final SdcCsarPackageParser sdcParser,
94 final KubConfigProvider kubConfigProvider, @Value("${cnfm.csar.dir:/app/csar}") final String csarDir) {
95 super(databaseServiceProvider);
96 this.sdcPackageProvider = sdcPackageProvider;
97 this.sdcParser = sdcParser;
98 this.kubConfigProvider = kubConfigProvider;
99 this.csarDir = csarDir;
102 public void setJobStatusToStarted(final DelegateExecution execution) {
103 setJobStatus(execution, STARTED, "Instantiate AS workflow process started");
106 public void setJobStatusToFinished(final DelegateExecution execution) {
107 setJobStatus(execution, FINISHED, "Instantiate AS workflow process finished");
110 public void updateAsInstanceStatusToInstantiating(final DelegateExecution execution) {
111 logger.info("Executing updateAsInstanceStatusToInstantiating");
112 setJobStatus(execution, IN_PROGRESS, "Updating AsInst Status to " + State.INSTANTIATING);
113 updateAsInstanceStatus(execution, State.INSTANTIATING);
115 logger.info("Finished executing updateNsInstanceStatusToInstantiating ...");
118 public void updateAsInstanceStatusToInstantiated(final DelegateExecution execution) {
119 logger.info("Executing updateAsInstanceStatusToInstantiated");
121 final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
122 setJobStatus(execution, FINISHED, "Successfully " + State.INSTANTIATED + " AS: " + asInstId);
124 updateAsInstanceStatus(execution, State.INSTANTIATED);
125 logger.info("Finished executing updateAsInstanceStatusToInstantiated ...");
128 public void downloadHelmPackagesFromSdc(final DelegateExecution execution) {
129 logger.info("Executing downloadHelmPackages ...");
130 setJobStatus(execution, IN_PROGRESS, "Downloading helm packages");
131 final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
133 final AsInst asInst = getAsInst(execution);
134 final Optional<byte[]> optional = getSdcResourcePackage(execution, asInst.getAsdId());
136 if (optional.isEmpty()) {
137 final String message = "Unable to find ASD package using asdId: " + asInst.getAsdId();
138 logger.error(message);
139 abortOperation(execution, message);
142 final List<AsDeploymentItem> asDeploymentItems =
143 databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId);
145 final File dir = mkdirIfnotExists(csarDir, asInstId);
147 final Map<String, String> asDeploymentItemInstIdToHelmFileMapping = new HashMap<>();
149 asDeploymentItems.forEach(asDeploymentItem -> {
150 try (final ByteArrayInputStream stream = new ByteArrayInputStream(optional.get());
151 final ZipInputStream zipInputStream = new ZipInputStream(stream);) {
153 final String artifactFilePath = asDeploymentItem.getArtifactFilePath();
154 final String asDeploymentItemInstId = asDeploymentItem.getAsDeploymentItemInstId();
155 try (final ByteArrayOutputStream helmByteArrayOutputStream =
156 sdcParser.getFileInZip(zipInputStream, artifactFilePath);) {
158 final Path artifactPath = Paths.get(artifactFilePath);
159 final Path path = dir.toPath().resolve(asDeploymentItem.getAsDeploymentItemInstId())
160 .resolve(artifactPath.getFileName());
162 if (!Files.exists(path.getParent())) {
163 final File parentDir = path.getParent().toFile();
164 logger.debug("Creating sub directories to download helm chart file {}", parentDir.toString());
168 if (Files.exists(path)) {
169 logger.debug("{} file already exists will remove it", path);
173 try (final OutputStream outputStream = new FileOutputStream(path.toString())) {
174 helmByteArrayOutputStream.writeTo(outputStream);
177 asDeploymentItemInstIdToHelmFileMapping.put(asDeploymentItemInstId, path.toString());
180 } catch (final IOException ioException) {
181 final String message = "Unexpected exception occured while processing CSAR " + asInst.getAsdId();
182 logger.error(message, ioException);
183 abortOperation(execution, message);
184 } catch (final NoSuchElementException noSuchElementException) {
185 final String message = "Unable to find artifact " + asDeploymentItem.getArtifactFilePath();
186 logger.error(message, noSuchElementException);
187 abortOperation(execution, message);
188 } catch (final Exception exception) {
189 final String message = "Unexpected exception occured while downloading helm packages";
190 logger.error(message, exception);
191 abortOperation(execution, message);
195 logger.info("asDeploymentItemInstIdToHelmFileMapping: {}", asDeploymentItemInstIdToHelmFileMapping);
196 execution.setVariable(DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME,
197 asDeploymentItemInstIdToHelmFileMapping);
199 logger.info("Finished executing downloadHelmPackages ...");
202 private Optional<byte[]> getSdcResourcePackage(final DelegateExecution execution, final String asdId) {
204 return sdcPackageProvider.getSdcResourcePackage(asdId);
205 } catch (final SdcPackageRequestFailureException exception) {
206 final String message = "Unexpected exception occured while getting asd package using asdId: " + asdId;
207 logger.error(message);
208 abortOperation(execution, message);
210 return Optional.empty();
213 public void prepareInstantiateDeploymentItemRequests(final DelegateExecution execution) {
214 logger.info("Executing prepareInstantiateDeploymentItemRequests ...");
215 setJobStatus(execution, IN_PROGRESS, "Preparing InstantiateDeploymentItemRequest requests");
217 final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
218 final InstantiateAsRequest instantiateAsRequest =
219 (InstantiateAsRequest) execution.getVariable(INSTANTIATE_AS_REQUEST_PARAM_NAME);
221 @SuppressWarnings("unchecked")
222 final Map<String, String> asDeploymentItemInstIdToHelmFileMapping =
223 (Map<String, String>) execution.getVariable(DEPLOY_ITEM_INST_ID_TO_HELM_FILE_MAPPING_PARAM_NAME);
225 final String kubeConfigFile = (String) execution.getVariable(KUBE_CONFIG_FILE_PARAM_NAME);
227 final List<AsDeploymentItem> asDeploymentItems =
228 databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId);
230 final Set<InstantiateDeploymentItemRequest> requests = new TreeSet<>();
231 final Map<String, Object> lifeCycleParamMap = instantiateAsRequest.getDeploymentItems().stream()
232 .collect(Collectors.toMap(AsInfoModificationRequestDeploymentItems::getDeploymentItemsId,
233 AsInfoModificationRequestDeploymentItems::getLifecycleParameterKeyValues));
234 asDeploymentItems.forEach(asDeploymentItem -> {
236 final String asDeploymentItemInstId = asDeploymentItem.getAsDeploymentItemInstId();
237 final String artifactFilePath = asDeploymentItemInstIdToHelmFileMapping.get(asDeploymentItemInstId);
238 final String releaseName = asDeploymentItem.getReleaseName();
240 if (Strings.isEmpty(artifactFilePath)) {
241 final String message =
242 "Unable to find helm artifact for asDeploymentItemInstId: " + asDeploymentItemInstId;
243 abortOperation(execution, message);
247 @SuppressWarnings("unchecked")
248 final Map<String, String> lifeCycleParams =
249 (Map<String, String>) lifeCycleParamMap.get(asDeploymentItem.getItemId());
251 final List<AsLifecycleParam> requiredParams = asDeploymentItem.getAsLifecycleParams();
253 checkForLifecycleParametersAbort(execution, lifeCycleParams, requiredParams);
254 requests.add(new InstantiateDeploymentItemRequest().asInstId(asInstId)
255 .asDeploymentItemInstId(asDeploymentItemInstId).asDeploymentItemName(asDeploymentItem.getName())
256 .helmArtifactFilePath(artifactFilePath).deploymentOrder(asDeploymentItem.getDeploymentOrder())
257 .kubeConfigFile(kubeConfigFile).lifeCycleParameters(lifeCycleParams).releaseName((releaseName)));
261 execution.setVariable(DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS, requests);
263 logger.info("Finished executing prepareInstantiateDeploymentItemRequests ...");
267 private void checkForLifecycleParametersAbort(final DelegateExecution execution,
268 final Map<String, String> lifeCycleParams, final List<AsLifecycleParam> requiredParams) {
269 if (!requiredParams.isEmpty()) {
270 if (isNullOrEmptyMap(lifeCycleParams)) {
271 abortOnLifecycleParams(execution, "no lifecycle parameters in request");
273 final Iterator<AsLifecycleParam> it = requiredParams.iterator();
274 while (it.hasNext()) {
275 final String next = it.next().getLifecycleParam();
276 if (!lifeCycleParams.containsKey(next)) {
277 abortOnLifecycleParams(execution, "parameter missing: " + next);
283 private void abortOnLifecycleParams(final DelegateExecution execution, final String reason) {
284 final String message = "Lifecycle parameter error, " + reason;
285 abortOperation(execution, message);
288 public void checkIfDeploymentItemsInstantiationWasSuccessful(final DelegateExecution execution) {
289 logger.info("Executing checkIfDeploymentItemsInstantiationWasSuccessful");
291 @SuppressWarnings("unchecked")
292 final Set<InstantiateDeploymentItemRequest> requests =
293 (Set<InstantiateDeploymentItemRequest>) execution.getVariable(DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS);
295 final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
296 final List<AsDeploymentItem> asDeploymentItems =
297 databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId);
300 if (asDeploymentItems == null || asDeploymentItems.isEmpty()) {
301 final String message = "Found empty asDeploymentItems";
302 abortOperation(execution, message);
305 if (requests.size() != asDeploymentItems.size()) {
306 final String message = "Missing asDeploymentItems. Request triggered has: " + requests.size()
307 + " asDeploymentItems but database has: " + asDeploymentItems.size();
308 abortOperation(execution, message);
311 execution.setVariable(IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME, true);
313 asDeploymentItems.stream().forEach(asDeploymentItem -> {
314 logger.info("Checking if AsDeploymentItem {} was successfull Status: {}",
315 asDeploymentItem.getAsDeploymentItemInstId(), asDeploymentItem.getStatus());
316 if (!State.INSTANTIATED.equals(asDeploymentItem.getStatus())) {
317 logger.error("AsDeploymentItem : {} {} instantiation failed",
318 asDeploymentItem.getAsDeploymentItemInstId(), asDeploymentItem.getName());
319 execution.setVariable(IS_AS_INSTANTIATION_SUCCESSFUL_PARAM_NAME, false);
321 cleanUpDeploymentItemDirectory(asInstId, asDeploymentItem.getAsDeploymentItemInstId());
325 cleanUpInstanceIdDirectory(asInstId);
326 logger.info("Finished executing checkIfDeploymentItemsInstantiationWasSuccessful ...");
329 private void cleanUpDeploymentItemDirectory(final String asInstId, final String deploymentItemInstId) {
330 logger.info("Executing Cleaning up Deployment Item Directory {}", deploymentItemInstId);
331 final Path helmChartDirPath = Paths.get(csarDir, asInstId).resolve(deploymentItemInstId);
332 if (Files.exists(helmChartDirPath)) {
333 logger.debug("Will clean up the directory {}", helmChartDirPath);
335 FileUtils.deleteDirectory(helmChartDirPath.toFile());
336 } catch (final IOException e) {
337 logger.debug("Error deleting the directory {}", helmChartDirPath);
342 private void cleanUpInstanceIdDirectory(final String asInstId) {
343 logger.debug("Executing Cleaning up Instance Id Directory {}", asInstId);
344 final Path dirPath = Paths.get(csarDir, asInstId);
345 if (Files.exists(dirPath) && (dirPath.toFile().list().length == 0)) {
346 logger.debug("Will clean up the instance id directory {}", dirPath);
348 Files.delete(dirPath);
349 } catch (final IOException e) {
350 logger.debug("Error deleting the instance id directory {}", dirPath);
353 logger.debug("Will not clean up the instance id directory. {} is not Empty", dirPath);
357 public void checkifKubConfigFileAvailable(final DelegateExecution execution) {
358 logger.info("Executing checkifKubConfigFileAvailable");
360 final AsInst asInst = getAsInst(execution);
362 final Path kubeConfigFile = kubConfigProvider.getKubeConfigFile(asInst.getCloudOwner(),
363 asInst.getCloudRegion(), asInst.getTenantId());
365 execution.setVariable(KUBE_CONFIG_FILE_PARAM_NAME, kubeConfigFile.toString());
367 } catch (final KubeConfigFileNotFoundException exception) {
368 final String message = "Unable to find kube-config file on filesystem";
369 logger.error(message, exception);
370 abortOperation(execution, message);
374 logger.info("Finished executing checkifKubConfigFileAvailable ...");
378 public void logTimeOut(final DelegateExecution execution) {
379 logger.error("Deployment items instantiation timedOut ...");
380 final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
381 final List<AsDeploymentItem> asDeploymentItems =
382 databaseServiceProvider.getAsDeploymentItemByAsInstId(asInstId);
383 if (asDeploymentItems != null) {
384 asDeploymentItems.stream().forEach(asDeploymentItem -> {
385 logger.info("Current status {} of asDeploymentItem: {}", asDeploymentItem.getStatus(),
386 asDeploymentItem.getName());
391 public void setJobStatusToError(final DelegateExecution execution) {
392 setJobStatusToError(execution, "Instantiate AS workflow process failed");
395 private File mkdirIfnotExists(final String parentDir, final String dirname) {
396 final Path dirPath = Paths.get(parentDir, dirname);
397 final File dir = dirPath.toFile();
399 logger.debug("Creating directory to download helm chart file {}", dir.toString());
405 public static boolean isNullOrEmptyMap(final Map<?, ?> map) {
406 return (map == null || map.isEmpty());