diff options
Diffstat (limited to 'so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main')
29 files changed, 2547 insertions, 0 deletions
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaCustomConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaCustomConfiguration.java new file mode 100644 index 0000000..765d25b --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaCustomConfiguration.java @@ -0,0 +1,49 @@ +/*- + * ============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; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.AS_WORKFLOW_ENGINE; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.TENANT_ID; +import static org.slf4j.LoggerFactory.getLogger; +import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration; +import org.camunda.bpm.spring.boot.starter.configuration.Ordering; +import org.camunda.bpm.spring.boot.starter.configuration.impl.AbstractCamundaConfiguration; +import org.slf4j.Logger; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +@Order(Ordering.DEFAULT_ORDER + 1) +public class CamundaCustomConfiguration extends AbstractCamundaConfiguration { + private static final Logger logger = getLogger(CamundaCustomConfiguration.class); + + @Override + public void preInit(final SpringProcessEngineConfiguration processEngineConfiguration) { + logger.info("Setting DeploymentTenantId to {} and DeploymentName to {}", TENANT_ID, AS_WORKFLOW_ENGINE); + processEngineConfiguration.setDeploymentTenantId(TENANT_ID); + processEngineConfiguration.setDeploymentName(AS_WORKFLOW_ENGINE); + super.preInit(processEngineConfiguration); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaDatabaseConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaDatabaseConfiguration.java new file mode 100644 index 0000000..cc8bb01 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaDatabaseConfiguration.java @@ -0,0 +1,89 @@ +/*- + * ============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; + + +import static org.slf4j.LoggerFactory.getLogger; +import javax.sql.DataSource; +import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration; +import org.camunda.bpm.spring.boot.starter.util.SpringBootProcessEnginePlugin; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +@EnableTransactionManagement +public class CamundaDatabaseConfiguration { + + private static final String CAMUNDA_TRANSACTION_MANAGER_BEAN_NAME = "camundaTransactionManager"; + + private static final String CAMUNDA_DATA_SOURCE_BEAN_NAME = "camundaBpmDataSource"; + + private static final Logger logger = getLogger(CamundaDatabaseConfiguration.class); + + @Bean + @ConfigurationProperties(prefix = "spring.datasource.hikari.camunda") + public HikariConfig camundaDbConfig() { + logger.debug("Creating Camunda HikariConfig bean ... "); + return new HikariConfig(); + } + + @Bean(name = CAMUNDA_DATA_SOURCE_BEAN_NAME) + public DataSource camundaDataSource(@Autowired(required = false) final MBeanExporter mBeanExporter) { + if (mBeanExporter != null) { + mBeanExporter.addExcludedBean(CAMUNDA_DATA_SOURCE_BEAN_NAME); + } + logger.debug("Creating Camunda HikariDataSource bean ... "); + final HikariConfig hikariConfig = this.camundaDbConfig(); + return new HikariDataSource(hikariConfig); + } + + @Bean(name = CAMUNDA_TRANSACTION_MANAGER_BEAN_NAME) + public PlatformTransactionManager camundaTransactionManager( + @Qualifier(CAMUNDA_DATA_SOURCE_BEAN_NAME) final DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean + public SpringBootProcessEnginePlugin transactionManagerProcessEnginePlugin( + @Qualifier(CAMUNDA_TRANSACTION_MANAGER_BEAN_NAME) final PlatformTransactionManager camundaTransactionManager) { + return new SpringBootProcessEnginePlugin() { + @Override + public void preInit(final SpringProcessEngineConfiguration processEngineConfiguration) { + logger.info("Setting Camunda TransactionManager ..."); + processEngineConfiguration.setTransactionManager(camundaTransactionManager); + + } + }; + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaVariableNameConstants.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaVariableNameConstants.java new file mode 100644 index 0000000..47c5795 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/CamundaVariableNameConstants.java @@ -0,0 +1,53 @@ +/*- + * ============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; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class CamundaVariableNameConstants { + + public static final String AS_DEPLOYMENT_ITEM_INST_ID_PARAM_NAME = "asDeploymentItemInstId"; + public static final String KUBE_KINDS_RESULT_PARAM_NAME = "kubeKindsResult"; + public static final String KUBE_CONFIG_FILE_PATH_PARAM_NAME = "kubeConfigFilePath"; + public static final String KUBE_KINDS_PARAM_NAME = "kubeKinds"; + public static final String KIND_PARAM_NAME = "kind"; + public static final String RELEASE_NAME_PARAM_NAME = "releaseName"; + public static final String JOB_ID_PARAM_NAME = "jobId"; + public static final String JOB_BUSINESS_KEY_PARAM_NAME = "jobBusinessKey"; + public static final String CREATE_AS_REQUEST_PARAM_NAME = "createAsRequest"; + + public static final String AS_PACKAGE_MODEL_PARAM_NAME = "AsPackageModel"; + public static final String AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME = "AsWorkflowProcessingException"; + public static final String CREATE_AS_RESPONSE_PARAM_NAME = "createAsResponse"; + + public static final String INSTANTIATE_AS_REQUEST_PARAM_NAME = "instantiateAsRequest"; + public static final String AS_INSTANCE_ID_PARAM_NAME = "AsInstanceId"; + public static final String OCC_ID_PARAM_NAME = "occId"; + + public static final String DEPLOYMENT_ITEM_INSTANTIATE_REQUESTS = "deploymentItemInstantiateRequests"; + public static final String DEPLOYMENT_ITEM_TERMINATE_REQUESTS = "deploymentItemTerminateRequests"; + + public static final String TERMINATE_AS_REQUEST_PARAM_NAME = "terminateAsRequest"; + + private CamundaVariableNameConstants() {} + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/Constants.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/Constants.java new file mode 100644 index 0000000..45c36be --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/Constants.java @@ -0,0 +1,45 @@ +/*- + * ============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; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class Constants { + + public static final String TENANT_ID = "as-workflow-engine-tenant"; + public static final String AS_WORKFLOW_ENGINE = "AS-WORKFLOW-ENGINE"; + public static final String CREATE_AS_WORKFLOW_NAME = "CreateAs"; + public static final String INSTANTIATE_AS_WORKFLOW_NAME = "InstantiateAs"; + public static final String TERMINATE_AS_WORKFLOW_NAME = "TerminateAs"; + public static final String DELETE_AS_WORKFLOW_NAME = "DeleteAs"; + + public static final String KIND_STATEFUL_SET = "StatefulSet"; + public static final String KIND_DAEMON_SET = "DaemonSet"; + public static final String KIND_REPLICA_SET = "ReplicaSet"; + public static final String KIND_DEPLOYMENT = "Deployment"; + public static final String KIND_SERVICE = "Service"; + public static final String KIND_POD = "Pod"; + public static final String KIND_JOB = "Job"; + + private Constants() {} + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/GsonProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/GsonProvider.java new file mode 100644 index 0000000..486c528 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/GsonProvider.java @@ -0,0 +1,45 @@ +/*- + * ============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; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import org.onap.so.cnfm.lcm.bpmn.flows.utils.LocalDateTimeTypeAdapter; +import org.onap.so.cnfm.lcm.bpmn.flows.utils.OffsetDateTimeTypeAdapter; +import org.springframework.stereotype.Component; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Component +public class GsonProvider { + + private final OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + + public Gson getGson() { + return new GsonBuilder().registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter) + .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter()).create(); + } + + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/AsRequestProcessingException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/AsRequestProcessingException.java new file mode 100644 index 0000000..991c3c3 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/AsRequestProcessingException.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.exceptions; + +import org.onap.so.cnfm.lcm.model.ErrorDetails; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class AsRequestProcessingException extends RuntimeException { + + private static final long serialVersionUID = 66862444537194516L; + private final ErrorDetails errorDetails; + + public AsRequestProcessingException(final String message) { + super(message); + errorDetails = null; + } + + public AsRequestProcessingException(final String message, final ErrorDetails errorContents) { + super(message); + this.errorDetails = errorContents; + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + + public ErrorDetails getErrorDetails() { + return errorDetails; + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/BasicAuthConfigException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/BasicAuthConfigException.java new file mode 100644 index 0000000..4b9bfb1 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/BasicAuthConfigException.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.exceptions; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +public class BasicAuthConfigException extends RuntimeException { + + private static final long serialVersionUID = -6317913344782441364L; + + public BasicAuthConfigException(final String message) { + super(message); + } + + public BasicAuthConfigException(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/FileNotFoundInCsarException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/FileNotFoundInCsarException.java new file mode 100644 index 0000000..4bad50c --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/FileNotFoundInCsarException.java @@ -0,0 +1,44 @@ +/*- + * ============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 FileNotFoundInCsarException extends RuntimeException { + + private static final long serialVersionUID = -3294117029811603499L; + + public FileNotFoundInCsarException(final String message) { + super(message); + } + + public FileNotFoundInCsarException(final String message, final Throwable cause) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/PropertyNotFoundException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/PropertyNotFoundException.java new file mode 100644 index 0000000..908a04d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/PropertyNotFoundException.java @@ -0,0 +1,44 @@ +/*- + * ============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 PropertyNotFoundException extends RuntimeException { + + private static final long serialVersionUID = 684205374040870233L; + + public PropertyNotFoundException(final String message) { + super(message); + } + + public PropertyNotFoundException(final String message, final Throwable cause) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/SdcPackageRequestFailureException.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/SdcPackageRequestFailureException.java new file mode 100644 index 0000000..d33c51f --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/exceptions/SdcPackageRequestFailureException.java @@ -0,0 +1,42 @@ +/*- + * ============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; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class SdcPackageRequestFailureException extends RuntimeException { + + private static final long serialVersionUID = 5816306976965772635L; + + public SdcPackageRequestFailureException(final String message) { + super(message); + } + + public SdcPackageRequestFailureException(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/aai/AaiClientProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiClientProvider.java new file mode 100644 index 0000000..aceafe7 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiClientProvider.java @@ -0,0 +1,34 @@ +/*- + * ============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.aai; + +import org.onap.aaiclient.client.aai.AAIResourcesClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AaiClientProvider { + + @Bean + public AAIResourcesClient getAaiClient() { + return new AAIResourcesClient(); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiPropertiesImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiPropertiesImpl.java new file mode 100644 index 0000000..b0986d8 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiPropertiesImpl.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.cnfm.lcm.bpmn.flows.extclients.aai; + +import org.onap.aaiclient.client.aai.AAIProperties; +import org.onap.aaiclient.client.aai.AAIVersion; +import org.onap.so.client.CacheProperties; +import org.onap.so.spring.SpringContextHelper; +import org.springframework.context.ApplicationContext; +import java.net.MalformedURLException; +import java.net.URL; + +public class AaiPropertiesImpl implements AAIProperties { + + private final String endpoint; + private final String encryptedBasicAuth; + private final String encryptionKey; + private final String aaiVersion; + private final Long readTimeout; + private final Long connectionTimeout; + private final boolean enableCaching; + private final Long cacheMaxAge; + + public AaiPropertiesImpl() { + final ApplicationContext context = SpringContextHelper.getAppContext(); + this.endpoint = context.getEnvironment().getProperty("aai.endpoint"); + this.encryptedBasicAuth = context.getEnvironment().getProperty("aai.auth"); + this.encryptionKey = context.getEnvironment().getProperty("mso.key"); + this.aaiVersion = context.getEnvironment().getProperty("aai.version"); + this.readTimeout = context.getEnvironment().getProperty("aai.readTimeout", Long.class, 60000L); + this.connectionTimeout = context.getEnvironment().getProperty("aai.connectionTimeout", Long.class, 60000L); + this.enableCaching = context.getEnvironment().getProperty("aai.caching.enabled", Boolean.class, false); + this.cacheMaxAge = context.getEnvironment().getProperty("aai.caching.maxAge", Long.class, 60000L); + } + + @Override + public URL getEndpoint() throws MalformedURLException { + return new URL(endpoint); + } + + @Override + public String getSystemName() { + return "MSO"; + } + + @Override + public AAIVersion getDefaultVersion() { + for (final AAIVersion version : AAIVersion.values()) { + if (version.toString().equalsIgnoreCase(this.aaiVersion)) { + return version; + } + } + return AAIVersion.LATEST; + } + + @Override + public String getAuth() { + return encryptedBasicAuth; + } + + @Override + public String getKey() { + return encryptionKey; + } + + @Override + public Long getReadTimeout() { + return this.readTimeout; + } + + @Override + public Long getConnectionTimeout() { + return this.connectionTimeout; + } + + @Override + public boolean isCachingEnabled() { + return this.enableCaching; + } + + @Override + public CacheProperties getCacheProperties() { + return new AAICacheProperties() { + @Override + public Long getMaxAge() { + return cacheMaxAge; + } + }; + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProvider.java new file mode 100644 index 0000000..fae677d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProvider.java @@ -0,0 +1,68 @@ +/*- + * ============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.aai; + +import java.util.List; +import java.util.Optional; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.K8SResource; +import org.onap.aai.domain.yang.VfModule; +import org.onap.so.beans.nsmf.OrchestrationStatusEnum; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesResource; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface AaiServiceProvider { + + void createGenericVnfAndConnectServiceInstance(final String serviceInstanceId, final String vnfId, + final GenericVnf genericVnf); + + void connectGenericVnfToTenant(final String vnfId, final String cloudOwner, final String cloudRegion, + final String tenantId); + + Optional<GenericVnf> getGenericVnf(final String vnfId); + + void deleteGenericVnf(final String vnfId); + + void updateGenericVnf(final String vnfId, final GenericVnf vnf); + + void createVfModule(final String vnfId, final String vfModuleId, final VfModule vfModule); + + void createK8sResource(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId, K8SResource k8sResource); + + void connectK8sResourceToVfModule(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId, final String vnfId, final String vfModuleId); + + void connectK8sResourceToGenericVnf(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId, final String vnfId); + + List<KubernetesResource> getK8sResources(final String vnfId, final String vfModuleId); + + void deleteK8SResource(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId); + + void deleteVfModule(final String vnfId, final String vfModuleId); + + boolean updateGenericVnfStatus(final String vnfId, final OrchestrationStatusEnum status); +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProviderImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProviderImpl.java new file mode 100644 index 0000000..4f5ec8d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/aai/AaiServiceProviderImpl.java @@ -0,0 +1,211 @@ +/*- + * ============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.aai; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.K8SResource; +import org.onap.aai.domain.yang.VfModule; +import org.onap.aaiclient.client.aai.entities.AAIResultWrapper; +import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri; +import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory; +import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder; +import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder.Types; +import org.onap.so.beans.nsmf.OrchestrationStatusEnum; +import org.onap.so.cnfm.lcm.bpmn.flows.GsonProvider; +import org.onap.so.cnfm.lcm.bpmn.flows.extclients.kubernetes.KubernetesResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.google.gson.Gson; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + */ +@Service +public class AaiServiceProviderImpl implements AaiServiceProvider { + private static final Logger logger = LoggerFactory.getLogger(AaiServiceProviderImpl.class); + private final AaiClientProvider aaiClientProvider; + private final Gson gson; + + @Autowired + public AaiServiceProviderImpl(final AaiClientProvider aaiClientProvider, final GsonProvider gsonProvider) { + this.aaiClientProvider = aaiClientProvider; + this.gson = gsonProvider.getGson(); + } + + @Override + public void createGenericVnfAndConnectServiceInstance(final String serviceInstanceId, final String vnfId, + final GenericVnf genericVnf) { + logger.info("Creating GenericVnf in AAI: {}", genericVnf); + final AAIResourceUri genericVnfURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId)); + final AAIResourceUri serviceInstanceURI = + AAIUriFactory.createResourceUri(Types.SERVICE_INSTANCE.getFragment(serviceInstanceId)); + aaiClientProvider.getAaiClient().createIfNotExists(genericVnfURI, Optional.of(genericVnf)) + .connect(genericVnfURI, serviceInstanceURI); + + } + + @Override + public void connectGenericVnfToTenant(final String vnfId, final String cloudOwner, final String cloudRegion, + final String tenantId) { + logger.info("Connecting GenericVnf {} to {}/{}/{} in AAI", vnfId, cloudOwner, cloudRegion, tenantId); + final AAIResourceUri tenantURI = AAIUriFactory.createResourceUri( + AAIFluentTypeBuilder.cloudInfrastructure().cloudRegion(cloudOwner, cloudRegion).tenant(tenantId)); + final AAIResourceUri genericVnfURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId)); + aaiClientProvider.getAaiClient().connect(tenantURI, genericVnfURI); + } + + @Override + public Optional<GenericVnf> getGenericVnf(final String vnfId) { + return aaiClientProvider.getAaiClient().get(GenericVnf.class, + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId))); + } + + @Override + public void deleteGenericVnf(final String vnfId) { + logger.info("Deleting GenericVnf with id: {} from AAI.", vnfId); + final AAIResourceUri aaiResourceUri = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId)); + aaiClientProvider.getAaiClient().delete(aaiResourceUri); + } + + @Override + public void updateGenericVnf(final String vnfId, final GenericVnf vnf) { + logger.info("Updating GenericVnf of id: {} in AAI.", vnfId); + final AAIResourceUri aaiResourceUri = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId)); + aaiClientProvider.getAaiClient().update(aaiResourceUri, vnf); + } + + @Override + public void createVfModule(final String vnfId, final String vfModuleId, final VfModule vfModule) { + logger.info("Creating VfModule in AAI: {}", vfModule); + + final AAIResourceUri vfModuleURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId).vfModule(vfModuleId)); + aaiClientProvider.getAaiClient().createIfNotExists(vfModuleURI, Optional.of(vfModule)); + + } + + @Override + public void createK8sResource(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId, final K8SResource k8sResource) { + logger.info("Creating K8SResource in AAI: {} using {}/{}/{}/{}", k8sResource, k8sResourceId, cloudOwner, + cloudRegion, tenantId); + + final AAIResourceUri k8sResourceURI = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure() + .cloudRegion(cloudOwner, cloudRegion).tenant(tenantId).k8sResource(k8sResourceId)); + + final String payload = gson.toJson(k8sResource); + logger.debug("Creating K8sResource in A&AI: {}", payload); + + aaiClientProvider.getAaiClient().createIfNotExists(k8sResourceURI, Optional.of(payload)); + + } + + @Override + public void connectK8sResourceToVfModule(final String k8sResourceId, final String cloudOwner, + final String cloudRegion, final String tenantId, final String vnfId, final String vfModuleId) { + logger.info("Connecting K8sResource {}/{}/{}/{} to VF Moudle {}/{} in AAI", cloudOwner, cloudRegion, tenantId, + k8sResourceId, vnfId, vfModuleId); + + final AAIResourceUri k8sResourceURI = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure() + .cloudRegion(cloudOwner, cloudRegion).tenant(tenantId).k8sResource(k8sResourceId)); + + final AAIResourceUri vfModuleURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId).vfModule(vfModuleId)); + aaiClientProvider.getAaiClient().connect(k8sResourceURI, vfModuleURI); + + } + + @Override + public void connectK8sResourceToGenericVnf(final String k8sResourceId, final String cloudOwner, + final String cloudRegion, final String tenantId, final String vnfId) { + logger.info("Connecting K8sResource {}/{}/{}/{} to Generic Vnf {} in AAI", cloudOwner, cloudRegion, tenantId, + k8sResourceId, vnfId); + final AAIResourceUri k8sResourceURI = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure() + .cloudRegion(cloudOwner, cloudRegion).tenant(tenantId).k8sResource(k8sResourceId)); + final AAIResourceUri genericVnfURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId)); + aaiClientProvider.getAaiClient().connect(k8sResourceURI, genericVnfURI); + + } + + @Override + public List<KubernetesResource> getK8sResources(final String vnfId, final String vfModuleId) { + logger.info("Getting K8S resources related to VfModule: {} from AAI", vfModuleId); + final AAIResourceUri vfModuleURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId).vfModule(vfModuleId)); + final AAIResultWrapper vfModuleInstance = aaiClientProvider.getAaiClient().get(vfModuleURI); + if (vfModuleInstance.hasRelationshipsTo(Types.K8S_RESOURCE) + && vfModuleInstance.getRelationships().isPresent()) { + logger.debug("VfModule has relations of type K8SResource"); + return vfModuleInstance.getRelationships().get().getByType(Types.K8S_RESOURCE).stream() + .map(relation -> relation.asBean(KubernetesResource.class)).filter(Optional::isPresent) + .map(Optional::get).collect(Collectors.toList()); + } + logger.info("No K8S resources found for VfModule :{}", vfModuleId); + return Collections.emptyList(); + } + + @Override + public void deleteK8SResource(final String k8sResourceId, final String cloudOwner, final String cloudRegion, + final String tenantId) { + logger.info("Deleting K8sResource {} from AAI", k8sResourceId); + + final AAIResourceUri k8sResourceURI = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure() + .cloudRegion(cloudOwner, cloudRegion).tenant(tenantId).k8sResource(k8sResourceId)); + aaiClientProvider.getAaiClient().deleteIfExists(k8sResourceURI); + + logger.info("K8S resource removed from AAI using URI: {}", k8sResourceURI); + } + + @Override + public void deleteVfModule(final String vnfId, final String vfModuleId) { + logger.info("Deleting VfModule {} from AAI", vfModuleId); + + final AAIResourceUri vfModuleURI = + AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId).vfModule(vfModuleId)); + aaiClientProvider.getAaiClient().deleteIfExists(vfModuleURI); + logger.info("VfModule deleted from AAI using URI: {}", vfModuleId); + } + + @Override + public boolean updateGenericVnfStatus(final String vnfId, final OrchestrationStatusEnum status) { + logger.info("Updating GenericVnf status to deactivated for vnfID: {}", vnfId); + final Optional<GenericVnf> optionalVnf = getGenericVnf(vnfId); + if (optionalVnf.isPresent()) { + final GenericVnf vnf = optionalVnf.get(); + vnf.setOrchestrationStatus(status.getValue()); + updateGenericVnf(vnfId, vnf); + return true; + } + 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/KubernetesResource.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesResource.java new file mode 100644 index 0000000..7ec50f0 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/kubernetes/KubernetesResource.java @@ -0,0 +1,209 @@ +/*- + * ============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.database.beans.utils.Utils.toIndentedString; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class KubernetesResource implements Serializable { + + private static final long serialVersionUID = -4342437130757578686L; + + private String id; + private String name; + private String group; + private String version; + private String kind; + private String namespace; + private String selflink; + private String resourceVersion; + private List<String> labels; + + public String getId() { + return id; + } + + public void setId(final String id) { + this.id = id; + } + + public KubernetesResource id(final String id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public KubernetesResource name(final String name) { + this.name = name; + return this; + } + + public String getGroup() { + return group; + } + + public void setGroup(final String group) { + this.group = group; + } + + public KubernetesResource group(final String group) { + this.group = group; + return this; + } + + public String getVersion() { + return version; + } + + public void setVersion(final String version) { + this.version = version; + } + + public KubernetesResource version(final String version) { + this.version = version; + return this; + } + + public String getKind() { + return kind; + } + + public void setKind(final String kind) { + this.kind = kind; + } + + public KubernetesResource kind(final String kind) { + this.kind = kind; + return this; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(final String namespace) { + this.namespace = namespace; + } + + public KubernetesResource namespace(final String namespace) { + this.namespace = namespace; + return this; + } + + public String getSelflink() { + return selflink; + } + + public void setSelflink(final String selflink) { + this.selflink = selflink; + } + + public KubernetesResource selflink(final String selflink) { + this.selflink = selflink; + return this; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(final String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public KubernetesResource resourceVersion(final String resourceVersion) { + this.resourceVersion = resourceVersion; + return this; + } + + public List<String> getLabels() { + return labels; + } + + public void setLabels(final List<String> labels) { + this.labels = labels; + } + + public KubernetesResource labels(final List<String> labels) { + this.labels = labels; + return this; + } + + public KubernetesResource label(final String label) { + if (this.labels == null) { + this.labels = new ArrayList<>(); + } + + this.labels.add(label); + return this; + } + + @Override + public int hashCode() { + return Objects.hash(id, name, group, version, kind, namespace, selflink, resourceVersion, labels); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof KubernetesResource) { + final KubernetesResource other = (KubernetesResource) obj; + return Objects.equals(id, other.id) && Objects.equals(name, other.name) + && Objects.equals(group, other.group) && Objects.equals(version, other.version) + && Objects.equals(kind, other.kind) && Objects.equals(namespace, other.namespace) + && Objects.equals(selflink, other.selflink) + && Objects.equals(resourceVersion, other.resourceVersion) && Objects.equals(labels, other.labels); + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("class KubernetesResource {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" group: ").append(toIndentedString(group)).append("\n"); + sb.append(" version: ").append(toIndentedString(version)).append("\n"); + sb.append(" kind: ").append(toIndentedString(kind)).append("\n"); + sb.append(" namespace: ").append(toIndentedString(namespace)).append("\n"); + sb.append(" selflink: ").append(toIndentedString(selflink)).append("\n"); + sb.append(" resourceVersion: ").append(toIndentedString(resourceVersion)).append("\n"); + sb.append(" labels: ").append(toIndentedString(labels)).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/extclients/sdc/DeploymentItem.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/DeploymentItem.java new file mode 100644 index 0000000..1062cb7 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/DeploymentItem.java @@ -0,0 +1,143 @@ +/*- + * ============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.sdc; + +import static org.onap.so.cnfm.lcm.database.beans.utils.Utils.toIndentedString; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class DeploymentItem implements Serializable { + + private static final long serialVersionUID = -1974244669409099225L; + private String name; + private String file; + private String itemId; + private String deploymentOrder; + + private List<String> lifecycleParameters; + + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public DeploymentItem name(final String name) { + this.name = name; + return this; + } + + + public String getFile() { + return file; + } + + public void setFile(final String file) { + this.file = file; + } + + public DeploymentItem file(final String file) { + this.file = file; + return this; + } + + + public String getItemId() { + return itemId; + } + + public void setItemId(final String itemId) { + this.itemId = itemId; + } + + public DeploymentItem itemId(final String itemId) { + this.itemId = itemId; + return this; + } + + public String getDeploymentOrder() { + return deploymentOrder; + } + + public void setDeploymentOrder(String deploymentOrder) { + this.deploymentOrder = deploymentOrder; + } + + public DeploymentItem deploymentOrder(final String deploymentOrder) { + this.deploymentOrder = deploymentOrder; + return this; + } + + + public List<String> getLifecycleParameters() { + return lifecycleParameters; + } + + public void setLifecycleParameters(final List<String> lifecycleParameters) { + this.lifecycleParameters = lifecycleParameters; + } + + public DeploymentItem lifecycleParameters(final List<String> lifecycleParameters) { + this.lifecycleParameters = lifecycleParameters; + return this; + } + + @Override + public int hashCode() { + return Objects.hash(name, file, itemId, deploymentOrder, lifecycleParameters); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + if (obj instanceof DeploymentItem) { + final DeploymentItem other = (DeploymentItem) obj; + return Objects.equals(name, other.name) && Objects.equals(file, other.file) + && Objects.equals(itemId, other.itemId) && Objects.equals(deploymentOrder, other.deploymentOrder) + && Objects.equals(lifecycleParameters, other.lifecycleParameters); + } + return false; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("class DeploymentItem {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" file: ").append(toIndentedString(file)).append("\n"); + sb.append(" itemId: ").append(toIndentedString(itemId)).append("\n"); + sb.append(" deploymentOrder: ").append(toIndentedString(deploymentOrder)).append("\n"); + sb.append(" lifecycleParameters: ").append(toIndentedString(lifecycleParameters)).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/extclients/sdc/SdcClientConfigurationProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java new file mode 100644 index 0000000..4ae1d43 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcClientConfigurationProvider.java @@ -0,0 +1,79 @@ +/*- + * ============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.sdc; + +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import org.apache.commons.codec.binary.Base64; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.BasicAuthConfigException; +import org.onap.so.utils.CryptoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class SdcClientConfigurationProvider { + + private static final Logger logger = LoggerFactory.getLogger(SdcClientConfigurationProvider.class); + + @Value("${sdc.username:mso}") + private String sdcUsername; + + @Value("${sdc.password:76966BDD3C7414A03F7037264FF2E6C8EEC6C28F2B67F2840A1ED857C0260FEE731D73F47F828E5527125D29FD25D3E0DE39EE44C058906BF1657DE77BF897EECA93BDC07FA64F}") + private String sdcPassword; + + @Value("${sdc.key:566B754875657232314F5548556D3665}") + private String sdcKey; + + @Value("${sdc.endpoint:https://sdc-be.onap:8443}") + private String baseUrl; + + private static String basicAuth = null; + + + public String getBasicAuth() { + if (basicAuth == null) { + synchronized (this) { + if (basicAuth == null) { + try { + final String auth = sdcUsername + ":" + CryptoUtils.decrypt(sdcPassword, sdcKey); + final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1)); + basicAuth = "Basic " + new String(encodedAuth); + } catch (final GeneralSecurityException exception) { + logger.error("Unable to process basic auth information", exception); + throw new BasicAuthConfigException("Unable to process basic auth information", exception); + } + } + } + } + return basicAuth; + } + + public String getSdcPackageUrl(final String packageId) { + return baseUrl + "/sdc/v1/catalog/resources/" + packageId + "/toscaModel"; + + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java new file mode 100644 index 0000000..0ade7bf --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParser.java @@ -0,0 +1,201 @@ +/*- + * ============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.sdc; + +import static com.google.common.base.Splitter.on; +import static com.google.common.collect.Iterables.filter; +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.APPLICATION_VERSION_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DEPLOYMENT_ITEMS_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; +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.PROVIDER_PARAM_NAME; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import com.google.gson.JsonArray; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.FileNotFoundInCsarException; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.PropertyNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.yaml.snakeyaml.Yaml; +import com.google.common.io.ByteStreams; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class SdcCsarPackageParser { + private static final String TOCSA_METADATA_FILE_PATH = "TOSCA-Metadata/TOSCA.meta"; + private static final String ENTRY_DEFINITIONS_ENTRY = "Entry-Definitions"; + + private static final Logger logger = LoggerFactory.getLogger(SdcCsarPackageParser.class); + + public Map<String, Object> getAsdProperties(final byte[] onapPackage) { + + try (final ByteArrayInputStream stream = new ByteArrayInputStream(onapPackage); + final ZipInputStream zipInputStream = new ZipInputStream(stream);) { + final String asdLocation = getAsdLocation(zipInputStream); + final String onapAsdContent = getFileInZip(zipInputStream, asdLocation).toString(); + logger.debug("ASD CONTENTS: {}", onapAsdContent); + final JsonObject root = new Gson().toJsonTree(new Yaml().load(onapAsdContent)).getAsJsonObject(); + + final JsonObject topologyTemplates = child(root, "topology_template"); + final JsonObject nodeTemplates = child(topologyTemplates, "node_templates"); + for (final JsonObject child : children(nodeTemplates)) { + final String type = childElement(child, "type").getAsString(); + if ("tosca.nodes.asd".equals(type)) { + final JsonObject properties = child(child, "properties"); + logger.debug("properties: {}", properties.toString()); + final Map<String, Object> propertiesValues = new HashMap<>(); + propertiesValues.put(DESCRIPTOR_ID_PARAM_NAME, + getStringValue(properties, DESCRIPTOR_ID_PARAM_NAME)); + propertiesValues.put(DESCRIPTOR_INVARIANT_ID_PARAM_NAME, + getStringValue(properties, DESCRIPTOR_INVARIANT_ID_PARAM_NAME)); + propertiesValues.put(PROVIDER_PARAM_NAME, getStringValue(properties, PROVIDER_PARAM_NAME)); + propertiesValues.put(APPLICATION_NAME_PARAM_NAME, + getStringValue(properties, APPLICATION_NAME_PARAM_NAME)); + propertiesValues.put(APPLICATION_VERSION_PARAM_NAME, + getStringValue(properties, APPLICATION_VERSION_PARAM_NAME)); + propertiesValues.put(DEPLOYMENT_ITEMS_PARAM_NAME, getDeploymentItems(child)); + + return propertiesValues; + + } + } + + + } catch (final Exception exception) { + throw new IllegalArgumentException("Unable to parser CSAR package", exception); + } + return Collections.emptyMap(); + } + + private String getStringValue(final JsonObject properties, final String key) { + final JsonElement element = properties.get(key); + if (element != null && element.isJsonPrimitive()) { + return element.getAsString(); + } + logger.warn("'{}' value is not Primitive or null val:{}", key, element != null ? element.toString() : null); + return null; + } + + private List<DeploymentItem> getDeploymentItems(final JsonObject child) { + final List<DeploymentItem> items = new ArrayList<>(); + + final JsonObject artifacts = child(child, "artifacts"); + artifacts.keySet().forEach(key -> { + final JsonObject element = artifacts.getAsJsonObject(key); + final JsonObject artifactsProperties = child(element, "properties"); + final List<String> lcp = getLifecycleParameters(artifactsProperties); + items.add(new DeploymentItem().name(key).itemId(getStringValue(artifactsProperties, "itemId")) + .file(getStringValue(element, "file")) + .deploymentOrder(getStringValue(artifactsProperties, "deployment_order")).lifecycleParameters(lcp)); + }); + return items; + } + + private List<String> getLifecycleParameters(final JsonObject artifactsProperties) { + final JsonArray lcParameters = childElement(artifactsProperties, "lifecycle_parameters").getAsJsonArray(); + final List<String> lifecycleParameters = new ArrayList<>(); + if(lcParameters != null) { + final Iterator<JsonElement> it = lcParameters.iterator(); + while(it.hasNext()){ + lifecycleParameters.add(it.next().getAsString()); + } + } + return lifecycleParameters; + } + + private String getAsdLocation(final ZipInputStream zipInputStream) throws IOException { + + try (final ByteArrayOutputStream fileContent = getFileInZip(zipInputStream, TOCSA_METADATA_FILE_PATH);) { + final String toscaMetadata = new String(fileContent.toByteArray()); + if (!toscaMetadata.isEmpty()) { + final String entry = + filter(on("\n").split(toscaMetadata), line -> line.contains(ENTRY_DEFINITIONS_ENTRY)).iterator() + .next(); + return entry.replace(ENTRY_DEFINITIONS_ENTRY + ":", "").trim(); + } + final String message = "Unable to find valid Tosca Path"; + logger.error(message); + throw new FileNotFoundInCsarException(message); + } + } + + public ByteArrayOutputStream getFileInZip(final ZipInputStream zipInputStream, final String path) + throws IOException { + ZipEntry zipEntry; + final Set<String> items = new HashSet<>(); + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + items.add(zipEntry.getName()); + if (zipEntry.getName().matches(path)) { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ByteStreams.copy(zipInputStream, byteArrayOutputStream); + return byteArrayOutputStream; + } + } + logger.error("Unable to find the {} in archive found: {}", path, items); + throw new NoSuchElementException("Unable to find the " + path + " in archive found: " + items); + } + + private JsonObject child(final JsonObject parent, final String name) { + return childElement(parent, name).getAsJsonObject(); + } + + private JsonElement childElement(final JsonObject parent, final String name) { + final JsonElement child = parent.get(name); + if (child == null) { + final String message = "Missing child " + name; + logger.error(message); + throw new PropertyNotFoundException(message); + } + return child; + } + + private Collection<JsonObject> children(final JsonObject parent) { + final ArrayList<JsonObject> childElements = new ArrayList<>(); + parent.keySet().stream().forEach(childKey -> { + if (parent.get(childKey).isJsonObject()) { + childElements.add(parent.get(childKey).getAsJsonObject()); + } + }); + return childElements; + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPropertiesConstants.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPropertiesConstants.java new file mode 100644 index 0000000..40a0d0d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPropertiesConstants.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class SdcCsarPropertiesConstants { + public static final String DEPLOYMENT_ITEMS_PARAM_NAME = "deployment_items"; + public static final String APPLICATION_VERSION_PARAM_NAME = "application_version"; + public static final String APPLICATION_NAME_PARAM_NAME = "application_name"; + public static final String PROVIDER_PARAM_NAME = "provider"; + public static final String DESCRIPTOR_INVARIANT_ID_PARAM_NAME = "descriptor_invariant_id"; + public static final String DESCRIPTOR_ID_PARAM_NAME = "descriptor_id"; + + private SdcCsarPropertiesConstants() {} + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcHttpRestServiceProviderConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcHttpRestServiceProviderConfiguration.java new file mode 100644 index 0000000..f727e07 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcHttpRestServiceProviderConfiguration.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc; + +import java.util.Iterator; +import javax.net.ssl.SSLContext; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.HttpClients; +import org.onap.logging.filter.spring.SpringClientPayloadFilter; +import org.onap.so.cnfm.lcm.bpmn.flows.GsonProvider; +import org.onap.so.configuration.rest.HttpComponentsClientConfiguration; +import org.onap.so.logging.jaxrs.filter.SOSpringClientFilter; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.onap.so.rest.service.HttpRestServiceProviderImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class SdcHttpRestServiceProviderConfiguration { + + private static final Logger logger = LoggerFactory.getLogger(SdcHttpRestServiceProviderConfiguration.class); + + public static final String SDC_REST_TEMPLATE_CLIENT_BEAN = "SdcRestTemplateClientBean"; + public static final String SDC_HTTP_REST_SERVICE_PROVIDER_BEAN = "SdcHttpRestServiceProviderBean"; + + @Autowired + private GsonProvider gsonProvider; + + @Bean + @Qualifier(SDC_REST_TEMPLATE_CLIENT_BEAN) + public RestTemplate sdcAdapterRestTemplate( + @Autowired final HttpComponentsClientConfiguration httpComponentsClientConfiguration) { + + final HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = + httpComponentsClientConfiguration.httpComponentsClientHttpRequestFactory(); + + final RestTemplate restTemplate = + new RestTemplate(new BufferingClientHttpRequestFactory(clientHttpRequestFactory)); + restTemplate.getInterceptors().add(new SOSpringClientFilter()); + restTemplate.getInterceptors().add((new SpringClientPayloadFilter())); + return restTemplate; + + } + + @Bean + @Qualifier(SDC_HTTP_REST_SERVICE_PROVIDER_BEAN) + public HttpRestServiceProvider sdcHttpRestServiceProvider( + @Qualifier(SDC_REST_TEMPLATE_CLIENT_BEAN) @Autowired final RestTemplate restTemplate) { + + try { + logger.info("Setting SSLConnectionSocketFactory with Default SSL ..."); + final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(SSLContext.getDefault()); + final HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build(); + final HttpComponentsClientHttpRequestFactory factory = + new HttpComponentsClientHttpRequestFactory(httpClient); + restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory)); + } catch (final Exception exception) { + logger.error("Error reading truststore, TLS connection to SDC will fail.", exception); + } + setGsonMessageConverter(restTemplate); + + + return new HttpRestServiceProviderImpl(restTemplate); + } + + private void setGsonMessageConverter(final RestTemplate restTemplate) { + final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator(); + while (iterator.hasNext()) { + if (iterator.next() instanceof MappingJackson2HttpMessageConverter) { + iterator.remove(); + } + } + restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gsonProvider.getGson())); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProvider.java new file mode 100644 index 0000000..f75d5f5 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProvider.java @@ -0,0 +1,33 @@ +/*- + * ============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.sdc; + +import java.util.Optional; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public interface SdcPackageProvider { + + Optional<byte[]> getSdcResourcePackage(final String packageId); + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProviderImpl.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProviderImpl.java new file mode 100644 index 0000000..5e69661 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcPackageProviderImpl.java @@ -0,0 +1,80 @@ +/*- + * ============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.sdc; + +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcHttpRestServiceProviderConfiguration.SDC_HTTP_REST_SERVICE_PROVIDER_BEAN; +import java.util.Optional; +import org.onap.so.cnfm.lcm.bpmn.flows.exceptions.SdcPackageRequestFailureException; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class SdcPackageProviderImpl implements SdcPackageProvider { + private static final Logger logger = LoggerFactory.getLogger(SdcPackageProviderImpl.class); + private final SdcClientConfigurationProvider sdcClientConfigurationProvider; + private final HttpRestServiceProvider httpServiceProvider; + private static final String SERVICE_NAME = "SO-CNFM"; + + @Autowired + public SdcPackageProviderImpl(final SdcClientConfigurationProvider sdcClientConfigurationProvider, + @Qualifier(SDC_HTTP_REST_SERVICE_PROVIDER_BEAN) final HttpRestServiceProvider httpServiceProvider) { + this.sdcClientConfigurationProvider = sdcClientConfigurationProvider; + this.httpServiceProvider = httpServiceProvider; + } + + @Override + public Optional<byte[]> getSdcResourcePackage(final String packageId) { + try { + final HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.AUTHORIZATION, sdcClientConfigurationProvider.getBasicAuth()); + headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE); + headers.add("X-ECOMP-InstanceID", SERVICE_NAME); + headers.add("X-FromAppId", SERVICE_NAME); + + logger.info("Will retrieve resource package with id: {} from SDC", packageId); + final String url = sdcClientConfigurationProvider.getSdcPackageUrl(packageId); + + final ResponseEntity<byte[]> response = httpServiceProvider.getHttpResponse(url, headers, byte[].class); + if (response.getStatusCode().is2xxSuccessful()) { + if (response.hasBody()) { + return Optional.of(response.getBody()); + } + logger.error("Received response without body ..."); + } + return Optional.empty(); + } catch (final Exception restProcessingException) { + final String message = "Caught exception while getting resource package content for: " + packageId; + throw new SdcPackageRequestFailureException(message, restProcessingException); + } + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java new file mode 100644 index 0000000..c4bd210 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/JobExecutorService.java @@ -0,0 +1,376 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.service; + +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.CREATE_AS_REQUEST_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.INSTANTIATE_AS_REQUEST_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.JOB_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.OCC_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.TERMINATE_AS_REQUEST_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.CREATE_AS_WORKFLOW_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.DELETE_AS_WORKFLOW_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.INSTANTIATE_AS_WORKFLOW_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.TERMINATE_AS_WORKFLOW_NAME; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.ERROR; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.FINISHED; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.FINISHED_WITH_ERROR; +import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.IN_PROGRESS; +import static org.slf4j.LoggerFactory.getLogger; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.tuple.ImmutablePair; +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.database.beans.AsInst; +import org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc; +import org.onap.so.cnfm.lcm.database.beans.AsLcmOpType; +import org.onap.so.cnfm.lcm.database.beans.Job; +import org.onap.so.cnfm.lcm.database.beans.JobAction; +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.database.service.DatabaseServiceProvider; +import org.onap.so.cnfm.lcm.model.AsInstance; +import org.onap.so.cnfm.lcm.model.CreateAsRequest; +import org.onap.so.cnfm.lcm.model.ErrorDetails; +import org.onap.so.cnfm.lcm.model.InstantiateAsRequest; +import org.onap.so.cnfm.lcm.model.TerminateAsRequest; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import com.google.common.collect.ImmutableSet; +import com.google.gson.Gson; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class JobExecutorService { + + private static final Logger logger = getLogger(JobExecutorService.class); + + private static final ImmutableSet<JobStatusEnum> JOB_FINISHED_STATES = + ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR); + + private static final int SLEEP_TIME_IN_SECONDS = 5; + + @Value("${so-cnfm-lcm.requesttimeout.timeoutInSeconds:300}") + private int timeOutInSeconds; + + private final DatabaseServiceProvider databaseServiceProvider; + private final WorkflowExecutorService workflowExecutorService; + private final WorkflowQueryService workflowQueryService; + private final Gson gson; + + @Autowired + public JobExecutorService(final DatabaseServiceProvider databaseServiceProvider, + final WorkflowExecutorService workflowExecutorService, final WorkflowQueryService workflowQueryService, + final GsonProvider gsonProvider) { + this.databaseServiceProvider = databaseServiceProvider; + this.workflowExecutorService = workflowExecutorService; + this.workflowQueryService = workflowQueryService; + this.gson = gsonProvider.getGson(); + } + + public AsInstance runCreateAsJob(final CreateAsRequest createAsRequest) { + logger.info("Starting 'Create AS' workflow job for request:\n{}", createAsRequest); + final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.CREATE) + .resourceId(createAsRequest.getAsdId()).resourceName(createAsRequest.getAsInstanceName()) + .status(JobStatusEnum.STARTING); + databaseServiceProvider.addJob(newJob); + + logger.info("New job created in database :\n{}", newJob); + + workflowExecutorService.executeWorkflow(newJob.getJobId(), CREATE_AS_WORKFLOW_NAME, + getVariables(newJob.getJobId(), createAsRequest)); + + final ImmutablePair<String, JobStatusEnum> immutablePair = + waitForJobToFinish(newJob.getJobId(), JOB_FINISHED_STATES); + + if (immutablePair.getRight() == null) { + final String message = "Failed to create AS for request: \n" + createAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + final JobStatusEnum finalJobStatus = immutablePair.getRight(); + final String processInstanceId = immutablePair.getLeft(); + + if (!FINISHED.equals(finalJobStatus)) { + + final Optional<ErrorDetails> optional = workflowQueryService.getErrorDetails(processInstanceId); + if (optional.isPresent()) { + final ErrorDetails errorDetails = optional.get(); + final String message = + "Failed to create AS for request: \n" + createAsRequest + " due to \n" + errorDetails; + logger.error(message); + throw new AsRequestProcessingException(message, errorDetails); + } + + final String message = "Received unexpected Job Status: " + finalJobStatus + + " Failed to Create AS for request: \n" + createAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + logger.debug("Will query for CreateAsResponse using processInstanceId:{}", processInstanceId); + final Optional<AsInstance> optional = workflowQueryService.getCreateNsResponse(processInstanceId); + if (optional.isEmpty()) { + final String message = + "Unable to find CreateAsReponse in Camunda History for process instance: " + processInstanceId; + logger.error(message); + throw new AsRequestProcessingException(message); + } + return optional.get(); + } + + public String runInstantiateAsJob(final String asInstanceId, final InstantiateAsRequest instantiateAsRequest) { + final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.INSTANTIATE) + .resourceId(asInstanceId).status(JobStatusEnum.STARTING); + databaseServiceProvider.addJob(newJob); + logger.info("New job created in database :\n{}", newJob); + + final LocalDateTime currentDateTime = LocalDateTime.now(); + final AsLcmOpOcc newAsLcmOpOcc = new AsLcmOpOcc().id(asInstanceId).operation(AsLcmOpType.INSTANTIATE) + .operationState(OperationStateEnum.PROCESSING).stateEnteredTime(currentDateTime) + .startTime(currentDateTime).asInst(getAsInst(asInstanceId)).isAutoInvocation(false) + .isCancelPending(false).operationParams(gson.toJson(instantiateAsRequest)); + databaseServiceProvider.addAsLcmOpOcc(newAsLcmOpOcc); + logger.info("New AsLcmOpOcc created in database :\n{}", newAsLcmOpOcc); + + workflowExecutorService.executeWorkflow(newJob.getJobId(), INSTANTIATE_AS_WORKFLOW_NAME, + getVariables(asInstanceId, newJob.getJobId(), newAsLcmOpOcc.getId(), instantiateAsRequest)); + + final ImmutableSet<JobStatusEnum> jobFinishedStates = + ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); + final ImmutablePair<String, JobStatusEnum> immutablePair = + waitForJobToFinish(newJob.getJobId(), jobFinishedStates); + + if (immutablePair.getRight() == null) { + final String message = "Failed to Instantiate AS for request: \n" + instantiateAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + final JobStatusEnum finalJobStatus = immutablePair.getRight(); + if (IN_PROGRESS.equals(finalJobStatus) || FINISHED.equals(finalJobStatus)) { + logger.info("Instantiation Job status: {}", finalJobStatus); + return newAsLcmOpOcc.getId(); + } + + final String message = "Received unexpected Job Status: " + finalJobStatus + + " Failed to instantiate AS for request: \n" + instantiateAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + public String runTerminateAsJob(final String asInstanceId, final TerminateAsRequest terminateAsRequest) { + doInitialTerminateChecks(asInstanceId, terminateAsRequest); + + final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.TERMINATE) + .resourceId(asInstanceId).status(JobStatusEnum.STARTING); + databaseServiceProvider.addJob(newJob); + logger.info("New job created in database :\n{}", newJob); + + final LocalDateTime currentDateTime = LocalDateTime.now(); + final AsLcmOpOcc newAsLcmOpOcc = new AsLcmOpOcc().id(asInstanceId).operation(AsLcmOpType.TERMINATE) + .operationState(OperationStateEnum.PROCESSING).stateEnteredTime(currentDateTime) + .startTime(currentDateTime).asInst(getAsInst(asInstanceId)).isAutoInvocation(false) + .isCancelPending(false).operationParams(gson.toJson(terminateAsRequest)); + databaseServiceProvider.addAsLcmOpOcc(newAsLcmOpOcc); + logger.info("New AsLcmOpOcc created in database :\n{}", newAsLcmOpOcc); + + workflowExecutorService.executeWorkflow(newJob.getJobId(), TERMINATE_AS_WORKFLOW_NAME, + getVariables(asInstanceId, newJob.getJobId(), newAsLcmOpOcc.getId(), terminateAsRequest)); + + final ImmutableSet<JobStatusEnum> jobFinishedStates = + ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS); + final ImmutablePair<String, JobStatusEnum> immutablePair = + waitForJobToFinish(newJob.getJobId(), jobFinishedStates); + + if (immutablePair.getRight() == null) { + final String message = + "Failed to Terminate AS with id: " + asInstanceId + " for request: \n" + terminateAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + final JobStatusEnum finalJobStatus = immutablePair.getRight(); + + if (IN_PROGRESS.equals(finalJobStatus) || FINISHED.equals(finalJobStatus)) { + logger.info("Termination Job status: {}", finalJobStatus); + return newAsLcmOpOcc.getId(); + } + + final String message = "Received unexpected Job Status: " + finalJobStatus + " Failed to Terminate AS with id: " + + asInstanceId + " for request: \n" + terminateAsRequest; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + public void runDeleteAsJob(final String asInstanceId) { + final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.DELETE) + .resourceId(asInstanceId).status(JobStatusEnum.STARTING); + databaseServiceProvider.addJob(newJob); + logger.info("New job created in database :\n{}", newJob); + + workflowExecutorService.executeWorkflow(newJob.getJobId(), DELETE_AS_WORKFLOW_NAME, + getVariables(asInstanceId, newJob.getJobId())); + + final ImmutablePair<String, JobStatusEnum> immutablePair = + waitForJobToFinish(newJob.getJobId(), JOB_FINISHED_STATES); + + if (immutablePair.getRight() == null) { + final String message = "Failed to Delete AS with id: " + asInstanceId; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + final JobStatusEnum finalJobStatus = immutablePair.getRight(); + final String processInstanceId = immutablePair.getLeft(); + + logger.info("Delete Job status: {}", finalJobStatus); + + if (!FINISHED.equals(finalJobStatus)) { + + final Optional<ErrorDetails> optional = workflowQueryService.getErrorDetails(processInstanceId); + if (optional.isPresent()) { + final ErrorDetails errorDetails = optional.get(); + final String message = "Failed to Delete AS with id: " + asInstanceId + " due to \n" + errorDetails; + logger.error(message); + throw new AsRequestProcessingException(message, errorDetails); + } + + final String message = "Received unexpected Job Status: " + finalJobStatus + + " Failed to Delete AS with id: " + asInstanceId; + logger.error(message); + throw new AsRequestProcessingException(message); + } + + logger.debug("Delete AS finished successfully ..."); + } + + private AsInst getAsInst(final String asInstId) { + logger.info("Getting AsInst with nsInstId: {}", asInstId); + final Optional<AsInst> optionalNfvoNsInst = databaseServiceProvider.getAsInst(asInstId); + + if (optionalNfvoNsInst.isEmpty()) { + final String message = "No matching AS Instance for id: " + asInstId + " found in database."; + throw new AsRequestProcessingException(message); + } + + return optionalNfvoNsInst.get(); + } + + private ImmutablePair<String, JobStatusEnum> waitForJobToFinish(final String jobId, + final ImmutableSet<JobStatusEnum> jobFinishedStates) { + try { + final long startTimeInMillis = System.currentTimeMillis(); + final long timeOutTime = startTimeInMillis + TimeUnit.SECONDS.toMillis(timeOutInSeconds); + + logger.info("Will wait till {} for {} job to finish", Instant.ofEpochMilli(timeOutTime).toString(), jobId); + JobStatusEnum currentJobStatus = null; + while (timeOutTime > System.currentTimeMillis()) { + + final Optional<Job> optional = databaseServiceProvider.getRefreshedJob(jobId); + + if (optional.isEmpty()) { + logger.error("Unable to find Job using jobId: {}", jobId); + return ImmutablePair.nullPair(); + } + + final Job job = optional.get(); + currentJobStatus = job.getStatus(); + logger.debug("Received job status response: \n {}", job); + if (jobFinishedStates.contains(currentJobStatus)) { + logger.info("Job finished \n {}", currentJobStatus); + return ImmutablePair.of(job.getProcessInstanceId(), currentJobStatus); + } + + logger.info("Haven't received one of finish state {} yet, will try again in {} seconds", + jobFinishedStates, SLEEP_TIME_IN_SECONDS); + TimeUnit.SECONDS.sleep(SLEEP_TIME_IN_SECONDS); + + } + logger.warn("Timeout current job status: {}", currentJobStatus); + return ImmutablePair.nullPair(); + } catch (final InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + logger.error("Sleep was interrupted", interruptedException); + return ImmutablePair.nullPair(); + } + } + + private void doInitialTerminateChecks(final String asInstanceId, final TerminateAsRequest terminateAsRequest) { + final AsInst asInst = getAsInst(asInstanceId); + if (isNotInstantiated(asInst)) { + final String message = "TerminateAsRequest received: " + terminateAsRequest + " for asInstanceId: " + + asInstanceId + "\nUnable to terminate. AS Instance is already in " + State.NOT_INSTANTIATED + + " state." + "\nThis method can only be used with an AS instance in the " + State.INSTANTIATED + + " state."; + logger.error(message); + throw new AsRequestProcessingException(message); + } + } + + private boolean isNotInstantiated(final AsInst asInst) { + return State.NOT_INSTANTIATED.equals(asInst.getStatus()); + } + + private Map<String, Object> getVariables(final String jobId, final CreateAsRequest createAsRequest) { + final Map<String, Object> variables = new HashMap<>(); + variables.put(JOB_ID_PARAM_NAME, jobId); + variables.put(CREATE_AS_REQUEST_PARAM_NAME, createAsRequest); + return variables; + } + + private Map<String, Object> getVariables(final String asInstanceId, final String jobId, final String occId, + final InstantiateAsRequest instantiateAsRequest) { + final Map<String, Object> variables = new HashMap<>(); + variables.put(AS_INSTANCE_ID_PARAM_NAME, asInstanceId); + variables.put(JOB_ID_PARAM_NAME, jobId); + variables.put(OCC_ID_PARAM_NAME, occId); + variables.put(INSTANTIATE_AS_REQUEST_PARAM_NAME, instantiateAsRequest); + return variables; + } + + private Map<String, Object> getVariables(final String asInstanceId, final String jobId, final String occId, + final TerminateAsRequest terminateAsRequest) { + final Map<String, Object> variables = new HashMap<>(); + variables.put(AS_INSTANCE_ID_PARAM_NAME, asInstanceId); + variables.put(JOB_ID_PARAM_NAME, jobId); + variables.put(OCC_ID_PARAM_NAME, occId); + variables.put(TERMINATE_AS_REQUEST_PARAM_NAME, terminateAsRequest); + return variables; + } + + private Map<String, Object> getVariables(final String asInstanceId, final String jobId) { + final Map<String, Object> variables = new HashMap<>(); + variables.put(AS_INSTANCE_ID_PARAM_NAME, asInstanceId); + variables.put(JOB_ID_PARAM_NAME, jobId); + return variables; + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowExecutorService.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowExecutorService.java new file mode 100644 index 0000000..57a8a41 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowExecutorService.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.service; + +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.TENANT_ID; +import static org.slf4j.LoggerFactory.getLogger; +import java.util.Map; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.runtime.ProcessInstance; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class WorkflowExecutorService { + + private static final Logger logger = getLogger(WorkflowExecutorService.class); + + private final RuntimeService runtimeService; + + @Autowired + public WorkflowExecutorService(final RuntimeService runtimeService) { + this.runtimeService = runtimeService; + } + + @Async + public void executeWorkflow(final String jobId, final String processDefinitionKey, + final Map<String, Object> variables) { + logger.info("Executing {} workflow with business key: {}", processDefinitionKey, jobId); + final ProcessInstance processInstance = runtimeService.createProcessInstanceByKey(processDefinitionKey) + .businessKey(jobId).setVariables(variables).processDefinitionTenantId(TENANT_ID).execute(); + + logger.info("Workflow running with processInstanceId: {} and business key: {}", + processInstance.getProcessInstanceId(), processInstance.getBusinessKey()); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java new file mode 100644 index 0000000..b6dbd77 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/service/WorkflowQueryService.java @@ -0,0 +1,111 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.cnfm.lcm.bpmn.flows.service; + +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.CREATE_AS_RESPONSE_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.Constants.TENANT_ID; +import static org.slf4j.LoggerFactory.getLogger; +import java.util.Optional; +import org.camunda.bpm.engine.HistoryService; +import org.camunda.bpm.engine.ProcessEngineException; +import org.camunda.bpm.engine.history.HistoricVariableInstance; +import org.onap.so.cnfm.lcm.model.AsInstance; +import org.onap.so.cnfm.lcm.model.ErrorDetails; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.google.common.base.Strings; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class WorkflowQueryService { + + private static final Logger logger = getLogger(WorkflowQueryService.class); + + private final HistoryService camundaHistoryService; + + @Autowired + public WorkflowQueryService(final HistoryService camundaHistoryService) { + this.camundaHistoryService = camundaHistoryService; + } + + public Optional<AsInstance> getCreateNsResponse(final String processInstanceId) { + try { + + if (Strings.isNullOrEmpty(processInstanceId)) { + logger.error("Invalid processInstanceId: {}", processInstanceId); + return Optional.empty(); + } + + final HistoricVariableInstance historicVariableInstance = + getVariable(processInstanceId, CREATE_AS_RESPONSE_PARAM_NAME); + + if (historicVariableInstance != null) { + logger.info("Found HistoricVariableInstance : {}", historicVariableInstance); + final Object variableValue = historicVariableInstance.getValue(); + if (variableValue instanceof AsInstance) { + return Optional.ofNullable((AsInstance) variableValue); + } + logger.error("Unknown CreateAsResponse object type {} received value: {}", + historicVariableInstance.getValue() != null ? variableValue.getClass() : null, variableValue); + } + } catch (final ProcessEngineException processEngineException) { + logger.error("Unable to find {} variable using processInstanceId: {}", CREATE_AS_RESPONSE_PARAM_NAME, + processInstanceId, processEngineException); + } + logger.error("Unable to find {} variable using processInstanceId: {}", CREATE_AS_RESPONSE_PARAM_NAME, + processInstanceId); + return Optional.empty(); + + } + + public Optional<ErrorDetails> getErrorDetails(final String processInstanceId) { + try { + final HistoricVariableInstance historicVariableInstance = + getVariable(processInstanceId, AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME); + + logger.info("Found HistoricVariableInstance : {}", historicVariableInstance); + if (historicVariableInstance != null) { + final Object variableValue = historicVariableInstance.getValue(); + if (variableValue instanceof ErrorDetails) { + return Optional.ofNullable((ErrorDetails) variableValue); + } + logger.error("Unknown ErrorContents object type {} received value: {}", + historicVariableInstance.getValue() != null ? variableValue.getClass() : null, variableValue); + } + logger.error("Unable to retrieve HistoricVariableInstance value was null"); + } catch (final ProcessEngineException processEngineException) { + logger.error("Unable to find {} variable using processInstanceId: {}", + AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, processInstanceId, processEngineException); + } + return Optional.empty(); + } + + + private HistoricVariableInstance getVariable(final String processInstanceId, final String name) { + return camundaHistoryService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId) + .variableName(name).tenantIdIn(TENANT_ID).singleResult(); + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapter.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapter.java new file mode 100644 index 0000000..57a4dd6 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapter.java @@ -0,0 +1,59 @@ +/*- + * ============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.utils; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class LocalDateTimeTypeAdapter extends TypeAdapter<LocalDateTime> { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Override + public void write(final JsonWriter out, final LocalDateTime localDateTime) throws IOException { + if (localDateTime == null) { + out.nullValue(); + } else { + out.value(FORMATTER.format(localDateTime)); + } + } + + @Override + public LocalDateTime read(final JsonReader in) throws IOException { + if (JsonToken.NULL == in.peek()) { + in.nextNull(); + return null; + + } + final String dateTime = in.nextString(); + return LocalDateTime.parse(dateTime, FORMATTER); + + } + +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapter.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapter.java new file mode 100644 index 0000000..1f63cc1 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapter.java @@ -0,0 +1,68 @@ +/*- + * ============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.utils; + +import java.io.IOException; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class OffsetDateTimeTypeAdapter extends TypeAdapter<OffsetDateTime> { + + private DateTimeFormatter formatter; + + public OffsetDateTimeTypeAdapter() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + public OffsetDateTimeTypeAdapter(final DateTimeFormatter formatter) { + this.formatter = formatter; + } + + @Override + public void write(final JsonWriter out, final OffsetDateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public OffsetDateTime read(final JsonReader in) throws IOException { + if (JsonToken.NULL == in.peek()) { + in.nextNull(); + return null; + + } + String date = in.nextString(); + if (date.endsWith("+0000")) { + date = date.substring(0, date.length() - 5) + "Z"; + } + return OffsetDateTime.parse(date, formatter); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java new file mode 100644 index 0000000..4cc1f8a --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverter.java @@ -0,0 +1,59 @@ +/*- + * ============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.utils; + +import java.util.Map; +import java.util.TreeMap; +import org.springframework.stereotype.Service; +import org.yaml.snakeyaml.Yaml; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ + +@Service +public class PropertiesToYamlConverter { + public String getValuesYamlFileContent(final Map<String, String> lifeCycleParams) { + final Map<String, Object> root = new TreeMap<>(); + lifeCycleParams.entrySet().stream().forEach(entry -> processProperty(root, entry.getKey(), entry.getValue())); + final Yaml yaml = new Yaml(); + return yaml.dumpAsMap(root); + } + + @SuppressWarnings("unchecked") + private void processProperty(final Map<String, Object> root, final String key, final String value) { + Map<String, Object> local = root; + final String[] keys = key.split("\\."); + final int lastIndex = keys.length - 1; + for (int index = 0; index < lastIndex; index++) { + final String currentKey = keys[index]; + if (!local.containsKey(currentKey)) { + final Map<String, Object> subMap = new TreeMap<>(); + local.put(currentKey, subMap); + local = subMap; + continue; + } else { + local = (Map<String, Object>) local.get(currentKey); + } + } + local.put(keys[lastIndex], value); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/META-INF/services/org.onap.so.client.RestProperties b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/META-INF/services/org.onap.so.client.RestProperties new file mode 100644 index 0000000..90c1ca7 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/META-INF/services/org.onap.so.client.RestProperties @@ -0,0 +1 @@ +org.onap.so.cnfm.lcm.bpmn.flows.extclients.aai.AaiPropertiesImpl
\ No newline at end of file |