diff options
23 files changed, 1077 insertions, 114 deletions
diff --git a/a1-policy-management/config/application.yaml b/a1-policy-management/config/application.yaml index 39b44863..205c21a1 100644 --- a/a1-policy-management/config/application.yaml +++ b/a1-policy-management/config/application.yaml @@ -3,6 +3,7 @@ # ONAP : ccsdk oran # ================================================================================ # Copyright (C) 2020-2023 Nordix Foundation. All rights reserved. +# Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,95 +20,84 @@ # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END========================================================= # -spring: - application: - name: a1-pms - profiles: - active: prod - main: - allow-bean-definition-overriding: true - aop: - auto: false -management: - tracing: - propagation: - produce: ${ONAP_PROPAGATOR_PRODUCE:[W3C]} - sampling: - probability: 1.0 - endpoints: - web: - exposure: - # Enabling of springboot actuator features. See springboot documentation. - include: "loggers,logfile,health,info,metrics,threaddump,heapdump,shutdown" - endpoint: - shutdown: - enabled: true -lifecycle: - timeout-per-shutdown-phase: "20s" -springdoc: - show-actuator: true -logging: - # Configuration of logging - level: - ROOT: ERROR - org.springframework: ERROR - org.springframework.data: ERROR - org.springframework.web.reactive.function.client.ExchangeFunctions: ERROR - org.springframework.web.servlet.DispatcherServlet: ERROR - org.onap.ccsdk.oran.a1policymanagementservice: INFO - pattern: - console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{20} - %msg%n" - file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{20} - %msg%n" - file: - name: /var/log/policy-agent/application.log -server: - # Configuration of the HTTP/REST server. The parameters are defined and handeled by the springboot framework. - # See springboot documentation. - port : 8433 - http-port: 8081 - shutdown: "graceful" - ssl: - key-store-type: JKS - key-store-password: policy_agent - key-store: /opt/app/policy-agent/etc/cert/keystore.jks - key-password: policy_agent - key-alias: policy_agent - # trust-store-password: - # trust-store: + app: - # Location of the component configuration file. - filepath: /opt/app/policy-agent/data/application_configuration.json - webclient: - # Configuration of the trust store used for the HTTP client (outgoing requests) - # The file location and the password for the truststore is only relevant if trust-store-used == true - # Note that the same keystore as for the server is used. - trust-store-used: false - trust-store-password: policy_agent - trust-store: /opt/app/policy-agent/etc/cert/truststore.jks - # Configuration of usage of HTTP Proxy for the southbound accesses. - # The HTTP proxy (if configured) will only be used for accessing NearRT RIC:s - # proxy-type can be either HTTP, SOCKS4 or SOCKS5 - http.proxy-host: - http.proxy-port: 0 - http.proxy-type: HTTP - # path where the service can store data. This parameter is not relevant if S3 Object store is configured. - vardata-directory: /var/policy-management-service - # the config-file-schema-path referres to a location in the jar file. If this property is empty or missing, - # no schema validation will be executed. - config-file-schema-path: /application_configuration_schema.json # A file containing an authorization token, which shall be inserted in each HTTP header (authorization). # If the file name is empty, no authorization token is sent. auth-token-file: # A URL to authorization provider such as OPA. Each time an A1 Policy is accessed, a call to this # authorization provider is done for access control. If this is empty, no fine grained access control is done. authorization-provider: + # the config-file-schema-path referres to a location in the jar file. If this property is empty or missing, + # no schema validation will be executed. + config-file-schema-path: /application_configuration_schema.json + # Postgres database usage is enabled using the below parameter. + # If this is enabled, the application will use postgres database for storage. + # This overrides the s3(s3.bucket) or file store(vardata-directory) configuration if enabled. + database-enabled: false + # Location of the component configuration file. + filepath: /opt/app/policy-agent/data/application_configuration.json # S3 object store usage is enabled by defining the bucket to use. This will override the vardata-directory parameter. s3: endpointOverride: http://localhost:9000 accessKeyId: minio secretAccessKey: miniostorage bucket: + webclient: + # Configuration of usage of HTTP Proxy for the southbound accesses. + # The HTTP proxy (if configured) will only be used for accessing NearRT RIC:s + # proxy-type can be either HTTP, SOCKS4 or SOCKS5 + http.proxy-host: + http.proxy-port: 0 + http.proxy-type: HTTP + # Configuration of the trust store used for the HTTP client (outgoing requests) + # The file location and the password for the truststore is only relevant if trust-store-used == true + # Note that the same keystore as for the server is used. + trust-store-used: false + trust-store-password: policy_agent + trust-store: /opt/app/policy-agent/etc/cert/truststore.jks + # path where the service can store data. This parameter is not relevant if S3 Object store is configured. + vardata-directory: /var/policy-management-service +lifecycle: + timeout-per-shutdown-phase: "20s" +logging: + # Configuration of logging + file: + name: /var/log/policy-agent/application.log + level: + ROOT: ERROR + org.onap.ccsdk.oran.a1policymanagementservice: INFO + org.springframework: ERROR + org.springframework.data: ERROR + org.springframework.web.reactive.function.client.ExchangeFunctions: ERROR + org.springframework.web.servlet.DispatcherServlet: ERROR + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{20} - %msg%n" + file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{20} - %msg%n" +management: + endpoint: + shutdown: + enabled: true + endpoints: + web: + exposure: + # Enabling of springboot actuator features. See springboot documentation. + include: "loggers,logfile,health,info,metrics,threaddump,heapdump,shutdown" + tracing: + propagation: + produce: ${ONAP_PROPAGATOR_PRODUCE:[W3C]} + sampling: + probability: 1.0 otel: + exporter: + otlp: + traces: + endpoint: ${ONAP_OTEL_EXPORTER_ENDPOINT:http://jaeger:4317} + protocol: ${ONAP_OTEL_EXPORTER_PROTOCOL:grpc} + logs: + exporter: none + metrics: + exporter: none sdk: disabled: ${ONAP_SDK_DISABLED:true} south: ${ONAP_TRACING_SOUTHBOUND:true} @@ -115,12 +105,44 @@ otel: sampler: jaeger_remote: endpoint: ${ONAP_OTEL_SAMPLER_JAEGER_REMOTE_ENDPOINT:http://jaeger:14250} - exporter: - otlp: - traces: - protocol: ${ONAP_OTEL_EXPORTER_PROTOCOL:grpc} - endpoint: ${ONAP_OTEL_EXPORTER_ENDPOINT:http://jaeger:4317} - metrics: - exporter: none - logs: - exporter: none +server: + # Configuration of the HTTP/REST server. The parameters are defined and handeled by the springboot framework. + # See springboot documentation. + port : 8433 + http-port: 8081 + shutdown: "graceful" + ssl: + key-store-type: JKS + key-store-password: policy_agent + key-store: /opt/app/policy-agent/etc/cert/keystore.jks + key-password: policy_agent + key-alias: policy_agent + # trust-store-password: + # trust-store: +spring: + aop: + auto: false + application: + name: a1-pms + flyway: + # Configuration of the postgres database to be used for database migration. + # This is where the flyway maintains the information about the sql files loaded. + # These values can be passed via configmap/secret/env variable based on the installation. + # By default, Flyway uses location classpath:db/migration to load the sql files. + # This can be overridden using "flyway.locations" to have a different location. + baseline-on-migrate: true + url: "jdbc:postgresql://127.0.0.1:5432/a1pms" + user: a1pms + password: mypwd + main: + allow-bean-definition-overriding: true + profiles: + active: prod + r2dbc: + # Configuration of the postgres database to be used by the application. + # These values can be passed via configmap/secret/env variable based on the installation. + url: "r2dbc:postgresql://127.0.0.1:5432/a1pms" + username: a1pms + password: mypwd +springdoc: + show-actuator: true
\ No newline at end of file diff --git a/a1-policy-management/pom.xml b/a1-policy-management/pom.xml index 46e0ec35..1455bad1 100644 --- a/a1-policy-management/pom.xml +++ b/a1-policy-management/pom.xml @@ -94,6 +94,24 @@ <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-r2dbc</artifactId> + </dependency> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>r2dbc-postgresql</artifactId> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>org.flywaydb</groupId> + <artifactId>flyway-core</artifactId> + </dependency> + <dependency> <!-- May be possible to remove this later when ccsdk parent bom stabilizes --> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java index 71eae06f..4d1fa331 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java @@ -3,6 +3,7 @@ * ONAP : ccsdk oran * ====================================================================== * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. + * Copyright (C) 2023-2024 OpenInfra Foundation Europe. All rights reserved. * ====================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +21,11 @@ package org.onap.ccsdk.oran.a1policymanagementservice; - import org.apache.catalina.connector.Connector; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; -import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies; -import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics; -import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory; @@ -54,25 +51,6 @@ public class BeanFactory { } @Bean - public Services getServices(@Autowired ApplicationConfig applicationConfig) { - Services services = new Services(applicationConfig); - services.restoreFromDatabase().subscribe(); - return services; - } - - @Bean - public PolicyTypes getPolicyTypes(@Autowired ApplicationConfig applicationConfig) { - PolicyTypes types = new PolicyTypes(applicationConfig); - types.restoreFromDatabase().blockLast(); - return types; - } - - @Bean - public Policies getPolicies(@Autowired ApplicationConfig applicationConfig) { - return new Policies(applicationConfig); - } - - @Bean public A1ClientFactory getA1ClientFactory(@Autowired ApplicationConfig applicationConfig, @Autowired SecurityContext securityContext) { return new A1ClientFactory(applicationConfig, securityContext); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/DatabaseIndependentBeanFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/DatabaseIndependentBeanFactory.java new file mode 100644 index 00000000..305499d0 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/DatabaseIndependentBeanFactory.java @@ -0,0 +1,57 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice; + +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(prefix = "app", name = "database-enabled", havingValue = "false") +@EnableAutoConfiguration(exclude = { R2dbcAutoConfiguration.class, FlywayAutoConfiguration.class }) +public class DatabaseIndependentBeanFactory { + @Bean + public Services getServices(@Autowired ApplicationConfig applicationConfig) { + Services services = new Services(applicationConfig); + services.restoreFromDatabase().subscribe(); + return services; + } + + @Bean + public PolicyTypes getPolicyTypes(@Autowired ApplicationConfig applicationConfig) { + PolicyTypes types = new PolicyTypes(applicationConfig); + types.restoreFromDatabase().blockLast(); + return types; + } + + @Bean + public Policies getPolicies(@Autowired ApplicationConfig applicationConfig) { + return new Policies(applicationConfig); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/SpringContextProvider.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/SpringContextProvider.java new file mode 100644 index 00000000..925e0c57 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/SpringContextProvider.java @@ -0,0 +1,41 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class SpringContextProvider implements ApplicationContextAware { + private static ApplicationContext localApplicationContext; + + @SuppressWarnings("java:S2696") + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + localApplicationContext = applicationContext; + } + + public static ApplicationContext getSpringContext() { + return localApplicationContext; + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java index 3de674bd..d3b51461 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java @@ -3,6 +3,7 @@ * ONAP : ccsdk oran * ====================================================================== * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. + * Copyright (C) 2023-2024 OpenInfra Foundation Europe. All rights reserved. * ====================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,6 +105,11 @@ public class ApplicationConfig { @Value("${app.authorization-provider:}") private String authProviderUrl; + @Getter + @Setter + @Value("${app.database-enabled:}") + private boolean databaseEnabled; + private Map<String, RicConfig> ricConfigs = new HashMap<>(); private WebClientConfig webClientConfig = null; @@ -188,4 +194,8 @@ public class ApplicationConfig { public boolean isS3Enabled() { return !(Strings.isNullOrEmpty(s3EndpointOverride) || Strings.isNullOrEmpty(s3Bucket)); } + + public boolean isDatabaseEnabled() { + return databaseEnabled; + } } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/DatabaseDependentBeanFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/DatabaseDependentBeanFactory.java new file mode 100644 index 00000000..f463ecd0 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/DatabaseDependentBeanFactory.java @@ -0,0 +1,57 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database; + +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; + +@Configuration +@ConditionalOnProperty(prefix = "app", name = "database-enabled", havingValue = "true") +public class DatabaseDependentBeanFactory { + @Bean + @DependsOn({ "springContextProvider", "flywayInitializer" }) + public Services getServices(@Autowired ApplicationConfig applicationConfig) { + Services services = new Services(applicationConfig); + services.restoreFromDatabase().subscribe(); + return services; + } + + @Bean + @DependsOn({ "springContextProvider", "flywayInitializer" }) + public PolicyTypes getPolicyTypes(@Autowired ApplicationConfig applicationConfig) { + PolicyTypes types = new PolicyTypes(applicationConfig); + types.restoreFromDatabase().blockLast(); + return types; + } + + @Bean + @DependsOn({ "springContextProvider", "flywayInitializer" }) + public Policies getPolicies(@Autowired ApplicationConfig applicationConfig) { + return new Policies(applicationConfig); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/BaseSchema.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/BaseSchema.java new file mode 100644 index 00000000..0713cdd3 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/BaseSchema.java @@ -0,0 +1,50 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.entities; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; + +@RequiredArgsConstructor +public class BaseSchema implements Persistable<String> { + @Id + final String id; + @Getter + final String payload; + + @Transient + @Setter + boolean isNew = true; + + @Override + public String getId() { + return id; + } + + @Override + public boolean isNew() { + return isNew; + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Policy.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Policy.java new file mode 100644 index 00000000..e3e61d3b --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Policy.java @@ -0,0 +1,30 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.entities; + +import org.springframework.data.relational.core.mapping.Table; + +@Table("policies") +public class Policy extends BaseSchema { + public Policy(String id, String payload) { + super(id, payload); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/PolicyType.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/PolicyType.java new file mode 100644 index 00000000..8dca3ce5 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/PolicyType.java @@ -0,0 +1,30 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.entities; + +import org.springframework.data.relational.core.mapping.Table; + +@Table("policy_types") +public class PolicyType extends BaseSchema { + public PolicyType(String id, String payload) { + super(id, payload); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Service.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Service.java new file mode 100644 index 00000000..cc402854 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/entities/Service.java @@ -0,0 +1,30 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.entities; + +import org.springframework.data.relational.core.mapping.Table; + +@Table("services") +public class Service extends BaseSchema { + public Service(String id, String payload) { + super(id, payload); + } +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PoliciesRepository.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PoliciesRepository.java new file mode 100644 index 00000000..0fb6c55e --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PoliciesRepository.java @@ -0,0 +1,29 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.repositories; + +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Policy; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import reactor.core.publisher.Flux; + +public interface PoliciesRepository extends ReactiveCrudRepository<Policy, String> { + Flux<Policy> findByIdStartingWith(String prefix); +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PolicyTypesRepository.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PolicyTypesRepository.java new file mode 100644 index 00000000..2083a9fc --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/PolicyTypesRepository.java @@ -0,0 +1,27 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.repositories; + +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.PolicyType; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface PolicyTypesRepository extends ReactiveCrudRepository<PolicyType, String> { +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/ServicesRepository.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/ServicesRepository.java new file mode 100644 index 00000000..97259694 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/database/repositories/ServicesRepository.java @@ -0,0 +1,27 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.database.repositories; + +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Service; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface ServicesRepository extends ReactiveCrudRepository<Service, String> { +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DataStore.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DataStore.java index 51b57dee..4f0a98e2 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DataStore.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DataStore.java @@ -21,9 +21,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.datastore; import com.google.common.base.Strings; - import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -42,7 +40,9 @@ public interface DataStore { public Mono<String> deleteAllObjects(); public static DataStore create(ApplicationConfig appConfig, String location) { - if (appConfig.isS3Enabled()) { + if (appConfig.isDatabaseEnabled()) { + return new DatabaseStore(location); + } else if (appConfig.isS3Enabled()) { return new S3ObjectStore(appConfig, location); } else if (!Strings.isNullOrEmpty(appConfig.getVardataDirectory())) { return new FileStore(appConfig, location); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStore.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStore.java new file mode 100644 index 00000000..5c0d00da --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStore.java @@ -0,0 +1,148 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.datastore; + +import java.lang.invoke.MethodHandles; +import org.onap.ccsdk.oran.a1policymanagementservice.SpringContextProvider; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.BaseSchema; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Policy; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.PolicyType; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Service; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.PoliciesRepository; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.PolicyTypesRepository; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.ServicesRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class DatabaseStore implements DataStore { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final String OK = "OK"; + + private final OperationTarget operationTarget; + private final PoliciesRepository policiesRepository; + private final ServicesRepository servicesRepository; + private final PolicyTypesRepository policyTypesRepository; + + private enum OperationTarget { + POLICYTYPES, + SERVICES, + POLICIES + } + + public DatabaseStore(String target) { + this.operationTarget = OperationTarget.valueOf(target.toUpperCase()); + this.policiesRepository = SpringContextProvider.getSpringContext().getBean(PoliciesRepository.class); + this.servicesRepository = SpringContextProvider.getSpringContext().getBean(ServicesRepository.class); + this.policyTypesRepository = SpringContextProvider.getSpringContext().getBean(PolicyTypesRepository.class); + } + + @Override + public Flux<String> listObjects(String prefix) { + logger.debug("Listing objects for prefix {} and target {}", prefix, operationTarget.name()); + return Flux.just(operationTarget).flatMap(localOperationTarget -> { + if (localOperationTarget == OperationTarget.POLICIES) { + return policiesRepository.findByIdStartingWith(prefix).map(BaseSchema::getId); + } else if (localOperationTarget == OperationTarget.POLICYTYPES) { + return policyTypesRepository.findAll().map(BaseSchema::getId); + } else { + return servicesRepository.findAll().map(BaseSchema::getId); + } + }); + } + + @Override + public Mono<byte[]> readObject(String name) { + logger.debug("Reading object {} for target {}", name, operationTarget.name()); + return Mono.just(operationTarget).flatMap(localOperationTarget -> { + if (localOperationTarget == OperationTarget.POLICIES) { + return policiesRepository.findById(name).map(policy -> policy.getPayload().getBytes()); + } else if (localOperationTarget == OperationTarget.POLICYTYPES) { + return policyTypesRepository.findById(name).map(policyType -> policyType.getPayload().getBytes()); + } else { + return servicesRepository.findById(name).map(service -> service.getPayload().getBytes()); + } + }); + } + + @Override + public Mono<byte[]> writeObject(String name, byte[] fileData) { + logger.debug("Writing object {} for target {}", name, operationTarget.name()); + return Mono.just(operationTarget).flatMap(localOperationTarget -> { + if (localOperationTarget == OperationTarget.POLICIES) { + return policiesRepository.findById(name).map(policy -> Boolean.FALSE).defaultIfEmpty(Boolean.TRUE) + .flatMap(isNewPolicy -> { + Policy policy = new Policy(name, new String(fileData)); + policy.setNew(isNewPolicy); + return policiesRepository.save(policy).map(savedPolicy -> fileData); + }); + } else if (localOperationTarget == OperationTarget.POLICYTYPES) { + return policyTypesRepository.findById(name).map(policyType -> Boolean.FALSE).defaultIfEmpty(Boolean.TRUE) + .flatMap(isNewPolicyType -> { + PolicyType policyType = new PolicyType(name, new String(fileData)); + policyType.setNew(isNewPolicyType); + return policyTypesRepository.save(policyType).map(savedPolicyType -> fileData); + }); + } else { + return servicesRepository.findById(name).map(service -> Boolean.FALSE).defaultIfEmpty(Boolean.TRUE) + .flatMap(isNewService -> { + Service service = new Service(name, new String(fileData)); + service.setNew(isNewService); + return servicesRepository.save(service).map(savedService -> fileData); + }); + } + }); + } + + @Override + public Mono<Boolean> deleteObject(String name) { + logger.debug("Deleting object {} for target {}", name, operationTarget.name()); + return Mono.just(operationTarget).flatMap(localOperationTarget -> { + if (localOperationTarget == OperationTarget.POLICIES) { + return policiesRepository.deleteById(name).thenReturn(Boolean.TRUE); + } else if (localOperationTarget == OperationTarget.POLICYTYPES) { + return policyTypesRepository.deleteById(name).thenReturn(Boolean.TRUE); + } else { + return servicesRepository.deleteById(name).thenReturn(Boolean.TRUE); + } + }); + } + + @Override + public Mono<String> createDataStore() { + return Mono.just(OK); + } + + @Override + public Mono<String> deleteAllObjects() { + logger.debug("Deleting All objects for target {}", operationTarget.name()); + return Mono.just(operationTarget).flatMap(localOperationTarget -> { + if (localOperationTarget == OperationTarget.POLICIES) { + return policiesRepository.deleteAll().thenReturn(OK); + } else if (localOperationTarget == OperationTarget.POLICYTYPES) { + return policyTypesRepository.deleteAll().thenReturn(OK); + } else { + return servicesRepository.deleteAll().thenReturn(OK); + } + }); + } +} diff --git a/a1-policy-management/src/main/resources/db/migration/V1__create_base_schema.sql b/a1-policy-management/src/main/resources/db/migration/V1__create_base_schema.sql new file mode 100644 index 00000000..a6d49989 --- /dev/null +++ b/a1-policy-management/src/main/resources/db/migration/V1__create_base_schema.sql @@ -0,0 +1,35 @@ +-- ============LICENSE_START======================================================= +-- Copyright (C) 2024 OpenInfra Foundation Europe +-- ================================================================================ +-- 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========================================================= + +CREATE TABLE IF NOT EXISTS policies ( + id varchar NOT NULL, + payload varchar NOT NULL, + CONSTRAINT policies_pk PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS policy_types ( + id varchar NOT NULL, + payload varchar NOT NULL, + CONSTRAINT policy_types_pk PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS services ( + id varchar NOT NULL, + payload varchar NOT NULL, + CONSTRAINT services_pk PRIMARY KEY (id) +);
\ No newline at end of file diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java index ac9d1fba..555f4639 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClientResponseException; @@ -40,6 +41,7 @@ import reactor.util.Loggers; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +@SpringBootTest class AsyncRestClientTest { private static final String BASE_URL = "BaseUrl"; private static final String REQUEST_URL = "/test"; diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStoreTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStoreTest.java new file mode 100644 index 00000000..31797c49 --- /dev/null +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/DatabaseStoreTest.java @@ -0,0 +1,371 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ +package org.onap.ccsdk.oran.a1policymanagementservice.datastore; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.ccsdk.oran.a1policymanagementservice.SpringContextProvider; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.BaseSchema; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Policy; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.PolicyType; +import org.onap.ccsdk.oran.a1policymanagementservice.database.entities.Service; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.PoliciesRepository; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.PolicyTypesRepository; +import org.onap.ccsdk.oran.a1policymanagementservice.database.repositories.ServicesRepository; +import org.springframework.context.ApplicationContext; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@ExtendWith(MockitoExtension.class) +public class DatabaseStoreTest { + + public static final String OK = "OK"; + @Mock + PoliciesRepository policiesRepository; + @Mock + ServicesRepository servicesRepository; + @Mock + PolicyTypesRepository policyTypesRepository; + @Mock + ApplicationContext applicationContext; + @InjectMocks + SpringContextProvider springContextProvider; + + private enum OperationTarget { + POLICYTYPES("policytypes"), + SERVICES("services"), + POLICIES("policies"); + + final String label; + + OperationTarget(String label) { + this.label = label; + } + } + + @BeforeEach + void initialize() { + when(applicationContext.getBean(PoliciesRepository.class)).thenReturn(policiesRepository); + when(applicationContext.getBean(PolicyTypesRepository.class)).thenReturn(policyTypesRepository); + when(applicationContext.getBean(ServicesRepository.class)).thenReturn(servicesRepository); + springContextProvider.setApplicationContext(applicationContext); + } + + @Test + void testCreateDataStore() { + DatabaseStore databaseStore = new DatabaseStore(OperationTarget.POLICYTYPES.name()); + StepVerifier.create(databaseStore.createDataStore()).expectNext(OK).verifyComplete(); + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testListObjectsSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + String prefix = "ric1"; + Policy policy1 = new Policy(prefix + "/listpolicy1.json", "{}"); + Policy policy2 = new Policy(prefix + "/listpolicy2.json", "{}"); + when(policiesRepository.findByIdStartingWith(any())).thenReturn(Flux.just(policy1, policy2)); + StepVerifier.create(databaseStore.listObjects(prefix)).expectNext(policy1.getId()).expectNext(policy2.getId()) + .verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + PolicyType policyType1 = new PolicyType("/listpolicytype1.json", "{}"); + PolicyType policyType2 = new PolicyType("/listpolicytype2.json", "{}"); + when(policyTypesRepository.findAll()).thenReturn(Flux.just(policyType1, policyType2)); + StepVerifier.create(databaseStore.listObjects("")).expectNext(policyType1.getId()) + .expectNext(policyType2.getId()).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + Service service1 = new Service("/listservice1.json", "{}"); + Service service2 = new Service("/listservice2.json", "{}"); + when(servicesRepository.findAll()).thenReturn(Flux.just(service1, service2)); + StepVerifier.create(databaseStore.listObjects("")).expectNext(service1.getId()).expectNext(service2.getId()) + .verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testListObjectsFailure(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + String errorMessage = "Unable to list the objects of type " + operationTarget.name(); + if (operationTarget == OperationTarget.POLICIES) { + String prefix = "ric1"; + when(policiesRepository.findByIdStartingWith(any())).thenReturn(Flux.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.listObjects(prefix)).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + when(policyTypesRepository.findAll()).thenReturn(Flux.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.listObjects("")).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.SERVICES) { + when(servicesRepository.findAll()).thenReturn(Flux.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.listObjects("")).expectErrorMessage(errorMessage).verify(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testReadObjectSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/readpolicy1.json"; + String policyPayload = "{\"name\":\"readpolicy1\"}"; + Policy policy1 = new Policy(policyName, policyPayload); + when(policiesRepository.findById(anyString())).thenReturn(Mono.just(policy1)); + StepVerifier.create(databaseStore.readObject(policyName)).consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyPayload.getBytes()); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "readpolicytype1.json"; + String policyTypePayload = "{\"name\":\"readpolicytype1\"}"; + PolicyType policyType1 = new PolicyType(policyTypeName, policyTypePayload); + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.just(policyType1)); + StepVerifier.create(databaseStore.readObject(policyTypeName)).consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyTypePayload.getBytes()); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "readservice1.json"; + String servicePayload = "{\"name\":\"readservice1\"}"; + Service service1 = new Service(serviceName, servicePayload); + when(servicesRepository.findById(anyString())).thenReturn(Mono.just(service1)); + StepVerifier.create(databaseStore.readObject(serviceName)).consumeNextWith(bytes -> { + assertArrayEquals(bytes, servicePayload.getBytes()); + }).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testReadObjectFailure(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + String errorMessage = "Unable to read the objects of type " + operationTarget.name(); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/readpolicy1.json"; + when(policiesRepository.findById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.readObject(policyName)).expectErrorMessage(errorMessage).verify(); + when(policiesRepository.findById(anyString())).thenReturn(Mono.empty()); + StepVerifier.create(databaseStore.readObject(policyName)).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "readpolicytype1.json"; + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.readObject(policyTypeName)).expectErrorMessage(errorMessage).verify(); + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.empty()); + StepVerifier.create(databaseStore.readObject(policyTypeName)).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "readservice1.json"; + when(servicesRepository.findById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.readObject(serviceName)).expectErrorMessage(errorMessage).verify(); + when(servicesRepository.findById(anyString())).thenReturn(Mono.empty()); + StepVerifier.create(databaseStore.readObject(serviceName)).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testWriteObjectInsertSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/writeinserpolicy1.json"; + String policyPayload = "{\"name\":\"writeinserpolicy1\"}"; + Policy policy1 = new Policy(policyName, policyPayload); + when(policiesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(policiesRepository.save(any(Policy.class))).thenReturn(Mono.just(policy1)); + StepVerifier.create(databaseStore.writeObject(policyName, policyPayload.getBytes())).consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyPayload.getBytes()); + verify(policiesRepository).save(argThat(BaseSchema::isNew)); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "writeinsertpolicytype1.json"; + String policyTypePayload = "{\"name\":\"writeinsertpolicytype1\"}"; + PolicyType policyType1 = new PolicyType(policyTypeName, policyTypePayload); + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(policyTypesRepository.save(any(PolicyType.class))).thenReturn(Mono.just(policyType1)); + StepVerifier.create(databaseStore.writeObject(policyTypeName, policyTypePayload.getBytes())) + .consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyTypePayload.getBytes()); + verify(policyTypesRepository).save(argThat(BaseSchema::isNew)); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "writeinsertservice1.json"; + String servicePayload = "{\"name\":\"writeinsertservice1\"}"; + Service service1 = new Service(serviceName, servicePayload); + when(servicesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(servicesRepository.save(any(Service.class))).thenReturn(Mono.just(service1)); + StepVerifier.create(databaseStore.writeObject(serviceName, servicePayload.getBytes())) + .consumeNextWith(bytes -> { + assertArrayEquals(bytes, servicePayload.getBytes()); + verify(servicesRepository).save(argThat(BaseSchema::isNew)); + }).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testWriteObjectUpdateSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/writeupdatepolicy1.json"; + String policyPayload = "{\"name\":\"writeupdatepolicy1\"}"; + Policy policy1 = new Policy(policyName, policyPayload); + when(policiesRepository.findById(anyString())).thenReturn(Mono.just(policy1)); + when(policiesRepository.save(any(Policy.class))).thenReturn(Mono.just(policy1)); + StepVerifier.create(databaseStore.writeObject(policyName, policyPayload.getBytes())).consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyPayload.getBytes()); + verify(policiesRepository).save(argThat(policy -> !policy.isNew())); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "writeupdatepolicytype1.json"; + String policyTypePayload = "{\"name\":\"writeupdatepolicytype1\"}"; + PolicyType policyType1 = new PolicyType(policyTypeName, policyTypePayload); + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.just(policyType1)); + when(policyTypesRepository.save(any(PolicyType.class))).thenReturn(Mono.just(policyType1)); + StepVerifier.create(databaseStore.writeObject(policyTypeName, policyTypePayload.getBytes())) + .consumeNextWith(bytes -> { + assertArrayEquals(bytes, policyTypePayload.getBytes()); + verify(policyTypesRepository).save(argThat(policy -> !policy.isNew())); + }).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "writeupdateservice1.json"; + String servicePayload = "{\"name\":\"writeupdateservice1\"}"; + Service service1 = new Service(serviceName, servicePayload); + when(servicesRepository.findById(anyString())).thenReturn(Mono.just(service1)); + when(servicesRepository.save(any(Service.class))).thenReturn(Mono.just(service1)); + StepVerifier.create(databaseStore.writeObject(serviceName, servicePayload.getBytes())) + .consumeNextWith(bytes -> { + assertArrayEquals(bytes, servicePayload.getBytes()); + verify(servicesRepository).save(argThat(policy -> !policy.isNew())); + }).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testWriteObjectFailure(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + String errorMessage = "Unable to write the objects of type " + operationTarget.name(); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/writepolicy1.json"; + String policyPayload = "{\"name\":\"writepolicy1\"}"; + when(policiesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(policiesRepository.save(any(Policy.class))).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.writeObject(policyName, policyPayload.getBytes())) + .expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "writepolicytype1.json"; + String policyTypePayload = "{\"name\":\"writepolicytype1\"}"; + when(policyTypesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(policyTypesRepository.save(any(PolicyType.class))).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.writeObject(policyTypeName, policyTypePayload.getBytes())) + .expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "writeservice1.json"; + String servicePayload = "{\"name\":\"writeservice1\"}"; + when(servicesRepository.findById(anyString())).thenReturn(Mono.empty()); + when(servicesRepository.save(any(Service.class))).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.writeObject(serviceName, servicePayload.getBytes())) + .expectErrorMessage(errorMessage).verify(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testDeleteObjectSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/deletepolicy1.json"; + when(policiesRepository.deleteById(anyString())).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteObject(policyName)).expectNext(true).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "deletepolicytype1.json"; + when(policyTypesRepository.deleteById(anyString())).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteObject(policyTypeName)).expectNext(true).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "deleteservice1.json"; + when(servicesRepository.deleteById(anyString())).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteObject(serviceName)).expectNext(true).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testDeleteObjectFailure(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + String errorMessage = "Unable to delete the objects of type " + operationTarget.name(); + if (operationTarget == OperationTarget.POLICIES) { + String policyName = "ric1/deletepolicy1.json"; + when(policiesRepository.deleteById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteObject(policyName)).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + String policyTypeName = "deletepolicytype1.json"; + when(policyTypesRepository.deleteById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteObject(policyTypeName)).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.SERVICES) { + String serviceName = "deleteservice1.json"; + when(servicesRepository.deleteById(anyString())).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteObject(serviceName)).expectErrorMessage(errorMessage).verify(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testDeleteAllObjectSuccess(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + if (operationTarget == OperationTarget.POLICIES) { + when(policiesRepository.deleteAll()).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteAllObjects()).expectNext(OK).verifyComplete(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + when(policyTypesRepository.deleteAll()).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteAllObjects()).expectNext(OK).verifyComplete(); + } else if (operationTarget == OperationTarget.SERVICES) { + when(servicesRepository.deleteAll()).thenReturn(Mono.just("").then()); + StepVerifier.create(databaseStore.deleteAllObjects()).expectNext(OK).verifyComplete(); + } + } + + @ParameterizedTest + @EnumSource(OperationTarget.class) + void testDeleteAllObjectFailure(OperationTarget operationTarget) { + DatabaseStore databaseStore = new DatabaseStore(operationTarget.name()); + String errorMessage = "Unable to delete all the objects of type " + operationTarget.name(); + if (operationTarget == OperationTarget.POLICIES) { + when(policiesRepository.deleteAll()).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteAllObjects()).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.POLICYTYPES) { + when(policyTypesRepository.deleteAll()).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteAllObjects()).expectErrorMessage(errorMessage).verify(); + } else if (operationTarget == OperationTarget.SERVICES) { + when(servicesRepository.deleteAll()).thenReturn(Mono.error(new Throwable(errorMessage))); + StepVerifier.create(databaseStore.deleteAllObjects()).expectErrorMessage(errorMessage).verify(); + } + } + +}
\ No newline at end of file diff --git a/csit/scripts/healthcheck/test/pms_a1sim_sdnc.sh b/csit/scripts/healthcheck/test/pms_a1sim_sdnc.sh index 79c08b63..be2bc578 100755 --- a/csit/scripts/healthcheck/test/pms_a1sim_sdnc.sh +++ b/csit/scripts/healthcheck/test/pms_a1sim_sdnc.sh @@ -1,7 +1,8 @@ #!/bin/bash # ============LICENSE_START=============================================== -# Copyright (C) 2021 Nordix Foundation. All rights reserved. +# Copyright (C) 2021-2023 Nordix Foundation. All rights reserved. +# Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved. # ======================================================================== # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/docs/consumedapis/consumedapis.rst b/docs/consumedapis/consumedapis.rst index 274dceec..d5dcf4e7 100755..100644 --- a/docs/consumedapis/consumedapis.rst +++ b/docs/consumedapis/consumedapis.rst @@ -16,7 +16,7 @@ O-RAN A1 Interface for A1 Policies (A1-P) Southbound, the ONAP A1 Policy functions communicate with *near-RT RIC* RAN functions using the **A1** interface, as defined by the `O-RAN Alliance <https://www.o-ran.org>`_ The *A1 Interface - Application Protocol Specification (A1-AP)* describes this interface. The specification can be viewed from the `O-RAN Alliance <https://www.o-ran.org>`_ website. -The **Montreal** ONAP A1 Policy functions implement the *A1 Policy* (*A1-P*) parts of A1-AP, supporting versions *v1.1*, *v2.0* and *v3.0*. +The **Oslo** ONAP A1 Policy functions implement the *A1 Policy* (*A1-P*) parts of A1-AP, supporting versions *v1.1*, *v2.0* and *v3.0*. An opensource implementation of a `near-RT RIC <https://lf-o-ran-sc.atlassian.net/wiki/spaces/RICP/overview>`_ is available from the `O-RAN Software Community <https://o-ran-sc.org>`_. It supports a pre-spec version of the A1-AP. The ONAP A1 Policy functions described here also supports this A1 version (*A1-OSC*). diff --git a/docs/guide/developer-guide.rst b/docs/guide/developer-guide.rst index bb737441..ef73af6b 100644 --- a/docs/guide/developer-guide.rst +++ b/docs/guide/developer-guide.rst @@ -10,7 +10,7 @@ Developer Guide This document provides a quickstart for developers of the CCSDK functions for O-RAN A1 Policies. -.. image:: ../media/ONAP-A1ControllerArchitecture-Montreal.png +.. image:: ../media/ONAP-A1ControllerArchitecture-NewDelhi.png :width: 500pt Source tree @@ -64,7 +64,7 @@ There are two configuration files for A1 Policy Management Service, *config/appl The first (*config/application_configuration.json*) contains application-specific configuration needed by the application, such as which near-RT RICs, or controller to use. The second (*config/application.yaml*) contains logging and security configurations. -For more information about these configuration files can be found as comments in the sample files provided with the source code, or on the `ONAP wiki <https://wiki.onap.org/display/DW/O-RAN+A1+Policies+in+ONAP+London>`_ +For more information about these configuration files can be found as comments in the sample files provided with the source code, or on the `ONAP wiki <https://wiki.onap.org/display/DW/O-RAN+A1+Policies+in+ONAP>`_ Static configuration - Settings that cannot be changed at runtime (*application.yaml*) -------------------------------------------------------------------------------------- diff --git a/docs/media/ONAP-A1ControllerArchitecture-NewDelhi.png b/docs/media/ONAP-A1ControllerArchitecture-NewDelhi.png Binary files differnew file mode 100644 index 00000000..15580c87 --- /dev/null +++ b/docs/media/ONAP-A1ControllerArchitecture-NewDelhi.png |