diff options
Diffstat (limited to 'so-cnfm')
43 files changed, 3047 insertions, 16 deletions
diff --git a/so-cnfm/so-cnfm-lcm/pom.xml b/so-cnfm/so-cnfm-lcm/pom.xml index 4d6df9e..ad758d1 100644 --- a/so-cnfm/so-cnfm-lcm/pom.xml +++ b/so-cnfm/so-cnfm-lcm/pom.xml @@ -14,5 +14,6 @@ <modules> <module>so-cnfm-lcm-api</module> <module>so-cnfm-lcm-database-service</module> + <module>so-cnfm-lcm-bpmn-flows</module> </modules> </project>
\ No newline at end of file diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/pom.xml b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/pom.xml new file mode 100644 index 0000000..3982680 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/pom.xml @@ -0,0 +1,145 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId> + <artifactId>so-cnfm-lcm</artifactId> + <version>1.9.0-SNAPSHOT</version> + </parent> + + <artifactId>so-cnfm-lcm-bpmn-flows</artifactId> + <name>SO CNFM LCM BPMN Flows</name> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <so.log.level>DEBUG</so.log.level> + </systemPropertyVariables> + <rerunFailingTestsCount>2</rerunFailingTestsCount> + <parallel>suites</parallel> + <useUnlimitedThreads>false</useUnlimitedThreads> + <threadCount>1</threadCount> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId> + <artifactId>so-cnfm-lcm-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId> + <artifactId>so-cnfm-lcm-database-service</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so</groupId> + <artifactId>aai-client</artifactId> + <version>${so-core-version}</version> + </dependency> + <dependency> + <groupId>org.onap.aai.schema-service</groupId> + <artifactId>aai-schema</artifactId> + </dependency> + <dependency> + <groupId>org.camunda.bpm.springboot</groupId> + <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId> + <exclusions> + <exclusion> + <groupId>org.camunda.bpmn</groupId> + <artifactId>camunda-engine-rest-core</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + </dependency> + <dependency> + <groupId>com.shazam</groupId> + <artifactId>shazamcrest</artifactId> + <version>${snakeyaml-version}</version> + <exclusions> + <exclusion> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </exclusion> + <exclusion> + <groupId>com.vaadin.external.google</groupId> + <artifactId>android-json</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>nl.jqno.equalsverifier</groupId> + <artifactId>equalsverifier</artifactId> + <version>${equalsverifier-version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-contract-wiremock</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.so</groupId> + <artifactId>common</artifactId> + <version>${so-core-version}</version> + <exclusions> + <exclusion> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-catalina</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>io.kubernetes</groupId> + <artifactId>client-java</artifactId> + <version>${kubernetes-client-version}</version> + <exclusions> + <exclusion> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib-common</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib</artifactId> + <version>${kotlin-stdlib-version}</version> + </dependency> + </dependencies> +</project>
\ No newline at end of file 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 diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java new file mode 100644 index 0000000..7de9bdc --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/extclients/sdc/SdcCsarPackageParserTest.java @@ -0,0 +1,83 @@ +/*- + * ============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.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.APPLICATION_NAME_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_ID_PARAM_NAME; +import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_INVARIANT_ID_PARAM_NAME; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import org.junit.Test; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class SdcCsarPackageParserTest { + + private static final String RESOURCE_ASD_PACKAGE_CSAR_PATH = + "src/test/resources/resource-Generatedasdpackage-csar.csar"; + + @Test + public void testResourceAsdCsar() throws IOException { + final SdcCsarPackageParser objUnderTest = new SdcCsarPackageParser(); + + final byte[] content = getFileContent(Paths.get(getAbsolutePath(RESOURCE_ASD_PACKAGE_CSAR_PATH))); + + final Map<String, Object> properties = objUnderTest.getAsdProperties(content); + assertEquals("123e4567-e89b-12d3-a456-426614174000", properties.get(DESCRIPTOR_ID_PARAM_NAME)); + assertEquals("123e4yyy-e89b-12d3-a456-426614174abc", properties.get(DESCRIPTOR_INVARIANT_ID_PARAM_NAME)); + assertEquals("SampleApp", properties.get(APPLICATION_NAME_PARAM_NAME)); + assertEquals("2.3", properties.get(SdcCsarPropertiesConstants.APPLICATION_VERSION_PARAM_NAME)); + assertEquals("MyCompany", properties.get(SdcCsarPropertiesConstants.PROVIDER_PARAM_NAME)); + + @SuppressWarnings("unchecked") + final List<DeploymentItem> items = + (List<DeploymentItem>) properties.get(SdcCsarPropertiesConstants.DEPLOYMENT_ITEMS_PARAM_NAME); + assertNotNull(items); + assertTrue(items.size() == 2); + + DeploymentItem deploymentItem = items.get(0); + assertEquals("sampleapp-db", deploymentItem.getName()); + assertEquals("1", deploymentItem.getItemId()); + assertEquals("1", deploymentItem.getDeploymentOrder()); + assertEquals("Artifacts/Deployment/HELM/sampleapp-db-operator-helm.tgz", deploymentItem.getFile()); + + + } + + private String getAbsolutePath(final String path) { + final File file = new File(path); + return file.getAbsolutePath(); + } + + private byte[] getFileContent(final Path path) throws IOException { + return Files.readAllBytes(path); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapterTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapterTest.java new file mode 100644 index 0000000..3015d87 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/LocalDateTimeTypeAdapterTest.java @@ -0,0 +1,64 @@ +/*- + * ============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 static org.junit.Assert.assertEquals; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.time.LocalDateTime; +import org.junit.Test; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class LocalDateTimeTypeAdapterTest { + private static final LocalDateTime LOCAL_DATETIME_VALUE = LocalDateTime.of(2023, 1, 1, 12, 0, 15); + private static final String STRING_VALUE = "\"2023-01-01 12:00:15\""; + + @Test + public void testReadWithValidLocalDateTimeString() throws IOException { + final LocalDateTimeTypeAdapter objUnderTest = new LocalDateTimeTypeAdapter(); + + final Reader reader = new StringReader(STRING_VALUE); + final JsonReader jsonReader = new JsonReader(reader); + + final LocalDateTime actual = objUnderTest.read(jsonReader); + assertEquals(LOCAL_DATETIME_VALUE, actual); + + } + + @Test + public void testWritedWithValidLocalDateTime() throws IOException { + final LocalDateTimeTypeAdapter objUnderTest = new LocalDateTimeTypeAdapter(); + + final StringWriter writer = new StringWriter(); + final JsonWriter jsonWriter = new JsonWriter(writer); + + objUnderTest.write(jsonWriter, LOCAL_DATETIME_VALUE); + assertEquals(STRING_VALUE, writer.toString()); + + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapterTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapterTest.java new file mode 100644 index 0000000..0adbef0 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/OffsetDateTimeTypeAdapterTest.java @@ -0,0 +1,66 @@ +/*- + * ============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 static org.junit.Assert.assertEquals; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import org.junit.Test; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class OffsetDateTimeTypeAdapterTest { + private static final OffsetDateTime OFF_SET_DATETIME_VALUE = + OffsetDateTime.of(2023, 1, 1, 12, 00, 15, 0, ZoneOffset.UTC); + private static final String STRING_VALUE = "\"2023-01-01T12:00:15Z\""; + + @Test + public void testReadWithValidOffsetDateTimeString() throws IOException { + final OffsetDateTimeTypeAdapter objUnderTest = new OffsetDateTimeTypeAdapter(); + + final Reader reader = new StringReader(STRING_VALUE); + final JsonReader jsonReader = new JsonReader(reader); + + final OffsetDateTime actual = objUnderTest.read(jsonReader); + assertEquals(OFF_SET_DATETIME_VALUE, actual); + + } + + @Test + public void testWritedWithValidOffsetDateTime() throws IOException { + final OffsetDateTimeTypeAdapter objUnderTest = new OffsetDateTimeTypeAdapter(); + + final StringWriter writer = new StringWriter(); + final JsonWriter jsonWriter = new JsonWriter(writer); + + objUnderTest.write(jsonWriter, OFF_SET_DATETIME_VALUE); + assertEquals(STRING_VALUE, writer.toString()); + + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverterTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverterTest.java new file mode 100644 index 0000000..2410d73 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/utils/PropertiesToYamlConverterTest.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.utils; + +import static org.junit.Assert.assertEquals; +import java.util.Map; +import org.junit.Test; + +/** + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class PropertiesToYamlConverterTest { + + @Test + public void testGetValuesYamlFileContent() { + final String expected = "primary:\n" + " service:\n" + " nodePorts:\n" + " mysql: '1234'\n" + + " ports:\n" + " mysql: dummy\n"; + final PropertiesToYamlConverter objUnderTest = new PropertiesToYamlConverter(); + final Map<String, String> lifeCycleParams = + Map.of("primary.service.ports.mysql", "dummy", "primary.service.nodePorts.mysql", "1234"); + final String actual = objUnderTest.getValuesYamlFileContent(lifeCycleParams); + + assertEquals(expected, actual); + + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml new file mode 100644 index 0000000..404bbdb --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml @@ -0,0 +1,52 @@ +# Copyright © 2022 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. +spring: + main: + allow-bean-definition-overriding: true + datasource: + hikari: + camunda: + jdbcUrl: jdbc:h2:mem:example-simple;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + driver-class-name: org.h2.Driver + pool-name: cnfm-lcm-bpmn-pool + registerMbeans: true + cnfm: + jdbcUrl: jdbc:h2:mem:nfvo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS cnfm;MODE=MYSQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE + driver-class-name: org.h2.Driver + pool-name: cnfm-lcm-bpmn-pool + registerMbeans: true + jpa: + generate-ddl: true + hibernate: + ddl-auto: create +hibernate: + dialect: org.hibernate.dialect.H2Dialect + hbm2ddl: + auto: create +aai: + version: v19 + endpoint: http://localhost:${wiremock.server.port} +sdc: + endpoint: http://localhost:${wiremock.server.port} +logging: + level: + org.reflections.Reflections: ERROR +cnfm: + kube-configs-dir: ${java.io.tmpdir}/kube-configs + csar: + dir: ${java.io.tmpdir} +kubernetes: + client: + http-request: + timeoutSeconds: 1
\ No newline at end of file diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json new file mode 100644 index 0000000..042247f --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/request.json @@ -0,0 +1,25 @@ +{ + "deploymentItems": [ + { + "deploymentItemsId": "1", + "lifecycleParameterKeyValues": { + ".Values.primary.service.ports.mysql": "dummy", + ".Values.primary.service.nodePorts.mysql": "dummy" + } + }, + { + "deploymentItemsId": "2", + "lifecycleParameterKeyValues": { + + } + } + ], + "asdExtCpdInputParams": { + "extCpdId": null, + "loadbalanceIP": null, + "externalIPs": [], + "nadNames": [], + "nadNamespace": null + }, + "additionalParams": {} +}
\ No newline at end of file diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/resource-Generatedasdpackage-csar.csar b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/resource-Generatedasdpackage-csar.csar Binary files differnew file mode 100644 index 0000000..b3c629d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/resource-Generatedasdpackage-csar.csar diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/AsLifecycleParam.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/AsLifecycleParam.java index 607886c..ed8b098 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/AsLifecycleParam.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/AsLifecycleParam.java @@ -54,7 +54,7 @@ public class AsLifecycleParam { private String lifecycleParam; public AsLifecycleParam() { - + // default constructor } public void setAsLifecycleParamId(final Integer asLifecycleParamId) { diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/utils/Utils.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/utils/Utils.java index 4d40087..5e1c638 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/utils/Utils.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/beans/utils/Utils.java @@ -40,19 +40,20 @@ public class Utils { return second == null; } - if (first.isEmpty()) { - return second.isEmpty(); + if (second == null) { + return false; + } + + if (first.size() != second.size()) { + return false; } - if ((first != null && second != null) && (first.size() == second.size())) { - for (int index = 0; index < first.size(); index++) { - if (!Objects.equals(first.get(index), second.get(index))) { - return false; - } - } - return true; + for (int index = 0; index < first.size(); index++) { + if (!Objects.equals(first.get(index), second.get(index))) { + return false; + } } - return false; + return true; } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/config/CnfmDatabaseConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/config/CnfmDatabaseConfiguration.java index 62a90f8..043b846 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/config/CnfmDatabaseConfiguration.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/main/java/org/onap/so/cnfm/lcm/database/config/CnfmDatabaseConfiguration.java @@ -55,9 +55,6 @@ public class CnfmDatabaseConfiguration { private static final String PERSISTENCE_UNIT = "cnfm"; private static final String CNFM_DATA_SOURCE_QUALIFIER = "cnfmDataSource"; - @Autowired(required = false) - private MBeanExporter mBeanExporter; - @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari.cnfm") public HikariConfig cnfmDbConfig() { @@ -68,7 +65,7 @@ public class CnfmDatabaseConfiguration { @Primary @FlywayDataSource @Bean(name = CNFM_DATA_SOURCE_QUALIFIER) - public DataSource dataSource() { + public DataSource dataSource(@Autowired(required = false) final MBeanExporter mBeanExporter) { if (mBeanExporter != null) { mBeanExporter.addExcludedBean(CNFM_DATA_SOURCE_QUALIFIER); } diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/beans/utils/UtilsTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/beans/utils/UtilsTest.java index ab24f94..9d9714e 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/beans/utils/UtilsTest.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/beans/utils/UtilsTest.java @@ -50,6 +50,11 @@ public class UtilsTest { public void testNullListAndEmptyList_notEqual() { assertFalse(Utils.isEquals(null, Collections.emptyList())); } + + @Test + public void testEmptyListAndNullList_notEqual() { + assertFalse(Utils.isEquals(Collections.emptyList(), null)); + } @Test public void testTwoNotEmptyListsContainSameObjects_equal() { diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/service/DatabaseServiceProviderTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/service/DatabaseServiceProviderTest.java index d353ea6..4397fb5 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/service/DatabaseServiceProviderTest.java +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-database-service/src/test/java/org/onap/so/cnfm/lcm/database/service/DatabaseServiceProviderTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. + * 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. |