diff options
Diffstat (limited to 'a1-policy-management')
12 files changed, 249 insertions, 17 deletions
diff --git a/a1-policy-management/config/application.yaml b/a1-policy-management/config/application.yaml index a40f172f..e1a778c3 100644 --- a/a1-policy-management/config/application.yaml +++ b/a1-policy-management/config/application.yaml @@ -74,4 +74,5 @@ app: http.proxy-type: HTTP # path where the service can store data vardata-directory: /var/policy-management-service + config-file-schema-path: diff --git a/a1-policy-management/config/application_configuration.json b/a1-policy-management/config/application_configuration.json index 6c21b166..6187c866 100644 --- a/a1-policy-management/config/application_configuration.json +++ b/a1-policy-management/config/application_configuration.json @@ -1,6 +1,6 @@ { - "config": { - "//description": "Application configuration", + "description": "Application configuration", + "config": { "controller": [ { "name": "controller1", @@ -21,4 +21,4 @@ } ] } -}
\ No newline at end of file +} diff --git a/a1-policy-management/pom.xml b/a1-policy-management/pom.xml index 4e3a9bd7..221cc081 100644 --- a/a1-policy-management/pom.xml +++ b/a1-policy-management/pom.xml @@ -223,6 +223,12 @@ <version>${commons-io.version}</version> <scope>test</scope> </dependency> + <!-- https://mvnrepository.com/artifact/com.github.erosb/everit-json-schema --> + <dependency> + <groupId>com.github.erosb</groupId> + <artifactId>everit-json-schema</artifactId> + <version>1.13.0</version> + </dependency> </dependencies> <build> <plugins> @@ -427,4 +433,4 @@ </plugin> </plugins> </build> -</project> +</project>
\ No newline at end of file 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 3a245190..40988e44 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 @@ -45,6 +45,10 @@ public class ApplicationConfig { private String localConfigurationFilePath; @Getter + @Value("${app.config-file-schema-path:\"\"}") + private String configurationFileSchemaPath; + + @Getter @Value("${app.vardata-directory:null}") private String vardataDirectory; diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParser.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParser.java index a6af2023..3cab8aa0 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParser.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParser.java @@ -24,6 +24,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -38,6 +42,7 @@ import javax.validation.constraints.NotNull; import org.immutables.gson.Gson; import org.immutables.value.Value; +import org.json.JSONObject; import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,6 +55,11 @@ public class ApplicationConfigParser { private static final String CONFIG = "config"; private static final String CONTROLLER = "controller"; + private final ApplicationConfig applicationConfig; + + public ApplicationConfigParser(ApplicationConfig applicationConfig) { + this.applicationConfig = applicationConfig; + } @Value.Immutable @Gson.TypeAdapters @@ -66,6 +76,8 @@ public class ApplicationConfigParser { public ConfigParserResult parse(JsonObject root) throws ServiceException { + validateJsonObjectAgainstSchema(root); + String dmaapProducerTopicUrl = ""; String dmaapConsumerTopicUrl = ""; @@ -97,6 +109,35 @@ public class ApplicationConfigParser { .build(); } + private void validateJsonObjectAgainstSchema(Object object) throws ServiceException { + if (applicationConfig.getConfigurationFileSchemaPath() == null + || applicationConfig.getConfigurationFileSchemaPath().isEmpty()) { + return; + } + + try { + String schemaAsString = readSchemaFile(); + + JSONObject schemaJSON = new JSONObject(schemaAsString); + var schema = org.everit.json.schema.loader.SchemaLoader.load(schemaJSON); + + String objectAsString = object.toString(); + JSONObject json = new JSONObject(objectAsString); + schema.validate(json); + } catch (Exception e) { + throw new ServiceException("Json schema validation failure: " + e.toString()); + } + } + + private String readSchemaFile() throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + String filePath = applicationConfig.getConfigurationFileSchemaPath(); + URL url = classLoader.getResource(filePath); + File file = new File(url.getFile()); + return new String(Files.readAllBytes(file.toPath())); + + } + private void checkConfigurationConsistency(List<RicConfig> ricConfigs, Map<String, ControllerConfig> controllerConfigs) throws ServiceException { Set<String> ricUrls = new HashSet<>(); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationController.java index b677a405..e07ea284 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationController.java @@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import java.io.IOException; import java.util.Optional; +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ConfigurationFile; import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse; @@ -57,11 +58,17 @@ public class ConfigurationController { public static final String API_NAME = "Management of configuration"; public static final String API_DESCRIPTION = ""; - @Autowired - ConfigurationFile configurationFile; + private final ConfigurationFile configurationFile; + private final RefreshConfigTask refreshConfigTask; + private final ApplicationConfig applicationConfig; - @Autowired - RefreshConfigTask refreshConfigTask; + ConfigurationController(@Autowired ConfigurationFile configurationFile, + @Autowired RefreshConfigTask refreshConfigTask, @Autowired ApplicationConfig applicationConfig) { + this.configurationFile = configurationFile; + this.refreshConfigTask = refreshConfigTask; + this.applicationConfig = applicationConfig; + + } private static Gson gson = new GsonBuilder() // .create(); // @@ -85,7 +92,7 @@ public class ConfigurationController { validateConfigFileIsUsed(); String configAsString = gson.toJson(configuration); JsonObject configJson = JsonParser.parseString(configAsString).getAsJsonObject(); - ApplicationConfigParser configParser = new ApplicationConfigParser(); + ApplicationConfigParser configParser = new ApplicationConfigParser(applicationConfig); configParser.parse(configJson); configurationFile.writeFile(configJson); logger.info("Configuration changed through REST call."); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java index 30279815..6177ee1b 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java @@ -189,7 +189,7 @@ public class RefreshConfigTask { private Mono<ApplicationConfigParser.ConfigParserResult> parseConfiguration(JsonObject jsonObject) { try { - ApplicationConfigParser parser = new ApplicationConfigParser(); + ApplicationConfigParser parser = new ApplicationConfigParser(this.appConfig); return Mono.just(parser.parse(jsonObject)); } catch (Exception e) { String str = e.toString(); diff --git a/a1-policy-management/src/main/resources/application_configuration_schema.json b/a1-policy-management/src/main/resources/application_configuration_schema.json new file mode 100644 index 00000000..05135e7c --- /dev/null +++ b/a1-policy-management/src/main/resources/application_configuration_schema.json @@ -0,0 +1,151 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "config": { + "type": "object", + "properties": { + "//description": { + "type": "string" + }, + "description": { + "type": "string" + }, + "controller": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "baseUrl": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "name", + "baseUrl", + "userName", + "password" + ], + "additionalProperties": false + } + ] + }, + "ric": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "baseUrl": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "managedElementIds": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "name", + "baseUrl", + "managedElementIds" + ], + "additionalProperties": false + } + ] + }, + "streams_publishes": { + "type": "object", + "properties": { + "dmaap_publisher": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "dmaap_info": { + "type": "object", + "properties": { + "topic_url": { + "type": "string" + } + }, + "required": [ + "topic_url" + ] + } + }, + "required": [ + "type", + "dmaap_info" + ] + } + }, + "required": [ + "dmaap_publisher" + ] + }, + "streams_subscribes": { + "type": "object", + "properties": { + "dmaap_subscriber": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "dmaap_info": { + "type": "object", + "properties": { + "topic_url": { + "type": "string" + } + }, + "required": [ + "topic_url" + ] + } + }, + "required": [ + "type", + "dmaap_info" + ] + } + }, + "required": [ + "dmaap_subscriber" + ] + } + }, + "required": [ + "ric" + ], + "additionalProperties": false + } + }, + "required": [ + "config" + ] +}
\ No newline at end of file diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java index 5e218582..d12fd6bc 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java @@ -20,8 +20,11 @@ package org.onap.ccsdk.oran.a1policymanagementservice.configuration; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import com.google.common.base.Charsets; import com.google.common.io.Resources; @@ -44,12 +47,16 @@ import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException class ApplicationConfigParserTest { - ApplicationConfigParser parserUnderTest = new ApplicationConfigParser(); + ApplicationConfig applicationConfigMock = spy(new ApplicationConfig()); + ApplicationConfigParser parserUnderTest = new ApplicationConfigParser(applicationConfigMock); @Test void whenCorrectConfig() throws Exception { JsonObject jsonRootObject = getJsonRootObject(); + when(applicationConfigMock.getConfigurationFileSchemaPath()) + .thenReturn("application_configuration_schema.json"); + ApplicationConfigParser.ConfigParserResult result = parserUnderTest.parse(jsonRootObject); String topicUrl = result.dmaapProducerTopicUrl(); @@ -153,6 +160,19 @@ class ApplicationConfigParserTest { assertEquals(message, actualException.getMessage(), "Wrong error message when wrong member name in object"); } + @Test + void schemaValidationError() throws Exception { + when(applicationConfigMock.getConfigurationFileSchemaPath()) + .thenReturn("application_configuration_schema.json"); + JsonObject jsonRootObject = getJsonRootObject(); + JsonObject json = jsonRootObject.getAsJsonObject("config"); + json.remove("ric"); + + Exception actualException = assertThrows(ServiceException.class, () -> parserUnderTest.parse(jsonRootObject)); + + assertThat(actualException.getMessage()).contains("Json schema validation failure"); + } + JsonObject getDmaapInfo(JsonObject jsonRootObject, String streamsPublishesOrSubscribes, String dmaapPublisherOrSubscriber) throws Exception { return jsonRootObject.getAsJsonObject("config").getAsJsonObject(streamsPublishesOrSubscribes) diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationControllerTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationControllerTest.java index adb29a70..d2805556 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationControllerTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationControllerTest.java @@ -60,7 +60,9 @@ import reactor.test.StepVerifier; @TestPropertySource(properties = { // "server.ssl.key-store=./config/keystore.jks", // "app.webclient.trust-store=./config/truststore.jks", // - "app.vardata-directory=./target"}) + "app.vardata-directory=./target", // + "app.config-file-schema-path=application_configuration_schema.json" // +}) class ConfigurationControllerTest { @Autowired ApplicationContext context; @@ -135,8 +137,7 @@ class ConfigurationControllerTest { String url = "a1-policy/v2/configuration"; // Valid JSON but invalid configuration. - testErrorCode(restClient().put(url, "{\"error\":\"error\"}"), HttpStatus.BAD_REQUEST, - "Missing root configuration"); + testErrorCode(restClient().put(url, "{\"error\":\"error\"}"), HttpStatus.BAD_REQUEST, ""); } private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) { diff --git a/a1-policy-management/src/test/resources/test_application_configuration.json b/a1-policy-management/src/test/resources/test_application_configuration.json index 3cbc371c..959f53fd 100644 --- a/a1-policy-management/src/test/resources/test_application_configuration.json +++ b/a1-policy-management/src/test/resources/test_application_configuration.json @@ -1,6 +1,6 @@ -{ +{ "config": { - "//description": "Application configuration", + "description": "Application configuration", "ric": [ { "name": "ric1", @@ -36,4 +36,4 @@ } } } -}
\ No newline at end of file +} diff --git a/a1-policy-management/src/test/resources/test_application_configuration_with_dmaap_config.json b/a1-policy-management/src/test/resources/test_application_configuration_with_dmaap_config.json index ed1501dd..b00720c3 100644 --- a/a1-policy-management/src/test/resources/test_application_configuration_with_dmaap_config.json +++ b/a1-policy-management/src/test/resources/test_application_configuration_with_dmaap_config.json @@ -1,5 +1,6 @@ { "config": { + "//description" : "Test", "controller": [ { "name": "controller1", |