diff options
5 files changed, 212 insertions, 19 deletions
diff --git a/netconfsimulator/src/it/java/integration/NetconfFunctionsIT.java b/netconfsimulator/src/it/java/integration/NetconfFunctionsIT.java index 5d1a25a..495714b 100644 --- a/netconfsimulator/src/it/java/integration/NetconfFunctionsIT.java +++ b/netconfsimulator/src/it/java/integration/NetconfFunctionsIT.java @@ -53,6 +53,10 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(BeforeAfterSpringTestRunner.class) public class NetconfFunctionsIT { + private static final String NEW_YANG_MODEL_NAME = "newyangmodel"; + private static final String NEW_YANG_MODEL_FILE = "newYangModel.yang"; + private static final String INITIAL_CONFIG_XML_FILE = "initialConfig.xml"; + private static final String CONFIG_NAME = "config2"; private static NetconfSimulatorClient client; private static ObjectMapper objectMapper; @@ -104,7 +108,7 @@ public class NetconfFunctionsIT { public void testShouldLoadModelEditConfigurationAndDeleteModule() throws IOException { // do load try (CloseableHttpResponse response = client - .loadModel("newyangmodel", "newYangModel.yang", "initialConfig.xml")) { + .loadModel(NEW_YANG_MODEL_NAME, NEW_YANG_MODEL_FILE, INITIAL_CONFIG_XML_FILE)) { assertResponseStatusCode(response, HttpStatus.OK); String original = client.getResponseContentAsString(response); assertThat(original).isEqualTo("\"Successfully started\"\n"); @@ -116,7 +120,7 @@ public class NetconfFunctionsIT { assertThat(afterUpdateConfigContent).isEqualTo("New configuration has been activated"); } // do delete - try (CloseableHttpResponse deleteResponse = client.deleteModel("newyangmodel")) { + try (CloseableHttpResponse deleteResponse = client.deleteModel(NEW_YANG_MODEL_NAME)) { assertResponseStatusCode(deleteResponse, HttpStatus.OK); String original = client.getResponseContentAsString(deleteResponse); assertThat(original).isEqualTo("\"Successfully deleted\"\n"); @@ -179,7 +183,7 @@ public class NetconfFunctionsIT { @Test public void testShouldLoadNewYangModelAndReconfigure() throws IOException { try (CloseableHttpResponse response = client - .loadModel("newyangmodel", "newYangModel.yang", "initialConfig.xml")) { + .loadModel(NEW_YANG_MODEL_NAME, NEW_YANG_MODEL_FILE, INITIAL_CONFIG_XML_FILE)) { assertResponseStatusCode(response, HttpStatus.OK); String original = client.getResponseContentAsString(response); @@ -188,23 +192,44 @@ public class NetconfFunctionsIT { } } - // ToDo: fix this integration test - // https://jira.onap.org/browse/INT-1535 - public void shouldGetLoadedModelByName() throws IOException { + @Test + public void shouldGetLoadedModelByName() throws IOException, InterruptedException { testShouldLoadNewYangModelAndReconfigure(); - try (CloseableHttpResponse response = client.getConfigByModelAndContainerNames("newyangmodel", "config2")) { - assertResponseStatusCode(response, HttpStatus.OK); - String config = client.getResponseContentAsString(response); - - assertThat(config).isEqualTo( - "<config2 xmlns=\"http://onap.org/newyangmodel\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" - + " <item1>100</item1>\n" - + "</config2>\n"); + if(checkIfModelIsPresentWithRetry(NEW_YANG_MODEL_NAME, CONFIG_NAME,4,500)) { + try (CloseableHttpResponse response = client.getConfigByModelAndContainerNames(NEW_YANG_MODEL_NAME, CONFIG_NAME)) { + assertResponseStatusCode(response, HttpStatus.OK); + String config = client.getResponseContentAsString(response); + + assertThat(config).isEqualTo( + "<config2 xmlns=\"http://onap.org/newyangmodel\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" + + " <item1>100</item1>\n" + + "</config2>\n"); + } + } else { + fail("Could not find new YANG model by name"); } } + private boolean checkIfModelIsPresentWithRetry(String model, String container,int retryCount,int interval) throws IOException, InterruptedException { + boolean isModelPresent = false; + + for(int i=0 ; i<retryCount ; i++ ) { + try (CloseableHttpResponse response = + client.getConfigByModelAndContainerNames(model, container)) { + if( response.getStatusLine().getStatusCode() == HttpStatus.BAD_REQUEST.value() ) { + System.out.println("New yang model not present on kafka, retrying in " + interval + " ms."); + Thread.sleep(interval); + } else { + isModelPresent = true; + break; + } + } + } + return isModelPresent; + } + private void assertResponseStatusCode(HttpResponse response, HttpStatus expectedStatus) { assertThat(response.getStatusLine().getStatusCode()).isEqualTo(expectedStatus.value()); } diff --git a/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java b/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java index 6bd8390..8f0f0cf 100644 --- a/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java +++ b/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java @@ -33,13 +33,14 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; @Slf4j @Service public class StoreService { private static final String CONFIG_TOPIC = "config"; - private static final long CONSUMING_DURATION_IN_MS = 1000; + private static final long CONSUMING_DURATION_IN_MS = 5000; private ConsumerFactory<String, String> consumerFactory; static final List<String> TOPICS_TO_SUBSCRIBE = Collections.singletonList(CONFIG_TOPIC); @@ -69,6 +70,9 @@ public class StoreService { ConsumerRecords<String, String> consumerRecords = pollConsumerRecords(consumer); consumerRecords.forEach(consumerRecord -> messages.add(new Message(consumerRecord.timestamp(), consumerRecord.value()))); + } catch (NoSuchElementException e) { + log.warn("not able to create consumer and to poll messages"); + return Collections.emptyList(); } return messages; } diff --git a/pnfsimulator/src/main/resources/application.properties b/pnfsimulator/src/main/resources/application.properties index 07a28dc..5c573b3 100644 --- a/pnfsimulator/src/main/resources/application.properties +++ b/pnfsimulator/src/main/resources/application.properties @@ -11,7 +11,7 @@ management.endpoints.web.base-path=/ management.endpoints.web.exposure.include=refresh,health ssl.clientCertificateEnabled=true -ssl.clientCertificateDir=/app/store/client.p12 -ssl.clientCertificatePassword=collector -ssl.trustStoreDir=/app/store/trustStore -ssl.trustStorePassword=collector +ssl.clientCertificateDir=/app/store/cert.p12 +ssl.clientCertificatePassword=${CLIENT_CERT_PASS} +ssl.trustStoreDir=/app/store/trust.jks +ssl.trustStorePassword=${TRUST_CERT_PASS} diff --git a/sanitycheck/tools/README.md b/sanitycheck/tools/README.md new file mode 100644 index 0000000..2d6b3d0 --- /dev/null +++ b/sanitycheck/tools/README.md @@ -0,0 +1,93 @@ +Standalone PNF Simulator configuration for HTTPS communication with VES +------------------------ + +### Description + +docker-compose.yml prepares PNF simulator container for HTTPS communication with VES. + +When docker-compose starts certs-init container fills connected volume with certificates, truststores, keystores, +passwords etc. Next pnf-simulator container starts and connects to the same volume. On startup it should read password +values from proper files and set them in system environment variables. With these variables and files in volume +application is ready to work on HTTPS. + +### Prerequisites + +1. certs-init container works with external AAF on cloud. Due to that fact it must have set correct IPs to workers that +has access to AAF. In docker-compose.yml fields with mentioned IPs are: + + * aaf-locate.onap + * aaf-cm.onap + * aaf-service.onap + +### Start + +**ATTENTION** + +Proper IPs to AAF must be set in the docker-compose.yml before start (as described in prerequisites)! + +``` +docker-compose up +``` + +### Send event + +**ATTENTION** + +``sanitycheck/events/eventToVes.json`` file which is request for sending event to VES must have correct ``vesServerURL`` +field before sending event. +IP of ``vesServerURL`` should be the same as given in docker-compose.yml in ``aaf-locate.onap`` field. +To use secured connection remember about setting protocol to https:// and port to proper secured port of VES. + +To send event from PNF simulator to VES use this command from ``pnf-simulator/sanitycheck`` directory: + +```` +make generate-event +```` + +Sample ``sanitycheck/events/eventToVes.json`` file content is: + +```json +{ + "vesServerUrl": "https://10.183.35.177:30417/eventListener/v7", + "event": { + "event": { + "commonEventHeader": { + "version": "4.0.1", + "vesEventListenerVersion": "7.0.1", + "domain": "fault", + "eventName": "Fault_Vscf:Acs-Ericcson_PilotNumberPoolExhaustion", + "eventId": "fault0000245", + "sequence": 1, + "priority": "High", + "reportingEntityId": "cc305d54-75b4-431b-adb2-eb6b9e541234", + "reportingEntityName": "ibcx0001vm002oam001", + "sourceId": "de305d54-75b4-431b-adb2-eb6b9e546014", + "sourceName": "scfx0001vm002cap001", + "nfVendorName": "Ericsson", + "nfNamingCode": "scfx", + "nfcNamingCode": "ssc", + "startEpochMicrosec": 1413378172000000, + "lastEpochMicrosec": 1413378172000000, + "timeZoneOffset": "UTC-05:30" + }, + "faultFields": { + "faultFieldsVersion": "4.0", + "alarmCondition": "PilotNumberPoolExhaustion", + "eventSourceType": "other", + "specificProblem": "Calls cannot complete - pilot numbers are unavailable", + "eventSeverity": "CRITICAL", + "vfStatus": "Active", + "alarmAdditionalInformation": { + "PilotNumberPoolSize": "1000" + } + } + } + } +} + +``` + +### Stop +``` +docker-compose down +```
\ No newline at end of file diff --git a/sanitycheck/tools/docker-compose.yml b/sanitycheck/tools/docker-compose.yml new file mode 100644 index 0000000..3016189 --- /dev/null +++ b/sanitycheck/tools/docker-compose.yml @@ -0,0 +1,71 @@ +version: '3' + +networks: + tls-init-network: + +volumes: + certs-volume: + +services: + certs-init: + image: nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tls-init-container:2.1.0 + extra_hosts: + #set worker IP with access to AAF + aaf-locate.onap: 10.183.35.177 + aaf-cm.onap: 10.183.35.177 + aaf-service.onap: 10.183.35.177 + environment: + - aaf_locate_url=https://aaf-locate.onap:31111 + - aaf_url_cm=https://aaf-cm.onap:31114 + - aaf_url=https://aaf-service.onap:31110 + networks: + - tls-init-network + volumes: + - certs-volume:/opt/app/osaaf + mongo: + image: mongo + restart: always + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: zXcVbN123! + MONGO_INITDB_DATABASE: pnf_simulator + networks: + - tls-init-network + volumes: + - ../../pnfsimulator/db:/docker-entrypoint-initdb.d + ports: + - "27017:27017" + + mongo-express: + image: mongo-express + restart: always + ports: + - 8081:8081 + networks: + - tls-init-network + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: zXcVbN123! + + pnf-simulator: + image: nexus3.onap.org:10001/onap/org.onap.integration.simulators.pnfsimulator + ports: + - "5000:5000" + command: bash -c " + while [[ $$(ls -1 /app/store | wc -l) != '10' ]]; do echo 'Waiting for certs...'; sleep 3; done + && export CLIENT_CERT_PASS=$$(cat /app/store/p12.pass) + && export TRUST_CERT_PASS=$$(cat /app/store/trust.pass) + && java -Dspring.config.location=file:/app/application.properties -cp /app/libs/*:/app/pnf-simulator.jar org.onap.pnfsimulator.Main + " + volumes: + - ../../pnfsimulator/logs:/var/log + - ../../pnfsimulator/templates:/app/templates + - ../../pnfsimulator/src/main/resources/application.properties:/app/application.properties + - certs-volume:/app/store + networks: + - tls-init-network + restart: on-failure + depends_on: + - certs-init + - mongo + - mongo-express |