From f71cb54beb33351d0bf078178c20b27bb11a6da4 Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Fri, 28 Jan 2022 16:06:58 +0100 Subject: [PATCH] Uplift from master branch Issue-ID: NONRTRIC-720 Signed-off-by: elinuxhenrik Change-Id: I9ec42863a87baaba3397eb6f42553d7371eb0da0 --- a1-policy-management-service/Dockerfile | 14 +- a1-policy-management-service/pom.xml | 45 +- dmaap-adaptor-java/Dockerfile | 12 +- dmaap-adaptor-java/api/api.json | 42 +- dmaap-adaptor-java/api/api.yaml | 26 +- dmaap-adaptor-java/pom.xml | 41 +- .../dmaapadapter/tasks/KafkaTopicConsumers.java | 4 +- .../src/main/resources/typeSchemaKafka.json | 10 +- .../org/oran/dmaapadapter/ApplicationTest.java | 6 +- .../org/oran/dmaapadapter/IntegrationWithIcs.java | 21 +- .../oran/dmaapadapter/IntegrationWithKafka.java | 30 +- dmaap-mediator-producer/.gitignore | 2 + dmaap-mediator-producer/Dockerfile | 2 +- dmaap-mediator-producer/README.md | 85 +- dmaap-mediator-producer/api/docs.go | 303 +++ dmaap-mediator-producer/api/swagger.json | 232 ++ dmaap-mediator-producer/api/swagger.yaml | 159 ++ .../configs/typeSchemaDmaap.json | 7 + .../configs/typeSchemaKafka.json | 23 + dmaap-mediator-producer/configs/type_config.json | 4 + dmaap-mediator-producer/container-tag.yaml | 5 + ...{build_and_test.sh => generate_swagger_docs.sh} | 8 +- dmaap-mediator-producer/go.mod | 26 +- dmaap-mediator-producer/go.sum | 111 + dmaap-mediator-producer/internal/config/config.go | 37 +- .../internal/config/config_test.go | 67 +- .../internal/config/registrator.go | 20 +- .../internal/config/registrator_test.go | 14 +- dmaap-mediator-producer/internal/jobs/jobs.go | 253 ++- dmaap-mediator-producer/internal/jobs/jobs_test.go | 298 ++- .../internal/kafkaclient/kafkaclient.go | 94 + .../internal/restclient/HTTPClient.go | 13 +- .../internal/restclient/HTTPClient_test.go | 4 +- dmaap-mediator-producer/internal/server/server.go | 67 +- .../internal/server/server_test.go | 106 +- dmaap-mediator-producer/main.go | 84 +- dmaap-mediator-producer/main_test.go | 205 ++ dmaap-mediator-producer/mocks/KafkaConsumer.go | 76 + dmaap-mediator-producer/mocks/KafkaFactory.go | 36 + .../JobHandler.go => jobshandler/JobsHandler.go} | 10 +- dmaap-mediator-producer/pom.xml | 112 - .../stub/consumer/consumerstub.go | 2 +- dmaap-mediator-producer/stub/ics/ics.go | 65 + docker-compose/.env | 22 +- docker-compose/policy-service/docker-compose.yaml | 2 +- docker-compose/sdnc/docker-compose.yml | 2 +- docs/api-docs.rst | 18 +- docs/conf.py | 6 + docs/developer-guide.rst | 22 +- docs/installation-guide.rst | 4 +- docs/overview.rst | 133 +- helm-manager/Dockerfile | 16 + helm-manager/docker-hm.sh | 8 +- helm-manager/helm-manager.yaml | 9 +- helm-manager/pom.xml | 52 +- information-coordinator-service/Dockerfile | 11 +- information-coordinator-service/api/ics-api.json | 45 +- information-coordinator-service/api/ics-api.yaml | 35 +- information-coordinator-service/pom.xml | 35 +- .../oransc/ics/clients/AsyncRestClientFactory.java | 1 - .../oransc/ics/controllers/a1e/A1eCallbacks.java | 14 +- .../org/oransc/ics/repository/InfoProducers.java | 6 +- .../org/oransc/ics/tasks/ProducerSupervision.java | 2 +- onap/oran | 2 +- pom.xml | 3 - r-app-catalogue/Dockerfile | 9 +- r-app-catalogue/api/rac-api.yaml | 16 +- r-app-catalogue/pom.xml | 12 +- .../org/oransc/rappcatalogue/HttpsRequestTest.java | 14 +- test/auto-test/FTC1.sh | 34 +- test/auto-test/FTC10.sh | 14 +- test/auto-test/FTC100.sh | 62 +- test/auto-test/FTC110.sh | 15 +- test/auto-test/FTC1100.sh | 2 +- test/auto-test/FTC150.sh | 7 +- test/auto-test/FTC1800.sh | 4 +- test/auto-test/FTC2001.sh | 15 +- test/auto-test/FTC2002.sh | 7 +- test/auto-test/FTC2003.sh | 2 +- test/auto-test/FTC300.sh | 67 +- test/auto-test/FTC3000.sh | 173 +- test/auto-test/FTC3001.sh | 261 +++ test/auto-test/FTC310.sh | 13 +- test/auto-test/FTC350.sh | 77 +- test/auto-test/FTC4000.sh | 99 + test/auto-test/FTC800.sh | 24 +- test/auto-test/FTC805.sh | 15 +- test/auto-test/FTC810.sh | 17 +- test/auto-test/FTC850.sh | 15 +- test/auto-test/FTC900.sh | 15 +- test/auto-test/FTC_HELM_E_RELEASE.sh | 16 +- test/auto-test/ONAP_UC.sh | 34 +- test/auto-test/PM_DEMO.sh | 15 +- test/auto-test/PM_EI_DEMO.sh | 15 +- test/auto-test/README.md | 27 +- test/auto-test/Suite-aegis.sh | 42 + test/auto-test/override_aegis_pms.sh | 21 + test/auto-test/override_ftc_helm_e_release.sh | 2 + test/auto-test/startMR.sh | 2 +- test/auto-test/testdata/OSC/pi_bad_template.json | 5 + .../testdata/dmaap-mediator/job-schema-1-kafka | 28 + .../dmaap-mediator/job-template-1-kafka.json | 6 + .../testdata/dmaap-mediator/job-template.json | 1 + test/common/README.md | 2300 +++++++++++++------- test/common/chartmus_api_functions.sh | 316 +++ test/common/clean_kube.sh | 6 +- test/common/consul_api_functions.sh | 12 + test/common/cp_api_functions.sh | 6 + test/common/cr_api_functions.sh | 31 +- test/common/dmaapadp_api_functions.sh | 6 + test/common/dmaapmed_api_functions.sh | 14 +- test/common/do_curl_function.sh | 4 +- test/common/format_endpoint_stats.sh | 130 ++ test/common/helmmanager_api_functions.sh | 530 +++++ test/common/httpproxy_api_functions.sh | 6 + test/common/ics_api_functions.sh | 6 + test/common/kafkapc_api_functions.sh | 6 + test/common/kubeproxy_api_functions.sh | 6 + test/common/localhelm_api_functions.sh | 193 ++ test/common/mr_api_functions.sh | 12 + test/common/ngw_api_functions.sh | 6 + test/common/pa_api_functions.sh | 99 +- test/common/prodstub_api_functions.sh | 14 +- test/common/pvccleaner_api_functions.sh | 6 + test/common/rc_api_functions.sh | 8 +- test/common/ricsim_api_functions.sh | 9 +- test/common/sdnc_api_functions.sh | 6 + test/common/test_env-onap-guilin.sh | 1 + test/common/test_env-onap-honolulu.sh | 1 + test/common/test_env-onap-istanbul.sh | 17 +- test/common/test_env-oran-cherry.sh | 1 + test/common/test_env-oran-d-release.sh | 1 + test/common/test_env-oran-e-release.sh | 93 +- test/common/testcase_common.sh | 295 ++- test/common/testengine_config.sh | 6 +- test/cr/app/cr.py | 66 +- test/cr/basic_test.sh | 65 + test/kafka-procon/.gitignore | 1 + test/simulator-group/chartmuseum/.gitignore | 3 + test/simulator-group/chartmuseum/app.yaml | 53 + .../simulator-group/chartmuseum/docker-compose.yml | 37 + test/simulator-group/chartmuseum/svc.yaml | 34 + test/simulator-group/dmaapmed/app.yaml | 6 +- test/simulator-group/dmaapmed/docker-compose.yml | 3 +- test/simulator-group/dmaapmed/type_config_1.json | 13 + test/simulator-group/helmmanager/.gitignore | 3 + test/simulator-group/helmmanager/app.yaml | 36 + .../simulator-group/helmmanager/docker-compose.yml | 36 + test/simulator-group/helmmanager/sa.yaml | 42 + test/simulator-group/helmmanager/svc.yaml | 37 + .../simulator-group/policy_agent/application2.yaml | 71 + .../usecases/odusliceassurance/goversion/README.md | 8 +- .../odusliceassurance/goversion/container-tag.yaml | 2 +- test/usecases/odusliceassurance/goversion/go.mod | 11 +- .../goversion/internal/config/config.go | 2 +- .../goversion/internal/config/config_test.go | 108 + .../goversion/internal/restclient/client.go | 5 - .../goversion/internal/restclient/client_test.go | 210 ++ .../goversion/internal/sliceassurance/app.go | 2 +- .../internal/structures/sliceassurance.go | 16 +- .../internal/structures/sliceassurance_test.go | 172 ++ test/usecases/odusliceassurance/goversion/main.go | 12 +- .../goversion/messages/stdVesMessage_test.go | 76 + test/usecases/odusliceassurance/goversion/pom.xml | 96 - .../goversion/stub/sdnr/sdnrstub.go | 15 +- .../LinkMonitorConfigDmaap2RestJsonEvent.json | 22 +- .../LinkMonitor/deployment/ToscaPolicy.json | 2 +- .../LinkMonitor/models/LinkFailureLogic.js | 22 +- .../schemas/LinkFailureOutputSchema.avsc | 94 +- .../oruclosedlooprecovery/goversion/README.md | 9 +- .../goversion/container-tag.yaml | 2 +- .../goversion/internal/config/config.go | 2 +- .../internal/linkfailure/linkfailurehandler.go | 16 +- .../linkfailure/linkfailurehandler_test.go | 10 +- .../oruclosedlooprecovery/goversion/main.go | 12 + .../oruclosedlooprecovery/goversion/main_test.go | 28 + .../goversion/o-ru-to-o-du-map.csv | 22 +- .../oruclosedlooprecovery/goversion/pom.xml | 112 - .../goversion/stub/ics/ics.go | 2 +- .../goversion/stub/producer/producerstub.go | 2 +- .../goversion/stub/sdnr/sdnrstub.go | 2 +- .../scriptversion/app/Dockerfile | 9 + .../scriptversion/app/main.py | 26 +- .../scriptversion/app/o-ru-to-o-du-map.txt | 22 +- .../scriptversion/simulators/sdnr_simulator.py | 18 +- 185 files changed, 8235 insertions(+), 2019 deletions(-) create mode 100644 dmaap-mediator-producer/api/docs.go create mode 100644 dmaap-mediator-producer/api/swagger.json create mode 100644 dmaap-mediator-producer/api/swagger.yaml create mode 100644 dmaap-mediator-producer/configs/typeSchemaDmaap.json create mode 100644 dmaap-mediator-producer/configs/typeSchemaKafka.json create mode 100644 dmaap-mediator-producer/container-tag.yaml rename dmaap-mediator-producer/{build_and_test.sh => generate_swagger_docs.sh} (86%) create mode 100644 dmaap-mediator-producer/internal/kafkaclient/kafkaclient.go create mode 100644 dmaap-mediator-producer/main_test.go create mode 100644 dmaap-mediator-producer/mocks/KafkaConsumer.go create mode 100644 dmaap-mediator-producer/mocks/KafkaFactory.go rename dmaap-mediator-producer/mocks/{jobhandler/JobHandler.go => jobshandler/JobsHandler.go} (66%) delete mode 100644 dmaap-mediator-producer/pom.xml create mode 100644 dmaap-mediator-producer/stub/ics/ics.go create mode 100755 test/auto-test/FTC3001.sh create mode 100755 test/auto-test/FTC4000.sh create mode 100755 test/auto-test/Suite-aegis.sh create mode 100644 test/auto-test/override_aegis_pms.sh create mode 100644 test/auto-test/testdata/OSC/pi_bad_template.json create mode 100644 test/auto-test/testdata/dmaap-mediator/job-schema-1-kafka create mode 100644 test/auto-test/testdata/dmaap-mediator/job-template-1-kafka.json create mode 100644 test/auto-test/testdata/dmaap-mediator/job-template.json create mode 100644 test/common/chartmus_api_functions.sh create mode 100755 test/common/format_endpoint_stats.sh create mode 100644 test/common/helmmanager_api_functions.sh create mode 100644 test/common/localhelm_api_functions.sh create mode 100644 test/simulator-group/chartmuseum/.gitignore create mode 100644 test/simulator-group/chartmuseum/app.yaml create mode 100644 test/simulator-group/chartmuseum/docker-compose.yml create mode 100644 test/simulator-group/chartmuseum/svc.yaml create mode 100644 test/simulator-group/dmaapmed/type_config_1.json create mode 100644 test/simulator-group/helmmanager/.gitignore create mode 100644 test/simulator-group/helmmanager/app.yaml create mode 100644 test/simulator-group/helmmanager/docker-compose.yml create mode 100644 test/simulator-group/helmmanager/sa.yaml create mode 100644 test/simulator-group/helmmanager/svc.yaml create mode 100644 test/simulator-group/policy_agent/application2.yaml create mode 100644 test/usecases/odusliceassurance/goversion/internal/config/config_test.go create mode 100644 test/usecases/odusliceassurance/goversion/internal/restclient/client_test.go create mode 100644 test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance_test.go create mode 100644 test/usecases/odusliceassurance/goversion/messages/stdVesMessage_test.go delete mode 100644 test/usecases/odusliceassurance/goversion/pom.xml mode change 100644 => 100755 test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json mode change 100644 => 100755 test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js mode change 100644 => 100755 test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc delete mode 100644 test/usecases/oruclosedlooprecovery/goversion/pom.xml diff --git a/a1-policy-management-service/Dockerfile b/a1-policy-management-service/Dockerfile index f64eebb6..6f8387eb 100644 --- a/a1-policy-management-service/Dockerfile +++ b/a1-policy-management-service/Dockerfile @@ -34,9 +34,15 @@ ADD /config/application_configuration.json /opt/app/policy-agent/data/applicatio ADD /config/keystore.jks /opt/app/policy-agent/etc/cert/keystore.jks ADD /config/truststore.jks /opt/app/policy-agent/etc/cert/truststore.jks -RUN chmod -R 777 /opt/app/policy-agent/config/ -RUN chmod -R 777 /opt/app/policy-agent/data/ +ARG user=nonrtric +ARG group=nonrtric -ADD target/${JAR} /opt/app/policy-agent/policy-agent.jar -CMD ["java", "-jar", "/opt/app/policy-agent/policy-agent.jar"] +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /opt/app/policy-agent +RUN chown -R $user:$group /var/log/policy-agent + +USER ${user} +ADD target/${JAR} /opt/app/policy-agent/policy-agent.jar +CMD ["java", "-jar", "/opt/app/policy-agent/policy-agent.jar"] \ No newline at end of file diff --git a/a1-policy-management-service/pom.xml b/a1-policy-management-service/pom.xml index 0ca42300..bc45d7e8 100644 --- a/a1-policy-management-service/pom.xml +++ b/a1-policy-management-service/pom.xml @@ -26,12 +26,12 @@ org.springframework.boot spring-boot-starter-parent - 2.5.3 + 2.6.2 org.o-ran-sc.nonrtric - policy-agent - 2.3.0-SNAPSHOT + a1-policy-management-service + 2.3.1-SNAPSHOT The Apache Software License, Version 2.0 @@ -49,30 +49,32 @@ 11 3.0.0 2.8.2 - 1.1.6 - 2.1.6 - 20190722 - 3.6 + 2.1.12 + 20211205 3.8.0 2.12.2 1.18.0 0.30.0 - 1.1.11 2.1.1 3.7.0.1746 0.8.5 3.0.0 + + commons-io + commons-io + 2.11.0 + com.google.guava guava - 30.0-jre + 31.0.1-jre org.springdoc springdoc-openapi-ui - 1.5.2 + 1.6.3 org.springframework.boot @@ -129,31 +131,16 @@ json ${json.version} - - commons-net - commons-net - ${commons-net.version} - org.springframework.boot spring-boot-configuration-processor true - - org.onap.dcaegen2.services.sdk.rest.services - cbs-client - ${sdk.version} - org.projectlombok lombok provided - - org.onap.dmaap.messagerouter.dmaapclient - dmaapClient - ${version.dmaap} - javax.ws.rs javax.ws.rs-api @@ -309,7 +296,7 @@ false - generate-policy-agent-image + generate-a1-policy-management-service-image package build @@ -318,7 +305,7 @@ ${env.CONTAINER_PULL_REGISTRY} - o-ran-sc/nonrtric-policy-agent:${project.version} + o-ran-sc/nonrtric-a1-policy-management-service:${project.version} try ${basedir} @@ -335,7 +322,7 @@ - push-policy-agent-image + push-a1-policy-management-service-image build push @@ -345,7 +332,7 @@ ${env.CONTAINER_PUSH_REGISTRY} - o-ran-sc/nonrtric-policy-agent:${project.version} + o-ran-sc/nonrtric-a1-policy-management-service:${project.version} ${basedir} Dockerfile diff --git a/dmaap-adaptor-java/Dockerfile b/dmaap-adaptor-java/Dockerfile index b2c0c30c..f565e801 100644 --- a/dmaap-adaptor-java/Dockerfile +++ b/dmaap-adaptor-java/Dockerfile @@ -30,14 +30,22 @@ WORKDIR /opt/app/dmaap-adaptor-service RUN mkdir -p /var/log/dmaap-adaptor-service RUN mkdir -p /opt/app/dmaap-adaptor-service/etc/cert/ RUN mkdir -p /var/dmaap-adaptor-service -RUN chmod -R 777 /var/dmaap-adaptor-service ADD /config/application.yaml /opt/app/dmaap-adaptor-service/config/application.yaml ADD /config/application_configuration.json /opt/app/dmaap-adaptor-service/data/application_configuration.json_example ADD /config/keystore.jks /opt/app/dmaap-adaptor-service/etc/cert/keystore.jks ADD /config/truststore.jks /opt/app/dmaap-adaptor-service/etc/cert/truststore.jks -RUN chmod -R 777 /opt/app/dmaap-adaptor-service/config/ +ARG user=nonrtric +ARG group=nonrtric + +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /opt/app/dmaap-adaptor-service +RUN chown -R $user:$group /var/log/dmaap-adaptor-service +RUN chown -R $user:$group /var/dmaap-adaptor-service + +USER ${user} ADD target/${JAR} /opt/app/dmaap-adaptor-service/dmaap-adaptor.jar CMD ["java", "-jar", "/opt/app/dmaap-adaptor-service/dmaap-adaptor.jar"] diff --git a/dmaap-adaptor-java/api/api.json b/dmaap-adaptor-java/api/api.json index 04c4ab00..88fed46b 100644 --- a/dmaap-adaptor-java/api/api.json +++ b/dmaap-adaptor-java/api/api.json @@ -109,7 +109,7 @@ "paths": { "/actuator/threaddump": {"get": { "summary": "Actuator web endpoint 'threaddump'", - "operationId": "handle_2_1_3", + "operationId": "threaddump_4", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -118,7 +118,7 @@ }}, "/actuator/info": {"get": { "summary": "Actuator web endpoint 'info'", - "operationId": "handle_9", + "operationId": "info_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -194,7 +194,7 @@ }, "/actuator/loggers": {"get": { "summary": "Actuator web endpoint 'loggers'", - "operationId": "handle_6", + "operationId": "loggers_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -203,7 +203,7 @@ }}, "/actuator/health/**": {"get": { "summary": "Actuator web endpoint 'health-path'", - "operationId": "handle_12", + "operationId": "health-path_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -262,7 +262,7 @@ }}, "/actuator/metrics/{requiredMetricName}": {"get": { "summary": "Actuator web endpoint 'metrics-requiredMetricName'", - "operationId": "handle_5", + "operationId": "metrics-requiredMetricName_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -292,7 +292,7 @@ }}, "/actuator/logfile": {"get": { "summary": "Actuator web endpoint 'logfile'", - "operationId": "handle_8", + "operationId": "logfile_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -302,7 +302,7 @@ "/actuator/loggers/{name}": { "post": { "summary": "Actuator web endpoint 'loggers-name'", - "operationId": "handle_0", + "operationId": "loggers-name_3", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -317,7 +317,7 @@ }, "get": { "summary": "Actuator web endpoint 'loggers-name'", - "operationId": "handle_7", + "operationId": "loggers-name_4", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -333,7 +333,7 @@ }, "/actuator/health": {"get": { "summary": "Actuator web endpoint 'health'", - "operationId": "handle_11", + "operationId": "health_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -366,7 +366,7 @@ }}, "/actuator/metrics": {"get": { "summary": "Actuator web endpoint 'metrics'", - "operationId": "handle_4", + "operationId": "metrics_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -375,7 +375,7 @@ }}, "/actuator/heapdump": {"get": { "summary": "Actuator web endpoint 'heapdump'", - "operationId": "handle_10", + "operationId": "heapdump_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -392,12 +392,18 @@ "title": "Generic Dmaap and Kafka Information Producer", "version": "1.0" }, - "tags": [{ - "name": "Actuator", - "description": "Monitor and interact", - "externalDocs": { - "description": "Spring Boot Actuator Web API Documentation", - "url": "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/" + "tags": [ + {"name": "Information Coordinator Service Simulator (exists only in test)"}, + {"name": "Producer job control API"}, + {"name": "Test Consumer Simulator (exists only in test)"}, + {"name": "DMAAP Simulator (exists only in test)"}, + { + "name": "Actuator", + "description": "Monitor and interact", + "externalDocs": { + "description": "Spring Boot Actuator Web API Documentation", + "url": "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/" + } } - }] + ] } \ No newline at end of file diff --git a/dmaap-adaptor-java/api/api.yaml b/dmaap-adaptor-java/api/api.yaml index 1fb78fa3..f6eb1f7f 100644 --- a/dmaap-adaptor-java/api/api.yaml +++ b/dmaap-adaptor-java/api/api.yaml @@ -10,6 +10,10 @@ info: servers: - url: / tags: +- name: Information Coordinator Service Simulator (exists only in test) +- name: Producer job control API +- name: Test Consumer Simulator (exists only in test) +- name: DMAAP Simulator (exists only in test) - name: Actuator description: Monitor and interact externalDocs: @@ -21,7 +25,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'threaddump' - operationId: handle_2_1_3 + operationId: threaddump_4 responses: 200: description: OK @@ -34,7 +38,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'info' - operationId: handle_9 + operationId: info_2 responses: 200: description: OK @@ -136,7 +140,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers' - operationId: handle_6 + operationId: loggers_2 responses: 200: description: OK @@ -149,7 +153,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'health-path' - operationId: handle_12 + operationId: health-path_2 responses: 200: description: OK @@ -230,7 +234,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'metrics-requiredMetricName' - operationId: handle_5 + operationId: metrics-requiredMetricName_2 parameters: - name: requiredMetricName in: path @@ -268,7 +272,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'logfile' - operationId: handle_8 + operationId: logfile_2 responses: 200: description: OK @@ -281,7 +285,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers-name' - operationId: handle_7 + operationId: loggers-name_4 parameters: - name: name in: path @@ -301,7 +305,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers-name' - operationId: handle_0 + operationId: loggers-name_3 parameters: - name: name in: path @@ -322,7 +326,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'health' - operationId: handle_11 + operationId: health_2 responses: 200: description: OK @@ -370,7 +374,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'metrics' - operationId: handle_4 + operationId: metrics_2 responses: 200: description: OK @@ -383,7 +387,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'heapdump' - operationId: handle_10 + operationId: heapdump_2 responses: 200: description: OK diff --git a/dmaap-adaptor-java/pom.xml b/dmaap-adaptor-java/pom.xml index 411b27c5..b8fc63f3 100644 --- a/dmaap-adaptor-java/pom.xml +++ b/dmaap-adaptor-java/pom.xml @@ -26,12 +26,12 @@ org.springframework.boot spring-boot-starter-parent - 2.5.3 + 2.5.8 org.o-ran-sc.nonrtric dmaap-adaptor - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT The Apache Software License, Version 2.0 @@ -49,17 +49,13 @@ 11 3.0.0 2.8.2 - 1.1.6 2.1.6 - 20190722 - 3.6 + 20211205 3.8.0 2.12.2 1.24.3 3.0.11 0.30.0 - 1.1.11 - 2.1.1 3.7.0.1746 0.8.5 true @@ -68,7 +64,7 @@ org.springdoc springdoc-openapi-ui - 1.5.4 + 1.6.3 org.springframework.boot @@ -96,10 +92,6 @@ swagger-jaxrs2-servlet-initializer ${swagger.version} - - javax.xml.bind - jaxb-api - org.immutables value @@ -116,32 +108,11 @@ json ${json.version} - - commons-net - commons-net - ${commons-net.version} - - - org.onap.dcaegen2.services.sdk.rest.services - cbs-client - ${sdk.version} - org.projectlombok lombok provided - - javax.ws.rs - javax.ws.rs-api - ${javax.ws.rs-api.version} - - - - com.github.erosb - everit-json-schema - 1.12.1 - org.springframework.boot @@ -208,7 +179,7 @@ io.projectreactor.kafka reactor-kafka - 1.3.7 + 1.3.9 com.google.guava @@ -390,4 +361,4 @@ JIRA https://jira.o-ran-sc.org/ - \ No newline at end of file + diff --git a/dmaap-adaptor-java/src/main/java/org/oran/dmaapadapter/tasks/KafkaTopicConsumers.java b/dmaap-adaptor-java/src/main/java/org/oran/dmaapadapter/tasks/KafkaTopicConsumers.java index 48090170..5233401b 100644 --- a/dmaap-adaptor-java/src/main/java/org/oran/dmaapadapter/tasks/KafkaTopicConsumers.java +++ b/dmaap-adaptor-java/src/main/java/org/oran/dmaapadapter/tasks/KafkaTopicConsumers.java @@ -100,7 +100,9 @@ public class KafkaTopicConsumers { public synchronized void restartNonRunningTopics() { for (String typeId : this.consumers.keySet()) { for (KafkaJobDataConsumer consumer : this.consumers.get(typeId)) { - restartTopic(consumer); + if (!consumer.isRunning()) { + restartTopic(consumer); + } } } } diff --git a/dmaap-adaptor-java/src/main/resources/typeSchemaKafka.json b/dmaap-adaptor-java/src/main/resources/typeSchemaKafka.json index 38e7807f..f7e6e875 100644 --- a/dmaap-adaptor-java/src/main/resources/typeSchemaKafka.json +++ b/dmaap-adaptor-java/src/main/resources/typeSchemaKafka.json @@ -6,16 +6,20 @@ "type": "string" }, "maxConcurrency": { - "type": "integer" + "type": "integer", + "minimum": 1 }, "bufferTimeout": { "type": "object", "properties": { "maxSize": { - "type": "integer" + "type": "integer", + "minimum": 1 }, "maxTimeMiliseconds": { - "type": "integer" + "type": "integer", + "minimum": 0, + "maximum": 160000 } }, "additionalProperties": false, diff --git a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/ApplicationTest.java b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/ApplicationTest.java index 8c414234..66601750 100644 --- a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/ApplicationTest.java +++ b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/ApplicationTest.java @@ -333,11 +333,11 @@ class ApplicationTest { () -> assertThat(icsSimulatorController.testResults.registrationInfo.supportedTypeIds).hasSize(2)); } - private void testErrorCode(Mono request, HttpStatus expStatus, String responseContains) { + public static void testErrorCode(Mono request, HttpStatus expStatus, String responseContains) { testErrorCode(request, expStatus, responseContains, true); } - private void testErrorCode(Mono request, HttpStatus expStatus, String responseContains, + public static void testErrorCode(Mono request, HttpStatus expStatus, String responseContains, boolean expectApplicationProblemJsonMediaType) { StepVerifier.create(request) // .expectSubscription() // @@ -346,7 +346,7 @@ class ApplicationTest { .verify(); } - private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains, + private static boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains, boolean expectApplicationProblemJsonMediaType) { assertTrue(throwable instanceof WebClientResponseException); WebClientResponseException responseException = (WebClientResponseException) throwable; diff --git a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithIcs.java b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithIcs.java index d1d7e910..9f0ef19f 100644 --- a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithIcs.java +++ b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithIcs.java @@ -49,9 +49,11 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; + @SuppressWarnings("java:S3577") // Rename class @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) @@ -232,7 +234,23 @@ class IntegrationWithIcs { } @Test - void testWholeChain() throws Exception { + void testKafkaJobParameterOutOfRange() { + await().untilAsserted(() -> assertThat(producerRegstrationTask.isRegisteredInIcs()).isTrue()); + final String TYPE_ID = "KafkaInformationType"; + + Job.Parameters param = new Job.Parameters("filter", new Job.BufferTimeout(123, 170 * 1000), 1); + + ConsumerJobInfo jobInfo = + new ConsumerJobInfo(TYPE_ID, jsonObject(gson.toJson(param)), "owner", consumerUri(), ""); + String body = gson.toJson(jobInfo); + + ApplicationTest.testErrorCode(restClient().put(jobUrl("KAFKA_JOB_ID"), body), HttpStatus.BAD_REQUEST, + "Json validation failure"); + + } + + @Test + void testDmaapMessage() throws Exception { await().untilAsserted(() -> assertThat(producerRegstrationTask.isRegisteredInIcs()).isTrue()); createInformationJobInIcs(DMAAP_TYPE_ID, DMAAP_JOB_ID, ".*DmaapResponse.*"); @@ -250,7 +268,6 @@ class IntegrationWithIcs { deleteInformationJobInIcs(DMAAP_JOB_ID); await().untilAsserted(() -> assertThat(this.jobs.size()).isZero()); - } } diff --git a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithKafka.java b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithKafka.java index c38af8a9..5a48d61f 100644 --- a/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithKafka.java +++ b/dmaap-adaptor-java/src/test/java/org/oran/dmaapadapter/IntegrationWithKafka.java @@ -215,7 +215,7 @@ class IntegrationWithKafka { Map props = new HashMap<>(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); - props.put(ProducerConfig.CLIENT_ID_CONFIG, "sample-producer"); + props.put(ProducerConfig.CLIENT_ID_CONFIG, "sample-producerx"); props.put(ProducerConfig.ACKS_CONFIG, "all"); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); @@ -236,6 +236,8 @@ class IntegrationWithKafka { .doOnError(e -> logger.error("Send failed", e)) // .blockLast(); + sender.close(); + } private void verifiedReceivedByConsumer(String... strings) { @@ -246,6 +248,29 @@ class IntegrationWithKafka { } } + @Test + void simpleCase() throws InterruptedException { + final String JOB_ID = "ID"; + + // Register producer, Register types + await().untilAsserted(() -> assertThat(icsSimulatorController.testResults.registrationInfo).isNotNull()); + assertThat(icsSimulatorController.testResults.registrationInfo.supportedTypeIds).hasSize(this.types.size()); + + this.icsSimulatorController.addJob(consumerJobInfo(null, Duration.ZERO, 0, 1), JOB_ID, restClient()); + await().untilAsserted(() -> assertThat(this.jobs.size()).isEqualTo(1)); + + Thread.sleep(4000); + var dataToSend = Flux.just(senderRecord("Message")); + sendDataToStream(dataToSend); + + verifiedReceivedByConsumer("Message"); + + this.icsSimulatorController.deleteJob(JOB_ID, restClient()); + + await().untilAsserted(() -> assertThat(this.jobs.size()).isZero()); + await().untilAsserted(() -> assertThat(this.kafkaTopicConsumers.getConsumers().keySet()).isEmpty()); + } + @Test void kafkaIntegrationTest() throws Exception { final String JOB_ID1 = "ID1"; @@ -256,12 +281,13 @@ class IntegrationWithKafka { assertThat(icsSimulatorController.testResults.registrationInfo.supportedTypeIds).hasSize(this.types.size()); // Create two jobs. One buffering and one with a filter - this.icsSimulatorController.addJob(consumerJobInfo(null, Duration.ofMillis(400), 1000, 20), JOB_ID1, + this.icsSimulatorController.addJob(consumerJobInfo(null, Duration.ofMillis(400), 10, 20), JOB_ID1, restClient()); this.icsSimulatorController.addJob(consumerJobInfo("^Message_1$", Duration.ZERO, 0, 1), JOB_ID2, restClient()); await().untilAsserted(() -> assertThat(this.jobs.size()).isEqualTo(2)); + Thread.sleep(2000); var dataToSend = Flux.range(1, 3).map(i -> senderRecord("Message_" + i)); // Message_1, Message_2 etc. sendDataToStream(dataToSend); diff --git a/dmaap-mediator-producer/.gitignore b/dmaap-mediator-producer/.gitignore index 5b1f8f91..aa6ce100 100644 --- a/dmaap-mediator-producer/.gitignore +++ b/dmaap-mediator-producer/.gitignore @@ -8,3 +8,5 @@ consumer !consumer/ dmaap !dmaap/ +ics +!ics/ diff --git a/dmaap-mediator-producer/Dockerfile b/dmaap-mediator-producer/Dockerfile index 1c7f45cb..6d9b2b87 100644 --- a/dmaap-mediator-producer/Dockerfile +++ b/dmaap-mediator-producer/Dockerfile @@ -30,7 +30,7 @@ RUN go build -o /dmaapmediatorproducer ## ## Deploy ## -FROM gcr.io/distroless/base-debian10 +FROM gcr.io/distroless/base-debian11 WORKDIR / ## Copy from "build" stage COPY --from=build /dmaapmediatorproducer . diff --git a/dmaap-mediator-producer/README.md b/dmaap-mediator-producer/README.md index 69a4626d..6009a8ff 100644 --- a/dmaap-mediator-producer/README.md +++ b/dmaap-mediator-producer/README.md @@ -14,7 +14,13 @@ The producer takes a number of environment variables, described below, as config >- PRODUCER_KEY_PATH Optional. The path to the key to the certificate to use for https. Defaults to `security/producer.key` >- LOG_LEVEL Optional. The log level, which can be `Error`, `Warn`, `Info` or `Debug`. Defaults to `Info`. -The file `configs/type_config.json` contains the configuration of job types that the producer will support. +Any of the addresses used by this product can be configured to use https, by specifying it as the scheme of the address URI. Clients configured to use https will not use server certificate verification. The communication towards the consumers will use https if their callback address URI uses that scheme. The producer's own callback will only listen to the scheme configured in the scheme of the info producer host address. + +The configured public key and cerificate shall be PEM-encoded. A self signed certificate and key are provided in the `security` folder of the project. These files should be replaced for production. To generate a self signed key and certificate, use the example code below: + + openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 + +The file `configs/type_config.json` contains the configuration of job types that the producer will support, see example below. { "types": @@ -22,36 +28,97 @@ The file `configs/type_config.json` contains the configuration of job types that { "id": The ID of the job type, e.g. "STD_Fault_Messages", "dmaapTopicUrl": The topic URL to poll from DMaaP Message Router, e.g. "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/STD_Fault_Messages" + }, + { + "id": The ID of the job type, e.g. "Kafka_TestTopic", + "kafkaInputTopic": The Kafka topic to poll } ] } -Any of the addresses used by this product can be configured to use https, by specifying it as the scheme of the address URI. Clients configured to use https will not use server certificate verification. The communication towards the consumers will use https if their callback address URI uses that scheme. The producer's own callback will only listen to the scheme configured in the scheme of the info producer host address. +Each information type has the following properties: + - id the information type identity as exposed in the Information Coordination Service data consumer API + - dmaapTopicUrl the URL to for fetching information from DMaaP + - kafkaInputTopic the Kafka topic to get input from -The configured public key and cerificate shall be PEM-encoded. A self signed certificate and key are provided in the `security` folder of the project. These files should be replaced for production. To generate a self signed key and certificate, use the example code below: - - openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 +Either the "dmaapTopicUrl" or the "kafkaInputTopic" must be provided for each type, not both. ## Functionality At start up the producer will register the configured job types in ICS and also register itself as a producer supporting these types. If ICS is unavailable, the producer will retry to connect indefinetely. The same goes for MR. -Once the initial registration is done, the producer will constantly poll MR for all configured job types. When receiving messages for a type, it will distribute these messages to all jobs registered for the type. If no jobs for that type are registered, the messages will be discarded. If a consumer is unavailable for distribution, the messages will be discarded for that consumer until it is available again. +Once the initial registration is done, the producer will constantly poll MR and/or Kafka for all configured job types. When receiving messages for a type, it will distribute these messages to all jobs registered for the type. If no jobs for that type are registered, the messages will be discarded. If a consumer is unavailable for distribution, the messages will be discarded for that consumer until it is available again. -The producer provides a REST API to control the log level. The available levels are the same as the ones used in the configuration above. +The producer provides a REST API that fulfills the ICS Data producer API, see [Data producer (callbacks)](). The health check method returns the registration status of the producer in ICS as JSON. It also provides a method to control the log level of the producer. The available log levels are the same as the ones used in the configuration above. PUT https://mrproducer:8085/admin/log?level= +The Swagger documentation of the producer's API is also available, through the `/swagger` path. + +When an Information Job is created in the Information Coordinator Service Consumer API, it is possible to define a number of job specific properties. For an Information type that has a Kafka topic defined, the following Json schema defines the properties that can be used: + + +```sh +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "bufferTimeout": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "maxTimeMiliseconds": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "maxSize", + "maxTimeMiliseconds" + ] + } + }, + "additionalProperties": false +} +``` +-bufferTimeout, can be used to reduce the number of REST calls to the consumer. If defined, a number of objects will be + buffered and sent in one REST call to the consumer. + The buffered objects will be put in a Json array and quoted. Example; + Object1 and Object2 may be posted in one call --> ["Object1", "Object2"] + The bufferTimeout is a Json object and the parameters in the object are: + - maxSize the maximum number of buffered objects before posting + - maxTimeMiliseconds the maximum delay time to buffer before posting + If no bufferTimeout is specified, each object will be posted as received in separate calls (not quoted and put in a Json array). + + +For an information type that only has a DMaaP topic, the following Json schema is used: + +```sh +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + }, + "additionalProperties": false +} + ## Development -To make it easy to test during development of the producer, two stubs are provided in the `stub` folder. +To make it easy to test during development of the producer, three stubs are provided in the `stub` folder. One, under the `dmaap` folder, called `dmaap` that stubs MR and respond with an array with one message with `eventSeverity` alternating between `NORMAL` and `CRITICAL`. The default port is `3905`, but this can be overridden by passing a `-port ` flag when starting the stub. To build and start the stub, do the following: >1. cd stub/dmaap >2. go build >3. ./dmaap [-port \] -One, under the `consumer` folder, called `consumer` that at startup will register a job of type `STD_Fault_Messages` in ICS, and then listen for REST calls and print the body of them. By default, it listens to the port `40935`, but his can be overridden by passing a `-port ` flag when starting the stub. To build and start the stub, do the following: +An ICS stub, under the `ics` folder, that listens for registration calls from the producer. When it gets a call it prints out the data of the call. By default, it listens to the port `8434`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following: +>1. cd stub/ics +>2. go build [-port \] +>3. ./ics + +One, under the `consumer` folder, called `consumer` that at startup will register a job of type `STD_Fault_Messages` in ICS, if it is available, and then listen for REST calls and print the body of them. By default, it listens to the port `40935`, but his can be overridden by passing a `-port ` flag when starting the stub. To build and start the stub, do the following: >1. cd stub/consumer >2. go build >3. ./consumer [-port \] diff --git a/dmaap-mediator-producer/api/docs.go b/dmaap-mediator-producer/api/docs.go new file mode 100644 index 00000000..dbfc42be --- /dev/null +++ b/dmaap-mediator-producer/api/docs.go @@ -0,0 +1,303 @@ +// Package api GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// This file was generated by swaggo/swag +package api + +import ( + "bytes" + "encoding/json" + "strings" + "text/template" + + "github.com/swaggo/swag" +) + +var doc = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/admin/log": { + "put": { + "description": "Set the log level of the producer.", + "tags": [ + "Admin" + ], + "summary": "Set log level", + "parameters": [ + { + "enum": [ + "Error", + "Warn", + "Info", + "Debug" + ], + "type": "string", + "description": "string enums", + "name": "level", + "in": "query" + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "Problem as defined in https://tools.ietf.org/html/rfc7807", + "schema": { + "$ref": "#/definitions/ErrorInfo" + }, + "headers": { + "Content-Type": { + "type": "string", + "description": "application/problem+json" + } + } + } + } + } + }, + "/health_check": { + "get": { + "description": "Get the status of the producer. Will show if the producer has registered in ICS.", + "produces": [ + "application/json" + ], + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Get status", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/" + } + } + } + } + }, + "/info_job": { + "post": { + "description": "Callback for ICS to add an info job", + "consumes": [ + "application/json" + ], + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Add info job", + "parameters": [ + { + "description": "Info job data", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/JobInfo" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "Problem as defined in https://tools.ietf.org/html/rfc7807", + "schema": { + "$ref": "#/definitions/ErrorInfo" + }, + "headers": { + "Content-Type": { + "type": "string", + "description": "application/problem+json" + } + } + } + } + } + }, + "/info_job/{infoJobId}": { + "delete": { + "description": "Callback for ICS to delete an info job", + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Delete info job", + "parameters": [ + { + "type": "string", + "description": "Info job ID", + "name": "infoJobId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/swagger": { + "get": { + "description": "Get the Swagger API documentation for the producer.", + "tags": [ + "Admin" + ], + "summary": "Get Swagger Documentation", + "responses": { + "200": { + "description": "" + } + } + } + } + }, + "definitions": { + "": { + "type": "object", + "properties": { + "registeredStatus": { + "description": "The registration status of the producer in Information Coordinator Service. Either ` + "`" + `registered` + "`" + ` or ` + "`" + `not registered` + "`" + `", + "type": "string", + "example": "registered" + } + } + }, + "BufferTimeout": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "maxTimeMiliseconds": { + "type": "integer" + } + } + }, + "ErrorInfo": { + "type": "object", + "properties": { + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "type": "string", + "example": "Info job type not found" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem.", + "type": "string" + }, + "status": { + "description": "The HTTP status code generated by the origin server for this occurrence of the problem.", + "type": "integer", + "example": 400 + }, + "title": { + "description": "A short, human-readable summary of the problem type.", + "type": "string" + }, + "type": { + "description": "A URI reference that identifies the problem type.", + "type": "string" + } + } + }, + "JobInfo": { + "type": "object", + "properties": { + "info_job_data": { + "$ref": "#/definitions/Parameters" + }, + "info_job_identity": { + "type": "string" + }, + "info_type_identity": { + "type": "string" + }, + "last_updated": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "target_uri": { + "type": "string" + } + } + }, + "Parameters": { + "type": "object", + "properties": { + "bufferTimeout": { + "$ref": "#/definitions/BufferTimeout" + } + } + } + } +}` + +type swaggerInfo struct { + Version string + Host string + BasePath string + Schemes []string + Title string + Description string +} + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = swaggerInfo{ + Version: "1.1.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "DMaaP Mediator Producer", + Description: "", +} + +type s struct{} + +func (s *s) ReadDoc() string { + sInfo := SwaggerInfo + sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) + + t, err := template.New("swagger_info").Funcs(template.FuncMap{ + "marshal": func(v interface{}) string { + a, _ := json.Marshal(v) + return string(a) + }, + "escape": func(v interface{}) string { + // escape tabs + str := strings.Replace(v.(string), "\t", "\\t", -1) + // replace " with \", and if that results in \\", replace that with \\\" + str = strings.Replace(str, "\"", "\\\"", -1) + return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1) + }, + }).Parse(doc) + if err != nil { + return doc + } + + var tpl bytes.Buffer + if err := t.Execute(&tpl, sInfo); err != nil { + return doc + } + + return tpl.String() +} + +func init() { + swag.Register("swagger", &s{}) +} diff --git a/dmaap-mediator-producer/api/swagger.json b/dmaap-mediator-producer/api/swagger.json new file mode 100644 index 00000000..89100227 --- /dev/null +++ b/dmaap-mediator-producer/api/swagger.json @@ -0,0 +1,232 @@ +{ + "swagger": "2.0", + "info": { + "title": "DMaaP Mediator Producer", + "contact": {}, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.1.0" + }, + "paths": { + "/admin/log": { + "put": { + "description": "Set the log level of the producer.", + "tags": [ + "Admin" + ], + "summary": "Set log level", + "parameters": [ + { + "enum": [ + "Error", + "Warn", + "Info", + "Debug" + ], + "type": "string", + "description": "string enums", + "name": "level", + "in": "query" + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "Problem as defined in https://tools.ietf.org/html/rfc7807", + "schema": { + "$ref": "#/definitions/ErrorInfo" + }, + "headers": { + "Content-Type": { + "type": "string", + "description": "application/problem+json" + } + } + } + } + } + }, + "/health_check": { + "get": { + "description": "Get the status of the producer. Will show if the producer has registered in ICS.", + "produces": [ + "application/json" + ], + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Get status", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/" + } + } + } + } + }, + "/info_job": { + "post": { + "description": "Callback for ICS to add an info job", + "consumes": [ + "application/json" + ], + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Add info job", + "parameters": [ + { + "description": "Info job data", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/JobInfo" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "Problem as defined in https://tools.ietf.org/html/rfc7807", + "schema": { + "$ref": "#/definitions/ErrorInfo" + }, + "headers": { + "Content-Type": { + "type": "string", + "description": "application/problem+json" + } + } + } + } + } + }, + "/info_job/{infoJobId}": { + "delete": { + "description": "Callback for ICS to delete an info job", + "tags": [ + "Data producer (callbacks)" + ], + "summary": "Delete info job", + "parameters": [ + { + "type": "string", + "description": "Info job ID", + "name": "infoJobId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/swagger": { + "get": { + "description": "Get the Swagger API documentation for the producer.", + "tags": [ + "Admin" + ], + "summary": "Get Swagger Documentation", + "responses": { + "200": { + "description": "" + } + } + } + } + }, + "definitions": { + "": { + "type": "object", + "properties": { + "registeredStatus": { + "description": "The registration status of the producer in Information Coordinator Service. Either `registered` or `not registered`", + "type": "string", + "example": "registered" + } + } + }, + "BufferTimeout": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "maxTimeMiliseconds": { + "type": "integer" + } + } + }, + "ErrorInfo": { + "type": "object", + "properties": { + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "type": "string", + "example": "Info job type not found" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem.", + "type": "string" + }, + "status": { + "description": "The HTTP status code generated by the origin server for this occurrence of the problem.", + "type": "integer", + "example": 400 + }, + "title": { + "description": "A short, human-readable summary of the problem type.", + "type": "string" + }, + "type": { + "description": "A URI reference that identifies the problem type.", + "type": "string" + } + } + }, + "JobInfo": { + "type": "object", + "properties": { + "info_job_data": { + "$ref": "#/definitions/Parameters" + }, + "info_job_identity": { + "type": "string" + }, + "info_type_identity": { + "type": "string" + }, + "last_updated": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "target_uri": { + "type": "string" + } + } + }, + "Parameters": { + "type": "object", + "properties": { + "bufferTimeout": { + "$ref": "#/definitions/BufferTimeout" + } + } + } + } +} \ No newline at end of file diff --git a/dmaap-mediator-producer/api/swagger.yaml b/dmaap-mediator-producer/api/swagger.yaml new file mode 100644 index 00000000..adf70a80 --- /dev/null +++ b/dmaap-mediator-producer/api/swagger.yaml @@ -0,0 +1,159 @@ +definitions: + "": + properties: + registeredStatus: + description: The registration status of the producer in Information Coordinator + Service. Either `registered` or `not registered` + example: registered + type: string + type: object + BufferTimeout: + properties: + maxSize: + type: integer + maxTimeMiliseconds: + type: integer + type: object + ErrorInfo: + properties: + detail: + description: A human-readable explanation specific to this occurrence of the + problem. + example: Info job type not found + type: string + instance: + description: A URI reference that identifies the specific occurrence of the + problem. + type: string + status: + description: The HTTP status code generated by the origin server for this + occurrence of the problem. + example: 400 + type: integer + title: + description: A short, human-readable summary of the problem type. + type: string + type: + description: A URI reference that identifies the problem type. + type: string + type: object + JobInfo: + properties: + info_job_data: + $ref: '#/definitions/Parameters' + info_job_identity: + type: string + info_type_identity: + type: string + last_updated: + type: string + owner: + type: string + target_uri: + type: string + type: object + Parameters: + properties: + bufferTimeout: + $ref: '#/definitions/BufferTimeout' + type: object +info: + contact: {} + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + title: DMaaP Mediator Producer + version: 1.1.0 +paths: + /admin/log: + put: + description: Set the log level of the producer. + parameters: + - description: string enums + enum: + - Error + - Warn + - Info + - Debug + in: query + name: level + type: string + responses: + "200": + description: "" + "400": + description: Problem as defined in https://tools.ietf.org/html/rfc7807 + headers: + Content-Type: + description: application/problem+json + type: string + schema: + $ref: '#/definitions/ErrorInfo' + summary: Set log level + tags: + - Admin + /health_check: + get: + description: Get the status of the producer. Will show if the producer has registered + in ICS. + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/' + summary: Get status + tags: + - Data producer (callbacks) + /info_job: + post: + consumes: + - application/json + description: Callback for ICS to add an info job + parameters: + - description: Info job data + in: body + name: user + required: true + schema: + $ref: '#/definitions/JobInfo' + responses: + "200": + description: "" + "400": + description: Problem as defined in https://tools.ietf.org/html/rfc7807 + headers: + Content-Type: + description: application/problem+json + type: string + schema: + $ref: '#/definitions/ErrorInfo' + summary: Add info job + tags: + - Data producer (callbacks) + /info_job/{infoJobId}: + delete: + description: Callback for ICS to delete an info job + parameters: + - description: Info job ID + in: path + name: infoJobId + required: true + type: string + responses: + "200": + description: "" + summary: Delete info job + tags: + - Data producer (callbacks) + /swagger: + get: + description: Get the Swagger API documentation for the producer. + responses: + "200": + description: "" + summary: Get Swagger Documentation + tags: + - Admin +swagger: "2.0" diff --git a/dmaap-mediator-producer/configs/typeSchemaDmaap.json b/dmaap-mediator-producer/configs/typeSchemaDmaap.json new file mode 100644 index 00000000..4abee49e --- /dev/null +++ b/dmaap-mediator-producer/configs/typeSchemaDmaap.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + }, + "additionalProperties": false +} diff --git a/dmaap-mediator-producer/configs/typeSchemaKafka.json b/dmaap-mediator-producer/configs/typeSchemaKafka.json new file mode 100644 index 00000000..9c3980f0 --- /dev/null +++ b/dmaap-mediator-producer/configs/typeSchemaKafka.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "bufferTimeout": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "maxTimeMiliseconds": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "maxSize", + "maxTimeMiliseconds" + ] + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/dmaap-mediator-producer/configs/type_config.json b/dmaap-mediator-producer/configs/type_config.json index f75d0e4b..11496693 100644 --- a/dmaap-mediator-producer/configs/type_config.json +++ b/dmaap-mediator-producer/configs/type_config.json @@ -4,6 +4,10 @@ { "id": "STD_Fault_Messages", "dmaapTopicUrl": "/events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/STD_Fault_Messages" + }, + { + "id": "Kafka_TestTopic", + "kafkaInputTopic": "TestTopic" } ] } \ No newline at end of file diff --git a/dmaap-mediator-producer/container-tag.yaml b/dmaap-mediator-producer/container-tag.yaml new file mode 100644 index 00000000..5b018097 --- /dev/null +++ b/dmaap-mediator-producer/container-tag.yaml @@ -0,0 +1,5 @@ +# The Jenkins job requires a tag to build the Docker image. +# By default this file is in the docker build directory, +# but the location can configured in the JJB template. +--- +tag: 1.0.1 diff --git a/dmaap-mediator-producer/build_and_test.sh b/dmaap-mediator-producer/generate_swagger_docs.sh similarity index 86% rename from dmaap-mediator-producer/build_and_test.sh rename to dmaap-mediator-producer/generate_swagger_docs.sh index 397124d7..8a13f304 100755 --- a/dmaap-mediator-producer/build_and_test.sh +++ b/dmaap-mediator-producer/generate_swagger_docs.sh @@ -1,7 +1,7 @@ #!/bin/bash ############################################################################## # -# Copyright (C) 2021: Nordix Foundation +# Copyright (C) 2022: Nordix Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,6 +17,6 @@ # ############################################################################## -go build - -go test ./... +go get -u github.com/swaggo/swag/cmd/swag +swag init --output api +swag fmt \ No newline at end of file diff --git a/dmaap-mediator-producer/go.mod b/dmaap-mediator-producer/go.mod index eaaecf7f..ea7b3615 100644 --- a/dmaap-mediator-producer/go.mod +++ b/dmaap-mediator-producer/go.mod @@ -3,17 +3,39 @@ module oransc.org/nonrtric/dmaapmediatorproducer go 1.17 require ( + github.com/confluentinc/confluent-kafka-go v1.8.2 github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-retryablehttp v0.7.0 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 + github.com/swaggo/http-swagger v1.1.2 + github.com/swaggo/swag v1.7.8 ) require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/stretchr/objx v0.1.0 // indirect - golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 // indirect + github.com/urfave/cli/v2 v2.3.0 // indirect + golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect + golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect ) diff --git a/dmaap-mediator-producer/go.sum b/dmaap-mediator-producer/go.sum index 4b3557bb..f7a6405b 100644 --- a/dmaap-mediator-producer/go.sum +++ b/dmaap-mediator-producer/go.sum @@ -1,6 +1,38 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/confluentinc/confluent-kafka-go v1.8.2 h1:PBdbvYpyOdFLehj8j+9ba7FL4c4Moxn79gy9cYKxG5E= +github.com/confluentinc/confluent-kafka-go v1.8.2/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= +github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= +github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= @@ -9,18 +41,97 @@ github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxC github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= +github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM= +github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= +github.com/swaggo/http-swagger v1.1.2 h1:ikcSD+EUOx+2oNZ2N6u8IYa8ScOsAvE7Jh+E1dW6i94= +github.com/swaggo/http-swagger v1.1.2/go.mod h1:mX5nhypDmoSt4iw2mc5aKXxRFvp1CLLcCiog2B9M+Ro= +github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= +github.com/swaggo/swag v1.7.8 h1:w249t0l/kc/DKMGlS0fppNJQxKyJ8heNaUWB6nsH3zc= +github.com/swaggo/swag v1.7.8/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/dmaap-mediator-producer/internal/config/config.go b/dmaap-mediator-producer/internal/config/config.go index e03c40ac..7582e9cc 100644 --- a/dmaap-mediator-producer/internal/config/config.go +++ b/dmaap-mediator-producer/internal/config/config.go @@ -24,6 +24,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "strconv" log "github.com/sirupsen/logrus" @@ -35,6 +36,7 @@ type Config struct { InfoProducerPort int InfoCoordinatorAddress string DMaaPMRAddress string + KafkaBootstrapServers string ProducerCertPath string ProducerKeyPath string } @@ -45,6 +47,7 @@ func New() *Config { InfoProducerPort: getEnvAsInt("INFO_PRODUCER_PORT", 8085), InfoCoordinatorAddress: getEnv("INFO_COORD_ADDR", "https://informationservice:8434"), DMaaPMRAddress: getEnv("DMAAP_MR_ADDR", "https://message-router.onap:3905"), + KafkaBootstrapServers: getEnv("KAFKA_BOOTSTRAP_SERVERS", "localhost:9092"), ProducerCertPath: getEnv("PRODUCER_CERT_PATH", "security/producer.crt"), ProducerKeyPath: getEnv("PRODUCER_KEY_PATH", "security/producer.key"), LogLevel: getLogLevel(), @@ -83,8 +86,8 @@ func getLogLevel() log.Level { } } -func GetJobTypesFromConfiguration(configFile string) ([]TypeDefinition, error) { - typeDefsByte, err := os.ReadFile(configFile) +func GetJobTypesFromConfiguration(configFolder string) ([]TypeDefinition, error) { + typeDefsByte, err := os.ReadFile(filepath.Join(configFolder, "type_config.json")) if err != nil { return nil, err } @@ -96,5 +99,35 @@ func GetJobTypesFromConfiguration(configFile string) ([]TypeDefinition, error) { return nil, err } + kafkaTypeSchema, err := getTypeSchema(filepath.Join(configFolder, "typeSchemaKafka.json")) + if err != nil { + return nil, err + } + + dMaaPTypeSchema, err := getTypeSchema(filepath.Join(configFolder, "typeSchemaDmaap.json")) + if err != nil { + return nil, err + } + + for i, typeDef := range typeDefs.Types { + if typeDef.IsKafkaType() { + typeDefs.Types[i].TypeSchema = kafkaTypeSchema + } else { + typeDefs.Types[i].TypeSchema = dMaaPTypeSchema + } + } return typeDefs.Types, nil } + +func getTypeSchema(schemaFile string) (interface{}, error) { + typeDefsByte, err := os.ReadFile(schemaFile) + if err != nil { + return nil, err + } + var schema interface{} + err = json.Unmarshal(typeDefsByte, &schema) + if err != nil { + return nil, err + } + return schema, nil +} diff --git a/dmaap-mediator-producer/internal/config/config_test.go b/dmaap-mediator-producer/internal/config/config_test.go index faf5900d..0e081a82 100644 --- a/dmaap-mediator-producer/internal/config/config_test.go +++ b/dmaap-mediator-producer/internal/config/config_test.go @@ -22,6 +22,7 @@ package config import ( "bytes" + "encoding/json" "os" "path/filepath" "testing" @@ -37,6 +38,7 @@ func TestNew_envVarsSetConfigContainSetValues(t *testing.T) { os.Setenv("INFO_PRODUCER_PORT", "8095") os.Setenv("INFO_COORD_ADDR", "infoCoordAddr") os.Setenv("DMAAP_MR_ADDR", "mrHost:3908") + os.Setenv("KAFKA_BOOTSTRAP_SERVERS", "localhost:9093") os.Setenv("PRODUCER_CERT_PATH", "cert") os.Setenv("PRODUCER_KEY_PATH", "key") t.Cleanup(func() { @@ -48,6 +50,7 @@ func TestNew_envVarsSetConfigContainSetValues(t *testing.T) { InfoProducerPort: 8095, InfoCoordinatorAddress: "infoCoordAddr", DMaaPMRAddress: "mrHost:3908", + KafkaBootstrapServers: "localhost:9093", ProducerCertPath: "cert", ProducerKeyPath: "key", } @@ -72,6 +75,7 @@ func TestNew_faultyIntValueSetConfigContainDefaultValueAndWarnInLog(t *testing.T InfoProducerPort: 8085, InfoCoordinatorAddress: "https://informationservice:8434", DMaaPMRAddress: "https://message-router.onap:3905", + KafkaBootstrapServers: "localhost:9092", ProducerCertPath: "security/producer.crt", ProducerKeyPath: "security/producer.key", } @@ -98,6 +102,7 @@ func TestNew_envFaultyLogLevelConfigContainDefaultValues(t *testing.T) { InfoProducerPort: 8085, InfoCoordinatorAddress: "https://informationservice:8434", DMaaPMRAddress: "https://message-router.onap:3905", + KafkaBootstrapServers: "localhost:9092", ProducerCertPath: "security/producer.crt", ProducerKeyPath: "security/producer.key", } @@ -109,29 +114,61 @@ func TestNew_envFaultyLogLevelConfigContainDefaultValues(t *testing.T) { assertions.Contains(logString, "Invalid log level: wrong. Log level will be Info!") } -const typeDefinition = `{"types": [{"id": "type1", "dmaapTopicUrl": "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1"}]}` - -func TestGetTypesFromConfiguration_fileOkShouldReturnSliceOfTypeDefinitions(t *testing.T) { +func TestGetJobTypesFromConfiguration_fileOkShouldReturnSliceOfTypeDefinitions(t *testing.T) { assertions := require.New(t) + typesDir := CreateTypeConfigFiles(t) + t.Cleanup(func() { + os.RemoveAll(typesDir) + }) + + var typeSchemaObj interface{} + json.Unmarshal([]byte(typeSchemaFileContent), &typeSchemaObj) + + types, err := GetJobTypesFromConfiguration(typesDir) + + wantedDMaaPType := TypeDefinition{ + Identity: "type1", + DMaaPTopicURL: "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1", + TypeSchema: typeSchemaObj, + } + wantedKafkaType := TypeDefinition{ + Identity: "type2", + KafkaInputTopic: "TestTopic", + TypeSchema: typeSchemaObj, + } + wantedTypes := []TypeDefinition{wantedDMaaPType, wantedKafkaType} + assertions.EqualValues(wantedTypes, types) + assertions.Nil(err) +} + +const typeDefinition = `{"types": [{"id": "type1", "dmaapTopicUrl": "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1"}, {"id": "type2", "kafkaInputTopic": "TestTopic"}]}` +const typeSchemaFileContent = `{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "filter": { + "type": "string" + } + }, + "additionalProperties": false + }` + +func CreateTypeConfigFiles(t *testing.T) string { typesDir, err := os.MkdirTemp("", "configs") if err != nil { t.Errorf("Unable to create temporary directory for types due to: %v", err) } fname := filepath.Join(typesDir, "type_config.json") - t.Cleanup(func() { - os.RemoveAll(typesDir) - }) if err = os.WriteFile(fname, []byte(typeDefinition), 0666); err != nil { t.Errorf("Unable to create temporary config file for types due to: %v", err) } - - types, err := GetJobTypesFromConfiguration(fname) - - wantedType := TypeDefinition{ - Id: "type1", - DmaapTopicURL: "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1", + fname = filepath.Join(typesDir, "typeSchemaDmaap.json") + if err = os.WriteFile(fname, []byte(typeSchemaFileContent), 0666); err != nil { + t.Errorf("Unable to create temporary schema file for DMaaP type due to: %v", err) } - wantedTypes := []TypeDefinition{wantedType} - assertions.EqualValues(wantedTypes, types) - assertions.Nil(err) + fname = filepath.Join(typesDir, "typeSchemaKafka.json") + if err = os.WriteFile(fname, []byte(typeSchemaFileContent), 0666); err != nil { + t.Errorf("Unable to create temporary schema file for Kafka type due to: %v", err) + } + return typesDir } diff --git a/dmaap-mediator-producer/internal/config/registrator.go b/dmaap-mediator-producer/internal/config/registrator.go index 83ed43f2..1dd0ad1c 100644 --- a/dmaap-mediator-producer/internal/config/registrator.go +++ b/dmaap-mediator-producer/internal/config/registrator.go @@ -32,11 +32,20 @@ import ( const registerTypePath = "/data-producer/v1/info-types/" const registerProducerPath = "/data-producer/v1/info-producers/" -const typeSchema = `{"type": "object","properties": {},"additionalProperties": false}` type TypeDefinition struct { - Id string `json:"id"` - DmaapTopicURL string `json:"dmaapTopicUrl"` + Identity string `json:"id"` + DMaaPTopicURL string `json:"dmaapTopicUrl"` + KafkaInputTopic string `json:"kafkaInputTopic"` + TypeSchema interface{} +} + +func (td TypeDefinition) IsKafkaType() bool { + return td.KafkaInputTopic != "" +} + +func (td TypeDefinition) IsDMaaPType() bool { + return td.DMaaPTopicURL != "" } type ProducerRegistrationInfo struct { @@ -64,8 +73,9 @@ func NewRegistratorImpl(infoCoordAddr string, client restclient.HTTPClient) *Reg func (r RegistratorImpl) RegisterTypes(jobTypes []TypeDefinition) error { for _, jobType := range jobTypes { - body := fmt.Sprintf(`{"info_job_data_schema": %v}`, typeSchema) - if error := restclient.Put(r.infoCoordinatorAddress+registerTypePath+url.PathEscape(jobType.Id), []byte(body), r.httpClient); error != nil { + s, _ := json.Marshal(jobType.TypeSchema) + body := fmt.Sprintf(`{"info_job_data_schema": %v}`, string(s)) + if error := restclient.Put(r.infoCoordinatorAddress+registerTypePath+url.PathEscape(jobType.Identity), []byte(body), r.httpClient); error != nil { return error } log.Debugf("Registered type: %v", jobType) diff --git a/dmaap-mediator-producer/internal/config/registrator_test.go b/dmaap-mediator-producer/internal/config/registrator_test.go index 324aed0c..b2f10ccd 100644 --- a/dmaap-mediator-producer/internal/config/registrator_test.go +++ b/dmaap-mediator-producer/internal/config/registrator_test.go @@ -21,6 +21,7 @@ package config import ( + "encoding/json" "io/ioutil" "net/http" "testing" @@ -39,8 +40,17 @@ func TestRegisterTypes(t *testing.T) { StatusCode: http.StatusCreated, }, nil) + schemaString := `{ + "type": "object", + "properties": {}, + "additionalProperties": false + }` + var schemaObj interface{} + json.Unmarshal([]byte(schemaString), &schemaObj) + type1 := TypeDefinition{ - Id: "Type1", + Identity: "Type1", + TypeSchema: schemaObj, } types := []TypeDefinition{type1} @@ -59,7 +69,7 @@ func TestRegisterTypes(t *testing.T) { assertions.Equal("/data-producer/v1/info-types/Type1", actualRequest.URL.Path) assertions.Equal("application/json", actualRequest.Header.Get("Content-Type")) body, _ := ioutil.ReadAll(actualRequest.Body) - expectedBody := []byte(`{"info_job_data_schema": {"type": "object","properties": {},"additionalProperties": false}}`) + expectedBody := []byte(`{"info_job_data_schema": {"additionalProperties":false,"properties":{},"type":"object"}}`) assertions.Equal(expectedBody, body) clientMock.AssertNumberOfCalls(t, "Do", 1) } diff --git a/dmaap-mediator-producer/internal/jobs/jobs.go b/dmaap-mediator-producer/internal/jobs/jobs.go index 867894f7..86bfe05c 100644 --- a/dmaap-mediator-producer/internal/jobs/jobs.go +++ b/dmaap-mediator-producer/internal/jobs/jobs.go @@ -22,28 +22,36 @@ package jobs import ( "fmt" + "strings" "sync" "time" + "github.com/confluentinc/confluent-kafka-go/kafka" log "github.com/sirupsen/logrus" "oransc.org/nonrtric/dmaapmediatorproducer/internal/config" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient" "oransc.org/nonrtric/dmaapmediatorproducer/internal/restclient" ) type TypeData struct { - TypeId string `json:"id"` - DMaaPTopicURL string `json:"dmaapTopicUrl"` - jobsHandler *jobsHandler + Identity string `json:"id"` + jobsHandler *jobsHandler } +type sourceType string + +const dMaaPSource = sourceType("dmaap") +const kafkaSource = sourceType("kafka") + type JobInfo struct { - Owner string `json:"owner"` - LastUpdated string `json:"last_updated"` - InfoJobIdentity string `json:"info_job_identity"` - TargetUri string `json:"target_uri"` - InfoJobData interface{} `json:"info_job_data"` - InfoTypeIdentity string `json:"info_type_identity"` -} + Owner string `json:"owner"` + LastUpdated string `json:"last_updated"` + InfoJobIdentity string `json:"info_job_identity"` + TargetUri string `json:"target_uri"` + InfoJobData Parameters `json:"info_job_data"` + InfoTypeIdentity string `json:"info_type_identity"` + sourceType sourceType +} // @name JobInfo type JobTypesManager interface { LoadTypesFromConfiguration(types []config.TypeDefinition) []config.TypeDefinition @@ -59,14 +67,16 @@ type JobsManagerImpl struct { allTypes map[string]TypeData pollClient restclient.HTTPClient mrAddress string + kafkaFactory kafkaclient.KafkaFactory distributeClient restclient.HTTPClient } -func NewJobsManagerImpl(pollClient restclient.HTTPClient, mrAddr string, distributeClient restclient.HTTPClient) *JobsManagerImpl { +func NewJobsManagerImpl(pollClient restclient.HTTPClient, mrAddr string, kafkaFactory kafkaclient.KafkaFactory, distributeClient restclient.HTTPClient) *JobsManagerImpl { return &JobsManagerImpl{ allTypes: make(map[string]TypeData), pollClient: pollClient, mrAddress: mrAddr, + kafkaFactory: kafkaFactory, distributeClient: distributeClient, } } @@ -74,6 +84,7 @@ func NewJobsManagerImpl(pollClient restclient.HTTPClient, mrAddr string, distrib func (jm *JobsManagerImpl) AddJobFromRESTCall(ji JobInfo) error { if err := jm.validateJobInfo(ji); err == nil { typeData := jm.allTypes[ji.InfoTypeIdentity] + ji.sourceType = typeData.jobsHandler.sourceType typeData.jobsHandler.addJobCh <- ji log.Debug("Added job: ", ji) return nil @@ -84,7 +95,7 @@ func (jm *JobsManagerImpl) AddJobFromRESTCall(ji JobInfo) error { func (jm *JobsManagerImpl) DeleteJobFromRESTCall(jobId string) { for _, typeData := range jm.allTypes { - log.Debugf("Deleting job %v from type %v", jobId, typeData.TypeId) + log.Debugf("Deleting job %v from type %v", jobId, typeData.Identity) typeData.jobsHandler.deleteJobCh <- jobId } log.Debug("Deleted job: ", jobId) @@ -106,10 +117,12 @@ func (jm *JobsManagerImpl) validateJobInfo(ji JobInfo) error { func (jm *JobsManagerImpl) LoadTypesFromConfiguration(types []config.TypeDefinition) []config.TypeDefinition { for _, typeDef := range types { - jm.allTypes[typeDef.Id] = TypeData{ - TypeId: typeDef.Id, - DMaaPTopicURL: typeDef.DmaapTopicURL, - jobsHandler: newJobsHandler(typeDef.Id, typeDef.DmaapTopicURL, jm.pollClient, jm.distributeClient), + if typeDef.DMaaPTopicURL == "" && typeDef.KafkaInputTopic == "" { + log.Fatal("DMaaPTopicURL or KafkaInputTopic must be defined for type: ", typeDef.Identity) + } + jm.allTypes[typeDef.Identity] = TypeData{ + Identity: typeDef.Identity, + jobsHandler: newJobsHandler(typeDef, jm.mrAddress, jm.kafkaFactory, jm.pollClient, jm.distributeClient), } } return types @@ -126,7 +139,7 @@ func (jm *JobsManagerImpl) GetSupportedTypes() []string { func (jm *JobsManagerImpl) StartJobsForAllTypes() { for _, jobType := range jm.allTypes { - go jobType.jobsHandler.startPollingAndDistribution(jm.mrAddress) + go jobType.jobsHandler.startPollingAndDistribution() } } @@ -134,30 +147,35 @@ func (jm *JobsManagerImpl) StartJobsForAllTypes() { type jobsHandler struct { mu sync.Mutex typeId string - topicUrl string + sourceType sourceType + pollingAgent pollingAgent jobs map[string]job addJobCh chan JobInfo deleteJobCh chan string - pollClient restclient.HTTPClient distributeClient restclient.HTTPClient } -func newJobsHandler(typeId string, topicURL string, pollClient restclient.HTTPClient, distributeClient restclient.HTTPClient) *jobsHandler { +func newJobsHandler(typeDef config.TypeDefinition, mRAddress string, kafkaFactory kafkaclient.KafkaFactory, pollClient restclient.HTTPClient, distributeClient restclient.HTTPClient) *jobsHandler { + pollingAgent := createPollingAgent(typeDef, mRAddress, pollClient, kafkaFactory, typeDef.KafkaInputTopic) + sourceType := kafkaSource + if typeDef.DMaaPTopicURL != "" { + sourceType = dMaaPSource + } return &jobsHandler{ - typeId: typeId, - topicUrl: topicURL, + typeId: typeDef.Identity, + sourceType: sourceType, + pollingAgent: pollingAgent, jobs: make(map[string]job), addJobCh: make(chan JobInfo), deleteJobCh: make(chan string), - pollClient: pollClient, distributeClient: distributeClient, } } -func (jh *jobsHandler) startPollingAndDistribution(mRAddress string) { +func (jh *jobsHandler) startPollingAndDistribution() { go func() { for { - jh.pollAndDistributeMessages(mRAddress) + jh.pollAndDistributeMessages() } }() @@ -168,19 +186,20 @@ func (jh *jobsHandler) startPollingAndDistribution(mRAddress string) { }() } -func (jh *jobsHandler) pollAndDistributeMessages(mRAddress string) { +func (jh *jobsHandler) pollAndDistributeMessages() { log.Debugf("Processing jobs for type: %v", jh.typeId) - messagesBody, error := restclient.Get(mRAddress+jh.topicUrl, jh.pollClient) + messagesBody, error := jh.pollingAgent.pollMessages() if error != nil { - log.Warn("Error getting data from MR. Cause: ", error) - time.Sleep(time.Minute) // Must wait before trying to call MR again + log.Warn("Error getting data from source. Cause: ", error) + time.Sleep(time.Minute) // Must wait before trying to call data source again + return } - log.Debug("Received messages: ", string(messagesBody)) jh.distributeMessages(messagesBody) } func (jh *jobsHandler) distributeMessages(messages []byte) { - if len(messages) > 2 { + if string(messages) != "[]" && len(messages) > 0 { // MR returns an ampty array if there are no messages. + log.Debug("Distributing messages: ", string(messages)) jh.mu.Lock() defer jh.mu.Unlock() for _, job := range jh.jobs { @@ -234,6 +253,61 @@ func (jh *jobsHandler) deleteJob(deletedJob string) { jh.mu.Unlock() } +type pollingAgent interface { + pollMessages() ([]byte, error) +} + +func createPollingAgent(typeDef config.TypeDefinition, mRAddress string, pollClient restclient.HTTPClient, kafkaFactory kafkaclient.KafkaFactory, topicID string) pollingAgent { + if typeDef.DMaaPTopicURL != "" { + return dMaaPPollingAgent{ + messageRouterURL: mRAddress + typeDef.DMaaPTopicURL, + pollClient: pollClient, + } + } else { + return newKafkaPollingAgent(kafkaFactory, typeDef.KafkaInputTopic) + } +} + +type dMaaPPollingAgent struct { + messageRouterURL string + pollClient restclient.HTTPClient +} + +func (pa dMaaPPollingAgent) pollMessages() ([]byte, error) { + return restclient.Get(pa.messageRouterURL, pa.pollClient) +} + +type kafkaPollingAgent struct { + kafkaClient kafkaclient.KafkaClient +} + +func newKafkaPollingAgent(kafkaFactory kafkaclient.KafkaFactory, topicID string) kafkaPollingAgent { + c, err := kafkaclient.NewKafkaClient(kafkaFactory, topicID) + if err != nil { + log.Fatalf("Cannot create Kafka client for topic: %v, error details: %v\n", topicID, err) + } + return kafkaPollingAgent{ + kafkaClient: c, + } +} + +func (pa kafkaPollingAgent) pollMessages() ([]byte, error) { + msg, err := pa.kafkaClient.ReadMessage() + if err == nil { + return msg, nil + } else { + if isKafkaTimedOutError(err) { + return []byte(""), nil + } + return nil, err + } +} + +func isKafkaTimedOutError(err error) bool { + kafkaErr, ok := err.(kafka.Error) + return ok && kafkaErr.Code() == kafka.ErrTimedOut +} + type job struct { jobInfo JobInfo client restclient.HTTPClient @@ -242,6 +316,7 @@ type job struct { } func newJob(j JobInfo, c restclient.HTTPClient) job { + return job{ jobInfo: j, client: c, @@ -250,7 +325,24 @@ func newJob(j JobInfo, c restclient.HTTPClient) job { } } +type Parameters struct { + BufferTimeout BufferTimeout `json:"bufferTimeout"` +} // @name Parameters + +type BufferTimeout struct { + MaxSize int `json:"maxSize"` + MaxTimeMiliseconds int64 `json:"maxTimeMiliseconds"` +} // @name BufferTimeout + func (j *job) start() { + if j.isJobBuffered() { + j.startReadingMessagesBuffered() + } else { + j.startReadingSingleMessages() + } +} + +func (j *job) startReadingSingleMessages() { out: for { select { @@ -263,10 +355,107 @@ out: } } +func (j *job) startReadingMessagesBuffered() { +out: + for { + select { + case <-j.controlChannel: + log.Debug("Stop distribution for job: ", j.jobInfo.InfoJobIdentity) + break out + default: + msgs := j.read(j.jobInfo.InfoJobData.BufferTimeout) + if len(msgs) > 0 { + j.sendMessagesToConsumer(msgs) + } + } + } +} + +func (j *job) read(bufferParams BufferTimeout) []byte { + wg := sync.WaitGroup{} + wg.Add(bufferParams.MaxSize) + rawMsgs := make([][]byte, 0, bufferParams.MaxSize) + c := make(chan struct{}) + go func() { + i := 0 + out: + for { + select { + case <-c: + break out + case msg := <-j.messagesChannel: + rawMsgs = append(rawMsgs, msg) + i++ + wg.Done() + if i == bufferParams.MaxSize { + break out + } + } + } + }() + j.waitTimeout(&wg, time.Duration(bufferParams.MaxTimeMiliseconds)*time.Millisecond) + close(c) + return getAsJSONArray(rawMsgs) +} + +func getAsJSONArray(rawMsgs [][]byte) []byte { + if len(rawMsgs) == 0 { + return []byte("") + } + strings := "" + for i := 0; i < len(rawMsgs); i++ { + strings = strings + makeIntoString(rawMsgs[i]) + strings = addSeparatorIfNeeded(strings, i, len(rawMsgs)) + } + return []byte(wrapInJSONArray(strings)) +} + +func makeIntoString(rawMsg []byte) string { + return `"` + strings.ReplaceAll(string(rawMsg), "\"", "\\\"") + `"` +} + +func addSeparatorIfNeeded(strings string, position, length int) string { + if position < length-1 { + strings = strings + "," + } + return strings +} + +func wrapInJSONArray(strings string) string { + return "[" + strings + "]" +} + +func (j *job) waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { + c := make(chan struct{}) + go func() { + defer close(c) + wg.Wait() + }() + select { + case <-c: + return false // completed normally + case <-time.After(timeout): + return true // timed out + } +} + func (j *job) sendMessagesToConsumer(messages []byte) { log.Debug("Processing job: ", j.jobInfo.InfoJobIdentity) - if postErr := restclient.Post(j.jobInfo.TargetUri, messages, j.client); postErr != nil { + contentType := restclient.ContentTypeJSON + if j.isJobKafka() && !j.isJobBuffered() { + contentType = restclient.ContentTypePlain + } + if postErr := restclient.Post(j.jobInfo.TargetUri, messages, contentType, j.client); postErr != nil { log.Warnf("Error posting data for job: %v. Cause: %v", j.jobInfo, postErr) + return } log.Debugf("Messages for job: %v distributed to consumer: %v", j.jobInfo.InfoJobIdentity, j.jobInfo.Owner) } + +func (j *job) isJobBuffered() bool { + return j.jobInfo.InfoJobData.BufferTimeout.MaxSize > 0 && j.jobInfo.InfoJobData.BufferTimeout.MaxTimeMiliseconds > 0 +} + +func (j *job) isJobKafka() bool { + return j.jobInfo.sourceType == kafkaSource +} diff --git a/dmaap-mediator-producer/internal/jobs/jobs_test.go b/dmaap-mediator-producer/internal/jobs/jobs_test.go index 30b4ffd9..7d021046 100644 --- a/dmaap-mediator-producer/internal/jobs/jobs_test.go +++ b/dmaap-mediator-producer/internal/jobs/jobs_test.go @@ -22,52 +22,62 @@ package jobs import ( "bytes" + "fmt" "io/ioutil" "net/http" + "strconv" "sync" "testing" "time" + "github.com/confluentinc/confluent-kafka-go/kafka" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "oransc.org/nonrtric/dmaapmediatorproducer/internal/config" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient" + "oransc.org/nonrtric/dmaapmediatorproducer/mocks" ) -const typeDefinition = `{"types": [{"id": "type1", "dmaapTopicUrl": "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1"}]}` - -func TestJobsManagerGetTypes_filesOkShouldReturnSliceOfTypesAndProvideSupportedTypes(t *testing.T) { +func TestJobsManagerLoadTypesFromConfiguration_shouldReturnSliceOfTypesAndProvideSupportedTypes(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) - wantedType := config.TypeDefinition{ - Id: "type1", - DmaapTopicURL: "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1", + wantedDMaaPType := config.TypeDefinition{ + Identity: "type1", + DMaaPTopicURL: "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1", + } + wantedKafkaType := config.TypeDefinition{ + Identity: "type2", + KafkaInputTopic: "topic", } - wantedTypes := []config.TypeDefinition{wantedType} + wantedTypes := []config.TypeDefinition{wantedDMaaPType, wantedKafkaType} types := managerUnderTest.LoadTypesFromConfiguration(wantedTypes) assertions.EqualValues(wantedTypes, types) supportedTypes := managerUnderTest.GetSupportedTypes() - assertions.EqualValues([]string{"type1"}, supportedTypes) + assertions.ElementsMatch([]string{"type1", "type2"}, supportedTypes) + assertions.Equal(dMaaPSource, managerUnderTest.allTypes["type1"].jobsHandler.sourceType) + assertions.Equal(kafkaSource, managerUnderTest.allTypes["type2"].jobsHandler.sourceType) } func TestJobsManagerAddJobWhenTypeIsSupported_shouldAddJobToChannel(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) wantedJob := JobInfo{ Owner: "owner", LastUpdated: "now", InfoJobIdentity: "job1", TargetUri: "target", - InfoJobData: "{}", + InfoJobData: Parameters{}, InfoTypeIdentity: "type1", } jobsHandler := jobsHandler{ addJobCh: make(chan JobInfo)} managerUnderTest.allTypes["type1"] = TypeData{ - TypeId: "type1", + Identity: "type1", jobsHandler: &jobsHandler, } @@ -83,7 +93,7 @@ func TestJobsManagerAddJobWhenTypeIsSupported_shouldAddJobToChannel(t *testing.T func TestJobsManagerAddJobWhenTypeIsNotSupported_shouldReturnError(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) jobInfo := JobInfo{ InfoTypeIdentity: "type1", } @@ -95,9 +105,9 @@ func TestJobsManagerAddJobWhenTypeIsNotSupported_shouldReturnError(t *testing.T) func TestJobsManagerAddJobWhenJobIdMissing_shouldReturnError(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) managerUnderTest.allTypes["type1"] = TypeData{ - TypeId: "type1", + Identity: "type1", } jobInfo := JobInfo{ @@ -105,14 +115,14 @@ func TestJobsManagerAddJobWhenJobIdMissing_shouldReturnError(t *testing.T) { } err := managerUnderTest.AddJobFromRESTCall(jobInfo) assertions.NotNil(err) - assertions.Equal("missing required job identity: { type1}", err.Error()) + assertions.Equal("missing required job identity: { {{0 0}} type1 }", err.Error()) } func TestJobsManagerAddJobWhenTargetUriMissing_shouldReturnError(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) managerUnderTest.allTypes["type1"] = TypeData{ - TypeId: "type1", + Identity: "type1", } jobInfo := JobInfo{ @@ -121,16 +131,16 @@ func TestJobsManagerAddJobWhenTargetUriMissing_shouldReturnError(t *testing.T) { } err := managerUnderTest.AddJobFromRESTCall(jobInfo) assertions.NotNil(err) - assertions.Equal("missing required target URI: { job1 type1}", err.Error()) + assertions.Equal("missing required target URI: { job1 {{0 0}} type1 }", err.Error()) } func TestJobsManagerDeleteJob_shouldSendDeleteToChannel(t *testing.T) { assertions := require.New(t) - managerUnderTest := NewJobsManagerImpl(nil, "", nil) + managerUnderTest := NewJobsManagerImpl(nil, "", kafkaclient.KafkaFactoryImpl{}, nil) jobsHandler := jobsHandler{ deleteJobCh: make(chan string)} managerUnderTest.allTypes["type1"] = TypeData{ - TypeId: "type1", + Identity: "type1", jobsHandler: &jobsHandler, } @@ -139,21 +149,21 @@ func TestJobsManagerDeleteJob_shouldSendDeleteToChannel(t *testing.T) { assertions.Equal("job2", <-jobsHandler.deleteJobCh) } -func TestAddJobToJobsManager_shouldStartPollAndDistributeMessages(t *testing.T) { +func TestStartJobsManagerAddDMaaPJob_shouldStartPollAndDistributeMessages(t *testing.T) { assertions := require.New(t) called := false - messages := `[{"message": {"data": "data"}}]` + dMaaPMessages := `[{"message": {"data": "dmaap"}}]` pollClientMock := NewTestClient(func(req *http.Request) *http.Response { if req.URL.String() == "http://mrAddr/topicUrl" { assertions.Equal(req.Method, "GET") body := "[]" if !called { called = true - body = messages + body = dMaaPMessages } return &http.Response{ - StatusCode: 200, + StatusCode: http.StatusOK, Body: ioutil.NopCloser(bytes.NewReader([]byte(body))), Header: make(http.Header), // Must be set to non-nil value or it panics } @@ -165,9 +175,9 @@ func TestAddJobToJobsManager_shouldStartPollAndDistributeMessages(t *testing.T) wg := sync.WaitGroup{} distributeClientMock := NewTestClient(func(req *http.Request) *http.Response { - if req.URL.String() == "http://consumerHost/target" { + if req.URL.String() == "http://consumerHost/dmaaptarget" { assertions.Equal(req.Method, "POST") - assertions.Equal(messages, getBodyAsString(req, t)) + assertions.Equal(dMaaPMessages, getBodyAsString(req, t)) assertions.Equal("application/json", req.Header.Get("Content-Type")) wg.Done() return &http.Response{ @@ -180,25 +190,88 @@ func TestAddJobToJobsManager_shouldStartPollAndDistributeMessages(t *testing.T) t.Fail() return nil }) - jobsHandler := newJobsHandler("type1", "/topicUrl", pollClientMock, distributeClientMock) - - jobsManager := NewJobsManagerImpl(pollClientMock, "http://mrAddr", distributeClientMock) - jobsManager.allTypes["type1"] = TypeData{ + dMaaPTypeDef := config.TypeDefinition{ + Identity: "type1", DMaaPTopicURL: "/topicUrl", - TypeId: "type1", - jobsHandler: jobsHandler, } + dMaaPJobsHandler := newJobsHandler(dMaaPTypeDef, "http://mrAddr", nil, pollClientMock, distributeClientMock) + jobsManager := NewJobsManagerImpl(pollClientMock, "http://mrAddr", kafkaclient.KafkaFactoryImpl{}, distributeClientMock) + jobsManager.allTypes["type1"] = TypeData{ + Identity: "type1", + jobsHandler: dMaaPJobsHandler, + } jobsManager.StartJobsForAllTypes() - jobInfo := JobInfo{ + dMaaPJobInfo := JobInfo{ InfoTypeIdentity: "type1", InfoJobIdentity: "job1", - TargetUri: "http://consumerHost/target", + TargetUri: "http://consumerHost/dmaaptarget", + } + + wg.Add(1) // Wait till the distribution has happened + err := jobsManager.AddJobFromRESTCall(dMaaPJobInfo) + assertions.Nil(err) + + if waitTimeout(&wg, 2*time.Second) { + t.Error("Not all calls to server were made") + t.Fail() + } +} + +func TestStartJobsManagerAddKafkaJob_shouldStartPollAndDistributeMessages(t *testing.T) { + assertions := require.New(t) + + kafkaMessages := `1` + wg := sync.WaitGroup{} + distributeClientMock := NewTestClient(func(req *http.Request) *http.Response { + if req.URL.String() == "http://consumerHost/kafkatarget" { + assertions.Equal(req.Method, "POST") + assertions.Equal(kafkaMessages, getBodyAsString(req, t)) + assertions.Equal("text/plain", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } + t.Error("Wrong call to client: ", req) + t.Fail() + return nil + }) + + kafkaTypeDef := config.TypeDefinition{ + Identity: "type2", + KafkaInputTopic: "topic", + } + kafkaFactoryMock := mocks.KafkaFactory{} + kafkaConsumerMock := mocks.KafkaConsumer{} + kafkaConsumerMock.On("Commit").Return([]kafka.TopicPartition{}, error(nil)) + kafkaConsumerMock.On("Subscribe", mock.Anything).Return(error(nil)) + kafkaConsumerMock.On("ReadMessage", mock.Anything).Return(&kafka.Message{ + Value: []byte(kafkaMessages), + }, error(nil)).Once() + kafkaConsumerMock.On("ReadMessage", mock.Anything).Return(nil, fmt.Errorf("Just to stop")) + kafkaFactoryMock.On("NewKafkaConsumer", mock.Anything).Return(kafkaConsumerMock, nil) + kafkaJobsHandler := newJobsHandler(kafkaTypeDef, "", kafkaFactoryMock, nil, distributeClientMock) + + jobsManager := NewJobsManagerImpl(nil, "", kafkaFactoryMock, distributeClientMock) + jobsManager.allTypes["type2"] = TypeData{ + Identity: "type2", + jobsHandler: kafkaJobsHandler, + } + + jobsManager.StartJobsForAllTypes() + + kafkaJobInfo := JobInfo{ + InfoTypeIdentity: "type2", + InfoJobIdentity: "job2", + TargetUri: "http://consumerHost/kafkatarget", } wg.Add(1) // Wait till the distribution has happened - err := jobsManager.AddJobFromRESTCall(jobInfo) + err := jobsManager.AddJobFromRESTCall(kafkaJobInfo) assertions.Nil(err) if waitTimeout(&wg, 2*time.Second) { @@ -210,7 +283,11 @@ func TestAddJobToJobsManager_shouldStartPollAndDistributeMessages(t *testing.T) func TestJobsHandlerDeleteJob_shouldDeleteJobFromJobsMap(t *testing.T) { jobToDelete := newJob(JobInfo{}, nil) go jobToDelete.start() - jobsHandler := newJobsHandler("type1", "/topicUrl", nil, nil) + typeDef := config.TypeDefinition{ + Identity: "type1", + DMaaPTopicURL: "/topicUrl", + } + jobsHandler := newJobsHandler(typeDef, "http://mrAddr", kafkaclient.KafkaFactoryImpl{}, nil, nil) jobsHandler.jobs["job1"] = jobToDelete go jobsHandler.monitorManagementChannels() @@ -233,7 +310,11 @@ func TestJobsHandlerEmptyJobMessageBufferWhenItIsFull(t *testing.T) { InfoJobIdentity: "job", }, nil) - jobsHandler := newJobsHandler("type1", "/topicUrl", nil, nil) + typeDef := config.TypeDefinition{ + Identity: "type1", + DMaaPTopicURL: "/topicUrl", + } + jobsHandler := newJobsHandler(typeDef, "http://mrAddr", kafkaclient.KafkaFactoryImpl{}, nil, nil) jobsHandler.jobs["job1"] = job fillMessagesBuffer(job.messagesChannel) @@ -243,6 +324,147 @@ func TestJobsHandlerEmptyJobMessageBufferWhenItIsFull(t *testing.T) { require.New(t).Len(job.messagesChannel, 0) } +func TestKafkaPollingAgentTimedOut_shouldResultInEMptyMessages(t *testing.T) { + assertions := require.New(t) + + kafkaFactoryMock := mocks.KafkaFactory{} + kafkaConsumerMock := mocks.KafkaConsumer{} + kafkaConsumerMock.On("Commit").Return([]kafka.TopicPartition{}, error(nil)) + kafkaConsumerMock.On("Subscribe", mock.Anything).Return(error(nil)) + kafkaConsumerMock.On("ReadMessage", mock.Anything).Return(nil, kafka.NewError(kafka.ErrTimedOut, "", false)) + kafkaFactoryMock.On("NewKafkaConsumer", mock.Anything).Return(kafkaConsumerMock, nil) + + pollingAgentUnderTest := newKafkaPollingAgent(kafkaFactoryMock, "") + messages, err := pollingAgentUnderTest.pollMessages() + + assertions.Equal([]byte(""), messages) + assertions.Nil(err) +} + +func TestJobWithoutParameters_shouldSendOneMessageAtATime(t *testing.T) { + assertions := require.New(t) + + wg := sync.WaitGroup{} + messageNo := 1 + distributeClientMock := NewTestClient(func(req *http.Request) *http.Response { + if req.URL.String() == "http://consumerHost/target" { + assertions.Equal(req.Method, "POST") + assertions.Equal(fmt.Sprint("message", messageNo), getBodyAsString(req, t)) + messageNo++ + assertions.Equal("text/plain", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } + t.Error("Wrong call to client: ", req) + t.Fail() + return nil + }) + + jobUnderTest := newJob(JobInfo{ + sourceType: kafkaSource, + TargetUri: "http://consumerHost/target", + }, distributeClientMock) + + wg.Add(2) + go jobUnderTest.start() + + jobUnderTest.messagesChannel <- []byte("message1") + jobUnderTest.messagesChannel <- []byte("message2") + + if waitTimeout(&wg, 2*time.Second) { + t.Error("Not all calls to server were made") + t.Fail() + } +} + +func TestJobWithBufferedParameters_shouldSendMessagesTogether(t *testing.T) { + assertions := require.New(t) + + wg := sync.WaitGroup{} + distributeClientMock := NewTestClient(func(req *http.Request) *http.Response { + if req.URL.String() == "http://consumerHost/target" { + assertions.Equal(req.Method, "POST") + assertions.Equal(`["{\"data\": 1}","{\"data\": 2}","ABCDEFGH"]`, getBodyAsString(req, t)) + assertions.Equal("application/json", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } + t.Error("Wrong call to client: ", req) + t.Fail() + return nil + }) + + jobUnderTest := newJob(JobInfo{ + TargetUri: "http://consumerHost/target", + InfoJobData: Parameters{ + BufferTimeout: BufferTimeout{ + MaxSize: 5, + MaxTimeMiliseconds: 200, + }, + }, + }, distributeClientMock) + + wg.Add(1) + go jobUnderTest.start() + + go func() { + jobUnderTest.messagesChannel <- []byte(`{"data": 1}`) + jobUnderTest.messagesChannel <- []byte(`{"data": 2}`) + jobUnderTest.messagesChannel <- []byte("ABCDEFGH") + }() + + if waitTimeout(&wg, 2*time.Second) { + t.Error("Not all calls to server were made") + t.Fail() + } +} + +func TestJobReadMoreThanBufferSizeMessages_shouldOnlyReturnMaxSizeNoOfMessages(t *testing.T) { + assertions := require.New(t) + + jobUnderTest := newJob(JobInfo{}, nil) + + go func() { + for i := 0; i < 4; i++ { + jobUnderTest.messagesChannel <- []byte(strconv.Itoa(i)) + } + }() + + msgs := jobUnderTest.read(BufferTimeout{ + MaxSize: 2, + MaxTimeMiliseconds: 200, + }) + + assertions.Equal([]byte("[\"0\",\"1\"]"), msgs) +} +func TestJobReadBufferedWhenTimeout_shouldOnlyReturnMessagesSentBeforeTimeout(t *testing.T) { + assertions := require.New(t) + + jobUnderTest := newJob(JobInfo{}, nil) + + go func() { + for i := 0; i < 4; i++ { + time.Sleep(10 * time.Millisecond) + jobUnderTest.messagesChannel <- []byte(strconv.Itoa(i)) + } + }() + + msgs := jobUnderTest.read(BufferTimeout{ + MaxSize: 2, + MaxTimeMiliseconds: 30, + }) + + assertions.Equal([]byte("[\"0\",\"1\"]"), msgs) +} + func fillMessagesBuffer(mc chan []byte) { for i := 0; i < cap(mc); i++ { mc <- []byte("msg") diff --git a/dmaap-mediator-producer/internal/kafkaclient/kafkaclient.go b/dmaap-mediator-producer/internal/kafkaclient/kafkaclient.go new file mode 100644 index 00000000..16abcb4e --- /dev/null +++ b/dmaap-mediator-producer/internal/kafkaclient/kafkaclient.go @@ -0,0 +1,94 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package kafkaclient + +import ( + "time" + + "github.com/confluentinc/confluent-kafka-go/kafka" +) + +type KafkaFactory interface { + NewKafkaConsumer(topicID string) (KafkaConsumer, error) +} + +type KafkaFactoryImpl struct { + BootstrapServer string +} + +func (kf KafkaFactoryImpl) NewKafkaConsumer(topicID string) (KafkaConsumer, error) { + consumer, err := kafka.NewConsumer(&kafka.ConfigMap{ + "bootstrap.servers": kf.BootstrapServer, + "group.id": "dmaap-mediator-producer", + "auto.offset.reset": "earliest", + }) + if err != nil { + return nil, err + } + return KafkaConsumerImpl{consumer: consumer}, nil +} + +func NewKafkaClient(factory KafkaFactory, topicID string) (KafkaClient, error) { + consumer, err := factory.NewKafkaConsumer(topicID) + if err != nil { + return KafkaClient{}, err + } + consumer.Commit() + err = consumer.Subscribe(topicID) + if err != nil { + return KafkaClient{}, err + } + return KafkaClient{consumer: consumer}, nil +} + +type KafkaClient struct { + consumer KafkaConsumer +} + +func (kc KafkaClient) ReadMessage() ([]byte, error) { + msg, err := kc.consumer.ReadMessage(time.Second) + if err != nil { + return nil, err + } + return msg.Value, nil +} + +type KafkaConsumer interface { + Commit() ([]kafka.TopicPartition, error) + Subscribe(topic string) (err error) + ReadMessage(timeout time.Duration) (*kafka.Message, error) +} + +type KafkaConsumerImpl struct { + consumer *kafka.Consumer +} + +func (kc KafkaConsumerImpl) Commit() ([]kafka.TopicPartition, error) { + return kc.consumer.Commit() +} + +func (kc KafkaConsumerImpl) Subscribe(topic string) error { + return kc.consumer.Subscribe(topic, nil) +} + +func (kc KafkaConsumerImpl) ReadMessage(timeout time.Duration) (*kafka.Message, error) { + return kc.consumer.ReadMessage(timeout) +} diff --git a/dmaap-mediator-producer/internal/restclient/HTTPClient.go b/dmaap-mediator-producer/internal/restclient/HTTPClient.go index 9a827e7a..a7582c2b 100644 --- a/dmaap-mediator-producer/internal/restclient/HTTPClient.go +++ b/dmaap-mediator-producer/internal/restclient/HTTPClient.go @@ -34,6 +34,9 @@ import ( log "github.com/sirupsen/logrus" ) +const ContentTypeJSON = "application/json" +const ContentTypePlain = "text/plain" + // HTTPClient interface type HTTPClient interface { Get(url string) (*http.Response, error) @@ -68,16 +71,16 @@ func Get(url string, client HTTPClient) ([]byte, error) { } func Put(url string, body []byte, client HTTPClient) error { - return do(http.MethodPut, url, body, client) + return do(http.MethodPut, url, body, ContentTypeJSON, client) } -func Post(url string, body []byte, client HTTPClient) error { - return do(http.MethodPost, url, body, client) +func Post(url string, body []byte, contentType string, client HTTPClient) error { + return do(http.MethodPost, url, body, contentType, client) } -func do(method string, url string, body []byte, client HTTPClient) error { +func do(method string, url string, body []byte, contentType string, client HTTPClient) error { if req, reqErr := http.NewRequest(method, url, bytes.NewBuffer(body)); reqErr == nil { - req.Header.Set("Content-Type", "application/json") + req.Header.Set("Content-Type", contentType) if response, respErr := client.Do(req); respErr == nil { if isResponseSuccess(response.StatusCode) { return nil diff --git a/dmaap-mediator-producer/internal/restclient/HTTPClient_test.go b/dmaap-mediator-producer/internal/restclient/HTTPClient_test.go index 20c26dda..90db6ae4 100644 --- a/dmaap-mediator-producer/internal/restclient/HTTPClient_test.go +++ b/dmaap-mediator-producer/internal/restclient/HTTPClient_test.go @@ -142,7 +142,7 @@ func TestPostOk(t *testing.T) { StatusCode: http.StatusOK, }, nil) - if err := Post("http://localhost:9990", []byte("body"), &clientMock); err != nil { + if err := Post("http://localhost:9990", []byte("body"), "application/json", &clientMock); err != nil { t.Errorf("Put() error = %v, did not want error", err) } var actualRequest *http.Request @@ -202,7 +202,7 @@ func Test_doErrorCases(t *testing.T) { StatusCode: tt.args.mockReturnStatus, Body: ioutil.NopCloser(bytes.NewReader(tt.args.mockReturnBody)), }, tt.args.mockReturnError) - err := do("PUT", tt.args.url, nil, &clientMock) + err := do("PUT", tt.args.url, nil, "", &clientMock) assertions.Equal(tt.wantErr, err, tt.name) }) } diff --git a/dmaap-mediator-producer/internal/server/server.go b/dmaap-mediator-producer/internal/server/server.go index 8c5577d7..46bc2a23 100644 --- a/dmaap-mediator-producer/internal/server/server.go +++ b/dmaap-mediator-producer/internal/server/server.go @@ -31,13 +31,26 @@ import ( "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs" ) -const StatusPath = "/status" -const AddJobPath = "/jobs" +const HealthCheckPath = "/health_check" +const AddJobPath = "/info_job" const jobIdToken = "infoJobId" const deleteJobPath = AddJobPath + "/{" + jobIdToken + "}" const logLevelToken = "level" const logAdminPath = "/admin/log" +type ErrorInfo struct { + // A URI reference that identifies the problem type. + Type string `json:"type" swaggertype:"string"` + // A short, human-readable summary of the problem type. + Title string `json:"title" swaggertype:"string"` + // The HTTP status code generated by the origin server for this occurrence of the problem. + Status int `json:"status" swaggertype:"integer" example:"400"` + // A human-readable explanation specific to this occurrence of the problem. + Detail string `json:"detail" swaggertype:"string" example:"Info job type not found"` + // A URI reference that identifies the specific occurrence of the problem. + Instance string `json:"instance" swaggertype:"string"` +} // @name ErrorInfo + type ProducerCallbackHandler struct { jobsManager jobs.JobsManager } @@ -48,10 +61,10 @@ func NewProducerCallbackHandler(jm jobs.JobsManager) *ProducerCallbackHandler { } } -func NewRouter(jm jobs.JobsManager) *mux.Router { +func NewRouter(jm jobs.JobsManager, hcf func(http.ResponseWriter, *http.Request)) *mux.Router { callbackHandler := NewProducerCallbackHandler(jm) r := mux.NewRouter() - r.HandleFunc(StatusPath, statusHandler).Methods(http.MethodGet).Name("status") + r.HandleFunc(HealthCheckPath, hcf).Methods(http.MethodGet).Name("health_check") r.HandleFunc(AddJobPath, callbackHandler.addInfoJobHandler).Methods(http.MethodPost).Name("add") r.HandleFunc(deleteJobPath, callbackHandler.deleteInfoJobHandler).Methods(http.MethodDelete).Name("delete") r.HandleFunc(logAdminPath, callbackHandler.setLogLevel).Methods(http.MethodPut).Name("setLogLevel") @@ -60,26 +73,38 @@ func NewRouter(jm jobs.JobsManager) *mux.Router { return r } -func statusHandler(w http.ResponseWriter, r *http.Request) { - // Just respond OK to show the server is alive for now. Might be extended later. -} - +// @Summary Add info job +// @Description Callback for ICS to add an info job +// @Tags Data producer (callbacks) +// @Accept json +// @Param user body jobs.JobInfo true "Info job data" +// @Success 200 +// @Failure 400 {object} ErrorInfo "Problem as defined in https://tools.ietf.org/html/rfc7807" +// @Header 400 {string} Content-Type "application/problem+json" +// @Router /info_job [post] func (h *ProducerCallbackHandler) addInfoJobHandler(w http.ResponseWriter, r *http.Request) { b, readErr := ioutil.ReadAll(r.Body) if readErr != nil { - http.Error(w, fmt.Sprintf("Unable to read body due to: %v", readErr), http.StatusBadRequest) + returnError(fmt.Sprintf("Unable to read body due to: %v", readErr), w) return } jobInfo := jobs.JobInfo{} if unmarshalErr := json.Unmarshal(b, &jobInfo); unmarshalErr != nil { - http.Error(w, fmt.Sprintf("Invalid json body. Cause: %v", unmarshalErr), http.StatusBadRequest) + returnError(fmt.Sprintf("Invalid json body. Cause: %v", unmarshalErr), w) return } if err := h.jobsManager.AddJobFromRESTCall(jobInfo); err != nil { - http.Error(w, fmt.Sprintf("Invalid job info. Cause: %v", err), http.StatusBadRequest) + returnError(fmt.Sprintf("Invalid job info. Cause: %v", err), w) + return } } +// @Summary Delete info job +// @Description Callback for ICS to delete an info job +// @Tags Data producer (callbacks) +// @Param infoJobId path string true "Info job ID" +// @Success 200 +// @Router /info_job/{infoJobId} [delete] func (h *ProducerCallbackHandler) deleteInfoJobHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id, ok := vars[jobIdToken] @@ -91,13 +116,21 @@ func (h *ProducerCallbackHandler) deleteInfoJobHandler(w http.ResponseWriter, r h.jobsManager.DeleteJobFromRESTCall(id) } +// @Summary Set log level +// @Description Set the log level of the producer. +// @Tags Admin +// @Param level query string false "string enums" Enums(Error, Warn, Info, Debug) +// @Success 200 +// @Failure 400 {object} ErrorInfo "Problem as defined in https://tools.ietf.org/html/rfc7807" +// @Header 400 {string} Content-Type "application/problem+json" +// @Router /admin/log [put] func (h *ProducerCallbackHandler) setLogLevel(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() logLevelStr := query.Get(logLevelToken) if loglevel, err := log.ParseLevel(logLevelStr); err == nil { log.SetLevel(loglevel) } else { - http.Error(w, fmt.Sprintf("Invalid log level: %v. Log level will not be changed!", logLevelStr), http.StatusBadRequest) + returnError(fmt.Sprintf("Invalid log level: %v. Log level will not be changed!", logLevelStr), w) return } } @@ -113,3 +146,13 @@ type methodNotAllowedHandler struct{} func (h *methodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed) } + +func returnError(msg string, w http.ResponseWriter) { + errInfo := ErrorInfo{ + Status: http.StatusBadRequest, + Detail: msg, + } + w.Header().Add("Content-Type", "application/problem+json") + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(errInfo) +} diff --git a/dmaap-mediator-producer/internal/server/server_test.go b/dmaap-mediator-producer/internal/server/server_test.go index 1db36446..dbe503dd 100644 --- a/dmaap-mediator-producer/internal/server/server_test.go +++ b/dmaap-mediator-producer/internal/server/server_test.go @@ -34,20 +34,20 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs" - "oransc.org/nonrtric/dmaapmediatorproducer/mocks/jobhandler" + "oransc.org/nonrtric/dmaapmediatorproducer/mocks/jobshandler" ) func TestNewRouter(t *testing.T) { assertions := require.New(t) - r := NewRouter(nil) - statusRoute := r.Get("status") + r := NewRouter(nil, nil) + statusRoute := r.Get("health_check") assertions.NotNil(statusRoute) supportedMethods, err := statusRoute.GetMethods() assertions.Equal([]string{http.MethodGet}, supportedMethods) assertions.Nil(err) path, _ := statusRoute.GetPathTemplate() - assertions.Equal("/status", path) + assertions.Equal("/health_check", path) addJobRoute := r.Get("add") assertions.NotNil(addJobRoute) @@ -55,7 +55,7 @@ func TestNewRouter(t *testing.T) { assertions.Equal([]string{http.MethodPost}, supportedMethods) assertions.Nil(err) path, _ = addJobRoute.GetPathTemplate() - assertions.Equal("/jobs", path) + assertions.Equal("/info_job", path) deleteJobRoute := r.Get("delete") assertions.NotNil(deleteJobRoute) @@ -63,7 +63,7 @@ func TestNewRouter(t *testing.T) { assertions.Equal([]string{http.MethodDelete}, supportedMethods) assertions.Nil(err) path, _ = deleteJobRoute.GetPathTemplate() - assertions.Equal("/jobs/{infoJobId}", path) + assertions.Equal("/info_job/{infoJobId}", path) notFoundHandler := r.NotFoundHandler handler := http.HandlerFunc(notFoundHandler.ServeHTTP) @@ -88,20 +88,7 @@ func TestNewRouter(t *testing.T) { assertions.Equal("/admin/log", path) } -func TestStatusHandler(t *testing.T) { - assertions := require.New(t) - - handler := http.HandlerFunc(statusHandler) - responseRecorder := httptest.NewRecorder() - r := newRequest(http.MethodGet, "/status", nil, t) - - handler.ServeHTTP(responseRecorder, r) - - assertions.Equal(http.StatusOK, responseRecorder.Code) - assertions.Equal("", responseRecorder.Body.String()) -} - -func TestAddInfoJobHandler(t *testing.T) { +func TestAddInfoJobToJobsHandler(t *testing.T) { assertions := require.New(t) type args struct { @@ -109,27 +96,27 @@ func TestAddInfoJobHandler(t *testing.T) { mockReturn error } tests := []struct { - name string - args args - wantedStatus int - wantedBody string + name string + args args + wantedStatus int + wantedErrorInfo *ErrorInfo }{ { - name: "AddInfoJobHandler with correct job, should return OK", + name: "AddInfoJobToJobsHandler with correct job, should return OK", args: args{ job: jobs.JobInfo{ Owner: "owner", LastUpdated: "now", InfoJobIdentity: "jobId", TargetUri: "target", - InfoJobData: "{}", + InfoJobData: jobs.Parameters{}, InfoTypeIdentity: "type", }, }, wantedStatus: http.StatusOK, }, { - name: "AddInfoJobHandler with incorrect job info, should return BadRequest", + name: "AddInfoJobToJobsHandler with incorrect job info, should return BadRequest", args: args{ job: jobs.JobInfo{ Owner: "bad", @@ -137,15 +124,18 @@ func TestAddInfoJobHandler(t *testing.T) { mockReturn: errors.New("error"), }, wantedStatus: http.StatusBadRequest, - wantedBody: "Invalid job info. Cause: error", + wantedErrorInfo: &ErrorInfo{ + Status: http.StatusBadRequest, + Detail: "Invalid job info. Cause: error", + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - jobHandlerMock := jobhandler.JobHandler{} - jobHandlerMock.On("AddJobFromRESTCall", tt.args.job).Return(tt.args.mockReturn) + jobsHandlerMock := jobshandler.JobsHandler{} + jobsHandlerMock.On("AddJobFromRESTCall", tt.args.job).Return(tt.args.mockReturn) - callbackHandlerUnderTest := NewProducerCallbackHandler(&jobHandlerMock) + callbackHandlerUnderTest := NewProducerCallbackHandler(&jobsHandlerMock) handler := http.HandlerFunc(callbackHandlerUnderTest.addInfoJobHandler) responseRecorder := httptest.NewRecorder() @@ -154,18 +144,27 @@ func TestAddInfoJobHandler(t *testing.T) { handler.ServeHTTP(responseRecorder, r) assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name) - assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name) - jobHandlerMock.AssertCalled(t, "AddJobFromRESTCall", tt.args.job) + if tt.wantedErrorInfo != nil { + var actualErrInfo ErrorInfo + err := json.Unmarshal(getBody(responseRecorder, t), &actualErrInfo) + if err != nil { + t.Error("Unable to unmarshal error body", err) + t.Fail() + } + assertions.Equal(*tt.wantedErrorInfo, actualErrInfo, tt.name) + assertions.Equal("application/problem+json", responseRecorder.Result().Header.Get("Content-Type")) + } + jobsHandlerMock.AssertCalled(t, "AddJobFromRESTCall", tt.args.job) }) } } func TestDeleteJob(t *testing.T) { assertions := require.New(t) - jobHandlerMock := jobhandler.JobHandler{} - jobHandlerMock.On("DeleteJobFromRESTCall", mock.Anything).Return(nil) + jobsHandlerMock := jobshandler.JobsHandler{} + jobsHandlerMock.On("DeleteJobFromRESTCall", mock.Anything).Return(nil) - callbackHandlerUnderTest := NewProducerCallbackHandler(&jobHandlerMock) + callbackHandlerUnderTest := NewProducerCallbackHandler(&jobsHandlerMock) responseRecorder := httptest.NewRecorder() r := mux.SetURLVars(newRequest(http.MethodDelete, "/jobs/", nil, t), map[string]string{"infoJobId": "job1"}) @@ -175,7 +174,7 @@ func TestDeleteJob(t *testing.T) { assertions.Equal("", responseRecorder.Body.String()) - jobHandlerMock.AssertCalled(t, "DeleteJobFromRESTCall", "job1") + jobsHandlerMock.AssertCalled(t, "DeleteJobFromRESTCall", "job1") } func TestSetLogLevel(t *testing.T) { @@ -185,10 +184,10 @@ func TestSetLogLevel(t *testing.T) { logLevel string } tests := []struct { - name string - args args - wantedStatus int - wantedBody string + name string + args args + wantedStatus int + wantedErrorInfo *ErrorInfo }{ { name: "Set to valid log level, should return OK", @@ -203,7 +202,10 @@ func TestSetLogLevel(t *testing.T) { logLevel: "bad", }, wantedStatus: http.StatusBadRequest, - wantedBody: "Invalid log level: bad", + wantedErrorInfo: &ErrorInfo{ + Detail: "Invalid log level: bad. Log level will not be changed!", + Status: http.StatusBadRequest, + }, }, } for _, tt := range tests { @@ -217,7 +219,16 @@ func TestSetLogLevel(t *testing.T) { handler.ServeHTTP(responseRecorder, r) assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name) - assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name) + if tt.wantedErrorInfo != nil { + var actualErrInfo ErrorInfo + err := json.Unmarshal(getBody(responseRecorder, t), &actualErrInfo) + if err != nil { + t.Error("Unable to unmarshal error body", err) + t.Fail() + } + assertions.Equal(*tt.wantedErrorInfo, actualErrInfo, tt.name) + assertions.Equal("application/problem+json", responseRecorder.Result().Header.Get("Content-Type")) + } }) } } @@ -235,3 +246,12 @@ func newRequest(method string, url string, jobInfo *jobs.JobInfo, t *testing.T) return nil } } + +func getBody(responseRecorder *httptest.ResponseRecorder, t *testing.T) []byte { + buf := new(bytes.Buffer) + if _, err := buf.ReadFrom(responseRecorder.Body); err != nil { + t.Error("Unable to read error body", err) + t.Fail() + } + return buf.Bytes() +} diff --git a/dmaap-mediator-producer/main.go b/dmaap-mediator-producer/main.go index 2d72466b..65a84a21 100644 --- a/dmaap-mediator-producer/main.go +++ b/dmaap-mediator-producer/main.go @@ -22,23 +22,36 @@ package main import ( "crypto/tls" + "encoding/json" "fmt" "net/http" "time" + "github.com/gorilla/mux" log "github.com/sirupsen/logrus" + _ "oransc.org/nonrtric/dmaapmediatorproducer/api" "oransc.org/nonrtric/dmaapmediatorproducer/internal/config" "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient" "oransc.org/nonrtric/dmaapmediatorproducer/internal/restclient" "oransc.org/nonrtric/dmaapmediatorproducer/internal/server" + + httpSwagger "github.com/swaggo/http-swagger" ) var configuration *config.Config +var registered bool func init() { configuration = config.New() } +// @title DMaaP Mediator Producer +// @version 1.1.0 + +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html + func main() { log.SetLevel(configuration.LogLevel) log.Debug("Initializing DMaaP Mediator Producer") @@ -54,24 +67,21 @@ func main() { } else { log.Fatalf("Stopping producer due to error: %v", err) } + retryClient := restclient.CreateRetryClient(cert) + kafkaFactory := kafkaclient.KafkaFactoryImpl{BootstrapServer: configuration.KafkaBootstrapServers} + distributionClient := restclient.CreateClientWithoutRetry(cert, 10*time.Second) + + jobsManager := jobs.NewJobsManagerImpl(retryClient, configuration.DMaaPMRAddress, kafkaFactory, distributionClient) + go startCallbackServer(jobsManager, callbackAddress) - jobsManager := jobs.NewJobsManagerImpl(retryClient, configuration.DMaaPMRAddress, restclient.CreateClientWithoutRetry(cert, 10*time.Second)) if err := registerTypesAndProducer(jobsManager, configuration.InfoCoordinatorAddress, callbackAddress, retryClient); err != nil { log.Fatalf("Stopping producer due to: %v", err) } + registered = true jobsManager.StartJobsForAllTypes() log.Debug("Starting DMaaP Mediator Producer") - go func() { - log.Debugf("Starting callback server at port %v", configuration.InfoProducerPort) - r := server.NewRouter(jobsManager) - if restclient.IsUrlSecure(callbackAddress) { - log.Fatalf("Server stopped: %v", http.ListenAndServeTLS(fmt.Sprintf(":%v", configuration.InfoProducerPort), configuration.ProducerCertPath, configuration.ProducerKeyPath, r)) - } else { - log.Fatalf("Server stopped: %v", http.ListenAndServe(fmt.Sprintf(":%v", configuration.InfoProducerPort), r)) - } - }() keepProducerAlive() } @@ -83,22 +93,25 @@ func validateConfiguration(configuration *config.Config) error { if configuration.ProducerCertPath == "" || configuration.ProducerKeyPath == "" { return fmt.Errorf("missing PRODUCER_CERT and/or PRODUCER_KEY") } + if configuration.DMaaPMRAddress == "" && configuration.KafkaBootstrapServers == "" { + return fmt.Errorf("at least one of DMAAP_MR_ADDR or KAFKA_BOOTSRAP_SERVERS must be provided") + } return nil } -func registerTypesAndProducer(jobTypesHandler jobs.JobTypesManager, infoCoordinatorAddress string, callbackAddress string, client restclient.HTTPClient) error { +func registerTypesAndProducer(jobTypesManager jobs.JobTypesManager, infoCoordinatorAddress string, callbackAddress string, client restclient.HTTPClient) error { registrator := config.NewRegistratorImpl(infoCoordinatorAddress, client) - configTypes, err := config.GetJobTypesFromConfiguration("configs/type_config.json") + configTypes, err := config.GetJobTypesFromConfiguration("configs") if err != nil { return fmt.Errorf("unable to register all types due to: %v", err) } - regErr := registrator.RegisterTypes(jobTypesHandler.LoadTypesFromConfiguration(configTypes)) + regErr := registrator.RegisterTypes(jobTypesManager.LoadTypesFromConfiguration(configTypes)) if regErr != nil { return fmt.Errorf("unable to register all types due to: %v", regErr) } producer := config.ProducerRegistrationInfo{ - InfoProducerSupervisionCallbackUrl: callbackAddress + server.StatusPath, - SupportedInfoTypes: jobTypesHandler.GetSupportedTypes(), + InfoProducerSupervisionCallbackUrl: callbackAddress + server.HealthCheckPath, + SupportedInfoTypes: jobTypesManager.GetSupportedTypes(), InfoJobCallbackUrl: callbackAddress + server.AddJobPath, } if err := registrator.RegisterProducer("DMaaP_Mediator_Producer", &producer); err != nil { @@ -107,6 +120,47 @@ func registerTypesAndProducer(jobTypesHandler jobs.JobTypesManager, infoCoordina return nil } +func startCallbackServer(jobsManager jobs.JobsManager, callbackAddress string) { + log.Debugf("Starting callback server at port %v", configuration.InfoProducerPort) + r := server.NewRouter(jobsManager, statusHandler) + addSwaggerHandler(r) + if restclient.IsUrlSecure(callbackAddress) { + log.Fatalf("Server stopped: %v", http.ListenAndServeTLS(fmt.Sprintf(":%v", configuration.InfoProducerPort), configuration.ProducerCertPath, configuration.ProducerKeyPath, r)) + } else { + log.Fatalf("Server stopped: %v", http.ListenAndServe(fmt.Sprintf(":%v", configuration.InfoProducerPort), r)) + } +} + +type ProducerStatus struct { + // The registration status of the producer in Information Coordinator Service. Either `registered` or `not registered` + RegisteredStatus string `json:"registeredStatus" swaggertype:"string" example:"registered"` +} // @name ProducerStatus + +// @Summary Get status +// @Description Get the status of the producer. Will show if the producer has registered in ICS. +// @Tags Data producer (callbacks) +// @Produce json +// @Success 200 {object} ProducerStatus +// @Router /health_check [get] +func statusHandler(w http.ResponseWriter, r *http.Request) { + status := ProducerStatus{ + RegisteredStatus: "not registered", + } + if registered { + status.RegisteredStatus = "registered" + } + json.NewEncoder(w).Encode(status) +} + +// @Summary Get Swagger Documentation +// @Description Get the Swagger API documentation for the producer. +// @Tags Admin +// @Success 200 +// @Router /swagger [get] +func addSwaggerHandler(r *mux.Router) { + r.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler) +} + func keepProducerAlive() { forever := make(chan int) <-forever diff --git a/dmaap-mediator-producer/main_test.go b/dmaap-mediator-producer/main_test.go new file mode 100644 index 00000000..19851be5 --- /dev/null +++ b/dmaap-mediator-producer/main_test.go @@ -0,0 +1,205 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2022: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "os/exec" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/config" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient" +) + +// This is not a real test, just a way to get the Swagger documentation generated automatically. +// Hence there are no assertions in this test. +func TestGenerateSwaggerDocs(t *testing.T) { + cmd := exec.Command("./generate_swagger_docs.sh") + + err := cmd.Run() + if err != nil { + fmt.Println("Error generating Swagger:", err) + } +} + +func TestValidateConfiguration(t *testing.T) { + assertions := require.New(t) + + validConfig := config.Config{ + InfoProducerHost: "host", + DMaaPMRAddress: "address", + KafkaBootstrapServers: "servers", + ProducerCertPath: "path", + ProducerKeyPath: "path", + } + assertions.Nil(validateConfiguration(&validConfig)) + + missingProducerHost := config.Config{ + DMaaPMRAddress: "address", + KafkaBootstrapServers: "servers", + ProducerCertPath: "path", + ProducerKeyPath: "path", + } + assertions.Contains(validateConfiguration(&missingProducerHost).Error(), "INFO_PRODUCER_HOST") + + missingCert := config.Config{ + InfoProducerHost: "host", + DMaaPMRAddress: "address", + KafkaBootstrapServers: "servers", + ProducerKeyPath: "path", + } + assertions.Contains(validateConfiguration(&missingCert).Error(), "PRODUCER_CERT") + + missingCertKey := config.Config{ + InfoProducerHost: "host", + DMaaPMRAddress: "address", + KafkaBootstrapServers: "servers", + ProducerCertPath: "path", + } + assertions.Contains(validateConfiguration(&missingCertKey).Error(), "PRODUCER_KEY") + + missingMRAddress := config.Config{ + InfoProducerHost: "host", + KafkaBootstrapServers: "servers", + ProducerCertPath: "path", + ProducerKeyPath: "path", + } + assertions.Nil(validateConfiguration(&missingMRAddress)) + + missingKafkaServers := config.Config{ + InfoProducerHost: "host", + DMaaPMRAddress: "address", + ProducerCertPath: "path", + ProducerKeyPath: "path", + } + assertions.Nil(validateConfiguration(&missingKafkaServers)) + + missingMRAddressdAndKafkaServers := config.Config{ + InfoProducerHost: "host", + ProducerCertPath: "path", + ProducerKeyPath: "path", + } + assertions.Contains(validateConfiguration(&missingMRAddressdAndKafkaServers).Error(), "DMAAP_MR_ADDR") + assertions.Contains(validateConfiguration(&missingMRAddressdAndKafkaServers).Error(), "KAFKA_BOOTSRAP_SERVERS") +} + +func TestRegisterTypesAndProducer(t *testing.T) { + assertions := require.New(t) + + wg := sync.WaitGroup{} + clientMock := NewTestClient(func(req *http.Request) *http.Response { + if req.URL.String() == configuration.InfoCoordinatorAddress+"/data-producer/v1/info-types/STD_Fault_Messages" { + assertions.Equal(req.Method, "PUT") + body := getBodyAsString(req, t) + assertions.Contains(body, "info_job_data_schema") + assertions.Equal("application/json", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } else if req.URL.String() == configuration.InfoCoordinatorAddress+"/data-producer/v1/info-types/Kafka_TestTopic" { + assertions.Equal(req.Method, "PUT") + body := getBodyAsString(req, t) + assertions.Contains(body, "info_job_data_schema") + assertions.Equal("application/json", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } else if req.URL.String() == configuration.InfoCoordinatorAddress+"/data-producer/v1/info-producers/DMaaP_Mediator_Producer" { + assertions.Equal(req.Method, "PUT") + body := getBodyAsString(req, t) + assertions.Contains(body, "callbackAddress/health_check") + assertions.Contains(body, "callbackAddress/info_job") + assertions.Contains(body, "Kafka_TestTopic") + assertions.Contains(body, "STD_Fault_Messages") + assertions.Equal("application/json", req.Header.Get("Content-Type")) + wg.Done() + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)), + Header: make(http.Header), // Must be set to non-nil value or it panics + } + } + t.Error("Wrong call to client: ", req) + t.Fail() + return nil + }) + jobsManager := jobs.NewJobsManagerImpl(clientMock, configuration.DMaaPMRAddress, kafkaclient.KafkaFactoryImpl{}, nil) + + wg.Add(3) + err := registerTypesAndProducer(jobsManager, configuration.InfoCoordinatorAddress, "callbackAddress", clientMock) + + assertions.Nil(err) + + if waitTimeout(&wg, 2*time.Second) { + t.Error("Not all calls to server were made") + t.Fail() + } +} + +type RoundTripFunc func(req *http.Request) *http.Response + +func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req), nil +} + +//NewTestClient returns *http.Client with Transport replaced to avoid making real calls +func NewTestClient(fn RoundTripFunc) *http.Client { + return &http.Client{ + Transport: RoundTripFunc(fn), + } +} + +func getBodyAsString(req *http.Request, t *testing.T) string { + buf := new(bytes.Buffer) + if _, err := buf.ReadFrom(req.Body); err != nil { + t.Fail() + } + return buf.String() +} + +// waitTimeout waits for the waitgroup for the specified max timeout. +// Returns true if waiting timed out. +func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { + c := make(chan struct{}) + go func() { + defer close(c) + wg.Wait() + }() + select { + case <-c: + return false // completed normally + case <-time.After(timeout): + return true // timed out + } +} diff --git a/dmaap-mediator-producer/mocks/KafkaConsumer.go b/dmaap-mediator-producer/mocks/KafkaConsumer.go new file mode 100644 index 00000000..8ae0893e --- /dev/null +++ b/dmaap-mediator-producer/mocks/KafkaConsumer.go @@ -0,0 +1,76 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import ( + kafka "github.com/confluentinc/confluent-kafka-go/kafka" + + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// KafkaConsumer is an autogenerated mock type for the KafkaConsumer type +type KafkaConsumer struct { + mock.Mock +} + +// Commit provides a mock function with given fields: +func (_m KafkaConsumer) Commit() ([]kafka.TopicPartition, error) { + ret := _m.Called() + + var r0 []kafka.TopicPartition + if rf, ok := ret.Get(0).(func() []kafka.TopicPartition); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]kafka.TopicPartition) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReadMessage provides a mock function with given fields: timeout +func (_m KafkaConsumer) ReadMessage(timeout time.Duration) (*kafka.Message, error) { + ret := _m.Called(timeout) + + var r0 *kafka.Message + if rf, ok := ret.Get(0).(func(time.Duration) *kafka.Message); ok { + r0 = rf(timeout) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*kafka.Message) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(time.Duration) error); ok { + r1 = rf(timeout) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Subscribe provides a mock function with given fields: topic +func (_m KafkaConsumer) Subscribe(topic string) error { + ret := _m.Called(topic) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(topic) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/dmaap-mediator-producer/mocks/KafkaFactory.go b/dmaap-mediator-producer/mocks/KafkaFactory.go new file mode 100644 index 00000000..f05457a5 --- /dev/null +++ b/dmaap-mediator-producer/mocks/KafkaFactory.go @@ -0,0 +1,36 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + "oransc.org/nonrtric/dmaapmediatorproducer/internal/kafkaclient" +) + +// KafkaFactory is an autogenerated mock type for the KafkaFactory type +type KafkaFactory struct { + mock.Mock +} + +// NewKafkaConsumer provides a mock function with given fields: topicID +func (_m KafkaFactory) NewKafkaConsumer(topicID string) (kafkaclient.KafkaConsumer, error) { + ret := _m.Called(topicID) + + var r0 kafkaclient.KafkaConsumer + if rf, ok := ret.Get(0).(func(string) kafkaclient.KafkaConsumer); ok { + r0 = rf(topicID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(kafkaclient.KafkaConsumer) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(topicID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/dmaap-mediator-producer/mocks/jobhandler/JobHandler.go b/dmaap-mediator-producer/mocks/jobshandler/JobsHandler.go similarity index 66% rename from dmaap-mediator-producer/mocks/jobhandler/JobHandler.go rename to dmaap-mediator-producer/mocks/jobshandler/JobsHandler.go index ad20752c..271590fa 100644 --- a/dmaap-mediator-producer/mocks/jobhandler/JobHandler.go +++ b/dmaap-mediator-producer/mocks/jobshandler/JobsHandler.go @@ -1,19 +1,19 @@ // Code generated by mockery v2.9.3. DO NOT EDIT. -package jobhandler +package jobshandler import ( mock "github.com/stretchr/testify/mock" jobs "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs" ) -// JobHandler is an autogenerated mock type for the JobHandler type -type JobHandler struct { +// JobsHandler is an autogenerated mock type for the JobsHandler type +type JobsHandler struct { mock.Mock } // AddJob provides a mock function with given fields: _a0 -func (_m *JobHandler) AddJobFromRESTCall(_a0 jobs.JobInfo) error { +func (_m *JobsHandler) AddJobFromRESTCall(_a0 jobs.JobInfo) error { ret := _m.Called(_a0) var r0 error @@ -27,6 +27,6 @@ func (_m *JobHandler) AddJobFromRESTCall(_a0 jobs.JobInfo) error { } // DeleteJob provides a mock function with given fields: jobId -func (_m *JobHandler) DeleteJobFromRESTCall(jobId string) { +func (_m *JobsHandler) DeleteJobFromRESTCall(jobId string) { _m.Called(jobId) } diff --git a/dmaap-mediator-producer/pom.xml b/dmaap-mediator-producer/pom.xml deleted file mode 100644 index 00c3d9fd..00000000 --- a/dmaap-mediator-producer/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - 4.0.0 - - oransc.org - dmaapmediatorproducer - 1.0.0 - - 0.30.0 - - - - - - exec-maven-plugin - org.codehaus.mojo - - - Build Go binary - generate-sources - - exec - - - ${basedir}/build_and_test.sh - - - - - - io.fabric8 - docker-maven-plugin - ${docker-maven-plugin.version} - false - - - generate-nonrtric-dmaap-mediator-producer-image - package - - build - - - ${env.CONTAINER_PULL_REGISTRY} - - - o-ran-sc/nonrtric-dmaap-mediator-producer:${project.version} - - try - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - - - - - - - - push-nonrtric-dmaap-mediator-producer-image - - build - push - - - ${env.CONTAINER_PULL_REGISTRY} - ${env.CONTAINER_PUSH_REGISTRY} - - - o-ran-sc/nonrtric-dmaap-mediator-producer:${project.version} - - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - latest - - - - - - - - - - - diff --git a/dmaap-mediator-producer/stub/consumer/consumerstub.go b/dmaap-mediator-producer/stub/consumer/consumerstub.go index 4260cae1..526e61e5 100644 --- a/dmaap-mediator-producer/stub/consumer/consumerstub.go +++ b/dmaap-mediator-producer/stub/consumer/consumerstub.go @@ -61,7 +61,7 @@ func registerJob(port int) { } fmt.Println("Registering consumer: ", jobInfo) body, _ := json.Marshal(jobInfo) - putErr := restclient.Put(fmt.Sprintf("http://localhost:8083/data-consumer/v1/info-jobs/job%v", port), body, &httpClient) + putErr := restclient.Put(fmt.Sprintf("https://localhost:8083/data-consumer/v1/info-jobs/job%v", port), body, &httpClient) if putErr != nil { fmt.Println("Unable to register consumer: ", putErr) } diff --git a/dmaap-mediator-producer/stub/ics/ics.go b/dmaap-mediator-producer/stub/ics/ics.go new file mode 100644 index 00000000..87457c2b --- /dev/null +++ b/dmaap-mediator-producer/stub/ics/ics.go @@ -0,0 +1,65 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "net/http" + + "github.com/gorilla/mux" +) + +func main() { + port := flag.Int("port", 8434, "The port this stub will listen on") + flag.Parse() + fmt.Println("Starting ICS stub on port ", *port) + + r := mux.NewRouter() + r.HandleFunc("/data-producer/v1/info-types/{typeId}", handleTypeRegistration).Methods(http.MethodPut, http.MethodPut) + r.HandleFunc("/data-producer/v1/info-producers/{producerId}", handleProducerRegistration).Methods(http.MethodPut, http.MethodPut) + fmt.Println(http.ListenAndServe(fmt.Sprintf(":%v", *port), r)) +} + +func handleTypeRegistration(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id, ok := vars["typeId"] + if ok { + fmt.Printf("Registered type %v with schema: %v\n", id, readBody(r)) + } +} + +func handleProducerRegistration(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id, ok := vars["producerId"] + if ok { + fmt.Printf("Registered producer %v with data: %v\n", id, readBody(r)) + } +} + +func readBody(r *http.Request) string { + b, readErr := ioutil.ReadAll(r.Body) + if readErr != nil { + return fmt.Sprintf("Unable to read body due to: %v", readErr) + } + return string(b) +} diff --git a/docker-compose/.env b/docker-compose/.env index b984df98..ad1c72a7 100644 --- a/docker-compose/.env +++ b/docker-compose/.env @@ -16,20 +16,20 @@ # #PMS -PMS_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-policy-agent" -PMS_IMAGE_TAG="2.2.0" +PMS_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-a1-policy-management-service" +PMS_IMAGE_TAG="2.3.1" #A1_SIM A1_SIM_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/a1-simulator" -A1_SIM_IMAGE_TAG="2.1.0" +A1_SIM_IMAGE_TAG="2.2.0" #RAPP RAPP_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-r-app-catalogue" -RAPP_IMAGE_TAG="1.0.0" +RAPP_IMAGE_TAG="1.0.2" #CONTROL_PANEL CONTROL_PANEL_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-controlpanel" -CONTROL_PANEL_IMAGE_TAG="2.2.0" +CONTROL_PANEL_IMAGE_TAG="2.3.0" #GATEWAY NONRTRIC_GATEWAY_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-gateway" @@ -37,7 +37,7 @@ NONRTRIC_GATEWAY_IMAGE_TAG="1.0.0" #ICS ICS_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-information-coordinator-service" -ICS_IMAGE_TAG="1.1.0" +ICS_IMAGE_TAG="1.2.1" #CONSUMER CONSUMER_IMAGE_BASE="eexit/mirror-http-server" @@ -45,11 +45,11 @@ CONSUMER_IMAGE_TAG="latest" #ORU ORU_APP_IMAGE_BASE="nexus3.o-ran-sc.org:10002/o-ran-sc/nonrtric-o-ru-closed-loop-recovery" -ORU_APP_IMAGE_TAG="1.0.0" +ORU_APP_IMAGE_TAG="1.0.1" #DB -DB_IMAGE_BASE="mysql/mysql-server" -DB_IMAGE_TAG="5.6" +DB_IMAGE_BASE="mariadb" +DB_IMAGE_TAG="10.5" #A1CONTROLLER A1CONTROLLER_IMAGE_BASE="nexus3.onap.org:10002/onap/sdnc-image" @@ -57,8 +57,8 @@ A1CONTROLLER_IMAGE_TAG="2.1.2" #DMAAP_MEDIATOR_GO DMAAP_MEDIATOR_GO_BASE="nexus3.o-ran-sc.org:10004/o-ran-sc/nonrtric-dmaap-mediator-producer" -DMAAP_MEDIATOR_GO_TAG="1.0.0" +DMAAP_MEDIATOR_GO_TAG="1.0.1" #DMAAP_MEDIATOR_JAVA DMAAP_MEDIATOR_JAVA_BASE="nexus3.o-ran-sc.org:10003/o-ran-sc/nonrtric-dmaap-adaptor" -DMAAP_MEDIATOR_JAVA_TAG="1.0.0-SNAPSHOT" +DMAAP_MEDIATOR_JAVA_TAG="1.0.1-SNAPSHOT" diff --git a/docker-compose/policy-service/docker-compose.yaml b/docker-compose/policy-service/docker-compose.yaml index 2dfc38c5..79e6a6ee 100644 --- a/docker-compose/policy-service/docker-compose.yaml +++ b/docker-compose/policy-service/docker-compose.yaml @@ -33,7 +33,7 @@ services: - 8433:8433 volumes: - ./policy-service/config/application-policyagent.yaml:/opt/app/policy-agent/config/application.yaml:ro - - ./policy-service/config/application_configuration.json:/opt/app/policy-agent/data/application_configuration.json:ro + - ./policy-service/config/application_configuration.json:/opt/app/policy-agent/data/application_configuration.json:rw # For using own certs instead of the default ones (built into the container), # place them in config/ directory, update the application-policyagent.yaml file, and uncomment the following lines # - ./policy-service/config/keystore-policyagent.jks:/opt/app/policy-agent/etc/cert/keystore.jks:ro diff --git a/docker-compose/sdnc/docker-compose.yml b/docker-compose/sdnc/docker-compose.yml index 3661db9e..69d8ac92 100644 --- a/docker-compose/sdnc/docker-compose.yml +++ b/docker-compose/sdnc/docker-compose.yml @@ -22,7 +22,7 @@ networks: services: db: - image: mysql/mysql-server:5.6 + image: "${DB_IMAGE_BASE}:${DB_IMAGE_TAG}" container_name: sdnc-db networks: - default diff --git a/docs/api-docs.rst b/docs/api-docs.rst index 8ab5b452..29207b8f 100644 --- a/docs/api-docs.rst +++ b/docs/api-docs.rst @@ -46,7 +46,7 @@ The API is also described in Swagger-JSON and YAML: DMaaP Adaptor ============= -The DMaaP Adaptor provides support for push delivery of any data received from DMaap or Kafka. +The DMaaP Adaptor provides support for push delivery of any data received from DMaaP or Kafka. See `DMaaP Adaptor API <./dmaap-adaptor-api.html>`_ for full details of the API. @@ -59,6 +59,22 @@ The API is also described in Swagger-JSON and YAML: "DMaaP Adaptor API", ":download:`link <../dmaap-adaptor-java/api/api.json>`", ":download:`link <../dmaap-adaptor-java/api/api.yaml>`" +DMaaP Mediator Producer +======================= + +The DMaaP Mediator Producer provides support for push delivery of any data received from DMaaP or Kafka. + +See `DMaaP Mediator Producer API <./dmaap-mediator-producer-api.html>`_ for full details of the API. + +The API is also described in Swagger-JSON and YAML: + + +.. csv-table:: + :header: "API name", "|swagger-icon|", "|yaml-icon|" + :widths: 10,5, 5 + + "DMaaP Mediator Producer API", ":download:`link <../dmaap-mediator-producer/api/swagger.json>`", ":download:`link <../dmaap-mediator-producer/api/swagger.yaml>`" + Non-RT-RIC App Catalogue (Initial) ================================== diff --git a/docs/conf.py b/docs/conf.py index c5e504d8..4ee69983 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,6 +11,7 @@ linkcheck_ignore = [ './rac-api.html', #Generated file that doesn't exist at link check. './ics-api.html', #Generated file that doesn't exist at link check. './dmaap-adaptor-api.html' #Generated file that doesn't exist at link check. + './dmaap-mediator-producer-api.html' #Generated file that doesn't exist at link check. ] extensions = ['sphinxcontrib.redoc', 'sphinx.ext.intersphinx',] @@ -32,6 +33,11 @@ redoc = [ 'name': 'DMaaP Adaptor API', 'page': 'dmaap-adaptor-api', 'spec': '../dmaap-adaptor-java/api/api.json', + }, + { + 'name': 'DMaaP Mediator Producer API', + 'page': 'dmaap-mediator-producer-api', + 'spec': '../dmaap-mediator-producer/api/swagger.json', 'embed': True, } ] diff --git a/docs/developer-guide.rst b/docs/developer-guide.rst index 0d950cd3..a3c34220 100644 --- a/docs/developer-guide.rst +++ b/docs/developer-guide.rst @@ -7,12 +7,12 @@ Developer Guide This document provides a quickstart for developers of the Non-RT RIC parts. -Additional developer guides are available on the `O-RAN SC NONRTRIC Developer wiki `_ +Additional developer guides are available on the `O-RAN SC NONRTRIC Developer wiki `_. A1 Policy Management Service & SDNC/A1 Controller & A1 Adapter -------------------------------------------------------------- -The A1 Policy Management Service is implemented in ONAP. For documentation see `ONAP CCSDK documentation `_ +The A1 Policy Management Service is implemented in ONAP. For documentation see `ONAP CCSDK documentation `_. and `wiki `_. Information Coordinator Service @@ -65,36 +65,42 @@ See the README.md file in the *r-app-catalogue* directory in the Gerrit repo for DMaaP Adaptor Service --------------------- -This is run in the same way as the Information Coordinator Service + +This Java implementation is run in the same way as the Information Coordinator Service. The following properties in the application.yaml file have to be modified: * server.ssl.key-store=./config/keystore.jks * app.webclient.trust-store=./config/truststore.jks * app.configuration-filepath=./src/test/resources/test_application_configuration.json +DMaaP Mediator Producer +----------------------- + +To build and run this Go implementation, see the README.md file under the folder "dmaap-mediator-producer" in the "nonrtric" repo. + O-DU & O-RU fronthaul recovery ------------------------------ -See the page in Wiki: `O-RU Fronthaul Recovery usecase `_ +See the page in Wiki: `O-RU Fronthaul Recovery usecase `_. O-DU Slicing use cases ---------------------- -See the page in Wiki: `O-DU Slice Assurance usecase `_ +See the page in Wiki: `O-DU Slice Assurance usecase `_. Helm Manager ------------ -See the page in Wiki: `Release E `_ +See the page in Wiki: `Release E `_. Kubernetes deployment ===================== -Non-RT RIC can be also deployed in a Kubernetes cluster, `it/dep repository `_ +Non-RT RIC can be also deployed in a Kubernetes cluster, `it/dep repository `_. hosts deployment and integration artifacts. Instructions and helm charts to deploy the Non-RT-RIC functions in the OSC NONRTRIC integrated test environment can be found in the *./nonrtric* directory. -For more information on installation of NonRT-RIC in Kubernetes, see `Deploy NONRTRIC in Kubernetes `_ +For more information on installation of NonRT-RIC in Kubernetes, see `Deploy NONRTRIC in Kubernetes `_. For more information see `Integration and Testing documentation on the O-RAN-SC wiki `_. diff --git a/docs/installation-guide.rst b/docs/installation-guide.rst index 17e3492f..18371522 100644 --- a/docs/installation-guide.rst +++ b/docs/installation-guide.rst @@ -25,8 +25,8 @@ command to start the components: -f policy-service/docker-compose.yaml -f ics/docker-compose.yaml -The example above is just an example to start some of the components. -For more information on running and configuring the functions can be found in the README file in the "`docker-compose `__" folder, and on the `wiki page `_ +The example above is just an example to start some of the components. +For more information on running and configuring the functions can be found in the README file in the "`docker-compose `__" folder, and on the `wiki page `_ Install with Helm +++++++++++++++++ diff --git a/docs/overview.rst b/docs/overview.rst index 8126776c..ca6834bb 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -8,13 +8,13 @@ Summary ------- -The Non-RealTime RIC (RAN Intelligent Controller) is an Orchestration and Automation function described by the O-RAN Alliance for non-real-time intelligent management of RAN (Radio Access Network) functions. +The Non-RealTime RIC (RAN Intelligent Controller) is an Orchestration and Automation function described by the O-RAN Alliance for non-real-time intelligent management of RAN (Radio Access Network) functions. -The primary goal of the Non-RealTime RIC is to support non-real-time radio resource management, higher layer procedure optimization, policy optimization in RAN, and providing guidance, parameters, policies and AI/ML models to support the operation of near-RealTime RIC functions in the RAN to achieve higher-level non-real-time objectives. +The primary goal of the Non-RealTime RIC is to support non-real-time radio resource management, higher layer procedure optimization, policy optimization in RAN, and providing guidance, parameters, policies and AI/ML models to support the operation of near-RealTime RIC functions in the RAN to achieve higher-level non-real-time objectives. -Non-RealTime RIC functions include service and policy management, RAN analytics and model-training for the near-RealTime RICs. +Non-RealTime RIC functions include service and policy management, RAN analytics and model-training for the near-RealTime RICs. The Non-RealTime RIC platform hosts and coordinates rApps (Non-RT RIC applications) to perform Non-RealTime RIC tasks. -The Non-RealTime RIC also hosts the new R1 interface (between rApps and SMO/Non-RealTime-RIC services) +The Non-RealTime RIC also hosts the new R1 interface (between rApps and SMO/Non-RealTime-RIC services). The O-RAN-SC (OSC) NONRTRIC project provides concepts, architecture and reference implementations as defined and described by the `O-RAN Alliance `_ architecture. The OSC NONRTRIC implementation communicates with near-RealTime RIC elements in the RAN via the A1 interface. Using the A1 interface the NONRTRIC will facilitate the provision of policies for individual UEs or groups of UEs; monitor and provide basic feedback on policy state from near-RealTime RICs; provide enrichment information as required by near-RealTime RICs; and facilitate ML model training, distribution and inference in cooperation with the near-RealTime RICs. @@ -49,7 +49,7 @@ The source code for "E" Release is in the `NONRTRIC `_ to set up in your local environment. -More details available at the `NONRTRIC-Portal documentation site `_ +More details available at the `NONRTRIC-Portal documentation site `_. Information Coordination Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,126 +94,125 @@ A1 Policy Management Service (from ONAP CCSDK) A1 Controller Service above A1 Controller/Adaptor that provides: -* Unified REST & DMaaP NBI APIs for managing A1 Policies in all near-RT-RICs +* Unified REST & DMaaP NBI APIs for managing A1 Policies in all near-RT-RICs. - + Query A1 Policy Types in near-RT-RICs - + Create/Query/Update/Delete A1 Policy Instances in near-RT-RICs - + Query Status for A1 Policy Instances + + Query A1 Policy Types in near-RT-RICs. + + Create/Query/Update/Delete A1 Policy Instances in near-RT-RICs. + + Query Status for A1 Policy Instances. -* Maintains (persistent) cache of RAN's A1 Policy information +* Maintains (persistent) cache of RAN's A1 Policy information. - * Support RAN-wide view of A1 Policy information - * Streamline A1 traffic - * Enable (optional) re-synchronization after inconsistencies / near-RT-RIC restarts - * Supports a large number of near-RT-RICs (& multi-version support) + * Support RAN-wide view of A1 Policy information. + * Streamline A1 traffic. + * Enable (optional) re-synchronization after inconsistencies / near-RT-RIC restarts. + * Supports a large number of near-RT-RICs (& multi-version support). -* Converged ONAP & O-RAN-SC A1 Adapter/Controller functions in ONAP SDNC/CCSDK (Optionally deploy without A1 Adaptor to connect direct to near-RT-RICs) -* Support for different Southbound connectors per near-RT-RIC - e.g. different A1 versions, different near-RT-RIC version, different A1 adapter/controllers supports different or proprietary A1 controllers/EMSs +* Converged ONAP & O-RAN-SC A1 Adapter/Controller functions in ONAP SDNC/CCSDK (Optionally deploy without A1 Adaptor to connect direct to near-RT-RICs). +* Support for different Southbound connectors per near-RT-RIC - e.g. different A1 versions, different near-RT-RIC version, different A1 adapter/controllers supports different or proprietary A1 controllers/EMSs. -See also: `A1 Policy Management Service in ONAP `_ +See also: `A1 Policy Management Service in ONAP `_ . Implementation: -* Implemented as a Java Spring Boot application +* Implemented as a Java Spring Boot application. A1/SDNC Controller & A1 Adapter (Controller plugin) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Mediation point for A1 interface termination in SMO/NONRTRIC -* Implemented as CCSDK OSGI Feature/Bundles -* A1 REST southbound -* RESTCONF Northbound -* NETCONF YANG > RESTCONF adapter -* SLI Mapping logic supported -* Can be included in an any controller based on ONAP CCSDK +Mediation point for A1 interface termination in SMO/NONRTRIC. + +* Implemented as CCSDK OSGI Feature/Bundles. +* A1 REST southbound. +* RESTCONF Northbound. +* NETCONF YANG > RESTCONF adapter. +* SLI Mapping logic supported. +* Can be included in an any controller based on ONAP CCSDK. -See also: `A1 Adapter/Controller Functions in ONAP `_ +See also: `A1 Adapter/Controller Functions in ONAP `_ . A1 Interface / Near-RT-RIC Simulator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Stateful A1 test stub. -* Used to create multiple stateful A1 providers (simulated near-rt-rics) -* Supports A1-Policy and A1-Enrichment Information -* Swagger-based northbound interface, so easy to change the A1 profile exposed (e.g. A1 version, A1 Policy Types, A1-E1 consumers, etc) -* All A1-AP versions supported +* Used to create multiple stateful A1 providers (simulated near-rt-rics). +* Supports A1-Policy and A1-Enrichment Information. +* Swagger-based northbound interface, so easy to change the A1 profile exposed (e.g. A1 version, A1 Policy Types, A1-E1 consumers, etc). +* All A1-AP versions supported. Implementation: -* Implemented as a Python application -* Repo: *sim/a1-interface* +* Implemented as a Python application. +* Repo: *sim/a1-interface*. More details available at the `A1 Simulator documentation site `_ Non-RT-RIC (Spring Cloud) Service Gateway ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Support Apps to use A1 Services +Support Apps to use A1 Services. -* `Spring Cloud Gateway `_ provides the library to build a basic API gateway -* Exposes A1 Policy Management Service & Information Coordinator Service. +* `Spring Cloud Gateway `_ provides the library to build a basic API gateway. +* Exposes A1 Policy Management Service & Information Coordinator Service. * Additional predicates can be added in code or preferably in the Gateway yaml configuration. Implementation: -* Implemented as a Java Spring Cloud application -* Repo: *portal/nonrtric-controlpanel* +* Implemented as a Java Spring Cloud application. +* Repo: *portal/nonrtric-controlpanel*. Non-RT-RIC (Kong) Service Exposure Prototyping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Support Apps to use NONRTRIC, SMO and other App interfaces -A building block for coming releases as the R1 Interface concept matures +Support Apps to use NONRTRIC, SMO and other App interfaces. +A building block for coming releases as the R1 Interface concept matures . -* Support dynamic registration and exposure of service interfaces to Non-RT-RIC applications (& NONRTRIC Control panel) -* Extends a static gateway function specifically for NONRTRIC Control panel (described above) -* Initial version based on `Kong API Gateway `_ function -* Initial exposure candidates include A1 (NONRTRIC) services & O1 (OAM/SMO) services +* Support dynamic registration and exposure of service interfaces to Non-RT-RIC applications (& NONRTRIC Control panel). +* Extends a static gateway function specifically for NONRTRIC Control panel (described above). +* Initial version based on `Kong API Gateway `_ function. +* Initial exposure candidates include A1 (NONRTRIC) services & O1 (OAM/SMO) services. -NONRTRIC Kubernetes deployment - including Kong configurations can be found in the OSC `it/dep `_ Gerrit repo. +NONRTRIC Kubernetes deployment - including Kong configurations can be found in the OSC `it/dep `_ Gerrit repo. DMaaP/Kafka Information Producer Adapters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Configurable mediators to take information from DMaaP (& Kafka) and present it as a coordinated Information Producer - -These mediators/adapters are generic information producers, which registers themselves as an information producers of defined information types (in Information Coordination Service). -The information types are defined in a configuration file. -Information jobs defined using Information Coordination Service (ICS) then allow information consumers to retrieve data from DMaaP MR or Kafka topics (accessing the ICS API). +Configurable mediators to take information from DMaaP and Kafka and present it as a coordinated Information Producer. -Two alternative implementations to allow Information Consumers to consume DMaaP or Kafka events as coordinated Information Jobs. +These mediators/adapters are generic information producers, which register themselves as information producers of defined information types in Information Coordination Service (ICS). +The information types are defined in a configuration file. +Information jobs defined using ICS then allow information consumers to retrieve data from DMaaP MR or Kafka topics (accessing the ICS API). -Implementations: +There are two alternative implementations to allow Information Consumers to consume DMaaP or Kafka events as coordinated Information Jobs. -1. A version implemented in Java (Spring) - Supporting DMaaP and Kafka mediation -2. A version implemented in Go - Supporting DMaaP mediation +1. A version implemented in Java Spring (DMaaP Adaptor Service). +2. A version implemented in Go (DMaaP Mediator Producer). Initial Non-RT-RIC App Catalogue ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Register for Non-RT-RIC Apps. -* Non-RT-RIC Apps can be registered / queried -* Limited functionality/integration for now -* *More work required in coming releases as the rApp concept matures* +* Non-RT-RIC Apps can be registered / queried. +* Limited functionality/integration for now. +* *More work required in coming releases as the rApp concept matures*. Initial K8S Helm Chart LCM Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Onboard, start, stop, and modify Non-RT-RIC App µServices as Helm Charts -*A building block for coming releases as the R-APP concept matures* +Onboard, start, stop, and modify Non-RT-RIC App µServices as Helm Charts. +*A building block for coming releases as the R-APP concept matures*. -* Interfaces that accepts Non-RT-RIC App µServices Helm Charts -* Support basic LCM operations -* Onboard, Start, Stop, Modify, Monitor -* Initial version co-developed with v. similar functions in ONAP -* *Limited functionality/integration for now* +* Interfaces that accepts Non-RT-RIC App µServices Helm Charts. +* Support basic LCM operations. +* Onboard, Start, Stop, Modify, Monitor. +* Initial version co-developed with v. similar functions in ONAP. +* *Limited functionality/integration for now*. Test Framework ~~~~~~~~~~~~~~ -A full test environment with extensive test cases/scripts can be found in the ``test`` directory in the *nonrtric* source code +A full test environment with extensive test cases/scripts can be found in the ``test`` directory in the *nonrtric* source code. Use Cases ~~~~~~~~~ @@ -221,9 +220,9 @@ Use Cases "Helloworld" O-RU Fronthaul Recovery use case ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A very simplified closed-loop rApp use case to re-establish front-haul connections between O-DUs and O-RUs if they fail. Not intended to to be 'real-world' +A very simplified closed-loop rApp use case to re-establish front-haul connections between O-DUs and O-RUs if they fail. Not intended to to be 'real-world'. "Helloworld" O-DU Slice Assurance use case ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A very simplified closed-loop rApp use case to re-prioritize a RAN slice's radio resource allocation priority if sufficient throughput cannot be maintained. Not intended to to be 'real-world' +A very simplified closed-loop rApp use case to re-prioritize a RAN slice's radio resource allocation priority if sufficient throughput cannot be maintained. Not intended to to be 'real-world'. diff --git a/helm-manager/Dockerfile b/helm-manager/Dockerfile index 5e96b60f..b50767cf 100644 --- a/helm-manager/Dockerfile +++ b/helm-manager/Dockerfile @@ -46,4 +46,20 @@ COPY config/application.yaml . WORKDIR /opt/app/helm-manager COPY target/app.jar app.jar +ARG user=nonrtric +ARG group=nonrtric + +RUN groupadd $group && \ + useradd -r -g $group $user +RUN chown -R $user:$group /opt/app/helm-manager +RUN chown -R $user:$group /etc/app/helm-manager + +RUN mkdir /var/helm-manager-service +RUN chown -R $user:$group /var/helm-manager-service + +RUN mkdir /home/$user +RUN chown -R $user:$group /home/$user + +USER $user + CMD [ "java", "-jar", "app.jar", "--spring.config.location=optional:file:/etc/app/helm-manager/"] diff --git a/helm-manager/docker-hm.sh b/helm-manager/docker-hm.sh index e51b5318..9844f4de 100755 --- a/helm-manager/docker-hm.sh +++ b/helm-manager/docker-hm.sh @@ -25,10 +25,10 @@ docker run \ --name helmmanagerservice \ --network nonrtric-docker-net \ -v $(pwd)/mnt/database:/var/helm-manager/database \ - -v ~/.kube:/root/.kube \ - -v ~/.helm:/root/.helm \ - -v ~/.config/helm:/root/.config/helm \ - -v ~/.cache/helm:/root/.cache/helm \ + -v ~/.kube:/home/nonrtric/.kube \ + -v ~/.helm:/home/nonrtric/.helm \ + -v ~/.config/helm:/home/nonrtric/.config/helm \ + -v ~/.cache/helm:/home/nonrtric/.cache/helm \ -v $(pwd)/config/KubernetesParticipantConfig.json:/opt/app/helm-manager/src/main/resources/config/KubernetesParticipantConfig.json \ -v $(pwd)/config/application.yaml:/opt/app/helm-manager/src/main/resources/config/application.yaml \ nexus3.o-ran-sc.org:10004/o-ran-sc/nonrtric-helm-manager:1.1.0-SNAPSHOT diff --git a/helm-manager/helm-manager.yaml b/helm-manager/helm-manager.yaml index 2dafed8e..dcc4bc5b 100644 --- a/helm-manager/helm-manager.yaml +++ b/helm-manager/helm-manager.yaml @@ -63,7 +63,14 @@ spec: - name: helm-manager-service-pv persistentVolumeClaim: claimName: helm-manager-service-pvc - + initContainers: + - name: change-ownership-container + image: busybox:latest + command: ["sh","-c","chown -R 999:1000 /var/helm-manager-service"] + resources: {} + volumeMounts: + - mountPath: /var/helm-manager-service + name: helm-manager-service-pv --- apiVersion: v1 diff --git a/helm-manager/pom.xml b/helm-manager/pom.xml index 5864f001..8faab97a 100644 --- a/helm-manager/pom.xml +++ b/helm-manager/pom.xml @@ -26,13 +26,13 @@ org.springframework.boot spring-boot-starter-parent - 2.3.8.RELEASE + 2.6.2 org.o-ran-sc.nonrtric helm-manager - 1.1.0-SNAPSHOT + 1.1.1-SNAPSHOT The Apache Software License, Version 2.0 @@ -53,9 +53,9 @@ - org.onap.policy.clamp.participant - policy-clamp-participant-impl-kubernetes - ${policy-clamp-participant-impl-kubernetes.version} + org.onap.policy.clamp.participant + policy-clamp-participant-impl-kubernetes + ${policy-clamp-participant-impl-kubernetes.version} @@ -65,26 +65,26 @@ org.apache.maven.plugins maven-dependency-plugin - - copy - package - - copy - - - - - org.onap.policy.clamp.participant - policy-clamp-participant-impl-kubernetes - ${policy-clamp-participant-impl-kubernetes.version} - jar - true - ${basedir}/target - app.jar - - - - + + copy + package + + copy + + + + + org.onap.policy.clamp.participant + policy-clamp-participant-impl-kubernetes + ${policy-clamp-participant-impl-kubernetes.version} + jar + true + ${basedir}/target + app.jar + + + + @@ -148,4 +148,4 @@ JIRA https://jira.o-ran-sc.org/ - \ No newline at end of file + diff --git a/information-coordinator-service/Dockerfile b/information-coordinator-service/Dockerfile index e9d179df..cc8813e9 100644 --- a/information-coordinator-service/Dockerfile +++ b/information-coordinator-service/Dockerfile @@ -25,7 +25,6 @@ WORKDIR /opt/app/information-coordinator-service RUN mkdir -p /var/log/information-coordinator-service RUN mkdir -p /opt/app/information-coordinator-service/etc/cert/ RUN mkdir -p /var/information-coordinator-service -RUN chmod -R 777 /var/information-coordinator-service EXPOSE 8083 8434 @@ -34,8 +33,16 @@ ADD target/${JAR} /opt/app/information-coordinator-service/information-coordinat ADD /config/keystore.jks /opt/app/information-coordinator-service/etc/cert/keystore.jks ADD /config/truststore.jks /opt/app/information-coordinator-service/etc/cert/truststore.jks +ARG user=nonrtric +ARG group=nonrtric -RUN chmod -R 777 /opt/app/information-coordinator-service/config/ +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /opt/app/information-coordinator-service +RUN chown -R $user:$group /var/log/information-coordinator-service +RUN chown -R $user:$group /var/information-coordinator-service + +USER ${user} CMD ["java", "-jar", "/opt/app/information-coordinator-service/information-coordinator-service.jar"] diff --git a/information-coordinator-service/api/ics-api.json b/information-coordinator-service/api/ics-api.json index 2fe34745..69ad473b 100644 --- a/information-coordinator-service/api/ics-api.json +++ b/information-coordinator-service/api/ics-api.json @@ -378,7 +378,7 @@ }}, "/actuator/threaddump": {"get": { "summary": "Actuator web endpoint 'threaddump'", - "operationId": "handle_2_1_3", + "operationId": "threaddump_4", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -556,7 +556,7 @@ }, "/actuator/loggers": {"get": { "summary": "Actuator web endpoint 'loggers'", - "operationId": "handle_6", + "operationId": "loggers_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -565,7 +565,7 @@ }}, "/actuator/health/**": {"get": { "summary": "Actuator web endpoint 'health-path'", - "operationId": "handle_12", + "operationId": "health-path_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -586,7 +586,7 @@ }}, "/actuator/metrics/{requiredMetricName}": {"get": { "summary": "Actuator web endpoint 'metrics-requiredMetricName'", - "operationId": "handle_5", + "operationId": "metrics-requiredMetricName_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -652,7 +652,7 @@ "/actuator/loggers/{name}": { "post": { "summary": "Actuator web endpoint 'loggers-name'", - "operationId": "handle_0", + "operationId": "loggers-name_3", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -667,7 +667,7 @@ }, "get": { "summary": "Actuator web endpoint 'loggers-name'", - "operationId": "handle_7", + "operationId": "loggers-name_4", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -766,7 +766,7 @@ }}, "/actuator/metrics": {"get": { "summary": "Actuator web endpoint 'metrics'", - "operationId": "handle_4", + "operationId": "metrics_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -775,7 +775,7 @@ }}, "/actuator/info": {"get": { "summary": "Actuator web endpoint 'info'", - "operationId": "handle_9", + "operationId": "info_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -1001,7 +1001,7 @@ }, "/actuator/logfile": {"get": { "summary": "Actuator web endpoint 'logfile'", - "operationId": "handle_8", + "operationId": "logfile_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -1148,7 +1148,7 @@ }}, "/actuator/health": {"get": { "summary": "Actuator web endpoint 'health'", - "operationId": "handle_11", + "operationId": "health_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -1231,7 +1231,7 @@ }}, "/actuator/heapdump": {"get": { "summary": "Actuator web endpoint 'heapdump'", - "operationId": "handle_10", + "operationId": "heapdump_2", "responses": {"200": { "description": "OK", "content": {"*/*": {"schema": {"type": "object"}}} @@ -1249,6 +1249,13 @@ "version": "1.0" }, "tags": [ + {"name": "A1-EI (callbacks)"}, + { + "name": "Data producer (callbacks)", + "description": "API implemented by data producers" + }, + {"name": "Data consumer"}, + {"name": "Data consumer (callbacks)"}, { "name": "A1-EI (registration)", "description": "Data consumer EI job registration" @@ -1257,22 +1264,22 @@ "name": "A1-EI (callbacks)", "description": "Data consumer EI job status callbacks" }, - { - "name": "Data producer (callbacks)", - "description": "API implemented by data producers" - }, + {"name": "Service status"}, + {"name": "A1-EI (registration)"}, + {"name": "Data producer (registration)"}, + {"name": "Data producer (callbacks)"}, { "name": "Data producer (registration)", "description": "API for data producers" }, - { - "name": "Service status", - "description": "API for monitoring of the service" - }, { "name": "Data consumer", "description": "API for data consumers" }, + { + "name": "Service status", + "description": "API for monitoring of the service" + }, { "name": "Actuator", "description": "Monitor and interact", diff --git a/information-coordinator-service/api/ics-api.yaml b/information-coordinator-service/api/ics-api.yaml index 03de106a..dafb0ffd 100644 --- a/information-coordinator-service/api/ics-api.yaml +++ b/information-coordinator-service/api/ics-api.yaml @@ -30,18 +30,25 @@ info: servers: - url: / tags: +- name: A1-EI (callbacks) +- name: Data producer (callbacks) + description: API implemented by data producers +- name: Data consumer +- name: Data consumer (callbacks) - name: A1-EI (registration) description: Data consumer EI job registration - name: A1-EI (callbacks) description: Data consumer EI job status callbacks +- name: Service status +- name: A1-EI (registration) +- name: Data producer (registration) - name: Data producer (callbacks) - description: API implemented by data producers - name: Data producer (registration) description: API for data producers -- name: Service status - description: API for monitoring of the service - name: Data consumer description: API for data consumers +- name: Service status + description: API for monitoring of the service - name: Actuator description: Monitor and interact externalDocs: @@ -118,7 +125,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'threaddump' - operationId: handle_2_1_3 + operationId: threaddump_4 responses: 200: description: OK @@ -348,7 +355,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers' - operationId: handle_6 + operationId: loggers_2 responses: 200: description: OK @@ -361,7 +368,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'health-path' - operationId: handle_12 + operationId: health-path_2 responses: 200: description: OK @@ -389,7 +396,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'metrics-requiredMetricName' - operationId: handle_5 + operationId: metrics-requiredMetricName_2 parameters: - name: requiredMetricName in: path @@ -466,7 +473,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers-name' - operationId: handle_7 + operationId: loggers-name_4 parameters: - name: name in: path @@ -486,7 +493,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'loggers-name' - operationId: handle_0 + operationId: loggers-name_3 parameters: - name: name in: path @@ -617,7 +624,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'metrics' - operationId: handle_4 + operationId: metrics_2 responses: 200: description: OK @@ -630,7 +637,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'info' - operationId: handle_9 + operationId: info_2 responses: 200: description: OK @@ -923,7 +930,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'logfile' - operationId: handle_8 + operationId: logfile_2 responses: 200: description: OK @@ -1107,7 +1114,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'health' - operationId: handle_11 + operationId: health_2 responses: 200: description: OK @@ -1211,7 +1218,7 @@ paths: tags: - Actuator summary: Actuator web endpoint 'heapdump' - operationId: handle_10 + operationId: heapdump_2 responses: 200: description: OK diff --git a/information-coordinator-service/pom.xml b/information-coordinator-service/pom.xml index 2de2bf2a..16a1fd50 100644 --- a/information-coordinator-service/pom.xml +++ b/information-coordinator-service/pom.xml @@ -26,12 +26,12 @@ org.springframework.boot spring-boot-starter-parent - 2.5.3 + 2.6.2 org.o-ran-sc.nonrtric information-coordinator-service - 1.2.0-SNAPSHOT + 1.2.1-SNAPSHOT The Apache Software License, Version 2.0 @@ -49,17 +49,13 @@ 11 3.0.0 2.8.2 - 1.1.6 2.1.6 - 20190722 - 3.6 + 20211205 3.8.0 2.12.2 1.24.3 3.0.11 0.30.0 - 1.1.11 - 2.1.1 3.7.0.1746 0.8.5 true @@ -68,7 +64,7 @@ org.springdoc springdoc-openapi-ui - 1.5.4 + 1.6.3 org.springframework.boot @@ -96,10 +92,6 @@ swagger-jaxrs2-servlet-initializer ${swagger.version} - - javax.xml.bind - jaxb-api - org.immutables value @@ -116,26 +108,11 @@ json ${json.version} - - commons-net - commons-net - ${commons-net.version} - - - org.onap.dcaegen2.services.sdk.rest.services - cbs-client - ${sdk.version} - org.projectlombok lombok provided - - javax.ws.rs - javax.ws.rs-api - ${javax.ws.rs-api.version} - com.github.erosb @@ -230,7 +207,7 @@ - com,java,javax,org + com,java,org @@ -380,4 +357,4 @@ JIRA https://jira.o-ran-sc.org/ - \ No newline at end of file + diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java index cfac5cf1..0b47733c 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java @@ -38,7 +38,6 @@ import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; - import javax.net.ssl.KeyManagerFactory; import org.oransc.ics.configuration.WebClientConfig; diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java index d0fda941..b3692613 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java @@ -53,26 +53,24 @@ public class A1eCallbacks { private final AsyncRestClient restClient; private final InfoJobs eiJobs; - private final InfoProducers eiProducers; @Autowired - public A1eCallbacks(ApplicationConfig config, InfoJobs eiJobs, InfoProducers eiProducers) { + public A1eCallbacks(ApplicationConfig config, InfoJobs eiJobs) { AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); this.restClient = restClientFactory.createRestClientUseHttpProxy(""); this.eiJobs = eiJobs; - this.eiProducers = eiProducers; } - public Flux notifyJobStatus(Collection eiTypes) { + public Flux notifyJobStatus(Collection eiTypes, InfoProducers eiProducers) { return Flux.fromIterable(eiTypes) // .flatMap(eiType -> Flux.fromIterable(this.eiJobs.getJobsForType(eiType))) // .filter(eiJob -> !eiJob.getJobStatusUrl().isEmpty()) // - .filter(eiJob -> this.eiProducers.isJobEnabled(eiJob) != eiJob.isLastStatusReportedEnabled()) - .flatMap(this::noifyStatusToJobOwner); + .filter(eiJob -> eiProducers.isJobEnabled(eiJob) != eiJob.isLastStatusReportedEnabled()) + .flatMap(eiJob -> noifyStatusToJobOwner(eiJob, eiProducers)); } - private Mono noifyStatusToJobOwner(InfoJob job) { - boolean isJobEnabled = this.eiProducers.isJobEnabled(job); + private Mono noifyStatusToJobOwner(InfoJob job, InfoProducers eiProducers) { + boolean isJobEnabled = eiProducers.isJobEnabled(job); A1eEiJobStatus status = isJobEnabled ? new A1eEiJobStatus(A1eEiJobStatus.EiJobStatusValues.ENABLED) : new A1eEiJobStatus(A1eEiJobStatus.EiJobStatusValues.DISABLED); String body = gson.toJson(status); diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/repository/InfoProducers.java b/information-coordinator-service/src/main/java/org/oransc/ics/repository/InfoProducers.java index 9d98eaad..19b26985 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/repository/InfoProducers.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/repository/InfoProducers.java @@ -91,9 +91,9 @@ public class InfoProducers { producerCallbacks.startInfoJobs(producer, this.infoJobs) // .collectList() // - .flatMapMany(list -> consumerCallbacks.notifyJobStatus(producer.getInfoTypes())) // + .flatMapMany(list -> consumerCallbacks.notifyJobStatus(producer.getInfoTypes(), this)) // .collectList() // - .flatMapMany(list -> consumerCallbacks.notifyJobStatus(previousTypes)) // + .flatMapMany(list -> consumerCallbacks.notifyJobStatus(previousTypes, this)) // .subscribe(); return producer; @@ -136,7 +136,7 @@ public class InfoProducers { this.logger.error("Bug, no producer found"); } } - this.consumerCallbacks.notifyJobStatus(producer.getInfoTypes()) // + this.consumerCallbacks.notifyJobStatus(producer.getInfoTypes(), this) // .subscribe(); } diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/tasks/ProducerSupervision.java b/information-coordinator-service/src/main/java/org/oransc/ics/tasks/ProducerSupervision.java index 690f47cd..36ca28e0 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/tasks/ProducerSupervision.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/tasks/ProducerSupervision.java @@ -89,7 +89,7 @@ public class ProducerSupervision { .filter(infoJob -> !producer.isJobEnabled(infoJob)) // .flatMap(infoJob -> producerCallbacks.startInfoJob(producer, infoJob, Retry.max(1)), MAX_CONCURRENCY) // .collectList() // - .flatMapMany(startedJobs -> consumerCallbacks.notifyJobStatus(producer.getInfoTypes())) // + .flatMapMany(startedJobs -> consumerCallbacks.notifyJobStatus(producer.getInfoTypes(), infoProducers)) // .collectList(); } diff --git a/onap/oran b/onap/oran index 6e318749..3d2a09b1 160000 --- a/onap/oran +++ b/onap/oran @@ -1 +1 @@ -Subproject commit 6e31874958b44f45c5dd78aef5c783916b16c6ee +Subproject commit 3d2a09b1bc7d6798c8083bfc3dc04c69a1b709c7 diff --git a/pom.xml b/pom.xml index 39c316e1..1a7d8886 100644 --- a/pom.xml +++ b/pom.xml @@ -38,9 +38,6 @@ r-app-catalogue helm-manager dmaap-adaptor-java - dmaap-mediator-producer - test/usecases/oruclosedlooprecovery/goversion - test/usecases/odusliceassurance/goversion diff --git a/r-app-catalogue/Dockerfile b/r-app-catalogue/Dockerfile index cd2efc9b..ed4be958 100644 --- a/r-app-catalogue/Dockerfile +++ b/r-app-catalogue/Dockerfile @@ -31,8 +31,15 @@ ADD /config/application.yaml /opt/app/r-app-catalogue/config/application.yaml ADD /config/r-app-catalogue-keystore.jks /opt/app/r-app-catalogue/etc/cert/keystore.jks ADD target/${JAR} /opt/app/r-app-catalogue/r-app-catalogue.jar +ARG user=nonrtric +ARG group=nonrtric -RUN chmod -R 777 /opt/app/r-app-catalogue/config/ +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /opt/app/r-app-catalogue +RUN chown -R $user:$group /var/log/r-app-catalogue + +USER ${user} CMD ["java", "-jar", "/opt/app/r-app-catalogue/r-app-catalogue.jar"] diff --git a/r-app-catalogue/api/rac-api.yaml b/r-app-catalogue/api/rac-api.yaml index 748cf2b4..9ba6c398 100644 --- a/r-app-catalogue/api/rac-api.yaml +++ b/r-app-catalogue/api/rac-api.yaml @@ -14,7 +14,7 @@ paths: summary: Services operationId: getServices responses: - 200: + "200": description: Services content: application/json: @@ -40,13 +40,13 @@ paths: type: string example: DroneIdentifier responses: - 200: + "200": description: Service content: application/json: schema: $ref: '#/components/schemas/service' - 404: + "404": description: Service is not found content: application/json: @@ -75,9 +75,9 @@ paths: $ref: '#/components/schemas/inputService' required: true responses: - 200: + "200": description: Service updated - 201: + "201": description: Service created headers: Location: @@ -86,14 +86,14 @@ paths: explode: false schema: type: string - 400: + "400": description: Provided service is not correct content: application/json: schema: $ref: '#/components/schemas/error_information' example: - detail: 'Service is missing required property: version' + detail: "Service is missing required property: version" status: 400 deprecated: false delete: @@ -111,7 +111,7 @@ paths: type: string example: DroneIdentifier responses: - 204: + "204": description: Service deleted deprecated: false components: diff --git a/r-app-catalogue/pom.xml b/r-app-catalogue/pom.xml index 5da52d34..d4db4b96 100644 --- a/r-app-catalogue/pom.xml +++ b/r-app-catalogue/pom.xml @@ -26,13 +26,13 @@ org.springframework.boot spring-boot-starter-parent - 2.3.4.RELEASE + 2.6.2 org.o-ran-sc.nonrtric r-app-catalogue - 1.1.0-SNAPSHOT - + 1.0.2-SNAPSHOT + The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt @@ -43,8 +43,8 @@ 1.5.22 2.9.2 0.2.1 - 4.3.1 - 3.0.11 + 5.3.1 + 3.0.31 2.12.2 1.24.3 0.8.6 @@ -328,4 +328,4 @@ - \ No newline at end of file + diff --git a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/HttpsRequestTest.java b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/HttpsRequestTest.java index 9b943df1..8a66e14b 100644 --- a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/HttpsRequestTest.java +++ b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/HttpsRequestTest.java @@ -18,9 +18,9 @@ package org.oransc.rappcatalogue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import javax.net.ssl.SSLContext; @@ -28,8 +28,8 @@ import org.apache.http.client.HttpClient; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; @@ -43,11 +43,11 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.ResourceUtils; import org.springframework.web.client.ResourceAccessException; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @TestPropertySource( properties = { // diff --git a/test/auto-test/FTC1.sh b/test/auto-test/FTC1.sh index 1e344055..00d37581 100755 --- a/test/auto-test/FTC1.sh +++ b/test/auto-test/FTC1.sh @@ -31,10 +31,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="NGW CBS CONSUL" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -120,10 +120,6 @@ for __httpx in $TESTED_PROTOCOLS ; do start_gateway $SIM_GROUP/$NRT_GATEWAY_COMPOSE_DIR/$NRT_GATEWAY_CONFIG_FILE fi - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [[ $interface = *"SDNC"* ]]; then start_sdnc prepare_consul_config SDNC ".consul_config.json" @@ -134,7 +130,31 @@ for __httpx in $TESTED_PROTOCOLS ; do if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + #Temporary switch to http/https if dmaap use. Otherwise it is not possibble to push config + if [ $__httpx == "HTTPS" ]; then + use_agent_rest_https + else + use_agent_rest_http + fi + api_put_configuration 200 ".consul_config.json" + if [ $__httpx == "HTTPS" ]; then + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_https + else + use_agent_rest_https + fi + else + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_http + else + use_agent_rest_http + fi + fi + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi mr_equal requests_submitted 0 diff --git a/test/auto-test/FTC10.sh b/test/auto-test/FTC10.sh index a561cc6b..481f450d 100755 --- a/test/auto-test/FTC10.sh +++ b/test/auto-test/FTC10.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -67,7 +67,9 @@ start_mr start_cr 1 if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs + if [[ "$PMS_FEATURE_LEVEL" != *"NOCONSUL"* ]]; then + start_consul_cbs + fi fi start_control_panel $SIM_GROUP/$CONTROL_PANEL_COMPOSE_DIR/$CONTROL_PANEL_CONFIG_FILE @@ -87,7 +89,11 @@ prepare_consul_config NOSDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + consul_config_app ".consul_config.json" + fi fi api_get_status 200 diff --git a/test/auto-test/FTC100.sh b/test/auto-test/FTC100.sh index da623ce1..1fafa711 100755 --- a/test/auto-test/FTC100.sh +++ b/test/auto-test/FTC100.sh @@ -31,10 +31,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -109,8 +109,14 @@ for __httpx in $TESTED_PROTOCOLS ; do start_ric_simulators ricsim_g1 1 OSC_2.1.0 start_ric_simulators ricsim_g2 1 STD_1.1.3 + + sim_put_policy_type 201 ricsim_g1_1 1 testdata/OSC/sim_1.json + sim_put_policy_type 201 ricsim_g1_1 2 testdata/OSC/sim_2.json + if [ "$PMS_VERSION" == "V2" ]; then start_ric_simulators ricsim_g3 1 STD_2.0.0 + sim_put_policy_type 201 ricsim_g3_1 STD_QOS_0_2_0 testdata/STD2/sim_qos.json + sim_put_policy_type 201 ricsim_g3_1 STD_QOS2_0.1.0 testdata/STD2/sim_qos2.json fi start_mr @@ -123,10 +129,6 @@ for __httpx in $TESTED_PROTOCOLS ; do start_gateway $SIM_GROUP/$NRT_GATEWAY_COMPOSE_DIR/$NRT_GATEWAY_CONFIG_FILE fi - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [[ $interface = *"SDNC"* ]]; then start_sdnc prepare_consul_config SDNC ".consul_config.json" @@ -137,16 +139,42 @@ for __httpx in $TESTED_PROTOCOLS ; do if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" - fi + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + #Temporary switch to http/https if dmaap use. Otherwise it is not possibble to push config + if [ $__httpx == "HTTPS" ]; then + use_agent_rest_https + else + use_agent_rest_http + fi + + if [[ $interface != *"DMAAP"* ]]; then + echo "{}" > ".consul_config_incorrect.json" + api_put_configuration 400 ".consul_config_incorrect.json" + fi + + api_put_configuration 200 ".consul_config.json" + api_get_configuration 200 ".consul_config.json" + if [ $__httpx == "HTTPS" ]; then + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_https + else + use_agent_rest_https + fi + else + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_http + else + use_agent_rest_http + fi + fi - sim_put_policy_type 201 ricsim_g1_1 1 testdata/OSC/sim_1.json - sim_put_policy_type 201 ricsim_g1_1 2 testdata/OSC/sim_2.json + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi + fi if [ "$PMS_VERSION" == "V2" ]; then - sim_put_policy_type 201 ricsim_g3_1 STD_QOS_0_2_0 testdata/STD2/sim_qos.json - sim_put_policy_type 201 ricsim_g3_1 STD_QOS2_0.1.0 testdata/STD2/sim_qos2.json - api_equal json:rics 3 300 api_equal json:policy-types 5 120 @@ -179,6 +207,8 @@ for __httpx in $TESTED_PROTOCOLS ; do api_get_status 200 + api_get_status_root 200 + echo "############################################" echo "##### Service registry and supervision #####" echo "############################################" @@ -384,6 +414,10 @@ for __httpx in $TESTED_PROTOCOLS ; do else notificationurl="" fi + if [[ $interface != *"DMAAP"* ]]; then + # Badly formatted json is not possible to send via dmaap + api_put_policy 400 "unregistered-service" ricsim_g1_1 1 2000 NOTRANSIENT $notificationurl testdata/OSC/pi_bad_template.json + fi deviation "TR10 - agent allows policy creation on unregistered service (orig problem) - test combo $interface and $__httpx" #Kept until decison #api_put_policy 400 "unregistered-service" ricsim_g1_1 1 2000 NOTRANSIENT testdata/OSC/pi1_template.json @@ -410,6 +444,8 @@ for __httpx in $TESTED_PROTOCOLS ; do api_put_policy 200 "service10" ricsim_g3_1 STD_QOS2_0.1.0 5200 false $notificationurl testdata/STD2/pi_qos2_template.json fi + api_get_policy_status 404 1 + api_get_policy_status 404 2 VAL='NOT IN EFFECT' api_get_policy_status 200 5000 OSC "$VAL" "false" api_get_policy_status 200 5100 STD "UNDEFINED" diff --git a/test/auto-test/FTC110.sh b/test/auto-test/FTC110.sh index f855f6fa..46a44d03 100755 --- a/test/auto-test/FTC110.sh +++ b/test/auto-test/FTC110.sh @@ -31,10 +31,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -65,10 +65,6 @@ start_mr start_cr 1 -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - start_control_panel $SIM_GROUP/$CONTROL_PANEL_COMPOSE_DIR/$CONTROL_PANEL_CONFIG_FILE if [ ! -z "$NRT_GATEWAY_APP_NAME" ]; then @@ -82,7 +78,12 @@ prepare_consul_config NOSDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi set_agent_debug diff --git a/test/auto-test/FTC1100.sh b/test/auto-test/FTC1100.sh index cf172a06..265db075 100755 --- a/test/auto-test/FTC1100.sh +++ b/test/auto-test/FTC1100.sh @@ -34,7 +34,7 @@ KUBE_PRESTARTED_IMAGES="" CONDITIONALLY_IGNORED_IMAGES="NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" diff --git a/test/auto-test/FTC150.sh b/test/auto-test/FTC150.sh index 822f835e..5219e1b3 100755 --- a/test/auto-test/FTC150.sh +++ b/test/auto-test/FTC150.sh @@ -27,8 +27,13 @@ KUBE_INCLUDED_IMAGES=" RICSIM SDNC KUBEPROXY" #Prestarted app (not started by script) to include in the test when running kubernetes, space separated list KUBE_PRESTARTED_IMAGES=" " +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="" + #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" diff --git a/test/auto-test/FTC1800.sh b/test/auto-test/FTC1800.sh index 0948b650..1284bf61 100755 --- a/test/auto-test/FTC1800.sh +++ b/test/auto-test/FTC1800.sh @@ -26,7 +26,7 @@ DOCKER_INCLUDED_IMAGES="ICS PRODSTUB CR CP NGW KUBEPROXY" #App names to include in the test when running kubernetes, space separated list KUBE_INCLUDED_IMAGES="ICS PRODSTUB CP CR KUBEPROXY NGW" #Prestarted app (not started by script) to include in the test when running kubernetes, space separated list -KUBE_PRESTARTED_IMAGES="" +KUBE_PRESTARTED_IMAGES="NGW" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file @@ -34,7 +34,7 @@ KUBE_PRESTARTED_IMAGES="" CONDITIONALLY_IGNORED_IMAGES="NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" diff --git a/test/auto-test/FTC2001.sh b/test/auto-test/FTC2001.sh index fa1aea12..c09bbadf 100755 --- a/test/auto-test/FTC2001.sh +++ b/test/auto-test/FTC2001.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -79,16 +79,17 @@ fi start_policy_agent PROXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CONFIG_FILE -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - prepare_consul_config NOSDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi start_cr 1 diff --git a/test/auto-test/FTC2002.sh b/test/auto-test/FTC2002.sh index 1b057639..28c8fa70 100755 --- a/test/auto-test/FTC2002.sh +++ b/test/auto-test/FTC2002.sh @@ -26,8 +26,13 @@ KUBE_INCLUDED_IMAGES="" #Prestarted app (not started by script) to include in the test when running kubernetes, space separated list KUBE_PRESTARTED_IMAGES=" " +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="" + #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-ISTANBUL" +SUPPORTED_PROFILES="ONAP-ISTANBUL ONAP-JAKARTA" #Supported run modes SUPPORTED_RUNMODES="DOCKER" diff --git a/test/auto-test/FTC2003.sh b/test/auto-test/FTC2003.sh index 32412b7c..824ff3eb 100755 --- a/test/auto-test/FTC2003.sh +++ b/test/auto-test/FTC2003.sh @@ -33,7 +33,7 @@ KUBE_PRESTARTED_IMAGES="" CONDITIONALLY_IGNORED_IMAGES="" #Supported test environment profiles -SUPPORTED_PROFILES="ORAN-E-RELEASE" +SUPPORTED_PROFILES="ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" diff --git a/test/auto-test/FTC300.sh b/test/auto-test/FTC300.sh index 232e5a84..2d9e9f92 100755 --- a/test/auto-test/FTC300.sh +++ b/test/auto-test/FTC300.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -102,10 +102,6 @@ for __httpx in $TESTED_PROTOCOLS ; do start_cr 1 - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - start_control_panel $SIM_GROUP/$CONTROL_PANEL_COMPOSE_DIR/$CONTROL_PANEL_CONFIG_FILE if [ ! -z "$NRT_GATEWAY_APP_NAME" ]; then @@ -126,7 +122,31 @@ for __httpx in $TESTED_PROTOCOLS ; do if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + #Temporary switch to http/https if dmaap use. Otherwise it is not possibble to push config + if [ $__httpx == "HTTPS" ]; then + use_agent_rest_https + else + use_agent_rest_http + fi + api_put_configuration 200 ".consul_config.json" + if [ $__httpx == "HTTPS" ]; then + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_https + else + use_agent_rest_https + fi + else + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_http + else + use_agent_rest_http + fi + fi + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi api_get_status 200 @@ -170,7 +190,12 @@ for __httpx in $TESTED_PROTOCOLS ; do sim_equal ricsim_g1_1 num_instances 0 - sim_equal ricsim_g1_1 num_instances $NUM_POLICIES 300 + if [[ $interface = *"SDNC"* ]]; then + deviation "Sync over SDNC seem to be slower from Jakarta version..." + sim_equal ricsim_g1_1 num_instances $NUM_POLICIES 2000 + else + sim_equal ricsim_g1_1 num_instances $NUM_POLICIES 300 + fi START_ID2=$(($START_ID+$NUM_POLICIES)) @@ -184,8 +209,12 @@ for __httpx in $TESTED_PROTOCOLS ; do sim_post_delete_instances 200 ricsim_g2_1 sim_equal ricsim_g2_1 num_instances 0 - - sim_equal ricsim_g2_1 num_instances $NUM_POLICIES 300 + if [[ $interface = *"SDNC"* ]]; then + deviation "Sync over SDNC seem to be slower from Jakarta version..." + sim_equal ricsim_g2_1 num_instances $NUM_POLICIES 2000 + else + sim_equal ricsim_g2_1 num_instances $NUM_POLICIES 300 + fi api_delete_policy 204 $(($START_ID+47)) @@ -193,7 +222,12 @@ for __httpx in $TESTED_PROTOCOLS ; do sim_post_delete_instances 200 ricsim_g1_1 - sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 300 + if [[ $interface = *"SDNC"* ]]; then + deviation "Sync over SDNC seem to be slower from Jakarta version..." + sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 2000 + else + sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 300 + fi api_delete_policy 204 $(($START_ID2+37)) @@ -203,9 +237,16 @@ for __httpx in $TESTED_PROTOCOLS ; do sim_post_delete_instances 200 ricsim_g2_1 - sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 300 + if [[ $interface = *"SDNC"* ]]; then + deviation "Sync over SDNC seem to be slower from Jakarta version..." + sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 2000 + + sim_equal ricsim_g2_1 num_instances $(($NUM_POLICIES-3)) 2000 + else + sim_equal ricsim_g1_1 num_instances $(($NUM_POLICIES-2)) 300 - sim_equal ricsim_g2_1 num_instances $(($NUM_POLICIES-3)) 300 + sim_equal ricsim_g2_1 num_instances $(($NUM_POLICIES-3)) 300 + fi api_equal json:policies $(($NUM_POLICIES-2+$NUM_POLICIES-3)) diff --git a/test/auto-test/FTC3000.sh b/test/auto-test/FTC3000.sh index 5b8544a7..6a1428df 100755 --- a/test/auto-test/FTC3000.sh +++ b/test/auto-test/FTC3000.sh @@ -34,7 +34,7 @@ KUBE_PRESTARTED_IMAGES="" CONDITIONALLY_IGNORED_IMAGES="" #Supported test environment profiles -SUPPORTED_PROFILES="ORAN-E-RELEASE" +SUPPORTED_PROFILES="ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -50,7 +50,6 @@ FLAT_A1_EI="1" NUM_CR=10 # Number of callback receivers, divide all callbacks to this number of servers - for load sharing ## Note: The number jobs must be a multiple of the number of CRs in order to calculate the number of expected event in each CR NUM_JOBS=200 # Mediator and adapter gets same number of jobs for every type - if [ $NUM_JOBS -lt $NUM_CR ]; then __log_conf_fail_general "Number of jobs: $NUM_JOBS must be greater then the number of CRs: $NUM_CR" fi @@ -85,14 +84,24 @@ start_dmaapadp NOPROXY $SIM_GROUP/$DMAAP_ADP_COMPOSE_DIR/$DMAAP_ADP_CONFIG_FILE set_dmaapadp_trace -start_dmaapmed NOPROXY $SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_DATA_FILE +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + kafkapc_api_create_topic 201 "unauthenticated.dmaapmed_kafka.text" "text/plain" + + kafkapc_api_start_sending 200 "unauthenticated.dmaapmed_kafka.text" +fi + +start_dmaapmed NOPROXY $SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_HOST_DATA_FILE ics_equal json:data-producer/v1/info-producers 2 60 # Check producers ics_api_idc_get_job_ids 200 NOTYPE NOWNER EMPTY -ics_api_idc_get_type_ids 200 ExampleInformationType STD_Fault_Messages ExampleInformationTypeKafka ics_api_edp_get_producer_ids_2 200 NOTYPE DmaapGenericInfoProducer DMaaP_Mediator_Producer +if [[ "$DMAAP_MED_FEATURE_LEVEL" != *"KAFKATYPES"* ]]; then + ics_api_idc_get_type_ids 200 ExampleInformationType STD_Fault_Messages ExampleInformationTypeKafka +else + ics_api_idc_get_type_ids 200 ExampleInformationType STD_Fault_Messages ExampleInformationTypeKafka Kafka_TestTopic +fi # Create jobs for adapter - CR stores data as MD5 hash @@ -126,16 +135,32 @@ do cr_index=$(($i%$NUM_CR)) service_mr="CR_SERVICE_MR_PATH_"$cr_index service_app="CR_SERVICE_APP_PATH_"$cr_index - ics_api_idc_put_job 201 job-med-$i STD_Fault_Messages ${!service_mr}/job-med-data$i"?storeas=md5" info-owner-med-$i ${!service_app}/job_status_info-owner-med-$i testdata/dmaap-adapter/job-template.json + ics_api_idc_put_job 201 job-med-$i STD_Fault_Messages ${!service_mr}/job-med-data$i"?storeas=md5" info-owner-med-$i ${!service_app}/job_status_info-owner-med-$i testdata/dmaap-mediator/job-template.json done print_timer +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + # Create jobs for mediator kafka - CR stores data as MD5 hash + start_timer "Create mediator (kafka) jobs: $NUM_JOBS" + for ((i=1; i<=$NUM_JOBS; i++)) + do + cr_index=$(($i%$NUM_CR)) + service_text="CR_SERVICE_TEXT_PATH_"$cr_index + service_app="CR_SERVICE_APP_PATH_"$cr_index + ics_api_idc_put_job 201 job-med-kafka-$i Kafka_TestTopic ${!service_text}/job-med-kafka-data$i"?storeas=md5" info-owner-med-kafka-$i ${!service_app}/job_status_info-owner-med-kafka-$i testdata/dmaap-mediator/job-template-1-kafka.json + done + print_timer +fi + # Check job status for ((i=1; i<=$NUM_JOBS; i++)) do ics_api_a1_get_job_status 200 job-med-$i ENABLED 30 ics_api_a1_get_job_status 200 job-adp-$i ENABLED 30 ics_api_a1_get_job_status 200 job-adp-kafka-$i ENABLED 30 + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + ics_api_a1_get_job_status 200 job-med-kafka-$i ENABLED 30 + fi done @@ -152,6 +177,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapadp.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -159,6 +185,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapadp.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -166,6 +193,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapadp.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -173,6 +201,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapadp.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -180,6 +209,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapadp.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done # Check received data callbacks from adapter @@ -202,6 +232,7 @@ kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 1 30 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -210,6 +241,7 @@ kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 2 30 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -218,6 +250,7 @@ kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 3 30 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -226,6 +259,7 @@ kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 4 30 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -234,6 +268,7 @@ kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 5 30 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done # Check received data callbacks from adapter kafka @@ -254,6 +289,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapmed.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -261,6 +297,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapmed.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -268,6 +305,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapmed.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -275,6 +313,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapmed.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) @@ -282,6 +321,7 @@ mr_api_send_json_file "/events/unauthenticated.dmaapmed.json" ./tmp/data_for_dma for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done # Check received data callbacks from mediator @@ -295,6 +335,65 @@ do cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-data$i ./tmp/data_for_dmaap_test.json done +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + ## Send text file via message-router to mediator kafka + + EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) + kafkapc_api_post_msg_from_file 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" ./tmp/data_for_dmaap_test.txt + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 1 30 + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + + EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) + kafkapc_api_post_msg_from_file 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" ./tmp/data_for_dmaap_test.txt + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 2 30 + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + + EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) + kafkapc_api_post_msg_from_file 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" ./tmp/data_for_dmaap_test.txt + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 3 30 + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + + EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) + kafkapc_api_post_msg_from_file 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" ./tmp/data_for_dmaap_test.txt + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 4 30 + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + + EXPECTED_DATA_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_DATA_DELIV)) + kafkapc_api_post_msg_from_file 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" ./tmp/data_for_dmaap_test.txt + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 5 30 + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + + # Check received data callbacks from adapter kafka + for ((i=1; i<=$NUM_JOBS; i++)) + do + cr_index=$(($i%$NUM_CR)) + cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-kafka-data$i ./tmp/data_for_dmaap_test.txt + cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-kafka-data$i ./tmp/data_for_dmaap_test.txt + cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-kafka-data$i ./tmp/data_for_dmaap_test.txt + cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-kafka-data$i ./tmp/data_for_dmaap_test.txt + cr_api_check_single_genric_event_md5_file 200 $cr_index job-med-kafka-data$i ./tmp/data_for_dmaap_test.txt + done +fi # Send small json via message-router to adapter mr_api_send_json "/events/unauthenticated.dmaapadp.json" '{"msg":"msg-1"}' @@ -308,10 +407,11 @@ start_timer "Data delivery adapter, 2 json per job" for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done print_timer -# Send small text via message-routere to adapter +# Send small text via message-router to adapter kafkapc_api_post_msg 200 "unauthenticated.dmaapadp_kafka.text" "text/plain" 'Message-------1' kafkapc_api_post_msg 200 "unauthenticated.dmaapadp_kafka.text" "text/plain" 'Message-------3' kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text/counters/sent 7 30 @@ -322,6 +422,7 @@ start_timer "Data delivery adapter kafka, 2 strings per job" for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 done print_timer @@ -335,16 +436,41 @@ start_timer "Data delivery mediator, 2 json per job" for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 100 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 100 done print_timer +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + # Send small text via message-router to mediator + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" 'Message-------0' + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" 'Message-------2' + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 7 30 + + # Wait for data recetption, adapter kafka + EXPECTED_DATA_DELIV=$(($NUM_JOBS*2/$NUM_CR+$EXPECTED_DATA_DELIV)) + start_timer "Data delivery mediator kafka, 2 strings per job" + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 60 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 60 + done + print_timer +fi + # Check received number of messages for mediator and adapter callbacks for ((i=1; i<=$NUM_JOBS; i++)) do cr_index=$(($i%$NUM_CR)) cr_equal $cr_index received_callbacks?id=job-med-data$i $DATA_DELIV_JOBS + cr_equal $cr_index received_callback_batches?id=job-med-data$i $DATA_DELIV_JOBS cr_equal $cr_index received_callbacks?id=job-adp-data$i $DATA_DELIV_JOBS + cr_equal $cr_index received_callback_batches?id=job-adp-data$i $DATA_DELIV_JOBS cr_equal $cr_index received_callbacks?id=job-adp-kafka-data$i $DATA_DELIV_JOBS + cr_equal $cr_index received_callback_batches?id=job-adp-kafka-data$i $DATA_DELIV_JOBS + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + cr_equal $cr_index received_callbacks?id=job-med-kafka-data$i $DATA_DELIV_JOBS + cr_equal $cr_index received_callback_batches?id=job-med-kafka-data$i $DATA_DELIV_JOBS + fi done # Check received data and order for mediator and adapter callbacks @@ -357,6 +483,10 @@ do cr_api_check_single_genric_event_md5 200 $cr_index job-adp-data$i '{"msg":"msg-3"}' cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------1' cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------3' + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------0' + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------2' + fi done # Set delay in the callback receiver to slow down callbacks @@ -376,6 +506,7 @@ start_timer "Data delivery adapter with $SEC_DELAY seconds delay in consumer, 2 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 100 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 100 done print_timer @@ -391,6 +522,7 @@ start_timer "Data delivery adapter kafka with $SEC_DELAY seconds delay in consum for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 100 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 100 done print_timer @@ -405,16 +537,41 @@ start_timer "Data delivery mediator with $SEC_DELAY seconds delay in consumer, 2 for ((i=0; i<$NUM_CR; i++)) do cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 100 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 100 done print_timer +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + # Send small text via message-router to mediator kafka + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" 'Message-------4' + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text" "text/plain" 'Message-------6' + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text/counters/sent 9 30 + + # Wait for data recetption, mediator kafka + EXPECTED_DATA_DELIV=$(($NUM_JOBS*2/$NUM_CR+$EXPECTED_DATA_DELIV)) + start_timer "Data delivery mediator kafka with $SEC_DELAY seconds delay in consumer, 2 strings per job" + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV 100 + cr_equal $i received_callback_batches $EXPECTED_DATA_DELIV 100 + done + print_timer +fi + # Check received number of messages for mediator and adapter callbacks for ((i=1; i<=$NUM_JOBS; i++)) do cr_index=$(($i%$NUM_CR)) cr_equal $cr_index received_callbacks?id=job-med-data$i 9 + cr_equal $cr_index received_callback_batches?id=job-med-data$i 9 cr_equal $cr_index received_callbacks?id=job-adp-data$i 9 + cr_equal $cr_index received_callback_batches?id=job-adp-data$i 9 cr_equal $cr_index received_callbacks?id=job-adp-kafka-data$i 9 + cr_equal $cr_index received_callback_batches?id=job-adp-kafka-data$i 9 + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + cr_equal $cr_index received_callbacks?id=job-med-kafka-data$i 9 + cr_equal $cr_index received_callback_batches?id=job-med-kafka-data$i 9 + fi done # Check received data and order for mediator and adapter callbacks @@ -427,6 +584,10 @@ do cr_api_check_single_genric_event_md5 200 $cr_index job-adp-data$i '{"msg":"msg-7"}' cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------5' cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------7' + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------4' + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------6' + fi done #### TEST COMPLETE #### diff --git a/test/auto-test/FTC3001.sh b/test/auto-test/FTC3001.sh new file mode 100755 index 00000000..2672d127 --- /dev/null +++ b/test/auto-test/FTC3001.sh @@ -0,0 +1,261 @@ +#!/usr/bin/env bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. 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================================================= +# + +TC_ONELINE_DESCR="App test DMAAP Meditor and DMAAP Adapter with 100 jobs,types and topics" + +#App names to include in the test when running docker, space separated list +DOCKER_INCLUDED_IMAGES="ICS DMAAPMED DMAAPADP KUBEPROXY MR DMAAPMR CR KAFKAPC HTTPPROXY" + +#App names to include in the test when running kubernetes, space separated list +KUBE_INCLUDED_IMAGES=" ICS DMAAPMED DMAAPADP KUBEPROXY MR DMAAPMR CR KAFKAPC HTTPPROXY" + +#Prestarted app (not started by script) to include in the test when running kubernetes, space separated list +KUBE_PRESTARTED_IMAGES="" + +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="" + +#Supported test environment profiles +SUPPORTED_PROFILES="ORAN-E-RELEASE ORAN-F-RELEASE" +#Supported run modes +SUPPORTED_RUNMODES="DOCKER KUBE" + +. ../common/testcase_common.sh $@ + +setup_testenvironment + +#### TEST BEGIN #### + +#Local vars in test script +########################## +FLAT_A1_EI="1" +NUM_CR=1 # Number of callback receivers, max 1 +## Note: The number jobs must be a multiple of the number of CRs in order to calculate the number of expected event in each CR +NUM_JOBS=100 # Mediator and adapter gets same number of jobs for every type +if [ $NUM_CR -gt 1 ]; then + __log_conf_fail_general "Max number of callback receivers is one in this test" +fi + +clean_environment + +#use_cr_https +use_cr_http +use_ics_rest_https +use_mr_https +use_dmaapadp_https +use_dmaapmed_https + +start_kube_proxy + +start_cr $NUM_CR + +start_ics NOPROXY $SIM_GROUP/$ICS_COMPOSE_DIR/$ICS_CONFIG_FILE + +set_ics_trace + +start_mr + +start_kafkapc + +for ((i=1; i<=$NUM_JOBS; i++)) +do + kafkapc_api_create_topic 201 "unauthenticated.dmaapadp_kafka.text$i" "text/plain" + + kafkapc_api_start_sending 200 "unauthenticated.dmaapadp_kafka.text$i" +done + +adp_med_type_list="" +adp_config_data='{"types": [' +for ((i=1; i<=$NUM_JOBS; i++)) +do + if [ $i -ne 1 ]; then + adp_config_data=$adp_config_data',' + fi + adp_config_data=$adp_config_data'{"id": "ADPKafkaType'$i'","kafkaInputTopic": "unauthenticated.dmaapadp_kafka.text'$i'","useHttpProxy": false}' + adp_med_type_list="$adp_med_type_list ADPKafkaType$i " +done +adp_config_data=$adp_config_data']}' +echo $adp_config_data > tmp/adp_config_data.json + +start_dmaapadp NOPROXY $SIM_GROUP/$DMAAP_ADP_COMPOSE_DIR/$DMAAP_ADP_CONFIG_FILE tmp/adp_config_data.json + +set_dmaapadp_trace + +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + for ((i=1; i<=$NUM_JOBS; i++)) + do + kafkapc_api_create_topic 201 "unauthenticated.dmaapmed_kafka.text$i" "text/plain" + + kafkapc_api_start_sending 200 "unauthenticated.dmaapmed_kafka.text$i" + done +fi + +med_config_data='{"types": [' +for ((i=1; i<=$NUM_JOBS; i++)) +do + if [ $i -ne 1 ]; then + med_config_data=$med_config_data',' + fi + med_config_data=$med_config_data'{"id": "MEDKafkaType'$i'","kafkaInputTopic": "unauthenticated.dmaapmed_kafka.text'$i'"}' + adp_med_type_list="$adp_med_type_list MEDKafkaType$i " +done +med_config_data=$med_config_data']}' +echo $med_config_data > tmp/med_config_data.json + +start_dmaapmed NOPROXY tmp/med_config_data.json + +ics_equal json:data-producer/v1/info-producers 2 60 + +# Check producers +ics_api_idc_get_job_ids 200 NOTYPE NOWNER EMPTY +ics_api_edp_get_producer_ids_2 200 NOTYPE DmaapGenericInfoProducer DMaaP_Mediator_Producer +ics_api_idc_get_type_ids 200 $adp_med_type_list + + +# Create jobs for adapter kafka - CR stores data as MD5 hash +start_timer "Create adapter (kafka) jobs: $NUM_JOBS" +for ((i=1; i<=$NUM_JOBS; i++)) +do + # Max buffer timeout for is about 160 sec for Adator jobs" + adp_timeout=$(($i*1000)) + adp_config_data='{"filter":"Message*","maxConcurrency": 1,"bufferTimeout": {"maxSize": 100,"maxTimeMiliseconds": '$adp_timeout'}}' + echo $adp_config_data > tmp/adp_config_data.json + + cr_index=$(($i%$NUM_CR)) + service_text="CR_SERVICE_TEXT_PATH_"$cr_index + service_app="CR_SERVICE_APP_PATH_"$cr_index + ics_api_idc_put_job 201 job-adp-kafka-$i "ADPKafkaType$i" ${!service_text}/job-adp-kafka-data$i"?storeas=md5" info-owner-adp-kafka-$i ${!service_app}/callbacks-null tmp/adp_config_data.json + +done +print_timer + +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + # Create jobs for mediator kafka - CR stores data as MD5 hash + start_timer "Create mediator (kafka) jobs: $NUM_JOBS" + for ((i=1; i<=$NUM_JOBS; i++)) + do + med_timeout=$(($i*5000)) + med_config_data='{"bufferTimeout": {"maxSize": 100,"maxTimeMiliseconds": '$med_timeout'}}' + echo $med_config_data > tmp/med_config_data.json + cr_index=$(($i%$NUM_CR)) + service_text="CR_SERVICE_TEXT_PATH_"$cr_index + service_app="CR_SERVICE_APP_PATH_"$cr_index + ics_api_idc_put_job 201 job-med-kafka-$i "MEDKafkaType$i" ${!service_text}/job-med-kafka-data$i"?storeas=md5" info-owner-med-kafka-$i ${!service_app}/callbacks-null tmp/med_config_data.json + done + print_timer +fi + +# Check job status +for ((i=1; i<=$NUM_JOBS; i++)) +do + ics_api_a1_get_job_status 200 job-adp-kafka-$i ENABLED 30 + if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + ics_api_a1_get_job_status 200 job-med-kafka-$i ENABLED 30 + fi +done + + +EXPECTED_DATA_DELIV=0 #Total delivered msg per CR +EXPECTED_BATCHES_DELIV=0 #Total delivered batches per CR +DATA_DELIV_JOBS=0 #Total delivered msg per job per CR + +sleep_wait 60 + +start_timer "Data delivery adapter kafka, 2 strings per job (short buffer timeouts)" +# Send small text via message-router to adapter +for ((i=1; i<=$NUM_JOBS; i++)) +do + kafkapc_api_post_msg 200 "unauthenticated.dmaapadp_kafka.text"$i "text/plain" 'Message-------1'$i + kafkapc_api_post_msg 200 "unauthenticated.dmaapadp_kafka.text"$i "text/plain" 'Discard-------3'$i #Should be filtered out + kafkapc_api_post_msg 200 "unauthenticated.dmaapadp_kafka.text"$i "text/plain" 'Message-------3'$i +done +for ((i=1; i<=$NUM_JOBS; i++)) +do + kafkapc_equal topics/unauthenticated.dmaapadp_kafka.text$i/counters/sent 3 30 +done + +# Wait for data recetption, adapter kafka +EXPECTED_DATA_DELIV=$(($NUM_JOBS*2/$NUM_CR+$EXPECTED_DATA_DELIV)) +EXPECTED_BATCHES_DELIV=$(($NUM_JOBS/$NUM_CR+$EXPECTED_BATCHES_DELIV)) + +adp_timeout=$(($NUM_JOBS*1*2+60)) #NUM_JOBS*MIN_BUFFERTIMEOUT*2+60_SEC_DELAY +for ((i=0; i<$NUM_CR; i++)) +do + #tmp_receptio + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV $adp_timeout + cr_greater_or_equal $i received_callback_batches $EXPECTED_BATCHES_DELIV +done +print_timer + +# Check received data callbacks from adapter +for ((i=1; i<=$NUM_JOBS; i++)) +do + cr_index=$(($i%$NUM_CR)) + cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------1'$i + cr_api_check_single_genric_event_md5 200 $cr_index job-adp-kafka-data$i 'Message-------3'$i +done + +if [[ "$DMAAP_MED_FEATURE_LEVEL" == *"KAFKATYPES"* ]]; then + + PREV_DATA_DELIV=$(cr_read 0 received_callbacks) + PREV_BATCHES_DELIV=$(cr_read 0 received_callback_batches) + start_timer "Data delivery mediator kafka, 2 strings per job (long buffer timeouts)" + # Send small text via message-router to mediator + for ((i=1; i<=$NUM_JOBS; i++)) + do + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text$i" "text/plain" 'Message-------0'$i + kafkapc_api_post_msg 200 "unauthenticated.dmaapmed_kafka.text$i" "text/plain" 'Message-------2'$i + done + for ((i=1; i<=$NUM_JOBS; i++)) + do + kafkapc_equal topics/unauthenticated.dmaapmed_kafka.text$i/counters/sent 2 30 + done + + # Wait for data recetption, adapter kafka + + EXPECTED_DATA_DELIV=$(($NUM_JOBS*2/$NUM_CR+$PREV_DATA_DELIV)) + EXPECTED_BATCHES_DELIV=$(($NUM_JOBS/$NUM_CR+$PREV_BATCHES_DELIV)) + + med_timeout=$(($NUM_JOBS*5*2+60)) #NUM_JOBS*MIN_BUFFERTIMEOUT*2+60_SEC_DELAY + for ((i=0; i<$NUM_CR; i++)) + do + cr_equal $i received_callbacks $EXPECTED_DATA_DELIV $med_timeout + cr_greater_or_equal $i received_callback_batches $EXPECTED_BATCHES_DELIV + done + + print_timer + + # Check received data callbacks from mediator + for ((i=1; i<=$NUM_JOBS; i++)) + do + cr_index=$(($i%$NUM_CR)) + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------0'$i + cr_api_check_single_genric_event_md5 200 $cr_index job-med-kafka-data$i 'Message-------2'$i + done +fi + +#### TEST COMPLETE #### + +store_logs END + +print_result + +auto_clean_environment diff --git a/test/auto-test/FTC310.sh b/test/auto-test/FTC310.sh index 53437e8e..767dc4ff 100755 --- a/test/auto-test/FTC310.sh +++ b/test/auto-test/FTC310.sh @@ -21,10 +21,15 @@ TC_ONELINE_DESCR="Resync of RIC via changes in the consul config or pushed config" #App names to include in the test when running docker, space separated list -DOCKER_INCLUDED_IMAGES="CBS CONSUL CP CR MR PA RICSIM NGW KUBEPROXY" +DOCKER_INCLUDED_IMAGES="CBS CONSUL CP CR MR PA RICSIM KUBEPROXY" + +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER" @@ -36,6 +41,9 @@ setup_testenvironment if [ "$PMS_VERSION" == "V2" ]; then TESTED_VARIANTS="CONSUL NOCONSUL" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + TESTED_VARIANTS="NOCONSUL" + fi else TESTED_VARIANTS="CONSUL" fi @@ -140,7 +148,6 @@ for consul_conf in $TESTED_VARIANTS ; do fi check_policy_agent_logs - check_sdnc_logs store_logs END_$consul_conf done diff --git a/test/auto-test/FTC350.sh b/test/auto-test/FTC350.sh index 31e40ab9..c7222457 100755 --- a/test/auto-test/FTC350.sh +++ b/test/auto-test/FTC350.sh @@ -20,15 +20,20 @@ TC_ONELINE_DESCR="Change supported policy types and reconfigure rics" #App names to include in the test when running docker, space separated list -DOCKER_INCLUDED_IMAGES="CBS CONSUL CP CR MR PA RICSIM SDNC NGW KUBEPROXY" +DOCKER_INCLUDED_IMAGES="CBS CONSUL CP CR MR PA RICSIM SDNC KUBEPROXY" #App names to include in the test when running kubernetes, space separated list -KUBE_INCLUDED_IMAGES="CP CR MR PA RICSIM SDNC KUBEPROXY NGW" +KUBE_INCLUDED_IMAGES="CP CR MR PA RICSIM SDNC KUBEPROXY" #Prestarted app (not started by script) to include in the test when running kubernetes, space separated list KUBE_PRESTARTED_IMAGES="" +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL" + #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -71,7 +76,9 @@ for interface in $TESTED_VARIANTS ; do start_mr if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs + if [[ "$PMS_FEATURE_LEVEL" != *"NOCONSUL"* ]]; then + start_consul_cbs + fi fi # Create first config @@ -91,7 +98,11 @@ for interface in $TESTED_VARIANTS ; do prepare_consul_config NOSDNC ".consul_config_all.json" fi - start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CONFIG_FILE + if [ $RUNMODE == "KUBE" ] && [[ "$PMS_FEATURE_LEVEL" == *"INITIALCONFIGMAP"* ]]; then + start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/application2.yaml + else + start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CONFIG_FILE + fi set_agent_trace @@ -103,9 +114,19 @@ for interface in $TESTED_VARIANTS ; do #Load first config if [ $RUNMODE == "KUBE" ]; then - agent_load_config ".consul_config_initial.json" + if [[ "$PMS_FEATURE_LEVEL" == *"INITIALCONFIGMAP"* ]]; then + api_put_configuration 200 ".consul_config_initial.json" + api_get_configuration 200 ".consul_config_initial.json" + else + agent_load_config ".consul_config_initial.json" + fi else - consul_config_app ".consul_config_initial.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config_initial.json" + api_get_configuration 200 ".consul_config_initial.json" + else + consul_config_app ".consul_config_initial.json" + fi fi for ((i=1; i<=${NUM_RICS}; i++)) @@ -202,9 +223,19 @@ for interface in $TESTED_VARIANTS ; do #Load config with all rics if [ $RUNMODE == "KUBE" ]; then - agent_load_config ".consul_config_all.json" + if [[ "$PMS_FEATURE_LEVEL" == *"INITIALCONFIGMAP"* ]]; then + api_put_configuration 200 ".consul_config_all.json" + api_get_configuration 200 ".consul_config_all.json" + else + agent_load_config ".consul_config_all.json" + fi else - consul_config_app ".consul_config_all.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config_all.json" + api_get_configuration 200 ".consul_config_all.json" + else + consul_config_app ".consul_config_all.json" + fi fi api_equal json:rics 10 120 @@ -284,9 +315,19 @@ for interface in $TESTED_VARIANTS ; do # Load config with reduced number of rics if [ $RUNMODE == "KUBE" ]; then - agent_load_config ".consul_config_initial.json" + if [[ "$PMS_FEATURE_LEVEL" == *"INITIALCONFIGMAP"* ]]; then + api_put_configuration 200 ".consul_config_initial.json" + api_get_configuration 200 ".consul_config_initial.json" + else + agent_load_config ".consul_config_initial.json" + fi else - consul_config_app ".consul_config_initial.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config_initial.json" + api_get_configuration 200 ".consul_config_initial.json" + else + consul_config_app ".consul_config_initial.json" + fi fi api_equal json:rics 8 120 @@ -345,9 +386,19 @@ for interface in $TESTED_VARIANTS ; do # Load config with all rics if [ $RUNMODE == "KUBE" ]; then - agent_load_config ".consul_config_all.json" + if [[ "$PMS_FEATURE_LEVEL" == *"INITIALCONFIGMAP"* ]]; then + api_put_configuration 200 ".consul_config_all.json" + api_get_configuration 200 ".consul_config_all.json" + else + agent_load_config ".consul_config_all.json" + fi else - consul_config_app ".consul_config_all.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config_all.json" + api_get_configuration 200 ".consul_config_all.json" + else + consul_config_app ".consul_config_all.json" + fi fi api_equal json:rics 10 120 diff --git a/test/auto-test/FTC4000.sh b/test/auto-test/FTC4000.sh new file mode 100755 index 00000000..227c04f9 --- /dev/null +++ b/test/auto-test/FTC4000.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +TC_ONELINE_DESCR="Test of Helm Manager" + +#App names to include in the test when running docker, space separated list +DOCKER_INCLUDED_IMAGES="KUBEPROXY CHARTMUS LOCALHELM HELMMANAGER" + +#App names to include in the test when running kubernetes, space separated list +KUBE_INCLUDED_IMAGES="KUBEPROXY CHARTMUS LOCALHELM HELMMANAGER" +#Prestarted app (not started by script) to include in the test when running kubernetes, space separated list +KUBE_PRESTARTED_IMAGES="" + +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="" + +#Supported test environment profiles +SUPPORTED_PROFILES="ORAN-E-RELEASE ORAN-F-RELEASE" +#Supported run modes +SUPPORTED_RUNMODES="DOCKER KUBE" + +. ../common/testcase_common.sh $@ + +setup_testenvironment + +#### TEST BEGIN #### + +clean_environment + +start_kube_proxy + +start_chart_museum + +localhelm_create_test_chart dummy + +localhelm_package_test_chart dummy + +chartmus_upload_test_chart dummy + +clean_and_create_namespace test-ns + +localhelm_installed_chart_release NOTINSTALLED test-release test-ns + +start_helm_manager + +helm_manager_api_get_charts 200 EMPTY + +helm_manager_api_exec_add_repo cm $CHART_MUS_SERVICE_PATH + +helm_manager_api_post_repo 201 cm $CHART_MUS_SERVICE_HTTPX $CHART_MUS_SERVICE_HOST $CHART_MUS_SERVICE_PORT + +helm_manager_api_post_onboard_chart 200 cm dummy DEFAULT-VERSION test-release test-ns + +helm_manager_api_get_charts 200 cm dummy DEFAULT-VERSION test-release test-ns + +helm_manager_api_post_install_chart 201 dummy DEFAULT-VERSION + +localhelm_installed_chart_release INSTALLED test-release test-ns + +helm_manager_api_get_charts 200 cm dummy DEFAULT-VERSION test-release test-ns + +helm_manager_api_uninstall_chart 204 dummy DEFAULT-VERSION + +helm_manager_api_get_charts 200 cm dummy DEFAULT-VERSION test-release test-ns + +helm_manager_api_delete_chart 204 dummy DEFAULT-VERSION + +helm_manager_api_get_charts 200 EMPTY + +localhelm_installed_chart_release NOTINSTALLED test-release test-ns + +#### TEST COMPLETE #### + +store_logs END + +print_result + +auto_clean_environment + + + diff --git a/test/auto-test/FTC800.sh b/test/auto-test/FTC800.sh index e509f6ce..3d514c4e 100755 --- a/test/auto-test/FTC800.sh +++ b/test/auto-test/FTC800.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -106,6 +106,10 @@ for __httpx in $TESTED_PROTOCOLS ; do mr_equal requests_submitted 0 + sim_put_policy_type 201 ricsim_g1_1 1 testdata/OSC/sim_1.json + if [ "$PMS_VERSION" == "V2" ]; then + sim_put_policy_type 201 ricsim_g3_1 STD_QOS2_0.1.0 testdata/STD2/sim_qos2.json + fi if [[ $interface == "SDNC" ]]; then start_sdnc prepare_consul_config SDNC ".consul_config.json" @@ -113,17 +117,17 @@ for __httpx in $TESTED_PROTOCOLS ; do prepare_consul_config NOSDNC ".consul_config.json" fi - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi - api_get_status 200 sim_print ricsim_g1_1 interface @@ -132,11 +136,7 @@ for __httpx in $TESTED_PROTOCOLS ; do sim_print ricsim_g3_1 interface fi - sim_put_policy_type 201 ricsim_g1_1 1 testdata/OSC/sim_1.json - if [ "$PMS_VERSION" == "V2" ]; then - sim_put_policy_type 201 ricsim_g3_1 STD_QOS2_0.1.0 testdata/STD2/sim_qos2.json - api_equal json:policy-types 3 300 #Wait for the agent to refresh types from the simulators else api_equal json:policy_types 2 300 #Wait for the agent to refresh types from the simulators diff --git a/test/auto-test/FTC805.sh b/test/auto-test/FTC805.sh index af468144..a9268a20 100755 --- a/test/auto-test/FTC805.sh +++ b/test/auto-test/FTC805.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-ISTANBUL ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-ISTANBUL ONAP-JAKARTA ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -106,10 +106,6 @@ for __httpx in $TESTED_PROTOCOLS ; do set_agent_debug - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [[ $interface = *"SDNC"* ]]; then start_sdnc prepare_consul_config SDNC ".consul_config.json" @@ -120,7 +116,12 @@ for __httpx in $TESTED_PROTOCOLS ; do if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi start_cr 1 diff --git a/test/auto-test/FTC810.sh b/test/auto-test/FTC810.sh index ad71f464..83e1be79 100755 --- a/test/auto-test/FTC810.sh +++ b/test/auto-test/FTC810.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -98,16 +98,17 @@ fi start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CONFIG_FILE -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - prepare_consul_config SDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then - agent_load_config ".consul_config.json" + agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi start_sdnc diff --git a/test/auto-test/FTC850.sh b/test/auto-test/FTC850.sh index bd61b3af..f9f5be32 100755 --- a/test/auto-test/FTC850.sh +++ b/test/auto-test/FTC850.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -107,10 +107,6 @@ for __httpx in $TESTED_PROTOCOLS ; do set_agent_debug - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [[ $interface = *"SDNC"* ]]; then start_sdnc prepare_consul_config SDNC ".consul_config.json" @@ -121,7 +117,12 @@ for __httpx in $TESTED_PROTOCOLS ; do if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi start_mr # Not used, but removes error messages from the agent log diff --git a/test/auto-test/FTC900.sh b/test/auto-test/FTC900.sh index 886b6648..f76d21e4 100755 --- a/test/auto-test/FTC900.sh +++ b/test/auto-test/FTC900.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -70,16 +70,17 @@ start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CO use_agent_rest_http -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - prepare_consul_config NOSDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi api_get_status 200 diff --git a/test/auto-test/FTC_HELM_E_RELEASE.sh b/test/auto-test/FTC_HELM_E_RELEASE.sh index dcbe7b3a..0f7e30a0 100755 --- a/test/auto-test/FTC_HELM_E_RELEASE.sh +++ b/test/auto-test/FTC_HELM_E_RELEASE.sh @@ -29,6 +29,11 @@ KUBE_INCLUDED_IMAGES=" MR DMAAPMR CR PRODSTUB KUBEPROXY KAFKAPC" #Prestarted app (not started by script) to include in the test when running kubernetes, space separated list KUBE_PRESTARTED_IMAGES=" PA RICSIM CP ICS RC SDNC DMAAPMED DMAAPADP" +#Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if +#the image is not configured in the supplied env_file +#Used for images not applicable to all supported profile +CONDITIONALLY_IGNORED_IMAGES="" + #Supported test environment profiles SUPPORTED_PROFILES="ORAN-E-RELEASE" #Supported run modes @@ -357,7 +362,8 @@ if [ $ICS_VERSION == "V1-1" ]; then else ics_api_edp_put_type_2 201 type1 testdata/ics/ei-type-1.json ics_api_edp_get_type_2 200 type1 - ics_api_edp_get_type_ids 200 STD_Fault_Messages ExampleInformationTypeKafka ExampleInformationType type1 + + ics_api_edp_get_type_ids 200 type1 ics_api_edp_put_producer_2 201 prod-a $CB_JOB/prod-a $CB_SV/prod-a type1 ics_api_edp_put_producer_2 200 prod-a $CB_JOB/prod-a $CB_SV/prod-a type1 @@ -407,11 +413,13 @@ fi # Dmaap mediator and adapter start_dmaapadp NOPROXY $SIM_GROUP/$DMAAP_ADP_COMPOSE_DIR/$DMAAP_ADP_CONFIG_FILE $SIM_GROUP/$DMAAP_ADP_COMPOSE_DIR/$DMAAP_ADP_DATA_FILE -start_dmaapmed NOPROXY $SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_DATA_FILE +start_dmaapmed NOPROXY $SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_HOST_DATA_FILE ics_equal json:data-producer/v1/info-producers 3 120 -ics_api_idc_get_type_ids 200 ExampleInformationType ExampleInformationTypeKafka STD_Fault_Messages type-1 +ics_equal json:data-producer/v1/info-types 4 30 + +ics_api_idc_get_type_ids 200 ExampleInformationType ExampleInformationTypeKafka STD_Fault_Messages type1 ics_api_edp_get_producer_ids_2 200 NOTYPE prod-a DmaapGenericInfoProducer DMaaP_Mediator_Producer @@ -435,6 +443,8 @@ do ics_api_a1_get_job_status 200 jobz$i ENABLED 30 done +sleep_wait 30 # Wait for mediator to listening to kafka + mr_api_send_json "/events/unauthenticated.dmaapmed.json" '{"msg":"msg-0"}' mr_api_send_json "/events/unauthenticated.dmaapadp.json" '{"msg":"msg-1"}' mr_api_send_json "/events/unauthenticated.dmaapmed.json" '{"msg":"msg-2"}' diff --git a/test/auto-test/ONAP_UC.sh b/test/auto-test/ONAP_UC.sh index 5d230345..7ddff001 100755 --- a/test/auto-test/ONAP_UC.sh +++ b/test/auto-test/ONAP_UC.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL" +SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -110,14 +110,34 @@ for interface in $TESTED_VARIANTS ; do set_agent_trace - if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs - fi - if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + #Temporary switch to http/https if dmaap use. Otherwise it is not possibble to push config + if [ $__httpx == "HTTPS" ]; then + use_agent_rest_https + else + use_agent_rest_http + fi + api_put_configuration 200 ".consul_config.json" + if [ $__httpx == "HTTPS" ]; then + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_https + else + use_agent_rest_https + fi + else + if [[ $interface = *"DMAAP"* ]]; then + use_agent_dmaap_http + else + use_agent_rest_http + fi + fi + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi # Check that all rics are synced in diff --git a/test/auto-test/PM_DEMO.sh b/test/auto-test/PM_DEMO.sh index f3d5dd44..f0ade77c 100755 --- a/test/auto-test/PM_DEMO.sh +++ b/test/auto-test/PM_DEMO.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-GUILIN ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -86,16 +86,17 @@ start_policy_agent NORPOXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CO set_agent_trace -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - prepare_consul_config SDNC ".consul_config.json" if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi api_get_status 200 diff --git a/test/auto-test/PM_EI_DEMO.sh b/test/auto-test/PM_EI_DEMO.sh index 4e6b87ce..a917032d 100755 --- a/test/auto-test/PM_EI_DEMO.sh +++ b/test/auto-test/PM_EI_DEMO.sh @@ -30,10 +30,10 @@ KUBE_PRESTARTED_IMAGES="" #Ignore image in DOCKER_INCLUDED_IMAGES, KUBE_INCLUDED_IMAGES if #the image is not configured in the supplied env_file #Used for images not applicable to all supported profile -CONDITIONALLY_IGNORED_IMAGES="NGW" +CONDITIONALLY_IGNORED_IMAGES="CBS CONSUL NGW" #Supported test environment profiles -SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE" +SUPPORTED_PROFILES="ONAP-HONOLULU ONAP-ISTANBUL ONAP-JAKARTA ORAN-CHERRY ORAN-D-RELEASE ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" @@ -88,16 +88,17 @@ start_sdnc # Comment this line to run PMS with proxy start_policy_agent PROXY $SIM_GROUP/$POLICY_AGENT_COMPOSE_DIR/$POLICY_AGENT_CONFIG_FILE -if [ $RUNMODE == "DOCKER" ]; then - start_consul_cbs -fi - prepare_consul_config SDNC ".consul_config.json" #Change to NOSDNC if running PMS with proxy if [ $RUNMODE == "KUBE" ]; then agent_load_config ".consul_config.json" else - consul_config_app ".consul_config.json" + if [[ "$PMS_FEATURE_LEVEL" == *"NOCONSUL"* ]]; then + api_put_configuration 200 ".consul_config.json" + else + start_consul_cbs + consul_config_app ".consul_config.json" + fi fi start_cr 1 diff --git a/test/auto-test/README.md b/test/auto-test/README.md index 76858fe8..cef50a3e 100644 --- a/test/auto-test/README.md +++ b/test/auto-test/README.md @@ -1,7 +1,7 @@ # Overview The bash scripts in this dir are intended for function test of the Non-RT RIC in different configurations, using simulators when needed for the external interfaces. -A few of the bash scripts are so called 'suites', These suite scripts calls a sequence of the other bash scripts. +A few of the bash scripts are so called 'suites', These suite scripts calls a sequence of the other bash test scripts. ## Automated test scripts @@ -9,11 +9,12 @@ There are two types of scripts, filenames in the format FTCXXX.sh test one or mo FTC is short for Function Test Case. In addition, there are also other test scripts with other naming format used for demo setup etc (e.g PM_DEMO.sh). The requirements, in terms of the execution enviroment, to run a script or a suite is to have docker, docker-compose and python3 installed (the scripts warns if not installed). As an option, the scripts can also be executed in a Minikube or Kubernetes installation. The additional requirement is to have a clean minikube/kubernetes installation, perferably with the kube dashboard installed. -The scripts have been tested to work on both MacOS and Ubuntu using docker. They should work also in git-bash on windows (for docker) but only partly verified. Running using minikube has only been verified on Ubuntu and running on kubernetes has only been verified on MacOS. +The scripts have been tested to work on both MacOS and Ubuntu using docker. They should work also in git-bash on windows (for docker) but only partly verified. Running using minikube has only been verified on Ubuntu and running on kubernetes has been verified on MacOS and Ubuntu. Successful sample tests has been made on google cloud. ## Configuration -The test scripts uses configuration from a single file, found in `../common/test_env.sh`, which contains all needed configuration in terms of image names, image tags, ports, file paths, passwords etc. This file can be modified if needed. See the README.md in `../common/` for all details of the config file. +The test scripts uses configuration from a single profile file, found in `../common/test_env-*.sh`, which contains all needed configuration in terms of image names, image tags, ports, file paths, passwords etc. There is one profile file for system (ORAN/ONAP) and release. +If temporary changes are needed to the settings in a profile file, use an override file containing only the variable to override. ## How to run @@ -30,7 +31,7 @@ Each test script prints out the overall result of the tests in the end of the ex The test scripts produce quite a number of logs; all container logs, a log of all http/htps calls from the test scripts including the payload, some configuration created during test and also a test case log (same as what is printed on the screen during execution). All these logs are stored in `logs/FTCXXX/`. So each test script is using its own log directory. To test all components on a very basic level, run the demo test script(s) for the desired release. -Note that oran tests only include components from oran. +Note that oran tests only include components from oran (exception is the onap sdnc). Note that onap test uses components from onap combined with released oran components available at that onap release (e.g. Honolulu contains onap images from honolulu and oran images from cherry) @@ -81,24 +82,26 @@ ONAP ISTANBUL The test script are number using these basic categories where 0-999 are releated to the policy managment and 1000-1999 are related to information management. 2000-2999 are for southbound http proxy. There are also demo test cases that test more or less all components. These test scripts does not use the numbering scheme below. The numbering in each series corresponds to the following groupings -1-99 - Basic sanity tests +1-99 - Basic sanity tests, PMS -100-199 - API tests +100-199 - API tests, PMS -300-399 - Config changes and sync +300-399 - Config changes and sync, PMS -800-899 - Stability and capacity test +800-899 - Stability and capacity test, PMS -900-999 - Misc test +900-999 - Misc test, PMS 11XX - ICS API Tests 18XX - ICS Stability and capacity test -2000 - Southbound http proxy tests +20XX - Southbound http proxy tests 30XX - rApp tests +40XX - Helm Manager tests + Suites To get an overview of the available test scripts, use the following command to print the test script description: @@ -121,7 +124,7 @@ TC_ONELINE_DESCR="" DOCKER_INCLUDED_IMAGES= KUBE_INCLUDED_IMAGES= -KUBE_PRESTARTED_IMAGES= +KUBE_PRESTARTED_IMAGES= SUPPORTED_PROFILES= @@ -141,6 +144,8 @@ setup_testenvironment #### TEST COMPLETE #### +print_result + store_logs END ``` diff --git a/test/auto-test/Suite-aegis.sh b/test/auto-test/Suite-aegis.sh new file mode 100755 index 00000000..e7a5a51f --- /dev/null +++ b/test/auto-test/Suite-aegis.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. 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================================================= +# + +TS_ONELINE_DESCR="Test suite - PMS endpoint aegis image testing. Agent REST, DMAAP and SNDC controller resconf" + +. ../common/testsuite_common.sh + +suite_setup + +############# TEST CASES ################# + +./FTC1.sh $@ +./FTC10.sh $@ +./FTC100.sh $@ +./FTC110.sh $@ +./FTC300.sh $@ +./FTC310.sh $@ +./FTC350.sh $@ +./FTC800.sh $@ +./FTC805.sh $@ +./FTC850.sh $@ +./FTC2001.sh $@ + +########################################## + +suite_complete \ No newline at end of file diff --git a/test/auto-test/override_aegis_pms.sh b/test/auto-test/override_aegis_pms.sh new file mode 100644 index 00000000..1c0ea01e --- /dev/null +++ b/test/auto-test/override_aegis_pms.sh @@ -0,0 +1,21 @@ +#!/bin/bash +################################################################################ +# Copyright (c) 2021 Nordix Foundation. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ + +# Override file for running the e-release helm recipe including all components + + +POLICY_AGENT_IMAGE_BASE="aegis-onap-docker-local.artifactory.est.tech/onap/ccsdk-oran-a1policymanagementservice" diff --git a/test/auto-test/override_ftc_helm_e_release.sh b/test/auto-test/override_ftc_helm_e_release.sh index 3894acef..67edcb70 100644 --- a/test/auto-test/override_ftc_helm_e_release.sh +++ b/test/auto-test/override_ftc_helm_e_release.sh @@ -34,3 +34,5 @@ SDNC_EXTERNAL_SECURE_PORT=8383 RAPP_CAT_EXTERNAL_PORT=9085 RAPP_CAT_EXTERNAL_SECURE_PORT=9086 + +HELM_MANAGER_APP_NAME="helmmanager" diff --git a/test/auto-test/startMR.sh b/test/auto-test/startMR.sh index 2ae67819..fcc9599a 100755 --- a/test/auto-test/startMR.sh +++ b/test/auto-test/startMR.sh @@ -33,7 +33,7 @@ KUBE_PRESTARTED_IMAGES="" CONDITIONALLY_IGNORED_IMAGES="" #Supported test environment profiles -SUPPORTED_PROFILES="ORAN-E-RELEASE" +SUPPORTED_PROFILES="ORAN-E-RELEASE ORAN-F-RELEASE" #Supported run modes SUPPORTED_RUNMODES="DOCKER KUBE" diff --git a/test/auto-test/testdata/OSC/pi_bad_template.json b/test/auto-test/testdata/OSC/pi_bad_template.json new file mode 100644 index 00000000..25aca002 --- /dev/null +++ b/test/auto-test/testdata/OSC/pi_bad_template.json @@ -0,0 +1,5 @@ +{ + "scope": { + "ueId": "ueXXX", + "qosId": "qosXXX" + } \ No newline at end of file diff --git a/test/auto-test/testdata/dmaap-mediator/job-schema-1-kafka b/test/auto-test/testdata/dmaap-mediator/job-schema-1-kafka new file mode 100644 index 00000000..290b70ae --- /dev/null +++ b/test/auto-test/testdata/dmaap-mediator/job-schema-1-kafka @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "filter": { + "type": "string" + }, + "maxConcurrency": { + "type": "integer" + }, + "bufferTimeout": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "maxTimeMiliseconds": { + "type": "integer" + } + }, + "required": [ + "maxSize", + "maxTimeMiliseconds" + ] + } + }, + "required": [] +} \ No newline at end of file diff --git a/test/auto-test/testdata/dmaap-mediator/job-template-1-kafka.json b/test/auto-test/testdata/dmaap-mediator/job-template-1-kafka.json new file mode 100644 index 00000000..48f0a116 --- /dev/null +++ b/test/auto-test/testdata/dmaap-mediator/job-template-1-kafka.json @@ -0,0 +1,6 @@ +{ + "bufferTimeout": { + "maxSize": 1, + "maxTimeMiliseconds": 0 + } +} \ No newline at end of file diff --git a/test/auto-test/testdata/dmaap-mediator/job-template.json b/test/auto-test/testdata/dmaap-mediator/job-template.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/test/auto-test/testdata/dmaap-mediator/job-template.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/common/README.md b/test/common/README.md index c52ee9ce..e179f30e 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -1,36 +1,42 @@ # Introduction # -This dir contains most scripts needed for the auto-test environment. There are scripts with functions to adapt to the apis of the components of the Non-RT RIC; Policy Agent, A1 Controller and Ric (A1) simulator. The test environment supports both test with docker and kubernetes(still experimental) +This dir contains most scripts needed for the auto-test environment. There are scripts with functions to adapt to the apis of the components of the Non-RT RIC; Policy Managerment Service, Information Coordinator Service , A1 simulator as well as other components and simulators. The test environment supports both test with docker and kubernetes. Some of the scripts can also be used for other kinds of tests, for example basic tests. ## Overview for common test scripts and files ## -`agent_api_functions.sh` \ -Contains functions for adapting towards the Policy Management Service (PMS) API, also via dmaap (using a message-router stub interface) - `api_curl.sh` \ A common curl based function for the agent and ics apis. Also partly used for the Callback receiver and RAPP Catalogue apis. +`cbs_api_function.sh` \ +All functions are implemented in `consul_api_function.sh`. + +`chartmus_api_functions.sh` \ +Contains functions for managing a Chartmuseum instance. + +`clean-docker.sh` \ +Cleans all containers started by the test environment in docker. + `clean-kube.sh` \ Cleans all services, deployments, pods, replica set etc started by the test environment in kubernetes. `compare_json.py` \ A python script to compare two json obects for equality. Note that the comparsion always sort json-arrays before comparing (that is, it does not care about the order of items within the array). In addition, the target json object may specify individual parameter values where equality is 'dont care'. -`consul_cbs_function.sh` \ -Contains functions for managing Consul and CBS as well as create the configuration for the PMS. - -`control_panel_api_function.sh` \ -Contains functions for managing Control Panel. +`consul_api_function.sh` \ +Contains functions for managing Consul and CBS. -`controller_api_functions.sh` \ -Contains functions for adaping towards the A1-controller API. +`count_json_elements.py` \ +A python script calculate the length of json array or size of a json dictionary'. `count_json_elements.py` \ A python script returning the number of items in a json array. +`cp_api_function.sh` \ +Contains functions for managing the Control Panel. + `cr_api_functions.sh` \ -Contains functions for adapting towards the Callback receiver for checking received callback event. +Contains functions for adapting towards the Callback receiver for checking received callback events. `create_policies_process.py` \ A python script to create a batch of policies. The script is intended to run in a number of processes to create policies in parallel. @@ -41,36 +47,66 @@ A python script to create a json file from a formatted string of ric info. Helpe `delete_policies_process.py` \ A python script to delete a batch of policies. The script is intended to run in a number of processes to delete policies in parallel. +`dmaapadp_api_function.sh` +Contains funnctions for managing the Dmaap Adaptor Service. + +`dmaapmed_api_function.sh` +Contains funnctions for managing the Dmaap Mediator Service. + +`dmaapmr_api_function.sh` +All functions are implemented in `mr_api_functions.sh`. + `do_curl_function.sh` A script for executing a curl call with a specific url and optional payload. It also compare the response with an expected result in terms of response code and optional returned payload. Intended to be used by test script (for example basic test scripts of other components) -`ics_api_functions.sh` \ -Contains functions for adapting towards the ICS API - `extract_sdnc_reply.py` \ A python script to extract the information from an sdnc (A1 Controller) reply json. Helper for the test environment. -`gateway_api_functions.sh` \ -Contains functions for managing the Non-RT RIC Gateway +`genstat.sh` \ +This script collects container statistics to a file. Works both in docker and kubernetes (only for docker runtime). + +`helmmanager_api_functions.sh` \ +Contains functions for managing and testing of the Helm Manager. `http_proxy_api_functions.sh` \ -Contains functions for managing the Http Proxy +Contains functions for managing the Http Proxy. + +`ics_api_functions.sh` \ +Contains functions for adapting towards the Information Coordinator Service API. + +`kafkapc_api_functions.sh` \ +Contains functions for managing the kafka producer/consumer. Kafka is started by the dmaap message router component. `kube_proxy_api_functions.sh` \ -Contains functions for managing the Kube Proxy - to gain access to all services pod inside a kube cluster. +Contains functions for managing the Kube Proxy - to gain access to all services pod inside a kube cluster or all containers in a private docker network. + +`localhelm_api_functions.sh` \ +Contains functions for helm access on localhost. `mr_api_functions.sh` \ Contains functions for managing the MR Stub and the Dmaap Message Router +`ngw_api_functions.sh` \ +Contains functions for managing the Non-RT RIC Gateway + +`pa_api_functions.sh` \ +Contains functions for adapting towards the Policy Management Service (PMS) API, also via dmaap (using a message-router stub interface) + `prodstub_api_functions.sh` \ Contains functions for adapting towards the Producer stub interface - simulates a producer. -`rapp_catalogue_api_functions.sh` \ +`pvccleaner_api_functions.sh` \ +Contains functions for managing the PVC Cleaner (used for reset mounted volumes in kubernetes). + +`rc_api_functions.sh` \ Contains functions for adapting towards the RAPP Catalogue. -`ricsimulator_api_functions.sh` \ +`ricsim_api_functions.sh` \ Contains functions for adapting towards the RIC (A1) simulator admin API. +`sdnc_api_functions.sh` \ +Contains functions for adaping towards the SDNC (used as an A1 controller). + `test_env*.sh` \ Common env variables for test in the auto-test dir. All configuration of port numbers, image names and version etc shall be made in this file. Used by the auto test scripts/suites but could be used for other test script as well. The test cases shall be started with the file for the intended target using command line argument '--env-file'. @@ -79,6 +115,9 @@ Used by the auto test scripts/suites but could be used for other test script as Common functions for auto test cases in the auto-test dir. This script is the foundation of test auto environment which sets up images and enviroment variables needed by this script as well as the script adapting to the APIs. The included functions are described in detail further below. +`testengine_config.sh` \ +Configuration file to setup the applications (components and simulators) the test enviroment handles. + `testsuite_common.sh` \ Common functions for running two or more auto test scripts as a suite. @@ -101,6 +140,10 @@ This file must implement the following functions used by the test engine. Note t | ___kube_scale_zero | | ___kube_scale_zero_and_wait | | ___kube_delete_all | +| ___store_docker_logs | +| ___initial_setup | +| ___statisics_setup | +| ___test_requirements | In addition, all other functions used for testing of the application shall also be added to the file. For example functions to start the application, setting interface parameters as well as functions to send rest call towards the api of the application and validating the result. @@ -148,12 +191,15 @@ The script can be started with these arguments | `--use-staging-image` | The script will use images from the nexus staging repo for the supplied apps, space separated list of app short names | | `--use-release-image` | The script will use images from the nexus release repo for the supplied apps, space separated list of app short names | | `--image-repo` | Url to optional image repo. Only locally built images will be re-tagged and pushed to this repo | -| `-repo-policy` | Policy controlling which images to re-tag and push to image repo in param --image-repo. Can be set to 'local' (push on locally built images) or 'remote' (push locally built images and images from nexus repo). Default is 'local' | +| `-repo-policy` | Policy controlling which images to re-tag and push to image repo in param --image-repo. Can be set to 'local' (push only locally built images) or 'remote' (push locally built images and images from nexus repo). Default is 'local' | | `--cluster-timeout` | Optional timeout for cluster where it takes time to obtain external ip/host-name. Timeout in seconds | | `--print-stats` | Prints the number of tests, failed tests, failed configuration and deviations after each individual test or config | | `--override ` | Override setting from the file supplied by --env-file | | `--pre-clean` | Clean kube resouces when running docker and vice versa | | `--gen-stats` | Collect container/pod runtime statistics | +| `--delete-namespaces` | Delete kubernetes namespaces before starting tests - but only those created by the test scripts. Kube mode only. Ignored if running with prestarted apps. | +| `--delete-containers` | Delete docker containers before starting tests - but only those created by the test scripts. Docker mode only. | +| `--endpoint-stats` | Collect http endpoint statistics | | `help` | Print this info along with the test script description and the list of app short names supported | ## Function: setup_testenvironment ## @@ -164,20 +210,6 @@ Must be called right after sourcing all component scripts. |--| | None | -## Function: indent1 ## - -Indent every line of a command output with one space char. -| arg list | -|--| -| None | - -## Function: indent2 ## - -Indent every line of a command output with two space chars. -| arg list | -|--| -| None | - ## Function: print_result ## Print a test report of an auto-test script. @@ -190,18 +222,15 @@ Print a test report of an auto-test script. Start a timer for time measurement. Only one timer can be running. | arg list | |--| +| `` | | None - but any args will be printed (It is good practice to use same args for this function as for the `print_timer`) | ## Function: print_timer ## -Print the value of the timer (in seconds) previously started by 'start_timer'. (Note that timer is still running after this function). The result of the timer as well as the args to the function will also be printed in the test report. +Print the value of the timer (in seconds) previously started by 'start_timer'. (Note that timer is still running after this function). The result of the timer as well as the arg to 'start_timer' will also be printed in the test report. | arg list | |--| -| `` | - -| parameter | description | -| --------- | ----------- | -| `` | Any text message to be printed along with the timer result.(It is good practice to use same args for this function as for the `start_timer`) | +| None | ## Function: deviation ## @@ -240,16 +269,9 @@ Make the script sleep for a number of seconds. | `` | Number of seconds to sleep | | `` | Optional. The text will be printed, if present | -## Function: check_control_panel_logs ## - -Check the Control Panel log for any warnings and errors and print the count of each. -| arg list | -|--| -| None | - ## Function: store_logs ## -Take a snap-shot of all logs for all running containers and stores them in `./logs/`. All logs will get the specified prefix in the file name. In general, one of the last steps in an auto-test script shall be to call this function. If logs shall be taken several times during a test script, different prefixes shall be used each time. +Take a snap-shot of all logs for all running containers/pods and stores them in `./logs/`. All logs will get the specified prefix in the file name. In general, one of the last steps in an auto-test script shall be to call this function. If logs shall be taken several times during a test script, different prefixes shall be used each time. | arg list | |--| | `` | @@ -274,868 +296,611 @@ Print out the overall result of the executed test cases. |--| | None | -# Description of functions in agent_api_functions.sh # - -## General ## - -Both PMS version 1 and 2 are supported. The version is controlled by the env variable `$PMS_VERSION` set in the test env file. -For api function in version 2, an url prefix is added if configured. +# Description of functions in chartmus_api_function.sh # -## Function: use_agent_rest_http ## +## Function: start_chart_museum ## -Use http for all API calls to the Policy Agent. This is the default. +Start the Chart Museum | arg list | |--| | None | -## Function: use_agent_rest_https ## +## Function: chartmus_upload_test_chart ## -Use https for all API calls to the Policy Agent. +Upload a package chart to chartmusem | arg list | |--| -| None | +| `` | -## Function: use_agent_dmaap_http ## +| parameter | description | +| --------- | ----------- | +| `` | Name of the chart to upload | -Send and recieve all API calls to the Policy Agent over Dmaap via the MR over http. +## Function: chartmus_delete_test_chart ## + +Delete a chart in chartmusem | arg list | |--| -| None | +| ` []` | -## Function: use_agent_dmaap_https ## +| parameter | description | +| --------- | ----------- | +| `` | Name of the chart to delete | +| `` | Chart version, default is 0.1.0 | -Send and recieve all API calls to the Policy Agent over Dmaap via the MR over https. -| arg list | -|--| -| None | -## Function: start_policy_agent ## +# Description of functions in consul_api_function.sh # + +## Function: consul_config_app ## + +Function to load a json config from a file into consul for the Policy Agent -Start the Policy Agent container or corresponding kube resources depending on docker/kube mode. | arg list | |--| -| `` | -| (docker) `PROXY\|NOPROXY ` | -| (kube) `PROXY\|NOPROXY [ ]` | +| `` | | parameter | description | | --------- | ----------- | -| `PROXY` | Configure with http proxy, if proxy is started | -| `NOPROXY` | Configure without http proxy | -| ``| Path to application.yaml | -| `` | Optional path to application_configuration.json | +| `` | The path to the json file to be loaded to Consul/CBS | -## Function: agent_load_config ## +## Function: start_consul_cbs ## -Load the config into a config map (kubernetes only). +Start the Consul and CBS containers | arg list | |--| -| `` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Path to application_configuration.json | +# Description of functions in cp_api_function.sh # -## Function: set_agent_debug ## +## Function: use_control_panel_http ## -Configure the Policy Agent log on debug level. The Policy Agent must be running. +Set http as the protocol to use for all communication to the Control Panel | arg list | |--| | None | -## Function: set_agent_trace ## +## Function: use_control_panel_https ## -Configure the Policy Agent log on trace level. The Policy Agent must be running. +Set https as the protocol to use for all communication to the Control Panel | arg list | |--| | None | -## Function: use_agent_retries ## +## Function: start_control_panel ## -Configure the Policy Agent to make upto 5 retries if an API calls return any of the specified http return codes. +Start the Control Panel container | arg list | |--| -| `[]*` | +| None | -## Function: check_policy_agent_logs ## +# Description of functions in cr_api_functions.sh # -Check the Policy Agent log for any warnings and errors and print the count of each. +## Function: use_cr_http ## + +Use http for getting event from CR. The admin API is not affected. This is the default. | arg list | |--| | None | -## Function: api_equal() ## - -Tests if the array length of a json array in the Policy Agent simulator is equal to a target value. -Without the timeout, the test sets pass or fail immediately depending on if the array length is equal to the target or not. -With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the array length becomes equal to the target value or not. -See the 'cr' dir for more details. +## Function: use_cr_https ## +Use https for getting event from CR. The admin API is not affected. +Note: Not yet used as callback event is not fully implemented/deciced. | arg list | |--| -| ` [ ]` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Relative url. Example 'json:policy_types' - checks the json array length of the url /policy_types | -| `` | Target value for the length | -| `` | Max time to wait for the length to reach the target value | +## Function: start_cr ## -## Function: api_get_policies() ## +Start the Callback Receiver container in docker or kube depending on start mode. +| arg list | +|--| +| None | -Test of GET '/policies' or V2 GET '/v2/policy-instances' and optional check of the array of returned policies. -To test the response code only, provide the response code parameter as well as the following three parameters. -To also test the response payload add the 'NOID' for an expected empty array or repeat the last five/seven parameters for each expected policy. +## Function: cr_equal ## +Tests if a variable value in the Callback Receiver (CR) simulator is equal to a target value. +Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. +See the 'cr' dir for more details. | arg list | |--| -| ` \|NORIC \|NOSERVICE \|NOTYPE [ NOID \| [ EMPTY\| ]*]` | +| ` [ ]` | -| arg list V2 | +| parameter | description | +| --------- | ----------- | +| `` | Variable index to CR | +| `` | Variable name in the CR | +| `` | Target value for the variable | +| `` | Max time to wait for the variable to reach the target value | + +## Function: cr_greater_or_equal ## +Tests if a variable value in the Callback Receiver (CR) simulator is equal to or greater than a target value. +Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to or greater than the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. +See the 'cr' dir for more details. +| arg list | |--| -| ` \|NORIC \|NOSERVICE \|NOTYPE [ NOID \| [ EMPTY\| ]*]` | +| ` [ ]` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the ric | -| `NORIC` | Indicator that no ric is provided | -| `` | Id of the service | -| `NOSERVICE` | Indicator that no service id is provided | -| `` | Id of the policy type | -| `NOTYPE` | Indicator that no type id is provided | -| `NOID` | Indicator that no policy id is provided - indicate empty list of policies| -| `` | Id of the policy | -| `EMPTY` | Indicate for the special empty policy type | -| `transient` | Transient, true or false | -| `notification-url` | Url for notifications | -| `` | Path to the template file for the policy (same template used when creating the policy) | +| `` | Variable index to CR | +| `` | Variable name in the CR | +| `` | Target value for the variable | +| `` | Max time to wait for the variable to reach the target value | -## Function: api_get_policy() ## +## Function: cr_contains_str ## -Test of GET '/policy' or V2 GET '/v2/policies/{policy_id}' and optional check of the returned json payload. -To test the the response code only, provide the expected response code and policy id. -To test the contents of the returned json payload, add a path to the template file used when creating the policy. +Tests if a variable value in the CR contains a target string. +Without the timeout, the test sets pass or fail immediately depending on if the variable contains the target string or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value contains the target string or not. +See the 'a1-interface' repo for more details. | arg list | |--| -| ` []` | +| ` [ ]` | -| arg list V2| -|--| -| ` [ \|NOTYPE \|NOURL ]` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the policy | -| `` | Path to the template file for the policy (same template used when creating the policy) | -| `` | Id of the service | -| `` | Id of the ric | -| `` | Id of the policy type | -| `NOTYPE` | Indicator that no type id is provided | -| `transient` | Transient, true or false | -| `notification-url` | Url for notifications | - -## Function: api_put_policy() ## +| `` | Variable index to CR | +| `` | Variable name in the CR | +| `` | Target substring for the variable | +| `` | Max time to wait for the variable to reach the target value | -Test of PUT '/policy' or V2 PUT '/policies'. -If more than one policy shall be created, add a count value to indicate the number of policies to create. Note that if more than one policy shall be created the provided policy-id must be numerical (will be used as the starting id). +## Function: cr_read ## +Reads the value of a variable in the CR simulator. The value is intended to be passed to a env variable in the test script. +See the 'mrstub' dir for more details. | arg list | |--| -| ` []` | - -| arg list V2 | -|--| -| ` \|NOTYPE \|NOTRANSIENT \|NOURL []` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the service | -| `` | Id of the ric | -| `` | Id of the policy type | -| `` | Id of the policy. This value shall be a numeric value if more than one policy shall be created | -| `transient>` | Transient 'true' or 'false'. 'NOTRANSIENT' can be used to indicate using the default value (no transient value provided) | -| `notification-url` | Url for notifications | -|`NOURL`| Indicator for no url | -| `` | Path to the template file for the policy | -| `` | An optional count (default is 1). If a value greater than 1 is given, the policy ids will use the given policy id as the first id and add 1 to that id for each new policy | - -## Function: api_put_policy_batch() ## - -This tests the same as function 'api_put_policy' except that all put requests are sent to dmaap in one go and then the responses are polled one by one. -If the agent api is not configured to use dmaap (see 'use_agent_dmaap', 'use_agent_rest_http' and 'use_agent_rest_https'), an error message is printed. -For arg list and parameters, see 'api_put_policy'. +| `` | Variable index to CR | +| `` | Variable name in the CR | -## Function: api_put_policy_parallel() ## +## Function: cr_delay_callback ## -This tests the same as function 'api_put_policy' except that the policy create is spread out over a number of processes and it only uses the agent rest API. The total number of policies created is determined by the product of the parameters 'number-of-rics' and 'count'. The parameter 'number-of-threads' shall be selected to be not evenly divisible by the product of the parameters 'number-of-rics' and 'count' - this is to ensure that one process does not handle the creation of all the policies in one ric. +Function to configure write delay on callbacks. Delay given in seconds. Setting remains until removed. | arg list | |--| -| ` ` +| ` []`| + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Variable index to CR | +| `` | Delay in seconds. If omitted, the delay is removed | + +## Function: cr_api_check_all_sync_events ## + +Check the contents of all ric events received for a callback id. | arg list | |--| -| ` \|NOURL ` +| ` [ EMPTY \| ( )+ ]` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the service | -| `` | The base id of the rics, ie ric id without the sequence number. The sequence number is added during processing | -| `` | The number of rics, assuming the first index is '1'. The index is added to the 'ric-id-base' id | -| `` | Id of the policy type | -| `` | Id of the policy. This value shall be a numeric value and will be the id of the first policy | -| `transient>` | Transient 'true' or 'false'. 'NOTRANSIENT' can be used to indicate using the default value (no transient value provide) | -| `notification-url` | Url for notifications | -| `` | Path to the template file for the policy | -| `` | Number of policies per ric | -| `` | Number of threads (processes) to run in parallel | +| `` | Variable index for CR | +| `` | Id of the callback destination | +| `EMPTY` | Indicator for an empty list | +| `` | Id of the ric | -## Function: api_delete_policy() ## +## Function: cr_api_check_all_ics_events ## -This tests the DELETE '/policy' or V2 DELETE '/v2/policies/{policy_id}'. Removes the indicated policy or a 'count' number of policies starting with 'policy-id' as the first id. +Check the contents of all current status events for one id from ICS | arg list | |--| -| ` []` +| ` [ EMPTY \| ( )+ ]` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the policy | -| `` | An optional count of policies to delete. The 'policy-id' will be the first id to be deleted. | - -## Function: api_delete_policy_batch() ## - -This tests the same as function 'api_delete_policy' except that all delete requests are sent to dmaap in one go and then the responses are polled one by one. -If the agent api is not configured to used dmaap (see 'use_agent_dmaap', 'use_agent_rest_http' and 'use_agent_rest_https'), an error message is printed. -For arg list and parameters, see 'api_delete_policy'. +| `` | Variable index for CR | +| `` | Id of the callback destination | +| `EMPTY` | Indicator for an empty list | +| `` | Status string | -## Function: api_delete_policy_parallel() ## +## Function: cr_api_check_all_ics_subscription_events ## -This tests the same as function 'api_delete_policy' except that the policy delete is spread out over a number of processes and it only uses the agent rest API. The total number of policies deleted is determined by the product of the parameters 'number-of-rics' and 'count'. The parameter 'number-of-threads' shall be selected to be not evenly divisible by the product of the parameters 'number-of-rics' and 'count' - this is to ensure that one process does not handle the deletion of all the policies in one ric. +Check the contents of all current subscription events for one id from ICS | arg list | |--| -| ` ` +| ` [ EMPTY | ( )+ ]` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | The base id of the rics, ie ric id without the sequence number. The sequence number is added during processing | -| `` | The number of rics, assuming the first index is '1' | -| `` | Id of the policy. This value shall be a numeric value and will be the id of the first policy | -| `` | Number of policies per ric | -| `` | Number of threads (processes) to run in parallel | +| `` | Variable index for CR | +| `` | Id of the callback destination | +| `EMPTY` | Indicator for an empty list | +| `` | Id of the data type | +| `` | Path to typeschema file | +| `` | Status string | -## Function: api_get_policy_ids() ## +## Function: cr_api_reset ## -Test of GET '/policy_ids' or V2 GET '/v2/policies'. -To test response code only, provide the response code parameter as well as the following three parameters. -To also test the response payload add the 'NOID' for an expected empty array or repeat the 'policy-instance-id' for each expected policy id. +Reset the callback receiver | arg list | |--| -| ` \|NORIC \|NOSERVICE \|NOTYPE ([` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the ric | -| `NORIC` | Indicator that no ric is provided | -| `` | Id of the service | -| `NOSERVICE` | Indicator that no service id is provided | -| `type-id>` | Id of the policy type | -| `NOTYPE` | Indicator that no type id is provided | -| `NOID` | Indicator that no policy id is provided - indicate empty list of policies| -| `` | Id of the policy | +| `` | Variable index for CR | -## Function: api_get_policy_schema() ## +## Function: cr_api_check_all_genric_json_events ## -Test of V2 GET '/v2/policy-types/{policyTypeId}' and optional check of the returned json schema. -To test the response code only, provide the expected response code and policy type id. -To test the contents of the returned json schema, add a path to a schema file to compare with. +Check the contents of all json events for path | arg list | |--| -| ` []` | +| ` (EMPTY | + )` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the policy type | -| `` | Path to the schema file for the policy type | +| `` | Variable index for CR | +| `` | Topic url | +| `EMPTY` | Indicator for an empty list | +| `json-msg` | Json msg string to compare with | -## Function: api_get_policy_schema() ## +## Function: cr_api_check_single_genric_json_event ## -Test of GET '/policy_schema' and optional check of the returned json schema. -To test the response code only, provide the expected response code and policy type id. -To test the contents of the returned json schema, add a path to a schema file to compare with. +Check a single (oldest) json event (or none if empty) for path | arg list | |--| -| ` []` | +| ` (EMPTY | )` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the policy type | -| `` | Path to the schema file for the policy type | +| `` | Variable index for CR | +| `` | Topic url | +| `EMPTY` | Indicator for no msg | +| `json-msg` | Json msg string to compare with | -## Function: api_get_policy_schemas() ## +## Function: cr_api_check_single_genric_event_md5 ## -Test of GET '/policy_schemas' and optional check of the returned json schemas. -To test the response code only, provide the expected response code and ric id (or NORIC if no ric is given). -To test the contents of the returned json schema, add a path to a schema file to compare with (or NOFILE to represent an empty '{}' type) +Check a single (oldest) json in md5 format (or none if empty) for path. +Note that if a json message is given, it shall be compact, no ws except inside string. +The MD5 will generate different hash if whitespace is present or not in otherwise equivalent json. | arg list | |--| -| ` \|NORIC [\|NOFILE]*` | +| ` (EMPTY | )` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the ric | -| `NORIC` | No ric id given | -| `` | Path to the schema file for the policy type | -| `NOFILE` | Indicate the template for an empty type | +| `` | Variable index for CR | +| `` | Topic url | +| `EMPTY` | Indicator for no msg | +| `data-msg` | msg string to compare with | -## Function: api_get_policy_status() ## +## Function: cr_api_check_single_genric_event_md5_file ## -Test of GET '/policy_status' or V2 GET '/policies/{policy_id}/status'. +Check a single (oldest) event in md5 format (or none if empty) for path. +Note that if a file with json message is given, the json shall be compact, no ws except inside string and not newlines. +The MD5 will generate different hash if ws/newlines is present or not in otherwise equivalent json | arg list | |--| -| ` (STD\|STD2 \|EMPTY [\|EMPTY])\|(OSC )` | +| ` (EMPTY | )` | | parameter | description | | --------- | ----------- | | `` | Expected http response code | -| `` | Id of the policy | -| `STD` | Indicator of status of Standarized A1 | -| `STD2` | Indicator of status of Standarized A1 version 2 | -| `` | Enforcement status | -| `` | Optional reason | -| `EMPTY` | Indicator of empty string status or reason | -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `` | Instance status | -| `` | Deleted status, true or false | +| `` | Variable index for CR | +| `` | Topic url | +| `EMPTY` | Indicator for no msg | +| `data-file` | path to file to compare with | -## Function: api_get_policy_types() ## +# Description of functions in dmaapadp_api_functions.sh # -Test of GET '/policy_types' or V2 GET '/v2/policy-types' and optional check of the returned ids. -To test the response code only, provide the expected response code and ric id (or NORIC if no ric is given). -To test the contents of the returned json payload, add the list of expected policy type id (or 'EMPTY' for the '{}' type) +## Function: use_dmaapadp_http ## + +Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. | arg list | |--| -| ` [\|NORIC [\|EMPTY []*]]` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the ric | -| `NORIC` | No ric id given | -| `` | Id of the policy type | -| `EMPTY` | Indicate the empty type | +## Function: use_dmaapadp_https ## -## Function: api_get_status() ## +Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. -Test of GET /status or V2 GET /status +| arg list | +|--| +| None | + +## Function: start_dmaapadp ## + +Start the dmaap adator service container in docker or kube depending on running mode. | arg list | |--| -| `` | +| (kube) `PROXY\|NOPROXY [ ]` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | - -## Function: api_get_ric() ## +| `PROXY` | Configure with http proxy, if proxy is started | +| `NOPROXY` | Configure without http proxy | +| ``| Path to application.yaml | +| `` | Optional path to application_configuration.json | -Test of GET '/ric' or V2 GET '/v2/rics/ric' -To test the response code only, provide the expected response code and managed element id. -To test the returned ric id, provide the expected ric id. +## Function: set_dmaapadp_trace ## +Configure the dmaap adaptor service log on trace level. The app must be running. | arg list | |--| -| ` []` | +| None | -| arg list V2 | +# Description of functions in dmaapmed_api_functions.sh # + +## Function: use_dmaapmed_http ## + +Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. + +| arg list | |--| -| ` \|NOME \| []` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the managed element | -| `NOME` | Indicator for no ME | -| `ric-id` | Id of the ric | -| `NORIC` | Indicator no RIC | -| `string-of-ricinfo` | String of ric info | +## Function: use_dmaapmed_https ## -## Function: api_get_rics() ## +Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. -Test of GET '/rics' or V2 GET '/v2/rics' and optional check of the returned json payload (ricinfo). -To test the response code only, provide the expected response code and policy type id (or NOTYPE if no type is given). -To test also the returned payload, add the formatted string of info in the returned payload. -Format of ricinfo:
`::`
-Example
` = "ricsim_g1_1:me1_ricsim_g1_1,me2_ricsim_g1_1:1,2,4 ricsim_g1_1:me2_........."` +| arg list | +|--| +| None | + +## Function: start_dmaapmed ## + +Start the dmaap mediator service container in docker or kube depending on running mode. | arg list | |--| -| ` \|NOTYPE []` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Policy type id of the ric | -| `NOTYPE>` | No type given | -| `` | A space separated string of ric info - needs to be quoted | +# Description of functions in httpproxy_api_functions.sh # -## Function: api_put_service() ## +## Function: use_http_proxy_http ## -Test of PUT '/service' or V2 PUT '/service'. +Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. | arg list | |--| -| ` ` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Service name | -| `` | Timeout value | -| `` | Callback url | +## Function: use_http_proxy_https ## -## Function: api_get_services() ## +Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. +| arg list | +|--| +| None | -Test of GET '/service' or V2 GET '/v2/services' and optional check of the returned json payload. -To test only the response code, omit all parameters except the expected response code. -To test the returned json, provide the parameters after the response code. +## Function: start_http_proxy ## +Start the http proxy container in docker or kube depending on running mode. | arg list | |--| -| ` [ ( ) \| (NOSERVICE [ ]* )]` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Service name for the query | -| `` | Target service name| -| `` | Timeout value | -| `` | Callback url | -| `NOSERVICE` | Indicator of no target service name | +# Description of functions in helmmanager_api_functions.sh # -## Function: api_get_service_ids() ## +## Function: use_helm_manager_http ## -Test of GET '/services' or V2 GET /'v2/services'. Only check of service ids. +Use http for all API calls to the Helm Manager. This is the default protocol. +| arg list | +|--| +| None | +## Function: use_helm_manager_https ## + +Use https for all API calls to the Helm Manager. | arg list | |--| -| ` []*` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Service name | +## Function: start_helm_manager ## -## Function: api_delete_services() ## +Start the Helm Manager container in docker or kube depending on running mode. +| arg list | +|--| +| None | -Test of DELETE '/services' or V2 DELETE '/v2/services/{serviceId}' +## Function: helm_manager_api_get_charts ## +Get all charts and compare the expected contents. | arg list | |--| -| ` []*` | +| ` [ EMPTY | ( )+ ]` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Service name | +| `` | Expected response code | +| `EMPTY` | Indicator for empty list | +| ``| Name of the chart | +| ``| Version of the chart | +| ``| Namespace to of the chart | +| ``| Release name of the chart | +| ``| Repository of the chart | -## Function: api_put_services_keepalive() ## - -Test of PUT '/services/keepalive' or V2 PUT '/v2/services/{service_id}/keepalive' +## Function: helm_manager_api_post_repo ## +Add repo to the helm manager. | arg list | |--| -| ` ` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Service name | - -## Function: api_put_configuration() ## +| `` | Expected response code | +| `` | Name of the repo | +| ``| Protocol http or https | +| ``| Host name of the repo | +| ``| Host port of the repo | -Test of PUT '/v2/configuration' +## Function: helm_manager_api_post_onboard_chart ## +Onboard a chart to the helm manager. | arg list | |--| -| ` ` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Path json config file | +| `` | Expected response code | +| ``| Target repo of the chart | +| ``| Name of the chart | +| ``| Version of the chart | +| ``| Namespace to of the chart | +| ``| Release name of the chart | -## Function: api_get_configuration() ## - -Test of GET '/v2/configuration' +## Function: helm_manager_api_post_install_chart ## +Install an onboarded chart. | arg list | |--| -| ` []` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `` | Path json config file to compare the retrieved config with | +| `` | Expected response code | +| ``| Name of the chart | +| ``| Version of the chart | -# Description of functions in consul_cbs_function.sh # +## Function: helm_manager_api_uninstall_chart ## -## Function: consul_config_app ## +Uninstall a chart. +| arg list | +|--| +| ` ` | -Function to load a json config from a file into consul for the Policy Agent +| parameter | description | +| --------- | ----------- | +| `` | Expected response code | +| ``| Name of the chart | +| ``| Version of the chart | + +## Function: helm_manager_api_delete_chart ## +Delete a chart. | arg list | |--| -| `` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | The path to the json file to be loaded to Consul/CBS | +| `` | Expected response code | +| ``| Name of the chart | +| ``| Version of the chart | -## Function: prepare_consul_config ## +## Function: helm_manager_api_exec_add_repo ## -Function to prepare a Consul config based on the previously configured (and started simulators). Note that all simulator must be running and the test script has to configure if http or https shall be used for the components (this is done by the functions 'use_simulator_http', 'use_simulator_https', 'use_sdnc_http', 'use_sdnc_https', 'use_mr_http', 'use_mr_https') +Add repo in helm manager by helm using exec. | arg list | |--| -| `` | +| ` ` | | parameter | description | | --------- | ----------- | -| `SDNC\|NOSDNC` | Configure based on a1-controller (SNDC) or without a controller/adapter (NOSDNC) | -| `` | The path to the json output file containing the prepared config. This file is used in 'consul_config_app' | +| `` | Expected response code | +| ``| Name of the repo | +| ``| Full url to the repo. Url must be accessible by the container | -## Function: start_consul_cbs ## -Start the Consul and CBS containers +# Description of functions in ics_api_functions.sh # + +## Function: use_ics_rest_http ## + +Use http for all API calls to the ICS. This is the default protocol. | arg list | |--| | None | -# Description of functions in control_panel_api_function.sh # - -## Function: use_control_panel_http ## +## Function: use_ics_rest_https ## -Set http as the protocol to use for all communication to the Control Panel +Use https for all API calls to the ICS. | arg list | |--| | None | -## Function: use_control_panel_https ## +## Function: use_ics_dmaap_http ## -Set https as the protocol to use for all communication to the Control Panel +Send and recieve all API calls to the ICS over Dmaap via the MR using http. | arg list | |--| | None | -## Function: start_control_panel ## +## Function: use_ics_dmaap_https ## -Start the Control Panel container +Send and recieve all API calls to the ICS over Dmaap via the MR using https. | arg list | |--| | None | -# Description of functions in controller_api_functions.sh # +## Function: start_ics ## + +Start the ICS container in docker or kube depending on running mode. +| arg list | +|--| +| `PROXY|NOPROXY ` | -The file contains a selection of the possible API tests towards the a1-controller +| parameter | description | +| --------- | ----------- | +| `PROXY` | Configure with http proxy, if proxy is started | +| `NOPROXY` | Configure without http proxy | +| ``| Path to application.yaml | -## Function: use_sdnc_http ## +## Function: stop_ics ## -Use http for all API calls towards the SDNC A1 Controller. This is the default. Note that this function shall be called before preparing the config for Consul. +Stop the ICS container. | arg list | |--| | None | -## Function: use_sdnc_https ## +## Function: start_stopped_ics ## -Use https for all API calls towards the SDNC A1 Controller. Note that this function shall be called before preparing the config for Consul. +Start a previously stopped ics. | arg list | |--| | None | -## Function: start_sdnc ## +## Function: set_ics_debug ## -Start the SDNC A1 Controller container and its database container +Configure the ICS log on debug level. The ICS must be running. | arg list | |--| | None | -## Function: check_sdnc_logs ## +## Function: set_ics_trace ## -Check the SDNC log for any warnings and errors and print the count of each. +Configure the ICS log on trace level. The ICS must be running. | arg list | |--| | None | -## Function: controller_api_get_A1_policy_ids ## - -Test of GET policy ids towards OSC or STD type simulator. -To test response code only, provide the response code, 'OSC' + policy type or 'STD' -To test the response payload, include the ids of the expexted response. +## Function: use_ics_retries ## +Perform curl retries when making direct call to ICS for the specified http response codes +Speace separated list of http response codes | arg list | |--| -| ` (OSC [ []* ]) \| ( STD [ []* ]` | +| `[]*` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `` | Id of the ric | -| `policy-type-id>` | Id of the policy type | -| `` | Id of the policy | -| `STD` | Indicator of status of Standarized A1 | - -## Function: controller_api_get_A1_policy_type ## - -Test of GET a policy type (OSC only) - -| arg list | -|--| -| ` OSC []` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `` | Id of the ric | -| `policy-type-id>` | Id of the policy type | -| `policy-type-file>` | Optional schema file to compare the returned type with | - -## Function: controller_api_delete_A1_policy ## - -Deletes a policy instance - -| arg list | -|--| -| `(STD ) \| (OSC )` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `STD` | Indicator of status of Standarized A1 | -| `` | Id of the ric | -| `` | Id of the policy | -| `policy-type-id>` | Id of the policy type | -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `policy-type-file>` | Optional schema file to compare the returned type with | - -## Function: controller_api_put_A1_policy ## - -Creates a policy instance - -| arg list | -|--| -| ` (STD ) \| (OSC )` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `STD` | Indicator of status of Standarized A1 | -| `` | Id of the ric | -| `` | Id of the policy | -| `` | Path to the template file of the policy| -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `` | Id of the policy type | - -## Function: controller_api_get_A1_policy_status ## - -Checks the status of a policy - - arg list | -|--| -| ` (STD []) \| (OSC )` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `STD` | Indicator of status of Standarized A1 | -| `` | Id of the ric | -| `` | Id of the policy | -| `` | Enforcement status | -| `` | Optional reason | -| `OSC` | Indicator of status of Non-Standarized OSC A1 | -| `` | Id of the policy type | -| `` | Instance status | -| `` | Deleted status, true or false | - -# Description of functions in cr_api_functions.sh # - -## Function: use_cr_http ## - -Use http for getting event from CR. The admin API is not affected. This is the default. -| arg list | -|--| -| None | - -## Function: use_cr_https ## - -Use https for getting event from CR. The admin API is not affected. -Note: Not yet used as callback event is not fully implemented/deciced. -| arg list | -|--| -| None | - -## Function: start_cr ## - -Start the Callback Receiver container in docker or kube depending on start mode. -| arg list | -|--| -| None | - -## Function: cr_equal ## - -Tests if a variable value in the Callback Receiver (CR) simulator is equal to a target value. -Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to the target or not. -With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. -See the 'cr' dir for more details. -| arg list | -|--| -| ` [ ]` | - -| parameter | description | -| --------- | ----------- | -| `` | Variable name in the CR | -| `` | Target value for the variable | -| `` | Max time to wait for the variable to reach the target value | - -## Function: cr_api_check_all_sync_events() ## - -Check the contents of all ric events received for a callback id. - -| arg list | -|--| -| ` [ EMPTY \| ( )+ ]` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the callback destination | -| `EMPTY` | Indicator for an empty list | -| `` | Id of the ric | - -## Function: cr_api_check_all_ics_events() ## - -Check the contents of all current status events for one id from ICS - -| arg list | -|--| -| ` [ EMPTY \| ( )+ ]` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the callback destination | -| `EMPTY` | Indicator for an empty list | -| `` | Status string | - -## Function: cr_api_check_all_ics_subscription_events() ## - -Check the contents of all current subscription events for one id from ICS - -| arg list | -|--| -| ` [ EMPTY | ( )+ ]` | - -| parameter | description | -| --------- | ----------- | -| `` | Expected http response code | -| `` | Id of the callback destination | -| `EMPTY` | Indicator for an empty list | -| `` | Id of the data type | -| `` | Path to typeschema file | -| `` | Status string | - - -## Function: cr_api_reset() ## - -Reset the callback receiver - -| arg list | -|--| -| - | - - -# Description of functions in ics_api_functions.sh # - -## Function: use_ics_rest_http ## - -Use http for all API calls to the ICS. This is the default protocol. -| arg list | -|--| -| None | - -## Function: use_ics_rest_https ## - -Use https for all API calls to the ICS. -| arg list | -|--| -| None | - -## Function: use_ics_dmaap_http ## - -Send and recieve all API calls to the ICS over Dmaap via the MR using http. -| arg list | -|--| -| None | - -## Function: use_ics_dmaap_https ## - -Send and recieve all API calls to the ICS over Dmaap via the MR using https. -| arg list | -|--| -| None | - -## Function: start_ics ## - -Start the ICS container in docker or kube depending on running mode. -| arg list | -|--| -| None | - -## Function: stop_ics ## - -Stop the ICS container. -| arg list | -|--| -| None | - -## Function: start_stopped_ics ## - -Start a previously stopped ics. -| arg list | -|--| -| None | - -## Function: set_ics_debug ## - -Configure the ICS log on debug level. The ICS must be running. -| arg list | -|--| -| None | - -## Function: set_ics_trace ## - -Configure the ICS log on trace level. The ICS must be running. -| arg list | -|--| -| None | +| `` | Http response code to make retry for | ## Function: check_ics_logs ## @@ -1161,9 +926,9 @@ See the 'a1-interface' repo for more details. | `` | Target value for the variable | | `` | Max time to wait for the variable to reach the target value | -## Function: ics_api_a1_get_job_ids() ## +## Function: ics_api_a1_get_job_ids ## -Test of GET '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs' and optional check of the array of returned job ids. +Test of GET '/A1-EI/v1/eitypes/{eiTypeId}/eijobs' and optional check of the array of returned job ids. To test the response code only, provide the response code parameter as well as a type id and an owner id. To also test the response payload add the 'EMPTY' for an expected empty array or repeat the last parameter for each expected job id. @@ -1180,9 +945,9 @@ To also test the response payload add the 'EMPTY' for an expected empty array or | `` | Id of the expected job | | `EMPTY` | The expected list of job id shall be empty | -## Function: ics_api_a1_get_type() ## +## Function: ics_api_a1_get_type ## -Test of GET '/A1-EI​/v1​/eitypes​/{eiTypeId}' and optional check of the returned schema. +Test of GET '/A1-EI/v1/eitypes/{eiTypeId}' and optional check of the returned schema. To test the response code only, provide the response code parameter as well as the type-id. To also test the response payload add a path to the expected schema file. @@ -1196,9 +961,9 @@ To also test the response payload add a path to the expected schema file. | `` | Id of the EI type | | `` | Path to a schema file to compare with the returned schema | -## Function: ics_api_a1_get_type_ids() ## +## Function: ics_api_a1_get_type_ids ## -Test of GET '/A1-EI​/v1​/eitypes' and optional check of returned list of type ids. +Test of GET '/A1-EI/v1/eitypes' and optional check of returned list of type ids. To test the response code only, provide the response only. To also test the response payload add the list of expected type ids (or EMPTY if the list is expected to be empty). @@ -1212,9 +977,9 @@ To also test the response payload add the list of expected type ids (or EMPTY if | `EMPTY` | The expected list of type ids shall be empty | | `` | Id of the EI type | -## Function: ics_api_a1_get_job_status() ## +## Function: ics_api_a1_get_job_status ## -Test of GET '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs​/{eiJobId}​/status' and optional check of the returned status. +Test of GET '/A1-EI/v1/eitypes/{eiTypeId}/eijobs/{eiJobId}/status' and optional check of the returned status. To test the response code only, provide the response code, type id and job id. To also test the response payload add the expected status. @@ -1229,9 +994,9 @@ To also test the response payload add the expected status. | `` | Id of the job | | `` | Expected status | -## Function: ics_api_a1_get_job() ## +## Function: ics_api_a1_get_job ## -Test of GET '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs​/{eiJobId}' and optional check of the returned job. +Test of GET '/A1-EI/v1/eitypes/{eiTypeId}/eijobs/{eiJobId}' and optional check of the returned job. To test the response code only, provide the response code, type id and job id. To also test the response payload add the remaining parameters. @@ -1248,9 +1013,9 @@ To also test the response payload add the remaining parameters. | `` | Expected owner for the job | | `` | Path to a job template for job parameters of the job | -## Function: ics_api_a1_delete_job() ## +## Function: ics_api_a1_delete_job ## -Test of DELETE '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs​/{eiJobId}'. +Test of DELETE '/A1-EI/v1/eitypes/{eiTypeId}/eijobs/{eiJobId}'. To test, provide all the specified parameters. | arg list | @@ -1263,9 +1028,9 @@ To test, provide all the specified parameters. | `` | Id of the EI type | | `` | Id of the job | -## Function: ics_api_a1_put_job() ## +## Function: ics_api_a1_put_job ## -Test of PUT '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs​/{eiJobId}'. +Test of PUT '/A1-EI/v1/eitypes/{eiTypeId}/eijobs/{eiJobId}'. To test, provide all the specified parameters. | arg list | @@ -1281,7 +1046,7 @@ To test, provide all the specified parameters. | `` | Owner of the job | | `` | Path to a job template for job parameters of the job | -## Function: ics_api_edp_get_type_ids() ## +## Function: ics_api_edp_get_type_ids ## Test of GET '/ei-producer/v1/eitypes' or '/data-producer/v1/info-types' depending on ics version and an optional check of the returned list of type ids. To test the response code only, provide the response code. @@ -1297,7 +1062,7 @@ To also test the response payload add list of expected type ids (or EMPTY if the | `` | Id of the type | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_get_producer_status() ## +## Function: ics_api_edp_get_producer_status ## Test of GET '/ei-producer/v1/eiproducers/{eiProducerId}/status' or '/data-producer/v1/info-producers/{infoProducerId}/status' depending on ics version and optional check of the returned status. To test the response code only, provide the response code and producer id. @@ -1313,7 +1078,7 @@ To also test the response payload add the expected status. | `` | Id of the producer | | `` | The expected status string | -## Function: ics_api_edp_get_producer_ids() ## +## Function: ics_api_edp_get_producer_ids ## Test of GET '/ei-producer/v1/eiproducers' and optional check of the returned producer ids. To test the response code only, provide the response. @@ -1329,7 +1094,7 @@ To also test the response payload add the list of expected producer-ids (or EMPT | `` | Id of the producer | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_get_producer_ids_2() ## +## Function: ics_api_edp_get_producer_ids_2 ## Test of GET '/ei-producer/v1/eiproducers' or '/data-producer/v1/info-producers' depending on ics version and optional check of the returned producer ids. To test the response code only, provide the response. @@ -1347,7 +1112,7 @@ To also test the response payload add the type (if any) and a list of expected p | `` | Id of the producer | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_get_type() ## +## Function: ics_api_edp_get_type ## Test of GET '/ei-producer/v1/eitypes/{eiTypeId}' and optional check of the returned type. To test the response code only, provide the response and the type-id. @@ -1365,7 +1130,7 @@ To also test the response payload add a path to a job schema file and a list exp | `` | Id of the producer | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_get_type_2() ## +## Function: ics_api_edp_get_type_2 ## Test of GET '/ei-producer/v1/eitypes/{eiTypeId}' or '/data-producer/v1/info-types/{infoTypeId}' depending on ics version and optional check of the returned type. To test the response code only, provide the response and the type-id. @@ -1382,7 +1147,7 @@ To also test the response payload add a path to a job schema file. | `` | Path to a job schema file | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_put_type_2() ## +## Function: ics_api_edp_put_type_2 ## Test of PUT '/ei-producer/v1/eitypes/{eiTypeId}' or '/data-producer/v1/info-types/{infoTypeId}' depending on ics version and optional check of the returned type. @@ -1397,7 +1162,7 @@ Test of PUT '/ei-producer/v1/eitypes/{eiTypeId}' or '/data-producer/v1/info-type | `` | Path to a job schema file | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_edp_delete_type_2() ## +## Function: ics_api_edp_delete_type_2 ## Test of DELETE '/ei-producer/v1/eitypes/{eiTypeId}' or '/data-producer/v1/info-types/{infoTypeId}' depending on ics version and optional check of the returned type. @@ -1410,7 +1175,7 @@ Test of DELETE '/ei-producer/v1/eitypes/{eiTypeId}' or '/data-producer/v1/info-t | `` | Expected http response code | | `` | Id of the type | -## Function: ics_api_edp_get_producer() ## +## Function: ics_api_edp_get_producer ## Test of GET '/ei-producer/v1/eiproducers/{eiProducerId}' and optional check of the returned producer. To test the response code only, provide the response and the producer-id. @@ -1431,7 +1196,7 @@ To also test the response payload add the remaining parameters defining thee pro | `` | Path to a schema file | | `EMPTY` | The expected list of type schema pairs shall be empty | -## Function: ics_api_edp_get_producer_2() ## +## Function: ics_api_edp_get_producer_2 ## Test of GET '/ei-producer/v1/eiproducers/{eiProducerId}' or '/data-producer/v1/info-producers/{infoProducerId}' depending on ics version and optional check of the returned producer. To test the response code only, provide the response and the producer-id. @@ -1450,7 +1215,7 @@ To also test the response payload add the remaining parameters defining thee pro | `` | Id of the type | | `EMPTY` | The expected list of types shall be empty | -## Function: ics_api_edp_delete_producer() ## +## Function: ics_api_edp_delete_producer ## Test of DELETE '/ei-producer/v1/eiproducers/{eiProducerId}' or '/data-producer/v1/info-producers/{infoProducerId}' depending on ics version. To test, provide all parameters. @@ -1464,7 +1229,7 @@ To test, provide all parameters. | `` | Expected http response code | | `` | Id of the producer | -## Function: ics_api_edp_put_producer() ## +## Function: ics_api_edp_put_producer ## Test of PUT '/ei-producer/v1/eiproducers/{eiProducerId}'. To test, provide all parameters. The list of type/schema pair may be empty. @@ -1483,7 +1248,7 @@ To test, provide all parameters. The list of type/schema pair may be empty. | `` | Path to a schema file | | `EMPTY` | The list of type/schema pairs is empty | -## Function: ics_api_edp_put_producer_2() ## +## Function: ics_api_edp_put_producer_2 ## Test of PUT '/ei-producer/v1/eiproducers/{eiProducerId}' or '/data-producer/v1/info-producers/{infoProducerId}' depending on ics version. To test, provide all parameters. The list of type/schema pair may be empty. @@ -1501,7 +1266,7 @@ To test, provide all parameters. The list of type/schema pair may be empty. | `` | Id of the type | | `NOTYPE` | The list of types is empty | -## Function: ics_api_edp_get_producer_jobs() ## +## Function: ics_api_edp_get_producer_jobs ## Test of GET '/ei-producer/v1/eiproducers/{eiProducerId}/eijobs' and optional check of the returned producer job. To test the response code only, provide the response and the producer-id. @@ -1522,7 +1287,7 @@ To also test the response payload add the remaining parameters. | `` | Path to a job template file | | `EMPTY` | The list of job/type/target/job-file tuples is empty | -## Function: ics_api_edp_get_producer_jobs_2() ## +## Function: ics_api_edp_get_producer_jobs_2 ## Test of GET '/ei-producer/v1/eiproducers/{eiProducerId}/eijobs' or '/data-producer/v1/info-producers/{infoProducerId}/info-jobs' depending on ics version and optional check of the returned producer job. To test the response code only, provide the response and the producer-id. @@ -1543,7 +1308,7 @@ To also test the response payload add the remaining parameters. | `` | Path to a job template file | | `EMPTY` | The list of job/type/target/job-file tuples is empty | -## Function: ics_api_service_status() ## +## Function: ics_api_service_status ## Test of GET '/status'. @@ -1555,7 +1320,7 @@ Test of GET '/status'. | --------- | ----------- | | `` | Expected http response code | -## Function: ics_api_idc_get_type_ids() ## +## Function: ics_api_idc_get_type_ids ## Test of GET '/data-consumer/v1/info-types' and an optional check of the returned list of type ids. To test the response code only, provide the response code. @@ -1571,7 +1336,7 @@ To also test the response payload add list of expected type ids (or EMPTY if the | `` | Id of the Info type | | `EMPTY` | The expected list of type ids shall be empty | -## Function: ics_api_idc_get_job_ids() ## +## Function: ics_api_idc_get_job_ids ## Test of GET '/data-consumer/v1/info-jobs' and optional check of the array of returned job ids. To test the response code only, provide the response code parameter as well as a type id and an owner id. @@ -1590,7 +1355,7 @@ To also test the response payload add the 'EMPTY' for an expected empty array or | `` | Id of the expected job | | `EMPTY` | The expected list of job id shall be empty | -## Function: ics_api_idc_get_job() ## +## Function: ics_api_idc_get_job ## Test of GET '/data-consumer/v1/info-jobs/{infoJobId}' and optional check of the returned job. To test the response code only, provide the response code, type id and job id. @@ -1609,9 +1374,9 @@ To also test the response payload add the remaining parameters. | `` | Expected owner for the job | | `` | Path to a job template for job parameters of the job | -## Function: ics_api_idc_put_job() ## +## Function: ics_api_idc_put_job ## -Test of PUT '​/data-consumer/v1/info-jobs/{infoJobId}'. +Test of PUT '/data-consumer/v1/info-jobs/{infoJobId}'. To test, provide all the specified parameters. | arg list | @@ -1628,9 +1393,9 @@ To test, provide all the specified parameters. | `` | Path to a job template for job parameters of the job | | `VALIIDATE` | Indicator to preform type validation at creation | -## Function: ics_api_idc_delete_job() ## +## Function: ics_api_idc_delete_job ## -Test of DELETE '/A1-EI​/v1​/eitypes​/{eiTypeId}​/eijobs​/{eiJobId}'. +Test of DELETE '/A1-EI/v1/eitypes/{eiTypeId}/eijobs/{eiJobId}'. To test, provide all the specified parameters. | arg list | @@ -1643,7 +1408,7 @@ To test, provide all the specified parameters. | `` | Id of the type | | `` | Id of the job | -## Function: ics_api_idc_get_type() ## +## Function: ics_api_idc_get_type ## Test of GET '/data-consumer/v1/info-types/{infoTypeId} and optional check of the returned schema. To test the response code only, provide the response code parameter as well as the type-id. @@ -1659,7 +1424,7 @@ To also test the response payload add a path to the expected schema file. | `` | Id of the Info type | | `` | Path to a schema file to compare with the returned schema | -## Function: ics_api_idc_get_job_status() ## +## Function: ics_api_idc_get_job_status ## Test of GET '/data-consumer/v1/info-jobs/{infoJobId}/status' and optional check of the returned status and timeout. To test the response code only, provide the response code and job id. @@ -1676,7 +1441,7 @@ To also test the response payload add the expected status. | `` | Expected status | | `` | Timeout | -## Function: ics_api_idc_get_job_status2() ## +## Function: ics_api_idc_get_job_status2 ## Test of GET '/data-consumer/v1/info-jobs/{infoJobId}/status' with returned producers and optional check of the returned status and timeout. To test the response code only, provide the response code and job id. @@ -1697,7 +1462,7 @@ To also test the response payload add the expected status. | `` | Timeout | -## Function: ics_api_idc_get_subscription_ids() ## +## Function: ics_api_idc_get_subscription_ids ## Test of GET '/data-consumer/v1/info-type-subscription' with the returned list of subscription ids | arg list | @@ -1712,7 +1477,7 @@ Test of GET '/data-consumer/v1/info-type-subscription' with the returned list of | `` | Indicated for empty list of subscription ids | | `` |Id of the subscription | -## Function: ics_api_idc_get_subscription() ## +## Function: ics_api_idc_get_subscription ## Test of GET '/data-consumer/v1/info-type-subscription/{subscriptionId}' with the subscription information | arg list | @@ -1727,7 +1492,7 @@ Test of GET '/data-consumer/v1/info-type-subscription/{subscriptionId}' with the | `` | Url for status notifications | -## Function: ics_api_idc_put_subscription() ## +## Function: ics_api_idc_put_subscription ## Test of PUT '/data-consumer/v1/info-type-subscription/{subscriptionId}' with the subscription information | arg list | @@ -1741,7 +1506,7 @@ Test of PUT '/data-consumer/v1/info-type-subscription/{subscriptionId}' with the | `` | Id of the owner | | `` | Url for status notifications | -## Function: ics_api_idc_delete_subscription() ## +## Function: ics_api_idc_delete_subscription ## Test of DELETE /data-consumer/v1/info-type-subscription/{subscriptionId} | arg list | @@ -1754,7 +1519,7 @@ Test of DELETE /data-consumer/v1/info-type-subscription/{subscriptionId} | `` |Id of the subscription | -## Function: ics_api_admin_reset() ## +## Function: ics_api_admin_reset ## Test of GET '/status'. @@ -1767,58 +1532,888 @@ Test of GET '/status'. | `` | Expected http response code | | `` | Type id, if the interface supports type in url | -# Description of functions in gateway_api_functions.sh # +## Function: ics_kube_pvc_reset ## -## Function: use_gateway_http ## +Admin reset to remove all data in ics; jobs, producers etc +NOTE - only works in kubernetes and the pod should not be running -Use http for all calls to the gateway. This is set by default. | arg list | |--| | None | -## Function: use_gateway_https ## - -Use https for all calls to the gateway. -| arg list | -|--| -| None | +# Description of functions in kafkapc_api_functions.sh # -## Function: set_gateway_debug ## +## Function: use_kafkapc_http ## -Set debug level logging in the gateway +Use http for all calls to the KAFKAPC. | arg list | |--| | None | -## Function: set_gateway_trace ## +## Function: use_kafkapc_https ## -Set debug level logging in the trace +Use https for all calls to the KAFKAPC. | arg list | |--| | None | -## Function: start_gateway ## +## Function: start_kafkapc ## -Start the the gateway container in docker or kube depending on start mode +Start the KAFKAPC container in docker or kube depending on start mode | arg list | |--| | None | -## Function: gateway_pms_get_status ## +## Function: kafkapc_equal ## -Sample test of pms api (status) +Tests if a variable value in the KAFKAPC is equal to a target value. +Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. +See the 'mrstub' dir for more details. | arg list | |--| -| `` | +| ` [ ]` | | parameter | description | | --------- | ----------- | -| `` | Expected http response code | +| `` | Variable name in the KAFKAPC | +| `` | Target value for the variable | +| `` | Max time to wait for the variable to reach the target value | + +## Function: kafkapc_api_reset ## + +Deep reset of KAFKAPC. Note that kafka itself is not affected, i.e. created topic still exist in kafka. +| arg list | +|--| +| None | + +## Function: kafkapc_api_create_topic ## + +Create a topic in kafka via kafkapc. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | +| `` | Mime type of the data to send to the topic. Data on the topic is expected to be of this type | + +## Function: kafkapc_api_get_topic ## + +Create a from kafkapc. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | +| `` | Mime type of the topic | + +## Function: kafkapc_api_start_sending ## + +Start sending msg from the msg queue to kafka for a topic. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | + +## Function: kafkapc_api_start_receiving ## + +Start receiving msg from a kafka topic to the msg queue in kafkapc. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | + +## Function: kafkapc_api_stop_sending ## + +Stop sending msg from the msg queue to kafka for a topic. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | + +## Function: kafkapc_api_stop_receiving ## + +Stop receiving msg from a kafka topic to the msg queue in kafkapc. +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Name of the topic | + +## Function: kafkapc_api_post_msg ## + +Send a message on a topic. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Topic name | +| `` | Mime type of the msg | +| `` | String msg to send | + +## Function: kafkapc_api_get_msg ## + +Get a message on a topic. +| arg list | +|--| +| ` ([ ] | NOMSG )` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Topic name | +| `` | Mime type of the msg | +| `` | String msg to receive | +| `NOMSG` | Indicated for no msg | + +## Function: kafkapc_api_post_msg_from_file ## + +Send a message in a file on a topic. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Topic name | +| `` | Mime type of the msg | +| `` | Filepath to the string msg to send | + +## Function: kafkapc_api_get_msg_from_file ## + +Get a message on a topic. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Http response code | +| `` | Topic name | +| `` | Mime type of the msg | +| `` | Filepath to the string msg to receive | + +## Function: kafkapc_api_generate_json_payload_file ## + +Create json file with dummy data for payload. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Generated size in kb | +| `` | Path to output file | + +## Function: kafkapc_api_generate_text_payload_file ## + +Create file with dummy text data for payload. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Generated size in kb | +| `` | Path to output file | + +# Description of functions in kubeproxy_api_functions.sh # + +## Function: use_kube_proxy_http ## + +Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. +| arg list | +|--| +| None | + +## Function: use_kube_proxy_https ## + +Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. +| arg list | +|--| +| None | + +## Function: start_kube_proxy ## + +Start the kube proxy container in kube. This proxy enabled the test env to access all services and pods in a kube cluster. +No proxy is started if the function is called in docker mode. +| arg list | +|--| +| None | + +# Description of functions in localhelm_api_functions.sh # + +## Function: localhelm_create_test_chart ## + +Create a dummy chart using helm +| arg list | +|--| +| `chart-name` | + +| parameter | description | +| --------- | ----------- | +| `chart-name` | Name of the chart | + +## Function: localhelm_package_test_chart ## + +Package a dummy chart using helm +| arg list | +|--| +| `chart-name` | + +| parameter | description | +| --------- | ----------- | +| `chart-name` | Name of the chart | + +## Function: localhelm_installed_chart_release ## + +Check if a chart is installed or not using helm +| arg list | +|--| +| `INSTALLED|NOTINSTALLED | + +| parameter | description | +| --------- | ----------- | +| `INSTALLED` | Expecting installed chart | +| `NOTINSTALLED` | Expecting a not installed chart | +| `release-name` | Name of the release | +| `name-space` | Expected namespace | + +# Description of functions in mr_api_functions.sh # + +## Function: use_mr_http ## + +Use http for all Dmaap calls to the MR. This is the default. The admin API is not affected. Note that this function shall be called before preparing the config for Consul. +| arg list | +|--| +| None | + +## Function: use_mr_https ## + +Use https for all Dmaap call to the MR. The admin API is not affected. Note that this function shall be called before preparing the config for Consul. +| arg list | +|--| +| None | + +## Function: start_mr ## + +Start the Message Router stub interface container in docker or kube depending on start mode +| arg list | +|--| +| None | + +## Function: dmaap_api_print_topics ## + +Prints the current list of topics in DMAAP MR + +| arg list | +|--| +| None | + +## Function: mr_equal ## + +Tests if a variable value in the Message Router (MR) simulator is equal to a target value. +Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. +See the 'mrstub' dir for more details. +| arg list | +|--| +| ` [ ]` | + +| parameter | description | +| --------- | ----------- | +| `` | Variable name in the MR | +| `` | Target value for the variable | +| `` | Max time to wait for the variable to reach the target value | + +## Function: mr_greater ## + +Tests if a variable value in the Message Router (MR) simulator is greater than a target value. +Without the timeout, the test sets pass or fail immediately depending on if the variable is greater than the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes greater than the target value or not. +See the 'mrstub' dir for more details. +| arg list | +|--| +| ` [ ]` | + +| parameter | description | +| --------- | ----------- | +| `` | Variable name in the MR | +| `` | Target value for the variable | +| `` | Max time to wait for the variable to become grater than the target value | + +## Function: mr_read ## + +Reads the value of a variable in the Message Router (MR) simulator. The value is intended to be passed to a env variable in the test script. +See the 'mrstub' dir for more details. +| arg list | +|--| +| `` | + +| parameter | description | +| --------- | ----------- | +| `` | Variable name in the MR | + +## Function: mr_print ## + +Prints the value of a variable in the Message Router (MR) simulator. +See the 'mrstub' dir for more details. +| arg list | +|--| +| `` | + +| parameter | description | +| --------- | ----------- | +| `` | Variable name in the MR | + +## Function: mr_api_send_json ## + +Send json to topic in mr-stub. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Topic url | +| `` | Json msg as string | + +## Function: mr_api_send_text ## + +Send text to topic in mr-stub. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Topic url | +| `` | Text (string) msg | + + + +## Function: mr_api_send_json_file ## + +Send json to topic in mr-stub. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Topic url | +| `` | Path to file with json msg as string | + +## Function: mr_api_send_text_file ## + +Send text to topic in mr-stub. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Topic url | +| `` | Path to file with text msg as string | + +## Function: mr_api_generate_json_payload_file ## + +Create json file with dummy data for payload. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Generated size in kb | +| `` | Path to output file | + +## Function: mr_api_generate_text_payload_file ## + +Create file with dummy text data for payload. +| arg list | +|--| +| ` ` | + +| parameter | description | +| --------- | ----------- | +| `` | Generated size in kb | +| `` | Path to output file | + +# Description of functions in ngw_api_functions.sh # + +## Function: use_gateway_http ## + +Use http for all calls to the gateway. This is set by default. +| arg list | +|--| +| None | + +## Function: use_gateway_https ## + +Use https for all calls to the gateway. +| arg list | +|--| +| None | + +## Function: set_gateway_debug ## + +Set debug level logging in the gateway +| arg list | +|--| +| None | + +## Function: set_gateway_trace ## + +Set debug level logging in the trace +| arg list | +|--| +| None | + +## Function: start_gateway ## + +Start the the gateway container in docker or kube depending on start mode +| arg list | +|--| +| None | + +## Function: gateway_pms_get_status ## + +Sample test of pms api (status) +Only response code tested - not payload +| arg list | +|--| +| `` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | ## Function: gateway_ics_get_types ## -Sample test of ics api (get types) -Only response code tested - not payload +Sample test of ics api (get types) +Only response code tested - not payload +| arg list | +|--| +| `` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | + +# Description of functions in pa_api_functions.sh # + +## General ## + +Both PMS version 1 and 2 are supported. The version is controlled by the env variable `$PMS_VERSION` set in the test env file. +For api function in version 2, an url prefix is added if configured. + +## Function: use_agent_rest_http ## + +Use http for all API calls to the Policy Agent. This is the default. +| arg list | +|--| +| None | + +## Function: use_agent_rest_https ## + +Use https for all API calls to the Policy Agent. +| arg list | +|--| +| None | + +## Function: use_agent_dmaap_http ## + +Send and recieve all API calls to the Policy Agent over Dmaap via the MR over http. +| arg list | +|--| +| None | + +## Function: use_agent_dmaap_https ## + +Send and recieve all API callss to the Policy Agent over Dmaap via the MR over https. +| arg list | +|--| +| None | + +## Function: start_policy_agent ## + +Start the Policy Agent container or corresponding kube resources depending on docker/kube mode. +| arg list | +|--| +| `` | +| (docker) `PROXY\|NOPROXY ` | +| (kube) `PROXY\|NOPROXY [ ]` | + +| parameter | description | +| --------- | ----------- | +| `PROXY` | Configure with http proxy, if proxy is started | +| `NOPROXY` | Configure without http proxy | +| ``| Path to application.yaml | +| `` | Optional path to application_configuration.json | + +## Function: stop_policy_agent ## + +Stop the pms container (docker) or scale it to zero (kubernetes). +| arg list | +|--| +| None | + +## Function: start_stopped_policy_agent ## + +Start a previousely stopped pms container (docker) or scale it to 1 (kubernetes). +| arg list | +|--| +| None | + +## Function: prepare_consul_config ## + +Function to prepare a Consul config based on the previously configured (and started simulators). Note that all simulator must be running and the test script has to configure if http or https shall be used for the components (this is done by the functions 'use_simulator_http', 'use_simulator_https', 'use_sdnc_http', 'use_sdnc_https', 'use_mr_http', 'use_mr_https') +| arg list | +|--| +| `SDNC|NOSDNC ` | + +| parameter | description | +| --------- | ----------- | +| `SDNC` | Configure with controller | +| `NOSDNC` | Configure without controller | +| `` | The path to the json output file containing the prepared config. This file is used in 'consul_config_app' | + +## Function: agent_load_config ## + +Load the config into a config map (kubernetes only). +| arg list | +|--| +| `` | + +| parameter | description | +| --------- | ----------- | +| `` | Path to application_configuration.json | + +## Function: set_agent_debug ## + +Configure the Policy Agent log on debug level. The Policy Agent must be running. +| arg list | +|--| +| None | + +## Function: set_agent_trace ## + +Configure the Policy Agent log on trace level. The Policy Agent must be running. +| arg list | +|--| +| None | + +## Function: use_agent_retries ## + +Configure the Policy Agent to make upto 5 retries if an API calls return any of the specified http return codes. +| arg list | +|--| +| `[]*` | + +## Function: check_policy_agent_logs ## + +Check the Policy Agent log for any warnings and errors and print the count of each. +| arg list | +|--| +| None | + +## Function: api_equal ## + +Tests if the array length of a json array in the Policy Agent simulator is equal to a target value. +Without the timeout, the test sets pass or fail immediately depending on if the array length is equal to the target or not. +With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the array length becomes equal to the target value or not. +See the 'cr' dir for more details. + +| arg list | +|--| +| ` [ ]` | + +| parameter | description | +| --------- | ----------- | +| `` | Relative url. Example 'json:policy_types' - checks the json array length of the url /policy_types | +| `` | Target value for the length | +| `` | Max time to wait for the length to reach the target value | + +## Function: api_get_policies ## + +Test of GET '/policies' or V2 GET '/v2/policy-instances' and optional check of the array of returned policies. +To test the response code only, provide the response code parameter as well as the following three parameters. +To also test the response payload add the 'NOID' for an expected empty array or repeat the last five/seven parameters for each expected policy. + +| arg list | +|--| +| ` \|NORIC \|NOSERVICE \|NOTYPE [ NOID \| [ EMPTY\| ]*]` | + +| arg list V2 | +|--| +| ` \|NORIC \|NOSERVICE \|NOTYPE [ NOID \| [ EMPTY\| ]*]` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the ric | +| `NORIC` | Indicator that no ric is provided | +| `` | Id of the service | +| `NOSERVICE` | Indicator that no service id is provided | +| `` | Id of the policy type | +| `NOTYPE` | Indicator that no type id is provided | +| `NOID` | Indicator that no policy id is provided - indicate empty list of policies| +| `` | Id of the policy | +| `EMPTY` | Indicate for the special empty policy type | +| `transient` | Transient, true or false | +| `notification-url` | Url for notifications | +| `` | Path to the template file for the policy (same template used when creating the policy) | + +## Function: api_get_policy ## + +Test of GET '/policy' or V2 GET '/v2/policies/{policy_id}' and optional check of the returned json payload. +To test the the response code only, provide the expected response code and policy id. +To test the contents of the returned json payload, add a path to the template file used when creating the policy. + +| arg list | +|--| +| ` []` | + +| arg list V2| +|--| +| ` [ \|NOTYPE \|NOURL ]` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the policy | +| `` | Path to the template file for the policy (same template used when creating the policy) | +| `` | Id of the service | +| `` | Id of the ric | +| `` | Id of the policy type | +| `NOTYPE` | Indicator that no type id is provided | +| `transient` | Transient, true or false | +| `notification-url` | Url for notifications | + +## Function: api_put_policy ## + +Test of PUT '/policy' or V2 PUT '/policies'. +If more than one policy shall be created, add a count value to indicate the number of policies to create. Note that if more than one policy shall be created the provided policy-id must be numerical (will be used as the starting id). + +| arg list | +|--| +| ` []` | + +| arg list V2 | +|--| +| ` \|NOTYPE \|NOTRANSIENT \|NOURL []` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the service | +| `` | Id of the ric | +| `` | Id of the policy type | +| `` | Id of the policy. This value shall be a numeric value if more than one policy shall be created | +| `transient>` | Transient 'true' or 'false'. 'NOTRANSIENT' can be used to indicate using the default value (no transient value provided) | +| `notification-url` | Url for notifications | +|`NOURL`| Indicator for no url | +| `` | Path to the template file for the policy | +| `` | An optional count (default is 1). If a value greater than 1 is given, the policy ids will use the given policy id as the first id and add 1 to that id for each new policy | + +## Function: api_put_policy_batch ## + +This tests the same as function 'api_put_policy' except that all put requests are sent to dmaap in one go and then the responses are polled one by one. +If the agent api is not configured to use dmaap (see 'use_agent_dmaap', 'use_agent_rest_http' and 'use_agent_rest_https'), an error message is printed. +For arg list and parameters, see 'api_put_policy'. + +## Function: api_put_policy_parallel ## + +This tests the same as function 'api_put_policy' except that the policy create is spread out over a number of processes and it only uses the agent rest API. The total number of policies created is determined by the product of the parameters 'number-of-rics' and 'count'. The parameter 'number-of-threads' shall be selected to be not evenly divisible by the product of the parameters 'number-of-rics' and 'count' - this is to ensure that one process does not handle the creation of all the policies in one ric. + +| arg list | +|--| +| ` ` + +| arg list | +|--| +| ` \|NOURL ` + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the service | +| `` | The base id of the rics, ie ric id without the sequence number. The sequence number is added during processing | +| `` | The number of rics, assuming the first index is '1'. The index is added to the 'ric-id-base' id | +| `` | Id of the policy type | +| `` | Id of the policy. This value shall be a numeric value and will be the id of the first policy | +| `transient>` | Transient 'true' or 'false'. 'NOTRANSIENT' can be used to indicate using the default value (no transient value provide) | +| `notification-url` | Url for notifications | +| `` | Path to the template file for the policy | +| `` | Number of policies per ric | +| `` | Number of threads (processes) to run in parallel | + +## Function: api_delete_policy ## + +This tests the DELETE '/policy' or V2 DELETE '/v2/policies/{policy_id}'. Removes the indicated policy or a 'count' number of policies starting with 'policy-id' as the first id. + +| arg list | +|--| +| ` []` + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the policy | +| `` | An optional count of policies to delete. The 'policy-id' will be the first id to be deleted. | + +## Function: api_delete_policy_batch ## + +This tests the same as function 'api_delete_policy' except that all delete requests are sent to dmaap in one go and then the responses are polled one by one. +If the agent api is not configured to used dmaap (see 'use_agent_dmaap', 'use_agent_rest_http' and 'use_agent_rest_https'), an error message is printed. +For arg list and parameters, see 'api_delete_policy'. + +## Function: api_delete_policy_parallel ## + +This tests the same as function 'api_delete_policy' except that the policy delete is spread out over a number of processes and it only uses the agent rest API. The total number of policies deleted is determined by the product of the parameters 'number-of-rics' and 'count'. The parameter 'number-of-threads' shall be selected to be not evenly divisible by the product of the parameters 'number-of-rics' and 'count' - this is to ensure that one process does not handle the deletion of all the policies in one ric. + +| arg list | +|--| +| ` ` + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | The base id of the rics, ie ric id without the sequence number. The sequence number is added during processing | +| `` | The number of rics, assuming the first index is '1' | +| `` | Id of the policy. This value shall be a numeric value and will be the id of the first policy | +| `` | Number of policies per ric | +| `` | Number of threads (processes) to run in parallel | + +## Function: api_get_policy_ids ## + +Test of GET '/policy_ids' or V2 GET '/v2/policies'. +To test response code only, provide the response code parameter as well as the following three parameters. +To also test the response payload add the 'NOID' for an expected empty array or repeat the 'policy-instance-id' for each expected policy id. + +| arg list | +|--| +| ` \|NORIC \|NOSERVICE \|NOTYPE ([` | Expected http response code | +| `` | Id of the ric | +| `NORIC` | Indicator that no ric is provided | +| `` | Id of the service | +| `NOSERVICE` | Indicator that no service id is provided | +| `type-id>` | Id of the policy type | +| `NOTYPE` | Indicator that no type id is provided | +| `NOID` | Indicator that no policy id is provided - indicate empty list of policies| +| `` | Id of the policy | + +## Function: api_get_policy_schema ## + +Test of V2 GET '/v2/policy-types/{policyTypeId}' and optional check of the returned json schema. +To test the response code only, provide the expected response code and policy type id. +To test the contents of the returned json schema, add a path to a schema file to compare with. + +| arg list | +|--| +| ` []` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the policy type | +| `` | Path to the schema file for the policy type | + +## Function: api_get_policy_schema ## + +Test of GET '/policy_schema' and optional check of the returned json schema. +To test the response code only, provide the expected response code and policy type id. +To test the contents of the returned json schema, add a path to a schema file to compare with. + +| arg list | +|--| +| ` []` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the policy type | +| `` | Path to the schema file for the policy type | + +## Function: api_get_policy_schemas ## + +Test of GET '/policy_schemas' and optional check of the returned json schemas. +To test the response code only, provide the expected response code and ric id (or NORIC if no ric is given). +To test the contents of the returned json schema, add a path to a schema file to compare with (or NOFILE to represent an empty '{}' type) + +| arg list | +|--| +| ` \|NORIC [\|NOFILE]*` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the ric | +| `NORIC` | No ric id given | +| `` | Path to the schema file for the policy type | +| `NOFILE` | Indicate the template for an empty type | + +## Function: api_get_policy_status ## + +Test of GET '/policy_status' or V2 GET '/policies/{policy_id}/status'. + +| arg list | +|--| +| ` (STD\|STD2 \|EMPTY [\|EMPTY])\|(OSC )` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the policy | +| `STD` | Indicator of status of Standarized A1 | +| `STD2` | Indicator of status of Standarized A1 version 2 | +| `` | Enforcement status | +| `` | Optional reason | +| `EMPTY` | Indicator of empty string status or reason | +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `` | Instance status | +| `` | Deleted status, true or false | + +## Function: api_get_policy_types ## + +Test of GET '/policy_types' or V2 GET '/v2/policy-types' and optional check of the returned ids. +To test the response code only, provide the expected response code and ric id (or NORIC if no ric is given). +To test the contents of the returned json payload, add the list of expected policy type id (or 'EMPTY' for the '{}' type) + +| arg list | +|--| +| ` [\|NORIC [\|EMPTY []*]]` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the ric | +| `NORIC` | No ric id given | +| `` | Id of the policy type | +| `EMPTY` | Indicate the empty type | + +## Function: api_get_status ## + +Test of GET /status or V2 GET /status + | arg list | |--| | `` | @@ -1827,131 +2422,155 @@ Only response code tested - not payload | --------- | ----------- | | `` | Expected http response code | -# Description of functions in http_proxy_api_functions.sh # +## Function: api_get_ric ## -## Function: use_http_proxy_http ## +Test of GET '/ric' or V2 GET '/v2/rics/ric' +To test the response code only, provide the expected response code and managed element id. +To test the returned ric id, provide the expected ric id. -Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. | arg list | |--| -| None | +| ` []` | -## Function: use_http_proxy_https ## +| arg list V2 | +|--| +| ` \|NOME \| []` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Id of the managed element | +| `NOME` | Indicator for no ME | +| `ric-id` | Id of the ric | +| `NORIC` | Indicator no RIC | +| `string-of-ricinfo` | String of ric info | -Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. -| arg list | -|--| -| None | +## Function: api_get_rics ## -## Function: start_http_proxy ## +Test of GET '/rics' or V2 GET '/v2/rics' and optional check of the returned json payload (ricinfo). +To test the response code only, provide the expected response code and policy type id (or NOTYPE if no type is given). +To test also the returned payload, add the formatted string of info in the returned payload. +Format of ricinfo:
`::`
+Example
` = "ricsim_g1_1:me1_ricsim_g1_1,me2_ricsim_g1_1:1,2,4 ricsim_g1_1:me2_........."` -Start the http proxy container in docker or kube depending on running mode. | arg list | |--| -| None | +| ` \|NOTYPE []` | -# Description of functions in kube_proxy_api_functions.sh # +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Policy type id of the ric | +| `NOTYPE>` | No type given | +| `` | A space separated string of ric info - needs to be quoted | -## Function: use_kube_proxy_http ## +## Function: api_put_service ## -Use http for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. +Test of PUT '/service' or V2 PUT '/service'. | arg list | |--| -| None | +| ` ` | -## Function: use_kube_proxy_https ## +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Service name | +| `` | Timeout value | +| `` | Callback url | -Use https for all proxy requests. Note that this only applicable to the actual proxy request, the proxied protocol can still be http and https. -| arg list | -|--| -| None | +## Function: api_get_services ## -## Function: start_kube_proxy ## +Test of GET '/service' or V2 GET '/v2/services' and optional check of the returned json payload. +To test only the response code, omit all parameters except the expected response code. +To test the returned json, provide the parameters after the response code. -Start the kube proxy container in kube. This proxy enabled the test env to access all services and pods in a kube cluster. -No proxy is started if the function is called in docker mode. | arg list | |--| -| None | +| ` [ ( ) \| (NOSERVICE [ ]* )]` | -# Description of functions in mr_api_functions.sh # +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Service name for the query | +| `` | Target service name| +| `` | Timeout value | +| `` | Callback url | +| `NOSERVICE` | Indicator of no target service name | -## Function: use_mr_http ## +## Function: api_get_service_ids ## + +Test of GET '/services' or V2 GET /'v2/services'. Only check of service ids. -Use http for all Dmaap calls to the MR. This is the default. The admin API is not affected. Note that this function shall be called before preparing the config for Consul. | arg list | |--| -| None | +| ` []*` | -## Function: use_mr_https ## +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Service name | -Use https for all Dmaap call to the MR. The admin API is not affected. Note that this function shall be called before preparing the config for Consul. -| arg list | -|--| -| None | +## Function: api_delete_services ## -## Function: start_mr ## +Test of DELETE '/services' or V2 DELETE '/v2/services/{serviceId}' -Start the Message Router stub interface container in docker or kube depending on start mode | arg list | |--| -| None | +| ` []*` | -## Function: mr_equal ## +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `` | Service name | + +## Function: api_put_services_keepalive ## + +Test of PUT '/services/keepalive' or V2 PUT '/v2/services/{service_id}/keepalive' -Tests if a variable value in the Message Router (MR) simulator is equal to a target value. -Without the timeout, the test sets pass or fail immediately depending on if the variable is equal to the target or not. -With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes equal to the target value or not. -See the 'mrstub' dir for more details. | arg list | |--| -| ` [ ]` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Variable name in the MR | -| `` | Target value for the variable | -| `` | Max time to wait for the variable to reach the target value | +| `` | Expected http response code | +| `` | Service name | -## Function: mr_greater ## +## Function: api_put_configuration ## + +Test of PUT '/v2/configuration' -Tests if a variable value in the Message Router (MR) simulator is greater than a target value. -Without the timeout, the test sets pass or fail immediately depending on if the variable is greater than the target or not. -With the timeout, the test waits up to the timeout seconds before setting pass or fail depending on if the variable value becomes greater than the target value or not. -See the 'mrstub' dir for more details. | arg list | |--| -| ` [ ]` | +| ` ` | | parameter | description | | --------- | ----------- | -| `` | Variable name in the MR | -| `` | Target value for the variable | -| `` | Max time to wait for the variable to become grater than the target value | +| `` | Expected http response code | +| `` | Path json config file | -## Function: mr_read ## +## Function: api_get_configuration ## + +Test of GET '/v2/configuration' -Reads the value of a variable in the Message Router (MR) simulator. The value is intended to be passed to a env variable in the test script. -See the 'mrstub' dir for more details. | arg list | |--| -| `` | +| ` []` | | parameter | description | | --------- | ----------- | -| `` | Variable name in the MR | +| `` | Expected http response code | +| `` | Path json config file to compare the retrieved config with | -## Function: mr_print ## +## Function: pms_kube_pvc_reset ## +Admin reset to remove all policies and services +All types and instances etc are removed - types and instances in a1 sims need to be removed separately +NOTE - only works in kubernetes and the pod should not be running -Prints the value of a variable in the Message Router (MR) simulator. -See the 'mrstub' dir for more details. | arg list | |--| -| `` | +| None | -| parameter | description | -| --------- | ----------- | -| `` | Variable name in the MR | # Description of functions in prodstub_api_functions.sh # @@ -1976,7 +2595,7 @@ Start the Producer stub container in docker or kube depending on start mode |--| | None | -## Function: prodstub_arm_producer() ## +## Function: prodstub_arm_producer ## Preconfigure the prodstub with a producer. The producer supervision response code is optional, if not given the response code will be set to 200. @@ -1990,7 +2609,7 @@ Preconfigure the prodstub with a producer. The producer supervision response cod | `` | Id of the producer | | `` | Forced response code for the producer callback url | -## Function: prodstub_arm_job_create() ## +## Function: prodstub_arm_job_create ## Preconfigure the prodstub with a job or update an existing job. Optional create/update job response code, if not given the response code will be set to 200/201 depending on if the job has been previously created or not. @@ -2004,7 +2623,7 @@ Preconfigure the prodstub with a job or update an existing job. Optional create/ | `` | Id of the job | | `` | Forced response code for the create callback url | -## Function: prodstub_arm_job_delete() ## +## Function: prodstub_arm_job_delete ## Preconfigure the prodstub with a job. Optional delete job response code, if not given the response code will be set to 204/404 depending on if the job exists or not. @@ -2018,7 +2637,7 @@ Preconfigure the prodstub with a job. Optional delete job response code, if not | `` | Id of the job | | `` | Forced response code for the delete callback url | -## Function: prodstub_arm_type() ## +## Function: prodstub_arm_type ## Preconfigure the prodstub with a type for a producer. Can be called multiple times to add more types. @@ -2032,7 +2651,7 @@ Preconfigure the prodstub with a type for a producer. Can be called multiple tim | `` | Id of the producer | | `` | Id of the type | -## Function: prodstub_disarm_type() ## +## Function: prodstub_disarm_type ## Remove a type for the producer in the rodstub. Can be called multiple times to remove more types. @@ -2046,7 +2665,7 @@ Remove a type for the producer in the rodstub. Can be called multiple times to r | `` | Id of the producer | | `` | Id of the type | -## Function: prodstub_check_jobdata() ## +## Function: prodstub_check_jobdata ## Check a job in the prodstub towards the list of provided parameters. @@ -2064,7 +2683,7 @@ Check a job in the prodstub towards the list of provided parameters. | `` | Id of the job owner | | `` | Path to a job template file | -## Function: prodstub_check_jobdata_2() ## +## Function: prodstub_check_jobdata_2 ## Check a job in the prodstub towards the list of provided parameters. @@ -2082,7 +2701,7 @@ Check a job in the prodstub towards the list of provided parameters. | `` | Id of the job owner | | `` | Path to a job template file | -## Function: prodstub_check_jobdata_3() ## +## Function: prodstub_check_jobdata_3 ## Check a job in the prodstub towards the list of provided parameters. @@ -2100,7 +2719,7 @@ Check a job in the prodstub towards the list of provided parameters. | `` | Id of the job owner | | `` | Path to a job template file | -## Function: prodstub_delete_jobdata() ## +## Function: prodstub_delete_jobdata ## Delete the job parameters, job data, for a job. @@ -2130,7 +2749,7 @@ With the timeout, the test waits up to the timeout seconds before setting pass o | `` | Target value for the variable | | `` | Max time to wait for the variable to reach the target value | -# Description of functions in rapp_catalogue_api_function.sh # +# Description of functions in rc_api_function.sh # ## Function: use_rapp_catalogue_http ## @@ -2169,7 +2788,7 @@ See the 'cr' dir for more details. | `` | Target value for the variable | | `` | Max time to wait for the variable to reach the target value | -## Function: rapp_cat_api_get_services() ## +## Function: rapp_cat_api_get_services ## Check all registered services. @@ -2186,7 +2805,7 @@ Check all registered services. | `` | Description of the service | | `EMPTY` | Indicator for an empty list | -## Function: rapp_cat_api_put_service() ## +## Function: rapp_cat_api_put_service ## Register a services. @@ -2202,7 +2821,7 @@ Register a services. | `` | Dislay name of the service | | `` | Description of the service | -## Function: rapp_cat_api_get_service() ## +## Function: rapp_cat_api_get_service ## Check a registered service. @@ -2218,7 +2837,7 @@ Check a registered service. | `` | Dislay name of the service | | `` | Description of the service | -## Function: rapp_cat_api_delete_service() ## +## Function: rapp_cat_api_delete_service ## Check a registered service. @@ -2231,7 +2850,7 @@ Check a registered service. | `` | Expected http response code | | `` | Id of the service | -# Description of functions in ricsimulator_api_functions.sh # +# Description of functions in ricsim_api_functions.sh # The functions below only use the admin interface of the simulator, no usage of the A1 interface. @@ -2413,6 +3032,145 @@ The intention is to delay responses on the A1 interface. Setting remains until r | `` | Id of the ric | | `` | Delay in seconds. If omitted, the delay is removed | +# Description of functions in sdnc_api_functions.sh # + +The file contains a selection of the possible API tests towards the SDNC (a1-controller) + +## Function: use_sdnc_http ## + +Use http for all API calls towards the SDNC A1 Controller. This is the default. Note that this function shall be called before preparing the config for Consul. +| arg list | +|--| +| None | + +## Function: use_sdnc_https ## + +Use https for all API calls towards the SDNC A1 Controller. Note that this function shall be called before preparing the config for Consul. +| arg list | +|--| +| None | + +## Function: start_sdnc ## + +Start the SDNC A1 Controller container and its database container +| arg list | +|--| +| None | + +## Function: stop_sdnc ## + +Stop the SDNC A1 Controller container and its database container +| arg list | +|--| +| None | + +## Function: start_stopped_sdnc ## + +Start a previously stopped SDNC +| arg list | +|--| +| None | + +## Function: check_sdnc_logs ## + +Check the SDNC log for any warnings and errors and print the count of each. +| arg list | +|--| +| None | + +## Function: controller_api_get_A1_policy_ids ## + +Test of GET policy ids towards OSC or STD type simulator. +To test response code only, provide the response code, 'OSC' + policy type or 'STD' +To test the response payload, include the ids of the expexted response. + +| arg list | +|--| +| ` (OSC [ []* ]) \| ( STD [ []* ]` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `` | Id of the ric | +| `policy-type-id>` | Id of the policy type | +| `` | Id of the policy | +| `STD` | Indicator of status of Standarized A1 | + +## Function: controller_api_get_A1_policy_type ## + +Test of GET a policy type (OSC only) + +| arg list | +|--| +| ` OSC []` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `` | Id of the ric | +| `policy-type-id>` | Id of the policy type | +| `policy-type-file>` | Optional schema file to compare the returned type with | + +## Function: controller_api_delete_A1_policy ## + +Deletes a policy instance + +| arg list | +|--| +| `(STD ) \| (OSC )` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `STD` | Indicator of status of Standarized A1 | +| `` | Id of the ric | +| `` | Id of the policy | +| `policy-type-id>` | Id of the policy type | +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `policy-type-file>` | Optional schema file to compare the returned type with | + +## Function: controller_api_put_A1_policy ## + +Creates a policy instance + +| arg list | +|--| +| ` (STD ) \| (OSC )` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `STD` | Indicator of status of Standarized A1 | +| `` | Id of the ric | +| `` | Id of the policy | +| `` | Path to the template file of the policy| +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `` | Id of the policy type | + +## Function: controller_api_get_A1_policy_status ## + +Checks the status of a policy + + arg list | +|--| +| ` (STD []) \| (OSC )` | + +| parameter | description | +| --------- | ----------- | +| `` | Expected http response code | +| `STD` | Indicator of status of Standarized A1 | +| `` | Id of the ric | +| `` | Id of the policy | +| `` | Enforcement status | +| `` | Optional reason | +| `OSC` | Indicator of status of Non-Standarized OSC A1 | +| `` | Id of the policy type | +| `` | Instance status | +| `` | Deleted status, true or false | + + ## License Copyright (C) 2020 Nordix Foundation. All rights reserved. diff --git a/test/common/chartmus_api_functions.sh b/test/common/chartmus_api_functions.sh new file mode 100644 index 00000000..a9f09c0f --- /dev/null +++ b/test/common/chartmus_api_functions.sh @@ -0,0 +1,316 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +# This is a script that contains container/service management functions and test functions for Chartmuseum + + +################ Test engine functions ################ + +# Create the image var used during the test +# arg: (selects staging, snapshot, release etc) +# is present only for images with staging, snapshot,release tags +__CHARTMUS_imagesetup() { + __check_and_create_image_var CHARTMUS "CHART_MUS_IMAGE" "CHART_MUS_IMAGE_BASE" "CHART_MUS_IMAGE_TAG" REMOTE_OTHER "$CHART_MUS_DISPLAY_NAME" +} + +# Pull image from remote repo or use locally built image +# arg: +# Shall be used for images allowing overriding. For example use a local image when test is started to use released images +# Shall be used for images that does not allow overriding +# Both var may contain: 'remote', 'remote-remove' or 'local' +__CHARTMUS_imagepull() { + __check_and_pull_image $2 "$CHART_MUS_DISPLAY_NAME" $CHART_MUS_APP_NAME CHART_MUS_IMAGE +} + +# Build image (only for simulator or interfaces stubs owned by the test environment) +# arg: (selects staging, snapshot, release etc) +# is present only for images with staging, snapshot,release tags +__CHARTMUS_imagebuild() { + echo -e $RED" Image for app CHARTMUS shall never be built"$ERED +} + +# Generate a string for each included image using the app display name and a docker images format string +# If a custom image repo is used then also the source image from the local repo is listed +# arg: +__CHARTMUS_image_data() { + echo -e "$CHART_MUS_DISPLAY_NAME\t$(docker images --format $1 $CHART_MUS_IMAGE)" >> $2 + if [ ! -z "$CHART_MUS_IMAGE_SOURCE" ]; then + echo -e "-- source image --\t$(docker images --format $1 $CHART_MUS_IMAGE_SOURCE)" >> $2 + fi +} + +# Scale kubernetes resources to zero +# All resources shall be ordered to be scaled to 0, if relevant. If not relevant to scale, then do no action. +# This function is called for apps fully managed by the test script +__CHARTMUS_kube_scale_zero() { + __kube_scale_all_resources $KUBE_SIM_NAMESPACE autotest CHARTMUS +} + +# Scale kubernetes resources to zero and wait until this has been accomplished, if relevant. If not relevant to scale, then do no action. +# This function is called for prestarted apps not managed by the test script. +__CHARTMUS_kube_scale_zero_and_wait() { + echo -e $RED" CHARTMUS app is not scaled in this state"$ERED +} + +# Delete all kube resouces for the app +# This function is called for apps managed by the test script. +__CHARTMUS_kube_delete_all() { + __kube_delete_all_resources $KUBE_SIM_NAMESPACE autotest CHARTMUS +} + +# Store docker logs +# This function is called for apps managed by the test script. +# args: +__CHARTMUS_store_docker_logs() { + if [ $RUNMODE == "KUBE" ]; then + kubectl logs -l "autotest=CHARTMUS" -n $KUBE_SIM_NAMESPACE --tail=-1 > $1$2_chartmuseum.log 2>&1 + else + docker logs $CHART_MUS_APP_NAME > $1$2_chartmuseum.log 2>&1 + fi +} + +# Initial setup of protocol, host and ports +# This function is called for apps managed by the test script. +# args: - +__CHARTMUS_initial_setup() { + use_chart_mus_http +} + +# Set app short-name, app name and namespace for logging runtime statistics of kubernets pods or docker containers +# For docker, the namespace shall be excluded +# This function is called for apps managed by the test script as well as for prestarted apps. +# args: - +__CHARTMUS_statisics_setup() { + if [ $RUNMODE == "KUBE" ]; then + echo "CHARTMUS $CHART_MUS_APP_NAME $KUBE_SIM_NAMESPACE" + else + echo "CHARTMUS $CHART_MUS_APP_NAME" + fi +} + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__CHARTMUS_test_requirements() { + : +} + +####################################################### + +# Set http as the protocol to use for all communication to the Chartmuseum +# args: - +# (Function for test scripts) +use_chart_mus_http() { + __chart_mus_set_protocoll "http" $CHART_MUS_INTERNAL_PORT $CHART_MUS_EXTERNAL_PORT +} + +# Set https as the protocol to use for all communication to the Chartmuseum +# args: - +# (Function for test scripts) +use_chart_mus_https() { + __chart_mus_set_protocoll "https" $CHART_MUS_INTERNAL_SECURE_PORT $CHART_MUS_EXTERNAL_SECURE_PORT +} + +# Setup paths to svc/container for internal and external access +# args: +__chart_mus_set_protocoll() { + echo -e $BOLD"$CHART_MUS_DISPLAY_NAME protocol setting"$EBOLD + echo -e " Using $BOLD $1 $EBOLD towards $CHART_MUS_DISPLAY_NAME" + + ## Access to Chartmuseum + + CHART_MUS_SERVICE_PATH=$1"://"$CHART_MUS_APP_NAME":"$2 # docker access, container->container and script->container via proxy + CHART_MUS_SERVICE_PORT=$2 + CHART_MUS_SERVICE_HOST=$CHART_MUS_APP_NAME + if [ $RUNMODE == "KUBE" ]; then + CHART_MUS_SERVICE_PATH=$1"://"$CHART_MUS_APP_NAME.$KUBE_SIM_NAMESPACE":"$3 # kube access, pod->svc and script->svc via proxy + CHART_MUS_SERVICE_PORT=$3 + CHART_MUS_SERVICE_HOST=$CHART_MUS_APP_NAME.$KUBE_SIM_NAMESPACE + fi + CHART_MUS_SERVICE_HTTPX=$1 + + echo "" +} + +### Admin API functions Chartmuseum + +########################### +### Chartmuseum functions +########################### + +# Export env vars for config files, docker compose and kube resources +# args: +__chartmuseum_export_vars() { + export CHART_MUS_APP_NAME + export CHART_MUS_DISPLAY_NAME + + export DOCKER_SIM_NWNAME + export KUBE_SIM_NAMESPACE + + export CHART_MUS_IMAGE + export CHART_MUS_INTERNAL_PORT + export CHART_MUS_EXTERNAL_PORT + + export CHART_MUS_CHART_CONTR_CHARTS + +} + + +# Start the Chartmuseum in the simulator group +# args: - +# (Function for test scripts) +start_chart_museum() { + + echo -e $BOLD"Starting $CHART_MUS_DISPLAY_NAME"$EBOLD + + if [ $RUNMODE == "KUBE" ]; then + + # Check if app shall be fully managed by the test script + __check_included_image "CHARTMUS" + retcode_i=$? + + # Check if app shall only be used by the testscipt + __check_prestarted_image "CHARTMUS" + retcode_p=$? + + if [ $retcode_i -ne 0 ] && [ $retcode_p -ne 0 ]; then + echo -e $RED"The $CHART_MUS_NAME app is not included as managed nor prestarted in this test script"$ERED + echo -e $RED"The $CHART_MUS_APP_NAME will not be started"$ERED + exit + fi + if [ $retcode_i -eq 0 ] && [ $retcode_p -eq 0 ]; then + echo -e $RED"The $CHART_MUS_APP_NAME app is included both as managed and prestarted in this test script"$ERED + echo -e $RED"The $CHART_MUS_APP_NAME will not be started"$ERED + exit + fi + + if [ $retcode_p -eq 0 ]; then + echo -e " Using existing $CHART_MUS_APP_NAME deployment and service" + echo " Setting RC replicas=1" + __kube_scale deployment $CHART_MUS_APP_NAME $KUBE_SIM_NAMESPACE 1 + fi + + if [ $retcode_i -eq 0 ]; then + echo -e " Creating $CHART_MUS_APP_NAME deployment and service" + + __kube_create_namespace $KUBE_SIM_NAMESPACE + + __chartmuseum_export_vars + + # Create service + input_yaml=$SIM_GROUP"/"$CHART_MUS_COMPOSE_DIR"/"svc.yaml + output_yaml=$PWD/tmp/chartmus_svc.yaml + __kube_create_instance service $CHART_MUS_APP_NAME $input_yaml $output_yaml + + # Create app + input_yaml=$SIM_GROUP"/"$CHART_MUS_COMPOSE_DIR"/"app.yaml + output_yaml=$PWD/tmp/chartmus_app.yaml + __kube_create_instance app $CHART_MUS_APP_NAME $input_yaml $output_yaml + fi + + __check_service_start $CHART_MUS_APP_NAME $CHART_MUS_SERVICE_PATH$CHART_MUS_ALIVE_URL + else + + # Check if docker app shall be fully managed by the test script + __check_included_image 'CHARTMUS' + if [ $? -eq 1 ]; then + echo -e $RED"The Chartmuseum app is not included as managed in this test script"$ERED + echo -e $RED"The Chartmuseum will not be started"$ERED + exit + fi + + __chartmuseum_export_vars + + __start_container $CHART_MUS_COMPOSE_DIR "" NODOCKERARGS 1 $CHART_MUS_APP_NAME + + __check_service_start $CHART_MUS_APP_NAME $CHART_MUS_SERVICE_PATH$CHART_MUS_ALIVE_URL + fi + echo "" + return 0 +} + +# Excute a curl cmd towards the chartmuseum simulator and check the response code. +# args: TEST|CONF +__execute_curl_to_chartmuseum() { + TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S") + echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG + proxyflag="" + if [ ! -z "$KUBE_PROXY_PATH" ]; then + if [ $KUBE_PROXY_HTTPX == "http" ]; then + proxyflag=" --proxy $KUBE_PROXY_PATH" + else + proxyflag=" --proxy-insecure --proxy $KUBE_PROXY_PATH" + fi + fi + echo " CMD: $3 -skw %{http_code} $proxyflag" >> $HTTPLOG + res="$($3 -skw %{http_code} $proxyflag)" + echo " RESP: $res" >> $HTTPLOG + retcode=$? + if [ $retcode -ne 0 ]; then + __log_conf_fail_general " Fatal error when executing curl, response: "$retcode + return 1 + fi + status=${res:${#res}-3} + if [ $status -eq $2 ]; then + if [ $1 == "TEST" ]; then + __log_test_pass + else + __log_conf_ok + fi + return 0 + fi + if [ $1 == "TEST" ]; then + __log_test_fail_status_code $2 $status + else + __log_conf_fail_status_code $2 $status + fi + return 1 +} + +# upload helmchart +# arg: +chartmus_upload_test_chart() { + __log_conf_start $@ + if [ $# -ne 1 ]; then + __print_err "" $@ + return 1 + fi + chart_path=$TESTENV_TEMP_FILES/$1"-0.1.0.tgz" + if [ ! -f "$chart_path" ]; then + echo -e $RED" Cannot find package chart: $chart_path"$ERED + __log_conf_fail_general + return 1 + fi + __execute_curl_to_chartmuseum CONF 201 "curl --data-binary @$chart_path $CHART_MUS_SERVICE_PATH/api/charts" +} + +# delete helmchart +# arg: [] +chartmus_delete_test_chart() { + __log_conf_start $@ + if [ $# -gt 2 ]; then + __print_err " []" $@ + return 1 + fi + if [ $# -eq 1 ]; then + chart_path="/$1/0.1.0" + else + chart_path="/$1/$2" + fi + __execute_curl_to_chartmuseum CONF 200 "curl -X DELETE $CHART_MUS_SERVICE_PATH/api/charts"$chart_path +} \ No newline at end of file diff --git a/test/common/clean_kube.sh b/test/common/clean_kube.sh index a3a3e5b0..281f8ce0 100755 --- a/test/common/clean_kube.sh +++ b/test/common/clean_kube.sh @@ -84,7 +84,7 @@ __kube_wait_for_zero_count() { __kube_delete_all_resources() { echo " Delete all in namespace $1 ..." namespace=$1 - resources="deployments replicaset statefulset services pods configmaps pvc " + resources="deployments replicaset statefulset services pods configmaps pvc serviceaccounts" for restype in $resources; do result=$(kubectl get $restype -n $namespace -o jsonpath='{.items[?(@.metadata.labels.autotest)].metadata.name}') if [ $? -eq 0 ] && [ ! -z "$result" ]; then @@ -97,8 +97,8 @@ __kube_delete_all_resources() { } __kube_delete_all_pv() { - echo " Delete pv ..." - resources="pv" + echo " Delete all non-namespaced resources ..." + resources="pv clusterrolebindings" for restype in $resources; do result=$(kubectl get $restype -o jsonpath='{.items[?(@.metadata.labels.autotest)].metadata.name}') if [ $? -eq 0 ] && [ ! -z "$result" ]; then diff --git a/test/common/consul_api_functions.sh b/test/common/consul_api_functions.sh index af85ff34..5adb1144 100644 --- a/test/common/consul_api_functions.sh +++ b/test/common/consul_api_functions.sh @@ -180,6 +180,18 @@ __CONSUL_statisics_setup() { __CBS_statisics_setup() { echo "" } + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__CONSUL_test_requirements() { + : +} + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__CBS_test_requirements() { + : +} ####################################################### diff --git a/test/common/cp_api_functions.sh b/test/common/cp_api_functions.sh index 992fd68a..803184aa 100644 --- a/test/common/cp_api_functions.sh +++ b/test/common/cp_api_functions.sh @@ -104,6 +104,12 @@ __CP_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__CP_test_requirements() { + : +} + ####################################################### diff --git a/test/common/cr_api_functions.sh b/test/common/cr_api_functions.sh index 51162737..a12b69e9 100644 --- a/test/common/cr_api_functions.sh +++ b/test/common/cr_api_functions.sh @@ -131,6 +131,12 @@ __CR_statisics_setup() { done } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__CR_test_requirements() { + : +} + ####################################################### ################ @@ -361,6 +367,27 @@ cr_equal() { fi } +# Tests if a variable value in the CR is equal to or greater than the target value and and optional timeout. +# Arg: - This test set pass or fail depending on if the variable is +# equal to the target or not. +# Arg: - This test waits up to the timeout seconds +# before setting pass or fail depending on if the variable value becomes equal to or greater than the target +# value or not. +# (Function for test scripts) +cr_greater_or_equal() { + if [ $# -eq 3 ] || [ $# -eq 4 ]; then + CR_SERVICE_PATH=$(__cr_get_service_path $1) + CR_ADAPTER=$CR_SERVICE_PATH + if [ $? -ne 0 ]; then + __print_err " missing or incorrect" $@ + return 1 + fi + __var_test "CR" "$CR_SERVICE_PATH/counter/" $2 ">=" $3 $4 + else + __print_err "Wrong args to cr_equal, needs three or four args: [ timeout ]" $@ + fi +} + # Tests if a variable value in the CR contains the target string and and optional timeout # Arg: - This test set pass or fail depending on if the variable contains # the target or not. @@ -385,7 +412,7 @@ cr_contains_str() { fi } -# Read a variable value from CR sim and send to stdout. Arg: +# Read a variable value from CR sim and send to stdout. Arg: cr_read() { CR_SERVICE_PATH=$(__cr_get_service_path $1) CR_ADAPTER=$CR_SERVICE_PATH @@ -393,7 +420,7 @@ cr_read() { __print_err " missing or incorrect" $@ return 1 fi - echo "$(__do_curl $CR_SERVICE_PATH/counter/$1)" + echo "$(__do_curl $CR_SERVICE_PATH/counter/$2)" } # Function to configure write delay on callbacks diff --git a/test/common/dmaapadp_api_functions.sh b/test/common/dmaapadp_api_functions.sh index a9605ecc..9f8dc5f6 100644 --- a/test/common/dmaapadp_api_functions.sh +++ b/test/common/dmaapadp_api_functions.sh @@ -104,6 +104,12 @@ __DMAAPADP_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__DMAAPADP_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to the Dmaap adapter diff --git a/test/common/dmaapmed_api_functions.sh b/test/common/dmaapmed_api_functions.sh index 35280a4c..ef99ee1e 100644 --- a/test/common/dmaapmed_api_functions.sh +++ b/test/common/dmaapmed_api_functions.sh @@ -104,6 +104,12 @@ __DMAAPMED_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__DMAAPMED_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to the Dmaap mediator @@ -159,7 +165,7 @@ __dmaapmed_export_vars() { export DMAAP_MED_DATA_MOUNT_PATH export DMAAP_MED_HOST_MNT_DIR - export DMAAP_MED_DATA_FILE + export DMAAP_MED_CONTR_DATA_FILE export DMAAP_MED_DATA_CONFIGMAP_NAME=$DMAAP_MED_APP_NAME"-data" if [ $1 == "PROXY" ]; then @@ -182,6 +188,8 @@ __dmaapmed_export_vars() { export DMAAP_MED_CONF_SELF_HOST=$(echo $DMAAP_MED_SERVICE_PATH | cut -d: -f1-2) export DMAAP_MED_CONF_SELF_PORT=$(echo $DMAAP_MED_SERVICE_PATH | cut -d: -f3) export MR_SERVICE_PATH + export MR_KAFKA_SERVICE_PATH + } # Start the Dmaap mediator @@ -227,7 +235,7 @@ start_dmaapmed() { __dmaapmed_export_vars $1 # Create config map for data - data_json=$PWD/tmp/$DMAAP_MED_DATA_FILE + data_json=$PWD/tmp/$DMAAP_MED_CONTR_DATA_FILE if [ $# -lt 2 ]; then #create empty dummy file echo "{}" > $data_json @@ -262,7 +270,7 @@ start_dmaapmed() { __dmaapmed_export_vars $1 - dest_file=$SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_HOST_MNT_DIR/$DMAAP_MED_DATA_FILE + dest_file=$SIM_GROUP/$DMAAP_MED_COMPOSE_DIR/$DMAAP_MED_HOST_MNT_DIR/$DMAAP_MED_CONTR_DATA_FILE envsubst < $2 > $dest_file diff --git a/test/common/do_curl_function.sh b/test/common/do_curl_function.sh index a3f5507e..6476711f 100755 --- a/test/common/do_curl_function.sh +++ b/test/common/do_curl_function.sh @@ -93,7 +93,9 @@ do_curl() { exit 1 else echo " OK, code: "$status" (Expected)" - if [[ "$content_type" == *"$resp_content"* ]]; then + if [[ "$resp_content" == '*' ]]; then + : + elif [[ "$content_type" == *"$resp_content"* ]]; then echo " Content type: "$content_type" (Expected)" else echo " Expected content type: "$resp_content diff --git a/test/common/format_endpoint_stats.sh b/test/common/format_endpoint_stats.sh new file mode 100755 index 00000000..c80f0831 --- /dev/null +++ b/test/common/format_endpoint_stats.sh @@ -0,0 +1,130 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +# This script format http endpoint stats generated by testscripts + +print_usage() { + echo "Usage: format_endpoint_stats [tc-id]+ " +} + +SUMMARYFILE="" +SUMMARYFILE_TMP="" + +update_summary() { + + input=$@ + inputarr=(${input// / }) + inputp=${inputarr[3]} + inputn=${inputarr[4]} + inputposarr=(${inputp//\// }) + inputnegarr=(${inputn//\// }) + > $SUMMARYFILE_TMP + found=0 + while read -r line; do + linearr=(${line// / }) + linep=${linearr[3]} + linen=${linearr[4]} + lineposarr=(${linep//\// }) + linenegarr=(${linen//\// }) + if [[ ${linearr[1]} == ${inputarr[1]} ]] && [[ ${linearr[2]} == ${inputarr[2]} ]]; then + let lineposarr[0]=lineposarr[0]+inputposarr[0] + let lineposarr[1]=lineposarr[1]+inputposarr[1] + let linenegarr[0]=linenegarr[0]+inputnegarr[0] + let linenegarr[1]=linenegarr[1]+inputnegarr[1] + found=1 + fi + printf '%-2s %-10s %-45s %-16s %-16s' "#" "${linearr[1]}" "${linearr[2]}" "${lineposarr[0]}/${lineposarr[1]}" "${linenegarr[0]}/${linenegarr[1]}" >> $SUMMARYFILE_TMP + echo "" >> $SUMMARYFILE_TMP + done < $SUMMARYFILE + if [ $found -eq 0 ]; then + printf '%-2s %-10s %-45s %-16s %-16s' "#" "${inputarr[1]}" "${inputarr[2]}" "${inputposarr[0]}/${inputposarr[1]}" "${inputnegarr[0]}/${inputnegarr[1]}" >> $SUMMARYFILE_TMP + echo "" >> $SUMMARYFILE_TMP + fi + cp $SUMMARYFILE_TMP $SUMMARYFILE +} + +if [ $# -lt 4 ]; then + print_usage + exit 1 +fi +BASE_DIR=$1 +if [ ! -d $BASE_DIR ]; then + print_usage + echo " $BASE_DIR does not exist or is not a dir" + exit 1 +fi +SUMMARYFILE=$BASE_DIR/endpoint_summary.log +rm $SUMMARYFILE +touch $SUMMARYFILE +SUMMARYFILE_TMP=$BASE_DIR/endpoint_summary_tmp.log +TC_FAIL=0 +shift +APP_ID=$1 +shift +echo "" +echo "===================================================" +echo "Functional test cases for $1" +echo "===================================================" +echo +shift +while [ $# -gt 0 ]; do + FTC_DIR=$BASE_DIR/$1 + if [ ! -d $FTC_DIR ]; then + echo "Dir $FTC_DIR does not exist" + exit 1 + fi + IMAGE_INFO_FILE=$FTC_DIR/imageinfo_$APP_ID".log" + if [ -f $IMAGE_INFO_FILE ]; then + echo "=== Testscript: $1 ===" + echo "Image: "$(cat $IMAGE_INFO_FILE) + echo + TC_RES_FILE=$FTC_DIR/.result$1.txt + if [ -f "$TC_RES_FILE" ]; then + TC_RESULT=$(< "$TC_RES_FILE") + if [ $TC_RESULT -ne 0 ]; then + echo " !!!!! TESTCASE FAILED !!!!!" + let TC_FAIL=TC_FAIL+1 + fi + fi + echo "=== Results: positive=2XX http status, negative=non 2XX http status - (ok/total)===" + echo "Method Endpoint Positive Negative" + grep --no-filename "#" $FTC_DIR/endpoint_$APP_ID* | cut -c 4- + for filename in $FTC_DIR/endpoint_$APP_ID* ; do + filedata=$(< $filename) + update_summary $filedata + done + echo "===============================" + echo + else + echo "=== No stats collected by Testscript $1 ===" + echo "" + fi + shift +done + +echo "Summary of all testscripts" +if [ $TC_FAIL -ne 0 ]; then + echo " !!!!! ONE OR MORE TESTCASE(S) FAILED - CHECK INDIVIDUAL TEST RESULT!!!!!" +fi +echo "=== Results: positive=2XX http status, negative=non 2XX http status - (ok/total)===" +echo "Method Endpoint Positive Negative" +cat $SUMMARYFILE | cut -c 4- + +exit 0 + diff --git a/test/common/helmmanager_api_functions.sh b/test/common/helmmanager_api_functions.sh new file mode 100644 index 00000000..a5a9a097 --- /dev/null +++ b/test/common/helmmanager_api_functions.sh @@ -0,0 +1,530 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +# This is a script that contains container/service managemnt functions test functions for Helm Manager + +################ Test engine functions ################ + +# Create the image var used during the test +# arg: [] (selects staging, snapshot, release etc) +# is present only for images with staging, snapshot,release tags +__HELMMANAGER_imagesetup() { + __check_and_create_image_var HELMMANAGER "HELM_MANAGER_IMAGE" "HELM_MANAGER_IMAGE_BASE" "HELM_MANAGER_IMAGE_TAG" $1 "$HELM_MANAGER_DISPLAY_NAME" +} + +# Pull image from remote repo or use locally built image +# arg: +# Shall be used for images allowing overriding. For example use a local image when test is started to use released images +# Shall be used for images that does not allow overriding +# Both arg var may contain: 'remote', 'remote-remove' or 'local' +__HELMMANAGER_imagepull() { + __check_and_pull_image $1 "$HELM_MANAGER_DISPLAY_NAME" $HELM_MANAGER_APP_NAME HELM_MANAGER_IMAGE +} + +# Generate a string for each included image using the app display name and a docker images format string +# If a custom image repo is used then also the source image from the local repo is listed +# arg: +__HELMMANAGER_image_data() { + echo -e "$HELM_MANAGER_DISPLAY_NAME\t$(docker images --format $1 $HELM_MANAGER_IMAGE)" >> $2 + if [ ! -z "$HELM_MANAGER_IMAGE_SOURCE" ]; then + echo -e "-- source image --\t$(docker images --format $1 $HELM_MANAGER_IMAGE_SOURCE)" >> $2 + fi +} + +# Scale kubernetes resources to zero +# All resources shall be ordered to be scaled to 0, if relevant. If not relevant to scale, then do no action. +# This function is called for apps fully managed by the test script +__HELMMANAGER_kube_scale_zero() { + __kube_scale_all_resources $KUBE_NONRTRIC_NAMESPACE autotest HELMMANAGER +} + +# Scale kubernetes resources to zero and wait until this has been accomplished, if relevant. If not relevant to scale, then do no action. +# This function is called for prestarted apps not managed by the test script. +__HELMMANAGER_kube_scale_zero_and_wait() { + __kube_scale_and_wait_all_resources $KUBE_NONRTRIC_NAMESPACE app "$KUBE_NONRTRIC_NAMESPACE"-"$HELM_MANAGER_APP_NAME" +} + +# Delete all kube resouces for the app +# This function is called for apps managed by the test script. +__HELMMANAGER_kube_delete_all() { + __kube_delete_all_resources $KUBE_NONRTRIC_NAMESPACE autotest HELMMANAGER +} + +# Store docker logs +# This function is called for apps managed by the test script. +# args: +__HELMMANAGER_store_docker_logs() { + if [ $RUNMODE == "KUBE" ]; then + kubectl logs -l "autotest=HELMMANAGER" -n $KUBE_NONRTRIC_NAMESPACE --tail=-1 > $1$2_helmmanager.log 2>&1 + else + docker logs $HELM_MANAGER_APP_NAME > $1$2_helmmanager.log 2>&1 + fi +} + +# Initial setup of protocol, host and ports +# This function is called for apps managed by the test script. +# args: - +__HELMMANAGER_initial_setup() { + use_helm_manager_http +} + +# Set app short-name, app name and namespace for logging runtime statistics of kubernets pods or docker containers +# For docker, the namespace shall be excluded +# This function is called for apps managed by the test script as well as for prestarted apps. +# args: - +__HELMMANAGER_statisics_setup() { + if [ $RUNMODE == "KUBE" ]; then + echo "HELMMANAGER $HELM_MANAGER_APP_NAME $KUBE_NONRTRIC_NAMESPACE" + else + echo "HELMMANAGER $HELM_MANAGER_APP_NAME" + fi +} + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__HELMMANAGER_test_requirements() { + tmp=$(which helm) + if [ $? -ne 0 ]; then + echo $RED" Helm3 is required for running helm manager tests. Pls install helm3" + exit 1 + fi + tmp_version=$(helm version | grep 'v3') + if [ -z "$tmp_version" ]; then + echo $RED" Helm3 is required for running helm manager tests. Pls install helm3" + exit 1 + fi +} + +####################################################### + +# Set http as the protocol to use for all communication to the Helm Manager +# args: - +# (Function for test scripts) +use_helm_manager_http() { + __helm_manager_set_protocoll "http" $HELM_MANAGER_INTERNAL_PORT $HELM_MANAGER_EXTERNAL_PORT +} + +# Set https as the protocol to use for all communication to the Helm Manager +# args: - +# (Function for test scripts) +use_helm_manager_https() { + __helm_manager_set_protocoll "https" $HELM_MANAGER_INTERNAL_SECURE_PORT $HELM_MANAGER_EXTERNAL_SECURE_PORT +} + +# Setup paths to svc/container for internal and external access +# args: +__helm_manager_set_protocoll() { + echo -e $BOLD"$HELM_MANAGER_DISPLAY_NAME protocol setting"$EBOLD + echo -e " Using $BOLD $1 $EBOLD towards $HELM_MANAGER_DISPLAY_NAME" + + ## Access to Helm Manager + + HELMMANAGER_SERVICE_PATH=$1"://$HELM_MANAGER_USER:$HELM_MANAGER_PWD@"$HELM_MANAGER_APP_NAME":"$2 # docker access, container->container and script->container via proxy + if [ $RUNMODE == "KUBE" ]; then + HELMMANAGER_SERVICE_PATH=$1"://$HELM_MANAGER_USER:$HELM_MANAGER_PWD@"$HELM_MANAGER_APP_NAME.$KUBE_NONRTRIC_NAMESPACE":"$3 # kube access, pod->svc and script->svc via proxy + fi + + echo "" +} + +# Export env vars for config files, docker compose and kube resources +# args: +__helm_manager_export_vars() { + + export HELM_MANAGER_APP_NAME + export HELM_MANAGER_DISPLAY_NAME + + export DOCKER_SIM_NWNAME + export KUBE_NONRTRIC_NAMESPACE + + export HELM_MANAGER_EXTERNAL_PORT + export HELM_MANAGER_INTERNAL_PORT + export HELM_MANAGER_EXTERNAL_SECURE_PORT + export HELM_MANAGER_INTERNAL_SECURE_PORT + export HELM_MANAGER_CLUSTER_ROLE + export HELM_MANAGER_SA_NAME + export HELM_MANAGER_ALIVE_URL + export HELM_MANAGER_COMPOSE_DIR + export HELM_MANAGER_USER + export HELM_MANAGER_PWD +} + +# Start the Helm Manager container +# args: - +# (Function for test scripts) +start_helm_manager() { + + echo -e $BOLD"Starting $HELM_MANAGER_DISPLAY_NAME"$EBOLD + + if [ $RUNMODE == "KUBE" ]; then + + # Check if app shall be fully managed by the test script + __check_included_image "HELMMANAGER" + retcode_i=$? + + # Check if app shall only be used by the testscipt + __check_prestarted_image "HELMMANAGER" + retcode_p=$? + + if [ $retcode_i -ne 0 ] && [ $retcode_p -ne 0 ]; then + echo -e $RED"The $HELM_MANAGER_APP_NAME app is not included as managed nor prestarted in this test script"$ERED + echo -e $RED"The $HELM_MANAGER_APP_NAME will not be started"$ERED + exit + fi + if [ $retcode_i -eq 0 ] && [ $retcode_p -eq 0 ]; then + echo -e $RED"The $HELM_MANAGER_APP_NAME app is included both as managed and prestarted in this test script"$ERED + echo -e $RED"The $HELM_MANAGER_APP_NAME will not be started"$ERED + exit + fi + + if [ $retcode_p -eq 0 ]; then + echo -e " Using existing $HELM_MANAGER_APP_NAME deployment and service" + echo " Setting $HELM_MANAGER_APP_NAME replicas=1" + __kube_scale sts $HELM_MANAGER_APP_NAME $KUBE_NONRTRIC_NAMESPACE 1 + fi + + if [ $retcode_i -eq 0 ]; then + + echo -e " Creating $HELM_MANAGER_APP_NAME app and expose service" + + #Check if nonrtric namespace exists, if not create it + __kube_create_namespace $KUBE_NONRTRIC_NAMESPACE + + __helm_manager_export_vars + + #Create sa + input_yaml=$SIM_GROUP"/"$HELM_MANAGER_COMPOSE_DIR"/"sa.yaml + output_yaml=$PWD/tmp/helmmanager_sa_svc.yaml + __kube_create_instance sa $HELM_MANAGER_APP_NAME $input_yaml $output_yaml + + #Create service + input_yaml=$SIM_GROUP"/"$HELM_MANAGER_COMPOSE_DIR"/"svc.yaml + output_yaml=$PWD/tmp/helmmanager_svc.yaml + __kube_create_instance service $HELM_MANAGER_APP_NAME $input_yaml $output_yaml + + #Create app + input_yaml=$SIM_GROUP"/"$HELM_MANAGER_COMPOSE_DIR"/"app.yaml + output_yaml=$PWD/tmp/helmmanager_app.yaml + __kube_create_instance app $HELM_MANAGER_APP_NAME $input_yaml $output_yaml + fi + + __check_service_start $HELM_MANAGER_APP_NAME $HELMMANAGER_SERVICE_PATH$HELM_MANAGER_ALIVE_URL + + else + __check_included_image 'HELMMANAGER' + if [ $? -eq 1 ]; then + echo -e $RED"The Helm Manager app is not included as managed in this test script"$ERED + echo -e $RED"The Helm Manager will not be started"$ERED + exit + fi + + __helm_manager_export_vars + + __start_container $HELM_MANAGER_COMPOSE_DIR "" NODOCKERARGS 1 $HELM_MANAGER_APP_NAME + + __check_service_start $HELM_MANAGER_APP_NAME $HELMMANAGER_SERVICE_PATH$HELM_MANAGER_ALIVE_URL + fi + echo "" +} + +# Excute a curl cmd towards the helm manager. +# args: GET +# args: POST +# args: POST3 +__execute_curl_to_helmmanger() { + TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S") + echo "(${BASH_LINENO[0]}) - ${TIMESTAMP}: ${FUNCNAME[0]}" $@ >> $HTTPLOG + proxyflag="" + if [ ! -z "$KUBE_PROXY_PATH" ]; then + if [ $KUBE_PROXY_HTTPX == "http" ]; then + proxyflag=" --proxy $KUBE_PROXY_PATH" + else + proxyflag=" --proxy-insecure --proxy $KUBE_PROXY_PATH" + fi + fi + if [ $1 == "GET" ]; then + curlstring="curl -skw %{http_code} $proxyflag $HELMMANAGER_SERVICE_PATH$2" + elif [ $1 == "POST" ]; then + curlstring="curl -skw %{http_code} $proxyflag $HELMMANAGER_SERVICE_PATH$2 -X POST --data-binary @$3 -H Content-Type:application/json" + elif [ $1 == "POST1_2" ]; then + curlstring="curl -skw %{http_code} $proxyflag $HELMMANAGER_SERVICE_PATH$2 -X POST -F $3=<$4 -F $5=@$6 -F $7=@$8 " + elif [ $1 == "DELETE" ]; then + curlstring="curl -skw %{http_code} $proxyflag $HELMMANAGER_SERVICE_PATH$2 -X DELETE" + else + echo " Unknown operation $1" >> $HTTPLOG + echo "000" + return 1 + fi + echo " CMD: $curlstring" >> $HTTPLOG + res="$($curlstring)" + retcode=$? + echo " RESP: $res" >> $HTTPLOG + if [ $retcode -ne 0 ]; then + echo "000" + return 1 + fi + echo $res + return 0 +} + +# API Test function: GET ​/helm/charts +# args: [ EMPTY | ( )+ ] +# (Function for test scripts) +helm_manager_api_get_charts() { + __log_test_start $@ + + error_params=1 + variablecount=$(($#-1)) + if [ $# -eq 1 ]; then + error_params=0 + elif [ $# -eq 2 ] && [ $2 == "EMPTY" ]; then + error_params=0 + elif [ $(($variablecount%5)) -eq 0 ]; then + error_params=0 + fi + + + if [ $error_params -eq 1 ]; then + __print_err "" $@ + return 1 + fi + + query="/helm/charts" + res="$(__execute_curl_to_helmmanger GET $query)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + if [ $# -gt 1 ]; then + body=${res:0:${#res}-3} + shift + if [ $# -eq 1 ]; then + targetJson='{"charts":[]}' + else + targetJson='{"charts":[' + arr=(${@}) + for ((i=0; i<$#; i=i+5)); do + if [ "$i" -gt 0 ]; then + targetJson=$targetJson"," + fi + chart_version=${arr[$i+2]} + if [ $chart_version == "DEFAULT-VERSION" ]; then + chart_version="0.1.0" + fi + targetJson=$targetJson'{"releaseName":"'${arr[$i+3]}'","chartId":{"name":"'${arr[$i+1]}'","version":"'0.1.0'"},"namespace":"'${arr[$i+4]}'","repository":{"repoName":"'${arr[$i+0]}'","protocol":null,"address":null,"port":null,"userName":null,"password":null},"overrideParams":null}' + done + targetJson=$targetJson']}' + fi + echo " TARGET JSON: $targetJson" >> $HTTPLOG + res=$(python3 ../common/compare_json.py "$targetJson" "$body") + + if [ $res -ne 0 ]; then + __log_test_fail_body + return 1 + fi + fi + + __log_test_pass + return 0 +} + +# API Test function: POST ​/helm/repo - add repo +# args: +# (Function for test scripts) +helm_manager_api_post_repo() { + __log_test_start $@ + + if [ $# -ne 5 ]; then + __print_err " " $@ + return 1 + fi + + query="/helm/repo" + file="./tmp/cm-repo.json" + file_data='{"address" : "'$4'","repoName": "'$2'","protocol": "'$3'","port": "'$5'"}' + echo $file_data > $file + echo " FILE: $file_data" >> $HTTPLOG + res="$(__execute_curl_to_helmmanger POST $query $file)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __log_test_pass + return 0 +} + +# API Test function: POST /helm/onboard/chart - onboard chart +# args: +# (Function for test scripts) +helm_manager_api_post_onboard_chart() { + __log_test_start $@ + + if [ $# -ne 6 ]; then + __print_err " " $@ + return 1 + fi + + query="/helm/onboard/chart" + file="./tmp/chart.json" + chart_version=$4 + if [ $chart_version == "DEFAULT-VERSION" ]; then + chart_version="0.1.0" + fi + file_data='{"chartId":{"name":"'$3'","version":"'$chart_version'"},"namespace":"'$6'","repository":{"repoName":"'$2'"},"releaseName":"'$5'"}' + echo $file_data > $file + echo " FILE - ($file): $file_data" >> $HTTPLOG + file2="./tmp/override.yaml" + echo "" >> $file2 + file3="$TESTENV_TEMP_FILES/"$3"-"$chart_version".tgz" + res="$(__execute_curl_to_helmmanger POST1_2 $query info $file values $file2 chart $file3)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __log_test_pass + return 0 +} + +# API Test function: POST /helm/install - install chart +# args: +# (Function for test scripts) +helm_manager_api_post_install_chart() { + __log_test_start $@ + + if [ $# -ne 3 ]; then + __print_err " " $@ + return 1 + fi + + query="/helm/install" + file="./tmp/app-installation.json" + chart_version=$3 + if [ $chart_version == "DEFAULT-VERSION" ]; then + chart_version="0.1.0" + fi + file_data='{"name": "'$2'","version": "'$chart_version'"}' + echo $file_data > $file + echo " FILE - ($file): $file_data" >> $HTTPLOG + res="$(__execute_curl_to_helmmanger POST $query $file)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __log_test_pass + return 0 +} + +# API Test function: DELETE /helm/uninstall - uninstall chart +# args: +# (Function for test scripts) +helm_manager_api_uninstall_chart() { + __log_test_start $@ + + if [ $# -ne 3 ]; then + __print_err " " $@ + return 1 + fi + + chart_version=$3 + if [ $chart_version == "DEFAULT-VERSION" ]; then + chart_version="0.1.0" + fi + query="/helm/uninstall/$2/$chart_version" + res="$(__execute_curl_to_helmmanger DELETE $query)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __log_test_pass + return 0 +} + +# API Test function: DELETE /helm/chart - delete chart +# args: +# (Function for test scripts) +helm_manager_api_delete_chart() { + __log_test_start $@ + + if [ $# -ne 3 ]; then + __print_err " " $@ + return 1 + fi + + chart_version=$3 + if [ $chart_version == "DEFAULT-VERSION" ]; then + chart_version="0.1.0" + fi + query="/helm/chart/$2/$chart_version" + res="$(__execute_curl_to_helmmanger DELETE $query)" + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __log_test_pass + return 0 +} + +# Config function: Add repo in helm manager by helm using exec +# args: +# (Function for test scripts) +helm_manager_api_exec_add_repo() { + __log_conf_start $@ + + if [ $# -ne 2 ]; then + __print_err " " $@ + return 1 + fi + + if [ $RUNMODE == "DOCKER" ]; then + retmsg=$(docker exec -it $HELM_MANAGER_APP_NAME helm repo add $1 $2) + retcode=$? + if [ $retcode -ne 0 ]; then + __log_conf_fail_general " Cannot add repo to helm, return code: $retcode, msg: $retmsg" + return 1 + fi + else + retmsg=$(kubectl exec -it $HELM_MANAGER_APP_NAME -n $KUBE_NONRTRIC_NAMESPACE -- helm repo add $1 $2) + retcode=$? + if [ $retcode -ne 0 ]; then + __log_conf_fail_general " Cannot add repo to helm, return code: $retcode, msg: $retmsg" + return 1 + fi + fi + __log_conf_ok + return 0 +} + diff --git a/test/common/httpproxy_api_functions.sh b/test/common/httpproxy_api_functions.sh index af11f146..c417d427 100644 --- a/test/common/httpproxy_api_functions.sh +++ b/test/common/httpproxy_api_functions.sh @@ -118,6 +118,12 @@ __HTTPPROXY_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__HTTPPROXY_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to the http proxy diff --git a/test/common/ics_api_functions.sh b/test/common/ics_api_functions.sh index df2de4f6..0e875171 100644 --- a/test/common/ics_api_functions.sh +++ b/test/common/ics_api_functions.sh @@ -103,6 +103,12 @@ __ICS_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__ICS_test_requirements() { + : +} + ####################################################### diff --git a/test/common/kafkapc_api_functions.sh b/test/common/kafkapc_api_functions.sh index 002657c8..4b15641e 100644 --- a/test/common/kafkapc_api_functions.sh +++ b/test/common/kafkapc_api_functions.sh @@ -119,6 +119,12 @@ __KAFKAPC_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__KAFKAPC_test_requirements() { + : +} + ####################################################### ####################################################### diff --git a/test/common/kubeproxy_api_functions.sh b/test/common/kubeproxy_api_functions.sh index eb4600cc..38aeb212 100644 --- a/test/common/kubeproxy_api_functions.sh +++ b/test/common/kubeproxy_api_functions.sh @@ -119,6 +119,12 @@ __KUBEPROXY_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__KUBEPROXY_test_requirements() { + : +} + ####################################################### ## Access to Kube http proxy diff --git a/test/common/localhelm_api_functions.sh b/test/common/localhelm_api_functions.sh new file mode 100644 index 00000000..c7a6d3da --- /dev/null +++ b/test/common/localhelm_api_functions.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +# This is a script that contains function to handle helm on localhost + + +################ Test engine functions ################ + +# Create the image var used during the test +# arg: (selects staging, snapshot, release etc) +# is present only for images with staging, snapshot,release tags +__LOCALHELM_imagesetup() { + : +} + +# Pull image from remote repo or use locally built image +# arg: +# Shall be used for images allowing overriding. For example use a local image when test is started to use released images +# Shall be used for images that does not allow overriding +# Both var may contain: 'remote', 'remote-remove' or 'local' +__LOCALHELM_imagepull() { + : +} + +# Build image (only for simulator or interfaces stubs owned by the test environment) +# arg: (selects staging, snapshot, release etc) +# is present only for images with staging, snapshot,release tags +__LOCALHELM_imagebuild() { + : +} + +# Generate a string for each included image using the app display name and a docker images format string +# If a custom image repo is used then also the source image from the local repo is listed +# arg: +__LOCALHELM_image_data() { + : +} + +# Scale kubernetes resources to zero +# All resources shall be ordered to be scaled to 0, if relevant. If not relevant to scale, then do no action. +# This function is called for apps fully managed by the test script +__LOCALHELM_kube_scale_zero() { + : +} + +# Scale kubernetes resources to zero and wait until this has been accomplished, if relevant. If not relevant to scale, then do no action. +# This function is called for prestarted apps not managed by the test script. +__LOCALHELM_kube_scale_zero_and_wait() { + : +} + +# Delete all kube resouces for the app +# This function is called for apps managed by the test script. +__LOCALHELM_kube_delete_all() { + : +} + +# Store docker logs +# This function is called for apps managed by the test script. +# args: +__LOCALHELM_store_docker_logs() { + : +} + +# Initial setup of protocol, host and ports +# This function is called for apps managed by the test script. +# args: - +__LOCALHELM_initial_setup() { + : +} + +# Set app short-name, app name and namespace for logging runtime statistics of kubernets pods or docker containers +# For docker, the namespace shall be excluded +# This function is called for apps managed by the test script as well as for prestarted apps. +# args: - +__LOCALHELM_statisics_setup() { + : +} + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__LOCALHELM_test_requirements() { + tmp=$(which helm) + if [ $? -ne 0 ]; then + echo $RED" Helm3 is required for running this test. Pls install helm3" + exit 1 + fi + tmp_version=$(helm version | grep 'v3') + if [ -z "$tmp_version" ]; then + echo $RED" Helm3 is required for running this test. Pls install helm3" + exit 1 + fi +} + +####################################################### + + +# Create a dummy helmchart +# arg: +localhelm_create_test_chart() { + __log_conf_start $@ + if [ $# -ne 1 ]; then + __print_err "" $@ + return 1 + fi + if [[ "$1" == *"/"* ]]; then + echo -e $RED"Chart name cannot contain '/'" + __log_conf_fail_general + return 1 + fi + helm create $TESTENV_TEMP_FILES/$1 | indent1 + if [ $? -ne 0 ]; then + __log_conf_fail_general + return 1 + fi + __log_conf_ok + return 0 +} + +# Package a created helmchart +# arg: +localhelm_package_test_chart() { + __log_conf_start $@ + if [ $# -ne 1 ]; then + __print_err "" $@ + return 1 + fi + if [[ "$1" == *"/"* ]]; then + echo -e $RED"Chart name cannot contain '/'" + __log_conf_fail_general + return 1 + fi + helm package -d $TESTENV_TEMP_FILES $TESTENV_TEMP_FILES/$1 | indent1 + if [ $? -ne 0 ]; then + __log_conf_fail_general + return 1 + fi + __log_conf_ok + return 0 +} + +# Check if a release is installed +# arg: INSTALLED|NOTINSTALLED +localhelm_installed_chart_release() { + __log_test_start $@ + if [ $# -ne 3 ]; then + __print_err "INSTALLED|NOTINSTALLED " $@ + return 1 + fi + if [ $1 != "INSTALLED" ] && [ $1 != "NOTINSTALLED" ]; then + __print_err "INSTALLED|NOTINSTALLED " $@ + return 1 + fi + + filter="helm ls -n $3 --filter ^$2" + res=$($filter -q) + if [ $? -ne 0 ]; then + __log_test_fail_general "Failed to list helm releases" + return 1 + fi + if [ $1 == "INSTALLED" ]; then + if [ "$res" != $2 ]; then + echo -e "$RED Release $2 does not exists $ERED" + __log_test_fail_general + return 1 + fi + elif [ $1 == "NOTINSTALLED" ]; then + if [ "$res" == $2 ]; then + __log_test_fail_general "Release $2 exists" + return 1 + fi + fi + echo " Currently installed releases in namespace $3" + helm ls -n $3 | indent2 + __log_test_pass + return 0 +} diff --git a/test/common/mr_api_functions.sh b/test/common/mr_api_functions.sh index 3e00ec37..122b4124 100755 --- a/test/common/mr_api_functions.sh +++ b/test/common/mr_api_functions.sh @@ -217,6 +217,18 @@ __DMAAPMR_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__MR_test_requirements() { + : +} + +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__DMAAPMR_test_requirements() { + : +} + ####################################################### # Description of port mappings when running MR-STUB only or MR-STUB + MESSAGE-ROUTER diff --git a/test/common/ngw_api_functions.sh b/test/common/ngw_api_functions.sh index 9e29278c..bb37799b 100644 --- a/test/common/ngw_api_functions.sh +++ b/test/common/ngw_api_functions.sh @@ -104,6 +104,12 @@ __NGW_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__NGW_test_requirements() { + : +} + ####################################################### diff --git a/test/common/pa_api_functions.sh b/test/common/pa_api_functions.sh index 7c917051..9076bab3 100644 --- a/test/common/pa_api_functions.sh +++ b/test/common/pa_api_functions.sh @@ -1,7 +1,7 @@ #!/bin/bash # ============LICENSE_START=============================================== -# Copyright (C) 2020 Nordix Foundation. All rights reserved. +# Copyright (C) 2021 Nordix Foundation. 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. @@ -103,6 +103,12 @@ __PA_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__PA_test_requirements() { + : +} + ####################################################### @@ -352,6 +358,8 @@ start_policy_agent() { __check_service_start $POLICY_AGENT_APP_NAME $PA_SERVICE_PATH$POLICY_AGENT_ALIVE_URL fi + + __collect_endpoint_stats_image_info "PMS" $POLICY_AGENT_IMAGE echo "" return 0 } @@ -818,7 +826,7 @@ api_get_policies() { fi fi fi - + __collect_endpoint_stats "PMS" 00 "GET" $PMS_API_PREFIX"/v2/policy-instances" $status __log_test_pass return 0 @@ -900,6 +908,7 @@ api_get_policy() { fi fi + __collect_endpoint_stats "PMS" 01 "GET" $PMS_API_PREFIX"/v2/policies/{policy_id}" $status __log_test_pass return 0 } @@ -988,11 +997,11 @@ api_put_policy() { __log_test_fail_status_code $1 $status return 1 fi - let pid=$pid+1 let count=$count+1 echo -ne " Executed "$count"("$max")${SAMELINE}" done + __collect_endpoint_stats "PMS" 02 "PUT" $PMS_API_PREFIX"/v2/policies" $status $max echo "" __log_test_pass @@ -1107,6 +1116,7 @@ api_put_policy_batch() { let count=$count+1 echo -ne " Accepted(batch) "$count"("$max")${SAMELINE}" done + __collect_endpoint_stats "PMS" 02 "PUT" $PMS_API_PREFIX"/v2/policies" $1 $max echo "" @@ -1218,6 +1228,7 @@ api_put_policy_parallel() { fi done if [ -z $msg ]; then + __collect_endpoint_stats "PMS" 02 "PUT" $PMS_API_PREFIX"/v2/policies" $resp_code $(($count*$num_rics)) __log_test_pass " $(($count*$num_rics)) policy request(s) executed" return 0 fi @@ -1261,10 +1272,12 @@ api_delete_policy() { __log_test_fail_status_code $1 $status return 1 fi + let pid=$pid+1 let count=$count+1 echo -ne " Executed "$count"("$max")${SAMELINE}" done + __collect_endpoint_stats "PMS" 03 "DELETE" $PMS_API_PREFIX"/v2/policies/{policy_id}" $status $max echo "" __log_test_pass @@ -1331,6 +1344,7 @@ api_delete_policy_batch() { let count=$count+1 echo -ne " Deleted(batch) "$count"("$max")${SAMELINE}" done + __collect_endpoint_stats "PMS" 03 "DELETE" $PMS_API_PREFIX"/v2/policies/{policy_id}" $1 $max echo "" @@ -1407,6 +1421,7 @@ api_delete_policy_parallel() { fi done if [ -z $msg ]; then + __collect_endpoint_stats "PMS" 03 "DELETE" $PMS_API_PREFIX"/v2/policies/{policy_id}" $resp_code $(($count*$num_rics)) __log_test_pass " $(($count*$num_rics)) policy request(s) executed" return 0 fi @@ -1506,6 +1521,7 @@ api_get_policy_ids() { fi fi + __collect_endpoint_stats "PMS" 04 "GET" $PMS_API_PREFIX"/v2/policies" $status __log_test_pass return 0 } @@ -1550,6 +1566,7 @@ api_get_policy_type() { fi fi + __collect_endpoint_stats "PMS" 05 "GET" $PMS_API_PREFIX"/v2/policy-types/{policyTypeId}" $status __log_test_pass return 0 } @@ -1593,6 +1610,7 @@ api_get_policy_schema() { fi fi + __collect_endpoint_stats "PMS" 06 "GET" $PMS_API_PREFIX"/v2/policy_schema" $status __log_test_pass return 0 } @@ -1660,30 +1678,32 @@ api_get_policy_schemas() { fi fi + __collect_endpoint_stats "PMS" 07 "GET" $PMS_API_PREFIX"/v2/policy-schemas" $status __log_test_pass return 0 } # API Test function: GET /policy_status and V2 GET /policies/{policy_id}/status -# arg: (STD|STD2 |EMPTY [|EMPTY])|(OSC ) +# arg: [ (STD|STD2 |EMPTY [|EMPTY])|(OSC ) ] # (Function for test scripts) api_get_policy_status() { __log_test_start $@ - if [ $# -lt 4 ] || [ $# -gt 5 ]; then - __print_err " (STD |EMPTY [|EMPTY])|(OSC )" $@ + if [ $# -lt 2 ] || [ $# -gt 5 ]; then + __print_err " [(STD |EMPTY [|EMPTY])|(OSC )]" $@ return 1 fi targetJson="" - - if [ $3 == "STD" ]; then + if [ $# -eq 2 ]; then + : + elif [ "$3" == "STD" ]; then targetJson="{\"enforceStatus\":\"$4\"" if [ $# -eq 5 ]; then targetJson=$targetJson",\"reason\":\"$5\"" fi targetJson=$targetJson"}" - elif [ $3 == "STD2" ]; then + elif [ "$3" == "STD2" ]; then if [ $4 == "EMPTY" ]; then targetJson="{\"enforceStatus\":\"\"" else @@ -1697,7 +1717,7 @@ api_get_policy_status() { fi fi targetJson=$targetJson"}" - elif [ $3 == "OSC" ]; then + elif [ "$3" == "OSC" ]; then targetJson="{\"instance_status\":\"$4\"" if [ $# -eq 5 ]; then targetJson=$targetJson",\"has_been_deleted\":\"$5\"" @@ -1722,16 +1742,17 @@ api_get_policy_status() { __log_test_fail_status_code $1 $status return 1 fi + if [ $# -gt 2 ]; then + echo "TARGET JSON: $targetJson" >> $HTTPLOG + body=${res:0:${#res}-3} + res=$(python3 ../common/compare_json.py "$targetJson" "$body") - echo "TARGET JSON: $targetJson" >> $HTTPLOG - body=${res:0:${#res}-3} - res=$(python3 ../common/compare_json.py "$targetJson" "$body") - - if [ $res -ne 0 ]; then - __log_test_fail_body - return 1 + if [ $res -ne 0 ]; then + __log_test_fail_body + return 1 + fi fi - + __collect_endpoint_stats "PMS" 08 "GET" $PMS_API_PREFIX"/v2/policies/{policy_id}/status" $status __log_test_pass return 0 } @@ -1800,6 +1821,7 @@ api_get_policy_types() { fi fi + __collect_endpoint_stats "PMS" 09 "GET" $PMS_API_PREFIX"/v2/policy-types" $status __log_test_pass return 0 } @@ -1830,6 +1852,33 @@ api_get_status() { return 1 fi + __collect_endpoint_stats "PMS" 10 "GET" $PMS_API_PREFIX"/v2/status" $status + __log_test_pass + return 0 +} + +# API Test function: GET /status (root) without api prefix +# args: +# (Function for test scripts) +api_get_status_root() { + __log_test_start $@ + if [ $# -ne 1 ]; then + __print_err "" $@ + return 1 + fi + query="/status" + TMP_PREFIX=$PMS_API_PREFIX + PMS_API_PREFIX="" + res="$(__do_curl_to_api PA GET $query)" + PMS_API_PREFIX=$TMP_PREFIX + status=${res:${#res}-3} + + if [ $status -ne $1 ]; then + __log_test_fail_status_code $1 $status + return 1 + fi + + __collect_endpoint_stats "PMS" 19 "GET" "/status" $status __log_test_pass return 0 } @@ -1916,6 +1965,8 @@ api_get_ric() { fi fi fi + + __collect_endpoint_stats "PMS" 11 "GET" $PMS_API_PREFIX"/v2/rics/ric" $status __log_test_pass return 0 } @@ -1977,6 +2028,7 @@ api_get_rics() { fi fi + __collect_endpoint_stats "PMS" 12 "GET" $PMS_API_PREFIX"/v2/rics" $status __log_test_pass return 0 } @@ -2013,6 +2065,7 @@ api_put_service() { return 1 fi + __collect_endpoint_stats "PMS" 13 "PUT" $PMS_API_PREFIX"/v2/service" $status __log_test_pass return 0 } @@ -2096,6 +2149,7 @@ api_get_services() { fi fi + __collect_endpoint_stats "PMS" 14 "GET" $PMS_API_PREFIX"/v2/services" $status __log_test_pass return 0 } @@ -2149,6 +2203,7 @@ api_get_service_ids() { return 1 fi + __collect_endpoint_stats "PMS" 14 "GET" $PMS_API_PREFIX"/v2/services" $status __log_test_pass return 0 } @@ -2176,6 +2231,7 @@ api_delete_services() { return 1 fi + __collect_endpoint_stats "PMS" 15 "DELETE" $PMS_API_PREFIX"/v2/services/{serviceId}" $status __log_test_pass return 0 } @@ -2204,6 +2260,7 @@ api_put_services_keepalive() { return 1 fi + __collect_endpoint_stats "PMS" 16 "PUT" $PMS_API_PREFIX"/v2/services/{service_id}/keepalive" $status __log_test_pass return 0 } @@ -2232,7 +2289,9 @@ api_put_configuration() { return 1 fi inputJson=$(< $2) - inputJson="{\"config\":"$inputJson"}" + if [ $RUNMODE == "DOCKER" ]; then #In kube the file already has a header + inputJson="{\"config\":"$inputJson"}" + fi file="./tmp/.config.json" echo $inputJson > $file query="/v2/configuration" @@ -2244,6 +2303,7 @@ api_put_configuration() { return 1 fi + __collect_endpoint_stats "PMS" 17 "PUT" $PMS_API_PREFIX"/v2/configuration" $status __log_test_pass return 0 } @@ -2292,6 +2352,7 @@ api_get_configuration() { fi fi + __collect_endpoint_stats "PMS" 18 "GET" $PMS_API_PREFIX"/v2/configuration" $status __log_test_pass return 0 } diff --git a/test/common/prodstub_api_functions.sh b/test/common/prodstub_api_functions.sh index f792d697..b3e3dea7 100644 --- a/test/common/prodstub_api_functions.sh +++ b/test/common/prodstub_api_functions.sh @@ -119,6 +119,12 @@ __PRODSTUB_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__PRODSTUB_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to the Prod stub sim @@ -192,13 +198,13 @@ start_prod_stub() { retcode_p=$? if [ $retcode_i -ne 0 ] && [ $retcode_p -ne 0 ]; then - echo -e $RED"The $ICS_APP_NAME app is not included as managed nor prestarted in this test script"$ERED - echo -e $RED"The $ICS_APP_NAME will not be started"$ERED + echo -e $RED"The $PROD_STUB_APP_NAME app is not included as managed nor prestarted in this test script"$ERED + echo -e $RED"The $PROD_STUB_APP_NAME will not be started"$ERED exit fi if [ $retcode_i -eq 0 ] && [ $retcode_p -eq 0 ]; then - echo -e $RED"The $ICS_APP_NAME app is included both as managed and prestarted in this test script"$ERED - echo -e $RED"The $ICS_APP_NAME will not be started"$ERED + echo -e $RED"The $PROD_STUB_APP_NAME app is included both as managed and prestarted in this test script"$ERED + echo -e $RED"The $PROD_STUB_APP_NAME will not be started"$ERED exit fi diff --git a/test/common/pvccleaner_api_functions.sh b/test/common/pvccleaner_api_functions.sh index 5d37bd0d..feb44401 100644 --- a/test/common/pvccleaner_api_functions.sh +++ b/test/common/pvccleaner_api_functions.sh @@ -98,6 +98,12 @@ __PVCCLEANER_statisics_setup() { echo "" } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__PVCCLEANER_test_requirements() { + : +} + ####################################################### # This is a system app, all usage in testcase_common.sh \ No newline at end of file diff --git a/test/common/rc_api_functions.sh b/test/common/rc_api_functions.sh index 3766d191..b17b6bf9 100644 --- a/test/common/rc_api_functions.sh +++ b/test/common/rc_api_functions.sh @@ -34,7 +34,7 @@ __RC_imagesetup() { # Shall be used for images that does not allow overriding # Both arg var may contain: 'remote', 'remote-remove' or 'local' __RC_imagepull() { - __check_and_pull_image $1 "$c" $RAPP_CAT_APP_NAME RAPP_CAT_IMAGE + __check_and_pull_image $1 "$RAPP_CAT_DISPLAY_NAME" $RAPP_CAT_APP_NAME RAPP_CAT_IMAGE } # Generate a string for each included image using the app display name and a docker images format string @@ -96,6 +96,12 @@ __RC_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__RC_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to the Rapp catalogue diff --git a/test/common/ricsim_api_functions.sh b/test/common/ricsim_api_functions.sh index bd526119..f433cad3 100644 --- a/test/common/ricsim_api_functions.sh +++ b/test/common/ricsim_api_functions.sh @@ -116,6 +116,12 @@ __RICSIM_statisics_setup() { done } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__RICSIM_test_requirements() { + : +} + ####################################################### @@ -257,7 +263,6 @@ start_ric_simulators() { done fi else - __check_included_image 'RICSIM' if [ $? -eq 1 ]; then echo -e $RED"The Near-RT RIC Simulator app is not included as managed in this test script"$ERED @@ -281,7 +286,7 @@ start_ric_simulators() { export DOCKER_SIM_NWNAME export RIC_SIM_DISPLAY_NAME - docker_args="--no-recreate --scale $RICSIM_COMPOSE_SERVICE_NAME=$2" + docker_args=" --scale $RICSIM_COMPOSE_SERVICE_NAME=$2" #Create a list of contsiner names #Will be __ diff --git a/test/common/sdnc_api_functions.sh b/test/common/sdnc_api_functions.sh index 3ac0a6c7..68cf9767 100644 --- a/test/common/sdnc_api_functions.sh +++ b/test/common/sdnc_api_functions.sh @@ -120,6 +120,12 @@ __SDNC_statisics_setup() { fi } +# Check application requirements, e.g. helm, the the test needs. Exit 1 if req not satisfied +# args: - +__SDNC_test_requirements() { + : +} + ####################################################### # Set http as the protocol to use for all communication to SDNC diff --git a/test/common/test_env-onap-guilin.sh b/test/common/test_env-onap-guilin.sh index 0fdb0652..012716b8 100755 --- a/test/common/test_env-onap-guilin.sh +++ b/test/common/test_env-onap-guilin.sh @@ -188,6 +188,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features MR_DMAAP_APP_NAME="message-router" # Name for the Dmaap MR MR_STUB_APP_NAME="mr-stub" # Name of the MR stub diff --git a/test/common/test_env-onap-honolulu.sh b/test/common/test_env-onap-honolulu.sh index efb54251..c9643a89 100755 --- a/test/common/test_env-onap-honolulu.sh +++ b/test/common/test_env-onap-honolulu.sh @@ -212,6 +212,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features ICS_APP_NAME="informationservice" # Name for ICS container ICS_DISPLAY_NAME="Enrichment Coordinator Service" # Display name for ICS container diff --git a/test/common/test_env-onap-istanbul.sh b/test/common/test_env-onap-istanbul.sh index 9d13a815..a1f59f58 100644 --- a/test/common/test_env-onap-istanbul.sh +++ b/test/common/test_env-onap-istanbul.sh @@ -69,17 +69,17 @@ NEXUS_RELEASE_REPO_ONAP=$NEXUS_RELEASE_REPO # Policy Agent image and tags POLICY_AGENT_IMAGE_BASE="onap/ccsdk-oran-a1policymanagementservice" -POLICY_AGENT_IMAGE_TAG_LOCAL="1.2.4-SNAPSHOT" -POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="1.2.4-SNAPSHOT" -POLICY_AGENT_IMAGE_TAG_REMOTE="1.2.4-STAGING-latest" #Will use snapshot repo -POLICY_AGENT_IMAGE_TAG_REMOTE_RELEASE="1.2.3" +POLICY_AGENT_IMAGE_TAG_LOCAL="1.2.6-SNAPSHOT" +POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="1.2.6-SNAPSHOT" +POLICY_AGENT_IMAGE_TAG_REMOTE="1.2.6-STAGING-latest" #Will use snapshot repo +POLICY_AGENT_IMAGE_TAG_REMOTE_RELEASE="1.2.5" # SDNC A1 Controller remote image and tag SDNC_A1_CONTROLLER_IMAGE_BASE="onap/sdnc-image" -SDNC_A1_CONTROLLER_IMAGE_TAG_LOCAL="2.2.1-SNAPSHOT" ###CHECK THIS -SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_SNAPSHOT="2.2.1-STAGING-latest" -SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE="2.2.1-STAGING-latest" #Will use snapshot repo -SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE="2.2.1" +SDNC_A1_CONTROLLER_IMAGE_TAG_LOCAL="2.2.5-SNAPSHOT" ###CHECK THIS +SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_SNAPSHOT="2.2.5-STAGING-latest" +SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE="2.2.5-STAGING-latest" #Will use snapshot repo +SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE="2.2.4" #SDNC DB remote image and tag #The DB is part of SDNC so handled in the same way as SDNC @@ -215,6 +215,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features ICS_APP_NAME="informationservice" # Name for ICS container ICS_DISPLAY_NAME="Enrichment Coordinator Service" # Display name for ICS container diff --git a/test/common/test_env-oran-cherry.sh b/test/common/test_env-oran-cherry.sh index fbf13f62..d794e693 100755 --- a/test/common/test_env-oran-cherry.sh +++ b/test/common/test_env-oran-cherry.sh @@ -215,6 +215,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features ICS_APP_NAME="informationservice" # Name for ICS container ICS_DISPLAY_NAME="Enrichment Coordinator Service" # Display name for ICS container diff --git a/test/common/test_env-oran-d-release.sh b/test/common/test_env-oran-d-release.sh index 51b11895..a4f725c5 100755 --- a/test/common/test_env-oran-d-release.sh +++ b/test/common/test_env-oran-d-release.sh @@ -234,6 +234,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features ICS_APP_NAME="informationservice" # Name for ICS container ICS_DISPLAY_NAME="Enrichment Coordinator Service" # Display name for ICS container diff --git a/test/common/test_env-oran-e-release.sh b/test/common/test_env-oran-e-release.sh index 65dd0afc..4523c4df 100755 --- a/test/common/test_env-oran-e-release.sh +++ b/test/common/test_env-oran-e-release.sh @@ -59,18 +59,18 @@ NEXUS_RELEASE_REPO_ORAN=$NEXUS_RELEASE_REPO # Policy Agent base image and tags -POLICY_AGENT_IMAGE_BASE="o-ran-sc/nonrtric-policy-agent" -POLICY_AGENT_IMAGE_TAG_LOCAL="2.3.0-SNAPSHOT" -POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="2.3.0-SNAPSHOT" -POLICY_AGENT_IMAGE_TAG_REMOTE="2.3.0" -POLICY_AGENT_IMAGE_TAG_REMOTE_RELEASE="2.3.0" +POLICY_AGENT_IMAGE_BASE="o-ran-sc/nonrtric-a1-policy-management-service" +POLICY_AGENT_IMAGE_TAG_LOCAL="2.3.1-SNAPSHOT" +POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="2.3.1-SNAPSHOT" +POLICY_AGENT_IMAGE_TAG_REMOTE="2.3.1" +POLICY_AGENT_IMAGE_TAG_REMOTE_RELEASE="2.3.1" # ICS image and tags ICS_IMAGE_BASE="o-ran-sc/nonrtric-information-coordinator-service" -ICS_IMAGE_TAG_LOCAL="1.2.0-SNAPSHOT" -ICS_IMAGE_TAG_REMOTE_SNAPSHOT="1.2.0-SNAPSHOT" -ICS_IMAGE_TAG_REMOTE="1.2.0" -ICS_IMAGE_TAG_REMOTE_RELEASE="1.2.0" +ICS_IMAGE_TAG_LOCAL="1.2.1-SNAPSHOT" +ICS_IMAGE_TAG_REMOTE_SNAPSHOT="1.2.1-SNAPSHOT" +ICS_IMAGE_TAG_REMOTE="1.2.1" +ICS_IMAGE_TAG_REMOTE_RELEASE="1.2.1" #Note: Update var ICS_FEATURE_LEVEL if image version is changed #Control Panel image and tags @@ -83,10 +83,10 @@ CONTROL_PANEL_IMAGE_TAG_REMOTE_RELEASE="2.3.0" # Gateway image and tags NRT_GATEWAY_IMAGE_BASE="o-ran-sc/nonrtric-gateway" -NRT_GATEWAY_IMAGE_TAG_LOCAL="1.1.0-SNAPSHOT" -NRT_GATEWAY_IMAGE_TAG_REMOTE_SNAPSHOT="1.1.0-SNAPSHOT" -NRT_GATEWAY_IMAGE_TAG_REMOTE="1.1.0" -NRT_GATEWAY_IMAGE_TAG_REMOTE_RELEASE="1.1.0" +NRT_GATEWAY_IMAGE_TAG_LOCAL="1.0.0-SNAPSHOT" +NRT_GATEWAY_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.0-SNAPSHOT" +NRT_GATEWAY_IMAGE_TAG_REMOTE="1.0.0" +NRT_GATEWAY_IMAGE_TAG_REMOTE_RELEASE="1.0.0" # SDNC A1 Controller image and tags - Note using released honolulu ONAP image @@ -116,10 +116,10 @@ SDNC_DB_IMAGE_TAG_REMOTE_PROXY="10.5" # RAPP Catalogue image and tags RAPP_CAT_IMAGE_BASE="o-ran-sc/nonrtric-r-app-catalogue" -RAPP_CAT_IMAGE_TAG_LOCAL="1.1.0-SNAPSHOT" -RAPP_CAT_IMAGE_TAG_REMOTE_SNAPSHOT="1.1.0-SNAPSHOT" -RAPP_CAT_IMAGE_TAG_REMOTE="1.1.0" -RAPP_CAT_IMAGE_TAG_REMOTE_RELEASE="1.1.0" +RAPP_CAT_IMAGE_TAG_LOCAL="1.0.2-SNAPSHOT" +RAPP_CAT_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.2-SNAPSHOT" +RAPP_CAT_IMAGE_TAG_REMOTE="1.0.2" +RAPP_CAT_IMAGE_TAG_REMOTE_RELEASE="1.0.2" # Near RT RIC Simulator image and tags - same version as cherry @@ -131,17 +131,24 @@ RIC_SIM_IMAGE_TAG_REMOTE_RELEASE="2.2.0" # DMAAP Mediator Service DMAAP_MED_IMAGE_BASE="o-ran-sc/nonrtric-dmaap-mediator-producer" -DMAAP_MED_IMAGE_TAG_LOCAL="1.0.0-SNAPSHOT" -DMAAP_MED_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.0-SNAPSHOT" -DMAAP_MED_IMAGE_TAG_REMOTE="1.0.0" -DMAAP_MED_IMAGE_TAG_REMOTE_RELEASE="1.0.0" +DMAAP_MED_IMAGE_TAG_LOCAL="1.0.1-SNAPSHOT" +DMAAP_MED_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.1-SNAPSHOT" +DMAAP_MED_IMAGE_TAG_REMOTE="1.0.1" +DMAAP_MED_IMAGE_TAG_REMOTE_RELEASE="1.0.1" # DMAAP Adapter Service DMAAP_ADP_IMAGE_BASE="o-ran-sc/nonrtric-dmaap-adaptor" -DMAAP_ADP_IMAGE_TAG_LOCAL="1.0.0-SNAPSHOT" -DMAAP_ADP_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.0-SNAPSHOT" -DMAAP_ADP_IMAGE_TAG_REMOTE="1.0.0" -DMAAP_ADP_IMAGE_TAG_REMOTE_RELEASE="1.0.0" +DMAAP_ADP_IMAGE_TAG_LOCAL="1.0.1-SNAPSHOT" +DMAAP_ADP_IMAGE_TAG_REMOTE_SNAPSHOT="1.0.1-SNAPSHOT" +DMAAP_ADP_IMAGE_TAG_REMOTE="1.0.1" +DMAAP_ADP_IMAGE_TAG_REMOTE_RELEASE="1.0.1" + +# Helm Manager +HELM_MANAGER_IMAGE_BASE="o-ran-sc/nonrtric-helm-manager" +HELM_MANAGER_IMAGE_TAG_LOCAL="1.1.1-SNAPSHOT" +HELM_MANAGER_IMAGE_TAG_REMOTE_SNAPSHOT="1.1.1-SNAPSHOT" +HELM_MANAGER_IMAGE_TAG_REMOTE="1.1.1" +HELM_MANAGER_IMAGE_TAG_REMOTE_RELEASE="1.1.1" #Consul remote image and tag CONSUL_IMAGE_BASE="consul" @@ -207,8 +214,13 @@ KAFKAPC_IMAGE_BASE="kafka-procon" KAFKAPC_IMAGE_TAG_LOCAL="latest" #No local image for pvc cleaner, remote image always used +#PVC Cleaner remote image and tag +CHART_MUS_IMAGE_BASE="ghcr.io/helm/chartmuseum" +CHART_MUS_IMAGE_TAG_REMOTE_OTHER="v0.13.1" +#No local image for chart museum, remote image always used + # List of app short names produced by the project -PROJECT_IMAGES_APP_NAMES="PA ICS CP RC RICSIM NGW DMAAPADP DMAAPMED" # Add SDNC here if oran image is used +PROJECT_IMAGES_APP_NAMES="PA ICS CP RC RICSIM NGW DMAAPADP DMAAPMED HELMMANAGER" # Add SDNC here if oran image is used # List of app short names which images pulled from ORAN ORAN_IMAGES_APP_NAMES="" # Not used @@ -265,6 +277,7 @@ POLICY_AGENT_DATA_MOUNT_PATH="/opt/app/policy-agent/data" # Path in container fo POLICY_AGENT_CONFIG_FILE="application.yaml" # Container config file name POLICY_AGENT_DATA_FILE="application_configuration.json" # Container data file name POLICY_AGENT_CONTAINER_MNT_DIR="/var/policy-management-service" # Mounted dir in the container +PMS_FEATURE_LEVEL="" # Space separated list of features ICS_APP_NAME="informationservice" # Name for ICS container ICS_DISPLAY_NAME="Information Coordinator Service" # Display name for ICS container @@ -527,10 +540,12 @@ DMAAP_MED_ALIVE_URL="/status" # Base path for alive c DMAAP_MED_COMPOSE_DIR="dmaapmed" # Dir in simulator_group for docker-compose #MAAP_MED_CONFIG_MOUNT_PATH="/app" # Internal container path for configuration DMAAP_MED_DATA_MOUNT_PATH="/configs" # Path in container for data file -DMAAP_MED_DATA_FILE="type_config.json" # Container data file name +DMAAP_MED_HOST_DATA_FILE="type_config.json" # Host data file name +DMAAP_MED_CONTR_DATA_FILE="type_config.json" # Container data file name +DMAAP_MED_FEATURE_LEVEL="" # Space separated list of features KAFKAPC_APP_NAME="kafka-procon" # Name for the Kafka procon -KAFKAPC_DISPLAY_NAME="Kafaka Producer/Consumer" +KAFKAPC_DISPLAY_NAME="Kafka Producer/Consumer" KAFKAPC_EXTERNAL_PORT=8096 # Kafka procon container external port (host -> container) KAFKAPC_INTERNAL_PORT=8090 # Kafka procon container internal port (container -> container) KAFKAPC_EXTERNAL_SECURE_PORT=8097 # Kafka procon container external secure port (host -> container) @@ -538,6 +553,28 @@ KAFKAPC_INTERNAL_SECURE_PORT=8091 # Kafka procon containe KAFKAPC_ALIVE_URL="/" # Base path for alive check KAFKAPC_COMPOSE_DIR="kafka-procon" # Dir in simulator_group for docker-compose KAFKAPC_BUILD_DIR="kafka-procon" # Build dir + +CHART_MUS_APP_NAME="chartmuseum" # Name for the chart museum app +CHART_MUS_DISPLAY_NAME="Chart Museum" +CHART_MUS_EXTERNAL_PORT=8201 # chart museum container external port (host -> container) +CHART_MUS_INTERNAL_PORT=8080 # chart museum container internal port (container -> container) +CHART_MUS_ALIVE_URL="/health" # Base path for alive check +CHART_MUS_COMPOSE_DIR="chartmuseum" # Dir in simulator_group for docker-compose +CHART_MUS_CHART_CONTR_CHARTS="/tmp/charts" # Local dir container for charts + +HELM_MANAGER_APP_NAME="helmmanagerservice" # Name for the helm manager app +HELM_MANAGER_DISPLAY_NAME="Helm Manager" +HELM_MANAGER_EXTERNAL_PORT=8211 # helm manager container external port (host -> container) +HELM_MANAGER_INTERNAL_PORT=8083 # helm manager container internal port (container -> container) +HELM_MANAGER_EXTERNAL_SECURE_PORT=8212 # helm manager container external secure port (host -> container) +HELM_MANAGER_INTERNAL_SECURE_PORT=8443 # helm manager container internal secure port (container -> container) +HELM_MANAGER_CLUSTER_ROLE=cluster-admin # Kubernetes cluster role for helm manager +HELM_MANAGER_SA_NAME=helm-manager-sa # Service account name +HELM_MANAGER_ALIVE_URL="/helm/charts" # Base path for alive check +HELM_MANAGER_COMPOSE_DIR="helmmanager" # Dir in simulator_group for docker-compose +HELM_MANAGER_USER="helmadmin" +HELM_MANAGER_PWD="itisasecret" + ######################################## # Setting for common curl-base function ######################################## diff --git a/test/common/testcase_common.sh b/test/common/testcase_common.sh index 0a253913..c9374cf8 100755 --- a/test/common/testcase_common.sh +++ b/test/common/testcase_common.sh @@ -28,7 +28,8 @@ __print_args() { echo " [--ricsim-prefix ] [--use-local-image +] [--use-snapshot-image +]" echo " [--use-staging-image +] [--use-release-image +] [--image-repo ] [--print-stats]" - echo " [--override --pre-clean --gen-stats]" + echo " [--override ] [--pre-clean] [--gen-stats] [--delete-namespaces]" + echo " [--delete-containers] [--endpoint-stats]" } if [ $# -eq 1 ] && [ "$1" == "help" ]; then @@ -60,7 +61,9 @@ if [ $# -eq 1 ] && [ "$1" == "help" ]; then echo "--override - Override setting from the file supplied by --env-file" echo "--pre-clean - Will clean kube resouces when running docker and vice versa" echo "--gen-stats - Collect container/pod runtime statistics" - + echo "--delete-namespaces - Delete kubernetes namespaces before starting tests - but only those created by the test scripts. Kube mode only. Ignored if running with prestarted apps." + echo "--delete-containers - Delete docker containers before starting tests - but only those created by the test scripts. Docker mode only." + echo "--endpoint-stats - Collect endpoint statistics" echo "" echo "List of app short names supported: "$APP_SHORT_NAMES exit 0 @@ -163,18 +166,52 @@ TESTLOGS=$PWD/logs # files in the ./tmp is moved to ./tmp/prev when a new test is started if [ ! -d "tmp" ]; then mkdir tmp + if [ $? -ne 0 ]; then + echo "Cannot create dir for temp files, $PWD/tmp" + echo "Exiting...." + exit 1 + fi fi curdir=$PWD cd tmp if [ $? -ne 0 ]; then echo "Cannot cd to $PWD/tmp" - echo "Dir cannot be created. Exiting...." + echo "Exiting...." + exit 1 fi + +TESTENV_TEMP_FILES=$PWD + if [ ! -d "prev" ]; then mkdir prev + if [ $? -ne 0 ]; then + echo "Cannot create dir for previous temp files, $PWD/prev" + echo "Exiting...." + exit 1 + fi fi + +TMPFILES=$(ls -A | grep -vw prev) +if [ ! -z "$TMPFILES" ]; then + cp -r $TMPFILES prev #Move all temp files to prev dir + if [ $? -ne 0 ]; then + echo "Cannot move temp files in $PWD to previous temp files in, $PWD/prev" + echo "Exiting...." + exit 1 + fi + if [ $(pwd | xargs basename) == "tmp" ]; then #Check that current dir is tmp...for safety + + rm -rf $TMPFILES # Remove all temp files + fi +fi + cd $curdir -mv ./tmp/* ./tmp/prev 2> /dev/null +if [ $? -ne 0 ]; then + echo "Cannot cd to $curdir" + echo "Exiting...." + exit 1 +fi + # Create a http message log for this testcase HTTPLOG=$PWD"/.httplog_"$ATC".txt" @@ -199,6 +236,9 @@ rm $TESTLOGS/$ATC/*.log &> /dev/null rm $TESTLOGS/$ATC/*.txt &> /dev/null rm $TESTLOGS/$ATC/*.json &> /dev/null +#Create result file in the log dir +echo "1" > "$TESTLOGS/$ATC/.result$ATC.txt" + # Log all output from the test case to a TC log TCLOG=$TESTLOGS/$ATC/TC.log exec &> >(tee ${TCLOG}) @@ -215,6 +255,16 @@ PRINT_CURRENT_STATS=0 #Var to control if container/pod runtim statistics shall be collected COLLECT_RUNTIME_STATS=0 +COLLECT_RUNTIME_STATS_PID=0 + +#Var to control if endpoint statistics shall be collected +COLLECT_ENDPOINT_STATS=0 + +#Var to control if namespaces shall be delete before test setup +DELETE_KUBE_NAMESPACES=0 + +#Var to control if containers shall be delete before test setup +DELETE_CONTAINERS=0 #File to keep deviation messages DEVIATION_FILE=".tmp_deviations" @@ -231,8 +281,13 @@ trap_fnc() { } trap trap_fnc ERR -# Trap to kill subprocesses -trap "kill 0" EXIT +# Trap to kill subprocess for stats collection (if running) +trap_fnc2() { + if [ $COLLECT_RUNTIME_STATS_PID -ne 0 ]; then + kill $COLLECT_RUNTIME_STATS_PID + fi +} +trap trap_fnc2 EXIT # Counter for tests TEST_SEQUENCE_NR=1 @@ -347,6 +402,44 @@ __log_conf_ok() { __print_current_stats } +# Function to collect stats on endpoints +# args: [] +__collect_endpoint_stats() { + if [ $COLLECT_ENDPOINT_STATS -eq 0 ]; then + return + fi + ENDPOINT_COUNT=1 + if [ $# -gt 5 ]; then + ENDPOINT_COUNT=$6 + fi + ENDPOINT_STAT_FILE=$TESTLOGS/$ATC/endpoint_$ATC_$1_$2".log" + ENDPOINT_POS=0 + ENDPOINT_NEG=0 + if [ -f $ENDPOINT_STAT_FILE ]; then + ENDPOINT_VAL=$(< $ENDPOINT_STAT_FILE) + ENDPOINT_POS=$(echo $ENDPOINT_VAL | cut -f4 -d ' ' | cut -f1 -d '/') + ENDPOINT_NEG=$(echo $ENDPOINT_VAL | cut -f5 -d ' ' | cut -f1 -d '/') + fi + + if [ $5 -ge 200 ] && [ $5 -lt 300 ]; then + let ENDPOINT_POS=ENDPOINT_POS+$ENDPOINT_COUNT + else + let ENDPOINT_NEG=ENDPOINT_NEG+$ENDPOINT_COUNT + fi + + printf '%-2s %-10s %-45s %-16s %-16s' "#" "$3" "$4" "$ENDPOINT_POS/$ENDPOINT_POS" "$ENDPOINT_NEG/$ENDPOINT_NEG" > $ENDPOINT_STAT_FILE +} + +# Function to collect stats on endpoints +# args: +__collect_endpoint_stats_image_info() { + if [ $COLLECT_ENDPOINT_STATS -eq 0 ]; then + return + fi + ENDPOINT_STAT_FILE=$TESTLOGS/$ATC/imageinfo_$ATC_$1".log" + echo $POLICY_AGENT_IMAGE > $ENDPOINT_STAT_FILE +} + #Var for measuring execution time TCTEST_START=$SECONDS @@ -361,7 +454,7 @@ TC_TIMER_CURRENT_FAILS="" # Then numer of failed test when timer starts. TIMER_MEASUREMENTS=".timer_measurement.txt" echo -e "Activity \t Duration \t Info" > $TIMER_MEASUREMENTS -# If this is set, some images (control by the parameter repo-polcy) will be re-tagged and pushed to this repo before any +# If this is set, some images (controlled by the parameter repo-policy) will be re-tagged and pushed to this repo before any IMAGE_REPO_ADR="" IMAGE_REPO_POLICY="local" CLUSTER_TIME_OUT=0 @@ -679,6 +772,44 @@ while [ $paramerror -eq 0 ] && [ $foundparm -eq 0 ]; do foundparm=0 fi fi + if [ $paramerror -eq 0 ]; then + if [ "$1" == "--delete-namespaces" ]; then + if [ $RUNMODE == "DOCKER" ]; then + DELETE_KUBE_NAMESPACES=0 + echo "Option ignored - Delete namespaces (ignored when running docker)" + else + if [ -z "KUBE_PRESTARTED_IMAGES" ]; then + DELETE_KUBE_NAMESPACES=0 + echo "Option ignored - Delete namespaces (ignored when using prestarted apps)" + else + DELETE_KUBE_NAMESPACES=1 + echo "Option set - Delete namespaces" + fi + fi + shift; + foundparm=0 + fi + fi + if [ $paramerror -eq 0 ]; then + if [ "$1" == "--delete-containers" ]; then + if [ $RUNMODE == "DOCKER" ]; then + DELETE_CONTAINERS=1 + echo "Option set - Delete containers started by previous test(s)" + else + echo "Option ignored - Delete containers (ignored when running kube)" + fi + shift; + foundparm=0 + fi + fi + if [ $paramerror -eq 0 ]; then + if [ "$1" == "--endpoint-stats" ]; then + COLLECT_ENDPOINT_STATS=1 + echo "Option set - Collect endpoint statistics" + shift; + foundparm=0 + fi + fi done echo "" @@ -775,6 +906,10 @@ if [ ! -z "$TMP_APPS" ]; then done echo " Auto-adding system app $padded_iapp Sourcing $file_pointer" . $file_pointer + if [ $? -ne 0 ]; then + echo " Include file $file_pointer contain errors. Exiting..." + exit 1 + fi __added_apps=" $iapp "$__added_apps done else @@ -797,11 +932,15 @@ echo -e $BOLD"Auto adding included apps"$EBOLD padded_iapp=$padded_iapp" " done echo " Auto-adding included app $padded_iapp Sourcing $file_pointer" - . $file_pointer if [ ! -f "$file_pointer" ]; then echo " Include file $file_pointer for app $iapp does not exist" exit 1 fi + . $file_pointer + if [ $? -ne 0 ]; then + echo " Include file $file_pointer contain errors. Exiting..." + exit 1 + fi fi done echo "" @@ -884,6 +1023,8 @@ else exit 1 fi + echo " Node(s) and container runtime config" + kubectl get nodes -o wide | indent2 fi fi @@ -1297,6 +1438,9 @@ setup_testenvironment() { # If the image suffix is none, then the component decides the suffix function_pointer="__"$imagename"_imagesetup" $function_pointer $IMAGE_SUFFIX + + function_pointer="__"$imagename"_test_requirements" + $function_pointer fi done @@ -1334,9 +1478,38 @@ setup_testenvironment() { #Temp var to check for image pull errors IMAGE_ERR=0 - # The following sequence pull the configured images + # Delete namespaces + echo -e $BOLD"Deleting namespaces"$EBOLD + + + if [ "$DELETE_KUBE_NAMESPACES" -eq 1 ]; then + test_env_namespaces=$(kubectl get ns --no-headers -o custom-columns=":metadata.name" -l autotest=engine) #Get list of ns created by the test env + if [ $? -ne 0 ]; then + echo " Cannot get list of namespaces...ignoring delete" + else + for test_env_ns in $test_env_namespaces; do + __kube_delete_namespace $test_env_ns + done + fi + else + echo " Namespace delete option not set" + fi + echo "" + # Delete containers + echo -e $BOLD"Deleting containers"$EBOLD + if [ "$DELETE_CONTAINERS" -eq 1 ]; then + echo " Stopping containers label 'nrttest_app'..." + docker stop $(docker ps -qa --filter "label=nrttest_app") 2> /dev/null + echo " Removing stopped containers..." + docker rm $(docker ps -qa --filter "label=nrttest_app") 2> /dev/null + else + echo " Contatiner delete option not set" + fi + echo "" + + # The following sequence pull the configured images echo -e $BOLD"Pulling configured images, if needed"$EBOLD if [ ! -z "$IMAGE_REPO_ADR" ] && [ $IMAGE_REPO_POLICY == "local" ]; then echo -e $YELLOW" Excluding all remote image check/pull when running with image repo: $IMAGE_REPO_ADR and image policy $IMAGE_REPO_POLICY"$EYELLOW @@ -1547,6 +1720,7 @@ setup_testenvironment() { if [ $COLLECT_RUNTIME_STATS -eq 1 ]; then ../common/genstat.sh $RUNMODE $SECONDS $TESTLOGS/$ATC/stat_data.csv $LOG_STAT_ARGS & + COLLECT_RUNTIME_STATS_PID=$! fi } @@ -1628,6 +1802,7 @@ print_result() { fi #Create file with OK exit code echo "0" > "$AUTOTEST_HOME/.result$ATC.txt" + echo "0" > "$TESTLOGS/$ATC/.result$ATC.txt" else echo -e "One or more tests with status \033[31m\033[1mFAIL\033[0m " echo -e "\033[31m\033[1m ___ _ ___ _ \033[0m" @@ -1724,6 +1899,16 @@ __check_stop_at_error() { if [ $STOP_AT_ERROR -eq 1 ]; then echo -e $RED"Test script configured to stop at first FAIL, taking all logs and stops"$ERED store_logs "STOP_AT_ERROR" + + # Update test suite counter + if [ -f .tmp_tcsuite_fail_ctr ]; then + tmpval=$(< .tmp_tcsuite_fail_ctr) + ((tmpval++)) + echo $tmpval > .tmp_tcsuite_fail_ctr + fi + if [ -f .tmp_tcsuite_fail ]; then + echo " - "$ATC " -- "$TC_ONELINE_DESCR" Execution stopped due to error" >> .tmp_tcsuite_fail + fi exit 1 fi return 0 @@ -2014,7 +2199,7 @@ __kube_delete_all_resources() { namespace=$1 labelname=$2 labelid=$3 - resources="deployments replicaset statefulset services pods configmaps persistentvolumeclaims persistentvolumes" + resources="deployments replicaset statefulset services pods configmaps persistentvolumeclaims persistentvolumes serviceaccounts clusterrolebindings" deleted_resourcetypes="" for restype in $resources; do ns_flag="-n $namespace" @@ -2023,6 +2208,10 @@ __kube_delete_all_resources() { ns_flag="" ns_text="" fi + if [ $restype == "clusterrolebindings" ]; then + ns_flag="" + ns_text="" + fi result=$(kubectl get $restype $ns_flag -o jsonpath='{.items[?(@.metadata.labels.'$labelname'=="'$labelid'")].metadata.name}') if [ $? -eq 0 ] && [ ! -z "$result" ]; then deleted_resourcetypes=$deleted_resourcetypes" "$restype @@ -2093,6 +2282,7 @@ __kube_create_namespace() { echo " Message: $(<./tmp/kubeerr)" return 1 else + kubectl label ns $1 autotest=engine echo -e " Creating namespace $1 $GREEN$BOLD OK $EBOLD$EGREEN" fi else @@ -2101,6 +2291,51 @@ __kube_create_namespace() { return 0 } +# Removes a namespace if it exists +# args: +# (Not for test scripts) +__kube_delete_namespace() { + + #Check if test namespace exists, if so remove it + kubectl get namespace $1 1> /dev/null 2> ./tmp/kubeerr + if [ $? -eq 0 ]; then + echo -ne " Removing namespace "$1 $SAMELINE + kubectl delete namespace $1 1> /dev/null 2> ./tmp/kubeerr + if [ $? -ne 0 ]; then + echo -e " Removing namespace $1 $RED$BOLD FAILED $EBOLD$ERED" + ((RES_CONF_FAIL++)) + echo " Message: $(<./tmp/kubeerr)" + return 1 + else + echo -e " Removing namespace $1 $GREEN$BOLD OK $EBOLD$EGREEN" + fi + else + echo -e " Namespace $1 $GREEN$BOLD does not exist, OK $EBOLD$EGREEN" + fi + return 0 +} + +# Removes a namespace +# args: +# (Not for test scripts) +clean_and_create_namespace() { + __log_conf_start $@ + + if [ $# -ne 1 ]; then + __print_err "" $@ + return 1 + fi + __kube_delete_namespace $1 + if [ $? -ne 0 ]; then + return 1 + fi + __kube_create_namespace $1 + if [ $? -ne 0 ]; then + return 1 + fi + +} + # Find the host ip of an app (using the service resource) # args: # (Not for test scripts) @@ -2344,14 +2579,14 @@ clean_environment() { __clean_kube if [ $PRE_CLEAN -eq 1 ]; then echo " Cleaning docker resouces to free up resources, may take time..." - ../common/clean_docker.sh 2&>1 /dev/null + ../common/clean_docker.sh 2>&1 /dev/null echo "" fi else __clean_containers if [ $PRE_CLEAN -eq 1 ]; then echo " Cleaning kubernetes resouces to free up resources, may take time..." - ../common/clean_kube.sh 2&>1 /dev/null + ../common/clean_kube.sh 2>&1 /dev/null echo "" fi fi @@ -2399,6 +2634,7 @@ __print_err() { echo -e $RED" Got: "${FUNCNAME[1]} ${@:2} $ERED fi ((RES_CONF_FAIL++)) + __check_stop_at_error } # Function to create the docker network for the test @@ -2454,9 +2690,14 @@ __start_container() { envsubst < $compose_file > "gen_"$compose_file compose_file="gen_"$compose_file + if [ $DOCKER_COMPOSE_VERION == "V1" ]; then + docker_compose_cmd="docker-compose" + else + docker_compose_cmd="docker compose" + fi if [ "$compose_args" == "NODOCKERARGS" ]; then - docker-compose -f $compose_file up -d &> .dockererr + $docker_compose_cmd -f $compose_file up -d &> .dockererr if [ $? -ne 0 ]; then echo -e $RED"Problem to launch container(s) with docker-compose"$ERED cat .dockererr @@ -2464,7 +2705,7 @@ __start_container() { exit 1 fi else - docker-compose -f $compose_file up -d $compose_args &> .dockererr + $docker_compose_cmd -f $compose_file up -d $compose_args &> .dockererr if [ $? -ne 0 ]; then echo -e $RED"Problem to launch container(s) with docker-compose"$ERED cat .dockererr @@ -2757,25 +2998,31 @@ __var_test() { __check_stop_at_error return fi - elif [ $4 = "=" ] && [ "$result" -eq $5 ]; then + elif [ "$4" == "=" ] && [ "$result" -eq $5 ]; then ((RES_PASS++)) echo -e " Result=${result} after ${duration} seconds${SAMELINE}" echo -e $GREEN" PASS${EGREEN} - Result=${result} after ${duration} seconds" __print_current_stats return - elif [ $4 = ">" ] && [ "$result" -gt $5 ]; then + elif [ "$4" == ">" ] && [ "$result" -gt $5 ]; then ((RES_PASS++)) echo -e " Result=${result} after ${duration} seconds${SAMELINE}" echo -e $GREEN" PASS${EGREEN} - Result=${result} after ${duration} seconds" __print_current_stats return - elif [ $4 = "<" ] && [ "$result" -lt $5 ]; then + elif [ "$4" == "<" ] && [ "$result" -lt $5 ]; then ((RES_PASS++)) echo -e " Result=${result} after ${duration} seconds${SAMELINE}" echo -e $GREEN" PASS${EGREEN} - Result=${result} after ${duration} seconds" __print_current_stats return - elif [ $4 = "contain_str" ] && [[ $result =~ $5 ]]; then + elif [ "$4" == ">=" ] && [ "$result" -ge $5 ]; then + ((RES_PASS++)) + echo -e " Result=${result} after ${duration} seconds${SAMELINE}" + echo -e $GREEN" PASS${EGREEN} - Result=${result} after ${duration} seconds" + __print_current_stats + return + elif [ "$4" == "contain_str" ] && [[ $result =~ $5 ]]; then ((RES_PASS++)) echo -e " Result=${result} after ${duration} seconds${SAMELINE}" echo -e $GREEN" PASS${EGREEN} - Result=${result} after ${duration} seconds" @@ -2817,19 +3064,23 @@ __var_test() { echo -e $RED" FAIL ${ERED}- ${3} ${4} ${5} not reached, result = ${result}" __print_current_stats __check_stop_at_error - elif [ $4 = "=" ] && [ "$result" -eq $5 ]; then + elif [ "$4" == "=" ] && [ "$result" -eq $5 ]; then + ((RES_PASS++)) + echo -e $GREEN" PASS${EGREEN} - Result=${result}" + __print_current_stats + elif [ "$4" == ">" ] && [ "$result" -gt $5 ]; then ((RES_PASS++)) echo -e $GREEN" PASS${EGREEN} - Result=${result}" __print_current_stats - elif [ $4 = ">" ] && [ "$result" -gt $5 ]; then + elif [ "$4" == "<" ] && [ "$result" -lt $5 ]; then ((RES_PASS++)) echo -e $GREEN" PASS${EGREEN} - Result=${result}" __print_current_stats - elif [ $4 = "<" ] && [ "$result" -lt $5 ]; then + elif [ "$4" == ">=" ] && [ "$result" -ge $5 ]; then ((RES_PASS++)) echo -e $GREEN" PASS${EGREEN} - Result=${result}" __print_current_stats - elif [ $4 = "contain_str" ] && [[ $result =~ $5 ]]; then + elif [ "$4" == "contain_str" ] && [[ $result =~ $5 ]]; then ((RES_PASS++)) echo -e $GREEN" PASS${EGREEN} - Result=${result}" __print_current_stats diff --git a/test/common/testengine_config.sh b/test/common/testengine_config.sh index 1048d76c..aed9226f 100644 --- a/test/common/testengine_config.sh +++ b/test/common/testengine_config.sh @@ -18,13 +18,13 @@ # # List of short names for all supported apps, including simulators etc -APP_SHORT_NAMES="PA ICS SDNC CP NGW RC RICSIM HTTPPROXY CBS CONSUL DMAAPMR MR CR PRODSTUB KUBEPROXY DMAAPMED DMAAPADP PVCCLEANER KAFKAPC" +APP_SHORT_NAMES="PA ICS SDNC CP NGW RC RICSIM HTTPPROXY CBS CONSUL DMAAPMR MR CR PRODSTUB KUBEPROXY DMAAPMED DMAAPADP PVCCLEANER KAFKAPC CHARTMUS HELMMANAGER LOCALHELM" # List of available apps that built and released of the project -PROJECT_IMAGES="PA ICS SDNC CP NGW RICSIM RC DMAAPMED DMAAPADP" +PROJECT_IMAGES="PA ICS SDNC CP NGW RICSIM RC DMAAPMED DMAAPADP HELMMANAGER" # List of available apps to override with local or remote staging/snapshot/release image -AVAILABLE_IMAGES_OVERRIDE="PA ICS SDNC CP NGW RICSIM RC DMAAPMED DMAAPADP" +AVAILABLE_IMAGES_OVERRIDE="PA ICS SDNC CP NGW RICSIM RC DMAAPMED DMAAPADP HELMMANAGER" # List of available apps where the image is built by the test environment LOCAL_IMAGE_BUILD="MR CR PRODSTUB KUBEPROXY HTTPPROXY KAFKAPC" diff --git a/test/cr/app/cr.py b/test/cr/app/cr.py index 94ef606d..2066e148 100644 --- a/test/cr/app/cr.py +++ b/test/cr/app/cr.py @@ -48,6 +48,7 @@ HOST_PORT = 2222 # Metrics vars cntr_msg_callbacks=0 +cntr_batch_callbacks=0 cntr_msg_fetched=0 cntr_callbacks={} hosts_set=set() @@ -59,6 +60,7 @@ CALLBACK_TEXT_URL="/callbacks-text/" # Callback for string of text APP_READ_URL="/get-event/" APP_READ_ALL_URL="/get-all-events/" DUMP_ALL_URL="/db" +NULL_URL="/callbacks-null" # Url for ignored callback. Callbacks are not checked, counted or stored MIME_TEXT="text/plain" MIME_JSON="application/json" @@ -200,10 +202,12 @@ def events_write(id): if (id in cntr_callbacks.keys()): cntr_callbacks[id][0] += 1 + cntr_callbacks[id][2] += 1 else: cntr_callbacks[id]=[] cntr_callbacks[id].append(1) cntr_callbacks[id].append(0) + cntr_callbacks[id].append(0) except Exception as e: print(CAUGHT_EXCEPTION+str(e)) @@ -223,6 +227,7 @@ def events_write(id): def events_write_mr(id): global msg_callbacks global cntr_msg_callbacks + global cntr_batch_callbacks storeas=request.args.get('storeas') #If set, store payload as a md5 hascode and dont log the payload #Large payloads will otherwise overload the server @@ -232,6 +237,7 @@ def events_write_mr(id): if (storeas is None): print("raw data: str(request.data): "+str(request.data)) do_delay() + list_data=False try: #if (request.content_type == MIME_JSON): if (MIME_JSON in request.content_type): @@ -239,6 +245,7 @@ def events_write_mr(id): msg_list = json.loads(data) if (storeas is None): print("Payload(json): "+str(msg_list)) + list_data=True else: msg_list=[] print("Payload(content-type="+request.content_type+"). Setting empty json as payload") @@ -249,6 +256,8 @@ def events_write_mr(id): with lock: remote_host_logging(request) + if (list_data): + cntr_batch_callbacks += 1 for msg in msg_list: if (storeas is None): msg=json.loads(msg) @@ -277,6 +286,9 @@ def events_write_mr(id): cntr_callbacks[id]=[] cntr_callbacks[id].append(1) cntr_callbacks[id].append(0) + cntr_callbacks[id].append(0) + if (id in msg_callbacks.keys() and list_data): + cntr_callbacks[id][2] += 1 except Exception as e: print(CAUGHT_EXCEPTION+str(e)) @@ -294,6 +306,7 @@ def events_write_mr(id): def events_write_text(id): global msg_callbacks global cntr_msg_callbacks + global cntr_batch_callbacks storeas=request.args.get('storeas') #If set, store payload as a md5 hascode and dont log the payload #Large payloads will otherwise overload the server @@ -306,26 +319,28 @@ def events_write_text(id): try: msg_list=None + list_data=False if (MIME_JSON in request.content_type): #Json array of strings msg_list=json.loads(request.data) + list_data=True else: data=request.data.decode("utf-8") #Assuming string msg_list=[] msg_list.append(data) + with lock: + cntr_batch_callbacks += 1 + for msg in msg_list: + if (storeas == "md5"): + md5msg={} + print("msg: "+str(msg)) + print("msg (endcode str): "+str(msg.encode('utf-8'))) + md5msg["md5"]=md5(msg.encode('utf-8')).hexdigest() + msg=md5msg + print("msg (data converted to md5 hash): "+str(msg["md5"])) + + if (isinstance(msg, dict)): + msg[TIME_STAMP]=str(datetime.now()) - for msg in msg_list: - if (storeas == "md5"): - md5msg={} - print("msg: "+str(msg)) - print("msg (endcode str): "+str(msg.encode('utf-8'))) - md5msg["md5"]=md5(msg.encode('utf-8')).hexdigest() - msg=md5msg - print("msg (data converted to md5 hash): "+str(msg["md5"])) - - if (isinstance(msg, dict)): - msg[TIME_STAMP]=str(datetime.now()) - - with lock: cntr_msg_callbacks += 1 if (id in msg_callbacks.keys()): msg_callbacks[id].append(msg) @@ -339,6 +354,9 @@ def events_write_text(id): cntr_callbacks[id]=[] cntr_callbacks[id].append(1) cntr_callbacks[id].append(0) + cntr_callbacks[id].append(0) + if (id in cntr_callbacks.keys() and list_data): + cntr_callbacks[id][2] += 1 except Exception as e: print(CAUGHT_EXCEPTION+str(e)) traceback.print_exc() @@ -352,7 +370,13 @@ def events_write_text(id): return 'OK',200 -### Functions for test ### +# Receive a callback message but ignore contents and return 200 +# URI and payload, (PUT or POST): /callbacks-text/ +# response: OK 200 +@app.route(NULL_URL, + methods=['PUT','POST']) +def null_url(id): + return 'OK',200 # Dump the whole db of current callbacks # URI and parameter, (GET): /db @@ -376,6 +400,18 @@ def requests_submitted(): else: return Response(str("0"), status=200, mimetype=MIME_TEXT) +@app.route('/counter/received_callback_batches', + methods=['GET']) +def batches_submitted(): + req_id = request.args.get('id') + if (req_id is None): + return Response(str(cntr_batch_callbacks), status=200, mimetype=MIME_TEXT) + + if (req_id in cntr_callbacks.keys()): + return Response(str(cntr_callbacks[req_id][2]), status=200, mimetype=MIME_TEXT) + else: + return Response(str("0"), status=200, mimetype=MIME_TEXT) + @app.route('/counter/fetched_callbacks', methods=['GET']) def requests_fetched(): @@ -440,6 +476,7 @@ def reset(): global msg_callbacks global cntr_msg_fetched global cntr_msg_callbacks + global cntr_batch_callbacks global cntr_callbacks global forced_settings @@ -447,6 +484,7 @@ def reset(): msg_callbacks={} cntr_msg_fetched=0 cntr_msg_callbacks=0 + cntr_batch_callbacks=0 cntr_callbacks={} forced_settings['delay']=None diff --git a/test/cr/basic_test.sh b/test/cr/basic_test.sh index 44e8526a..ea0a5761 100755 --- a/test/cr/basic_test.sh +++ b/test/cr/basic_test.sh @@ -45,6 +45,8 @@ fi # source function to do curl and check result . ../common/do_curl_function.sh +RESP_CONTENT='*' #Dont check resp content type + echo "=== CR hello world ===" RESULT="OK" do_curl GET / 200 @@ -57,6 +59,10 @@ echo "=== Get counter - callbacks ===" RESULT="0" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="0" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks 200 @@ -91,6 +97,10 @@ echo "=== Get counter - callbacks ===" RESULT="2" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="2" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks 200 @@ -104,6 +114,10 @@ echo "=== Get counter - callbacks ===" RESULT="2" do_curl GET /counter/received_callbacks?id=test 200 +echo "=== Get counter - callback batches ===" +RESULT="2" +do_curl GET /counter/received_callback_batches?id=test 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks?id=test 200 @@ -117,6 +131,10 @@ echo "=== Get counter - callbacks ===" RESULT="0" do_curl GET /counter/received_callbacks?id=dummy 200 +echo "=== Get counter - callback batches ===" +RESULT="0" +do_curl GET /counter/received_callback_batches?id=dummy 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks?id=dummy 200 @@ -142,6 +160,10 @@ echo "=== Get counter - callbacks ===" RESULT="2" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="2" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="2" do_curl GET /counter/fetched_callbacks 200 @@ -155,6 +177,10 @@ echo "=== Get counter - callbacks ===" RESULT="2" do_curl GET /counter/received_callbacks?id=test 200 +echo "=== Get counter - callback batches ===" +RESULT="2" +do_curl GET /counter/received_callback_batches?id=test 200 + echo "=== Get counter - fetched events ===" RESULT="2" do_curl GET /counter/fetched_callbacks?id=test 200 @@ -185,6 +211,10 @@ echo "=== Get counter - callbacks ===" RESULT="5" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="5" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="2" do_curl GET /counter/fetched_callbacks 200 @@ -198,6 +228,10 @@ echo "=== Get counter - callbacks ===" RESULT="1" do_curl GET /counter/received_callbacks?id=test1 200 +echo "=== Get counter - callback batches ===" +RESULT="1" +do_curl GET /counter/received_callback_batches?id=test1 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks?id=test1 200 @@ -214,6 +248,10 @@ echo "=== Get counter - callbacks ===" RESULT="5" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="5" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="4" do_curl GET /counter/fetched_callbacks 200 @@ -222,6 +260,29 @@ echo "=== Get counter - current events ===" RESULT="1" do_curl GET /counter/current_messages 200 +echo "=== Send a request ===" +RESULT="*" +#create payload +echo "[{\"DATA-MSG\":\"msg\"},{\"DATA-MSG\":\"msg\"}]" > .tmp.json +do_curl POST '/callbacks-text/test' 200 .tmp.json + +echo "=== Get counter - callbacks ===" +RESULT="7" +do_curl GET /counter/received_callbacks 200 + +echo "=== Get counter - callback batches ===" +RESULT="6" +do_curl GET /counter/received_callback_batches 200 + +echo "=== Get counter - fetched events ===" +RESULT="4" +do_curl GET /counter/fetched_callbacks 200 + +echo "=== Get counter - current events ===" +RESULT="3" +do_curl GET /counter/current_messages 200 + + echo "=== CR reset ===" RESULT="OK" do_curl GET /reset 200 @@ -230,6 +291,10 @@ echo "=== Get counter - callbacks ===" RESULT="0" do_curl GET /counter/received_callbacks 200 +echo "=== Get counter - callback batches ===" +RESULT="0" +do_curl GET /counter/received_callback_batches 200 + echo "=== Get counter - fetched events ===" RESULT="0" do_curl GET /counter/fetched_callbacks 200 diff --git a/test/kafka-procon/.gitignore b/test/kafka-procon/.gitignore index 6703e3c7..aa0b599f 100644 --- a/test/kafka-procon/.gitignore +++ b/test/kafka-procon/.gitignore @@ -2,3 +2,4 @@ .dockererr .env .payload +kafkaprocon diff --git a/test/simulator-group/chartmuseum/.gitignore b/test/simulator-group/chartmuseum/.gitignore new file mode 100644 index 00000000..7dc00c5d --- /dev/null +++ b/test/simulator-group/chartmuseum/.gitignore @@ -0,0 +1,3 @@ +.tmp.json +.dockererr +gen_docker-compose* \ No newline at end of file diff --git a/test/simulator-group/chartmuseum/app.yaml b/test/simulator-group/chartmuseum/app.yaml new file mode 100644 index 00000000..3ce3a325 --- /dev/null +++ b/test/simulator-group/chartmuseum/app.yaml @@ -0,0 +1,53 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: $CHART_MUS_APP_NAME + namespace: $KUBE_SIM_NAMESPACE + labels: + run: $CHART_MUS_APP_NAME + autotest: CHARTMUS +spec: + replicas: 1 + selector: + matchLabels: + run: $CHART_MUS_APP_NAME + template: + metadata: + labels: + run: $CHART_MUS_APP_NAME + autotest: CHARTMUS + spec: + containers: + - name: $CHART_MUS_APP_NAME + image: $CHART_MUS_IMAGE + imagePullPolicy: $KUBE_IMAGE_PULL_POLICY + ports: + - name: http + containerPort: $CHART_MUS_INTERNAL_PORT + env: + - name: STORAGE + value: "local" + - name: STORAGE_LOCAL_ROOTDIR + value: ${CHART_MUS_CHART_CONTR_CHARTS} + - name: DEBUG + value: "1" +# Selector will be set when pod is started first time + nodeSelector: + diff --git a/test/simulator-group/chartmuseum/docker-compose.yml b/test/simulator-group/chartmuseum/docker-compose.yml new file mode 100644 index 00000000..a336f1dd --- /dev/null +++ b/test/simulator-group/chartmuseum/docker-compose.yml @@ -0,0 +1,37 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2020 Nordix Foundation. 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================================================= +# + +version: '3.0' +networks: + default: + external: true + name: ${DOCKER_SIM_NWNAME} +services: + chartmuseum: + networks: + - default + container_name: ${CHART_MUS_APP_NAME} + image: ${CHART_MUS_IMAGE} + ports: + - ${CHART_MUS_EXTERNAL_PORT}:${CHART_MUS_INTERNAL_PORT} + environment: + - STORAGE=local + - STORAGE_LOCAL_ROOTDIR=${CHART_MUS_CHART_CONTR_CHARTS} + - DEBUG=1 + labels: + - "nrttest_app=CHARTMUS" + - "nrttest_dp=${CHART_MUS_DISPLAY_NAME}" diff --git a/test/simulator-group/chartmuseum/svc.yaml b/test/simulator-group/chartmuseum/svc.yaml new file mode 100644 index 00000000..a5301f41 --- /dev/null +++ b/test/simulator-group/chartmuseum/svc.yaml @@ -0,0 +1,34 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +apiVersion: v1 +kind: Service +metadata: + name: $CHART_MUS_APP_NAME + namespace: $KUBE_SIM_NAMESPACE + labels: + run: $CHART_MUS_APP_NAME + autotest: CHARTMUS +spec: + type: ClusterIP + ports: + - port: $CHART_MUS_EXTERNAL_PORT + targetPort: $CHART_MUS_INTERNAL_PORT + protocol: TCP + name: htt + selector: + run: $CHART_MUS_APP_NAME \ No newline at end of file diff --git a/test/simulator-group/dmaapmed/app.yaml b/test/simulator-group/dmaapmed/app.yaml index 7c39bea3..2a94a536 100644 --- a/test/simulator-group/dmaapmed/app.yaml +++ b/test/simulator-group/dmaapmed/app.yaml @@ -27,8 +27,8 @@ spec: - name: https containerPort: $DMAAP_MED_INTERNAL_SECURE_PORT volumeMounts: - - mountPath: $DMAAP_MED_DATA_MOUNT_PATH/$DMAAP_MED_DATA_FILE - subPath: $DMAAP_MED_DATA_FILE + - mountPath: $DMAAP_MED_DATA_MOUNT_PATH/$DMAAP_MED_CONTR_DATA_FILE + subPath: $DMAAP_MED_CONTR_DATA_FILE name: dmaapadp-data-name env: - name: INFO_PRODUCER_HOST @@ -41,6 +41,8 @@ spec: value: "$MR_SERVICE_PATH" - name: LOG_LEVEL value: Debug + - name: KAFKA_BOOTSTRAP_SERVERS + value: "$MR_KAFKA_SERVICE_PATH" volumes: - configMap: defaultMode: 420 diff --git a/test/simulator-group/dmaapmed/docker-compose.yml b/test/simulator-group/dmaapmed/docker-compose.yml index 9cb929cf..53d126fb 100644 --- a/test/simulator-group/dmaapmed/docker-compose.yml +++ b/test/simulator-group/dmaapmed/docker-compose.yml @@ -33,8 +33,9 @@ services: - INFO_COORD_ADDR=${ICS_SERVICE_PATH} - DMAAP_MR_ADDR=${MR_SERVICE_PATH} - LOG_LEVEL=Debug + - KAFKA_BOOTSTRAP_SERVERS=${MR_KAFKA_SERVICE_PATH} volumes: - - ${DMAAP_MED_HOST_MNT_DIR}/$DMAAP_MED_DATA_FILE:${DMAAP_MED_DATA_MOUNT_PATH}/$DMAAP_MED_DATA_FILE + - ${DMAAP_MED_HOST_MNT_DIR}/${DMAAP_MED_CONTR_DATA_FILE}:${DMAAP_MED_DATA_MOUNT_PATH}/${DMAAP_MED_CONTR_DATA_FILE} labels: - "nrttest_app=DMAAPMED" - "nrttest_dp=${DMAAP_MED_DISPLAY_NAME}" diff --git a/test/simulator-group/dmaapmed/type_config_1.json b/test/simulator-group/dmaapmed/type_config_1.json new file mode 100644 index 00000000..de1b1a46 --- /dev/null +++ b/test/simulator-group/dmaapmed/type_config_1.json @@ -0,0 +1,13 @@ +{ + "types": + [ + { + "id": "STD_Fault_Messages", + "dmaapTopicUrl": "/events/unauthenticated.dmaapmed.json/dmaapmediatorproducer/STD_Fault_Messages?timeout=15000&limit=100" + }, + { + "id": "Kafka_TestTopic", + "kafkaInputTopic": "unauthenticated.dmaapmed_kafka.text" + } + ] + } \ No newline at end of file diff --git a/test/simulator-group/helmmanager/.gitignore b/test/simulator-group/helmmanager/.gitignore new file mode 100644 index 00000000..7dc00c5d --- /dev/null +++ b/test/simulator-group/helmmanager/.gitignore @@ -0,0 +1,3 @@ +.tmp.json +.dockererr +gen_docker-compose* \ No newline at end of file diff --git a/test/simulator-group/helmmanager/app.yaml b/test/simulator-group/helmmanager/app.yaml new file mode 100644 index 00000000..5c171692 --- /dev/null +++ b/test/simulator-group/helmmanager/app.yaml @@ -0,0 +1,36 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +apiVersion: v1 +kind: Pod +metadata: + name: helmmanagerservice + namespace: $KUBE_NONRTRIC_NAMESPACE + labels: + run: $HELM_MANAGER_APP_NAME + autotest: HELMMANAGER +spec: + serviceAccountName: $HELM_MANAGER_SA_NAME + containers: + - name: $HELM_MANAGER_APP_NAME + image: $HELM_MANAGER_IMAGE + imagePullPolicy: $KUBE_IMAGE_PULL_POLICY + ports: + - name: http + containerPort: $HELM_MANAGER_INTERNAL_PORT + - name: https + containerPort: $HELM_MANAGER_INTERNAL_SECURE_PORT diff --git a/test/simulator-group/helmmanager/docker-compose.yml b/test/simulator-group/helmmanager/docker-compose.yml new file mode 100644 index 00000000..cc69ed0a --- /dev/null +++ b/test/simulator-group/helmmanager/docker-compose.yml @@ -0,0 +1,36 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +version: '3.0' +networks: + default: + external: true + name: ${DOCKER_SIM_NWNAME} +services: + chartmuseum: + networks: + - default + container_name: ${HELM_MANAGER_APP_NAME} + image: ${HELM_MANAGER_IMAGE} + ports: + - ${HELM_MANAGER_EXTERNAL_PORT}:${HELM_MANAGER_INTERNAL_PORT} + - ${HELM_MANAGER_EXTERNAL_SECURE_PORT}:${HELM_MANAGER_INTERNAL_SECURE_PORT} + volumes: + - ~/.kube:/root/.kube + labels: + - "nrttest_app=CHARTMUS" + - "nrttest_dp=${HELM_MANAGER_DISPLAY_NAME}" diff --git a/test/simulator-group/helmmanager/sa.yaml b/test/simulator-group/helmmanager/sa.yaml new file mode 100644 index 00000000..1769b7c9 --- /dev/null +++ b/test/simulator-group/helmmanager/sa.yaml @@ -0,0 +1,42 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: $HELM_MANAGER_SA_NAME + namespace: $KUBE_NONRTRIC_NAMESPACE + labels: + run: $HELM_MANAGER_APP_NAME + autotest: HELMMANAGER +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ${HELM_MANAGER_SA_NAME}-clusterrolebinding + namespace: $KUBE_NONRTRIC_NAMESPACE + labels: + run: $HELM_MANAGER_APP_NAME + autotest: HELMMANAGER +subjects: +- kind: ServiceAccount + name: $HELM_MANAGER_SA_NAME + namespace: $KUBE_NONRTRIC_NAMESPACE +roleRef: + kind: ClusterRole + name: $HELM_MANAGER_CLUSTER_ROLE + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/test/simulator-group/helmmanager/svc.yaml b/test/simulator-group/helmmanager/svc.yaml new file mode 100644 index 00000000..37036976 --- /dev/null +++ b/test/simulator-group/helmmanager/svc.yaml @@ -0,0 +1,37 @@ +# ============LICENSE_START=============================================== +# Copyright (C) 2021 Nordix Foundation. 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================================================= +# + +apiVersion: v1 +kind: Service +metadata: + name: helmmanagerservice + namespace: $KUBE_NONRTRIC_NAMESPACE + labels: + run: $HELM_MANAGER_APP_NAME + autotest: HELMMANAGER +spec: + ports: + - port: $HELM_MANAGER_EXTERNAL_PORT + targetPort: $HELM_MANAGER_INTERNAL_PORT + protocol: TCP + name: http + - port: $HELM_MANAGER_EXTERNAL_SECURE_PORT + targetPort: $HELM_MANAGER_INTERNAL_SECURE_PORT + protocol: TCP + name: https + selector: + run: $HELM_MANAGER_APP_NAME diff --git a/test/simulator-group/policy_agent/application2.yaml b/test/simulator-group/policy_agent/application2.yaml new file mode 100644 index 00000000..05c5db12 --- /dev/null +++ b/test/simulator-group/policy_agent/application2.yaml @@ -0,0 +1,71 @@ +################################################################################ +# Copyright (c) 2020 Nordix Foundation. # +# # +# Licensed under the Apache License, Version 2.0 (the \"License\"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an \"AS IS\" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ + +spring: + profiles: + active: prod + main: + allow-bean-definition-overriding: true + aop: + auto: false +management: + endpoints: + web: + exposure: + # Enabling of springboot actuator features. See springboot documentation. + include: "loggers,logfile,health,info,metrics,threaddump,heapdump" + +logging: + # Configuration of logging + level: + ROOT: ERROR + org.springframework: ERROR + org.springframework.data: ERROR + org.springframework.web.reactive.function.client.ExchangeFunctions: ERROR + ${POLICY_AGENT_PKG_NAME}: INFO + file: /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 + 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 +app: + # Location of the component configuration file. The file will only be used if the Consul database is not used; + # configuration from the Consul will override the file. + filepath: /var/policy-management-service/application_configuration.json + # path where the service can store data + vardata-directory: /var/policy-management-service + # path to json schema for config validation + config-file-schema-path: /application_configuration_schema.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 + http.proxy-host: $AGENT_HTTP_PROXY_CONFIG_HOST_NAME + http.proxy-port: $AGENT_HTTP_PROXY_CONFIG_PORT + http.proxy-type: HTTP diff --git a/test/usecases/odusliceassurance/goversion/README.md b/test/usecases/odusliceassurance/goversion/README.md index dbab20f1..d6eb4f8c 100644 --- a/test/usecases/odusliceassurance/goversion/README.md +++ b/test/usecases/odusliceassurance/goversion/README.md @@ -1,4 +1,4 @@ -# O-RAN-SC Non-RealTime RIC O-DU Closed Loop Usecase Slice Assurance +# O-RAN-SC Non-RealTime RIC O-DU Closed Loop Usecase Slice Assurance ## Configuration @@ -12,12 +12,16 @@ The consumer takes a number of environment variables, described below, as config >- LOG_LEVEL Optional. The log level, which can be `Error`, `Warn`, `Info` or `Debug`. Defaults to `Info`. >- POLLTIME Optional. Waiting time between one pull request to Dmaap and another. Defaults to 10 sec +## Functionality + +There is a status call provided in a REST API on port 40936. +>- /status OK ## Development To make it easy to test during development of the consumer, there is a stub provided in the `stub` folder. -This stub is used to simulate both received VES messages from Dmaap MR with information about performance measurements for the slices in a determinated DU and also SDNR, that sends information about Radio Resource Management Policy Ratio and allows to modify value for RRM Policy Dedicated Ratio from default to higher value. +This stub is used to simulate both received VES messages from Dmaap MR with information about performance measurements for the slices in a determinated DU and also SDNR, that sends information about Radio Resource Management Policy Ratio and allows to modify value for RRM Policy Dedicated Ratio from default to higher value. By default, SDNR stub listens to the port `3904`, but his can be overridden by passing a `--sdnr-port [PORT]` flag when starting the stub. For Dmaap MR stub default port is `3905` but it can be overriden by passing a `--dmaap-port [PORT]` flag when starting the stub. diff --git a/test/usecases/odusliceassurance/goversion/container-tag.yaml b/test/usecases/odusliceassurance/goversion/container-tag.yaml index 6b1c9db7..5b018097 100644 --- a/test/usecases/odusliceassurance/goversion/container-tag.yaml +++ b/test/usecases/odusliceassurance/goversion/container-tag.yaml @@ -2,4 +2,4 @@ # By default this file is in the docker build directory, # but the location can configured in the JJB template. --- -tag: 1.0.0 +tag: 1.0.1 diff --git a/test/usecases/odusliceassurance/goversion/go.mod b/test/usecases/odusliceassurance/goversion/go.mod index e2fb61d9..d0c4dc2f 100644 --- a/test/usecases/odusliceassurance/goversion/go.mod +++ b/test/usecases/odusliceassurance/goversion/go.mod @@ -4,6 +4,13 @@ go 1.17 require github.com/sirupsen/logrus v1.8.1 -require github.com/gorilla/mux v1.8.0 +require ( + github.com/gorilla/mux v1.8.0 + github.com/stretchr/testify v1.3.0 +) -require golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect +) diff --git a/test/usecases/odusliceassurance/goversion/internal/config/config.go b/test/usecases/odusliceassurance/goversion/internal/config/config.go index 48cbb85c..f1eb26f9 100644 --- a/test/usecases/odusliceassurance/goversion/internal/config/config.go +++ b/test/usecases/odusliceassurance/goversion/internal/config/config.go @@ -51,7 +51,7 @@ func New() *Config { } func (c Config) String() string { - return fmt.Sprintf("ConsumerHost: %v, ConsumerPort: %v, SDNRAddress: %v, SDNRUser: %v, SDNRPassword: %v, LogLevel: %v", c.MRHost, c.MRPort, c.SDNRAddress, c.SDNRUser, c.SDNPassword, c.LogLevel) + return fmt.Sprintf("[MRHost: %v, MRPort: %v, SDNRAddress: %v, SDNRUser: %v, SDNRPassword: %v, PollTime: %v, LogLevel: %v]", c.MRHost, c.MRPort, c.SDNRAddress, c.SDNRUser, c.SDNPassword, c.Polltime, c.LogLevel) } func getEnv(key string, defaultVal string) string { diff --git a/test/usecases/odusliceassurance/goversion/internal/config/config_test.go b/test/usecases/odusliceassurance/goversion/internal/config/config_test.go new file mode 100644 index 00000000..1005946a --- /dev/null +++ b/test/usecases/odusliceassurance/goversion/internal/config/config_test.go @@ -0,0 +1,108 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package config + +import ( + "bytes" + "os" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func TestNewEnvVarsSetConfigContainSetValues(t *testing.T) { + assertions := require.New(t) + os.Setenv("MR_HOST", "consumerHost") + os.Setenv("MR_PORT", "8095") + os.Setenv("SDNR_ADDR", "http://localhost:3904") + os.Setenv("SDNR_USER", "admin") + os.Setenv("SDNR_PASSWORD", "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U") + os.Setenv("Polltime", "30") + os.Setenv("LOG_LEVEL", "Debug") + t.Cleanup(func() { + os.Clearenv() + }) + wantConfig := Config{ + MRHost: "consumerHost", + MRPort: "8095", + SDNRAddress: "http://localhost:3904", + SDNRUser: "admin", + SDNPassword: "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U", + Polltime: 30, + LogLevel: log.DebugLevel, + } + + got := New() + assertions.Equal(&wantConfig, got) +} + +func TestNewFaultyIntValueSetConfigContainDefaultValueAndWarnInLog(t *testing.T) { + assertions := require.New(t) + var buf bytes.Buffer + log.SetOutput(&buf) + + os.Setenv("Polltime", "wrong") + t.Cleanup(func() { + log.SetOutput(os.Stderr) + os.Clearenv() + }) + wantConfig := Config{ + MRHost: "", + MRPort: "", + SDNRAddress: "http://localhost:3904", + SDNRUser: "admin", + SDNPassword: "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U", + Polltime: 30, + LogLevel: log.InfoLevel, + } + + got := New() + assertions.Equal(&wantConfig, got) + + logString := buf.String() + assertions.Contains(logString, "Invalid int value: wrong for variable: Polltime. Default value: 30 will be used") +} + +func TestNewEnvFaultyLogLevelConfigContainDefaultValues(t *testing.T) { + assertions := require.New(t) + var buf bytes.Buffer + log.SetOutput(&buf) + + os.Setenv("LOG_LEVEL", "wrong") + t.Cleanup(func() { + log.SetOutput(os.Stderr) + os.Clearenv() + }) + wantConfig := Config{ + MRHost: "", + MRPort: "", + SDNRAddress: "http://localhost:3904", + SDNRUser: "admin", + SDNPassword: "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U", + Polltime: 30, + LogLevel: log.InfoLevel, + } + got := New() + assertions.Equal(&wantConfig, got) + logString := buf.String() + assertions.Contains(logString, "Invalid log level: wrong. Log level will be Info!") +} diff --git a/test/usecases/odusliceassurance/goversion/internal/restclient/client.go b/test/usecases/odusliceassurance/goversion/internal/restclient/client.go index 61cf6148..3983840b 100644 --- a/test/usecases/odusliceassurance/goversion/internal/restclient/client.go +++ b/test/usecases/odusliceassurance/goversion/internal/restclient/client.go @@ -40,11 +40,6 @@ func New(httpClient *http.Client) *Client { } } -type HTTPClient interface { - Get(path string, v interface{}) error - Post(path string, payload interface{}, v interface{}) error -} - func (c *Client) Get(path string, v interface{}) error { req, err := c.newRequest(http.MethodGet, path, nil) if err != nil { diff --git a/test/usecases/odusliceassurance/goversion/internal/restclient/client_test.go b/test/usecases/odusliceassurance/goversion/internal/restclient/client_test.go new file mode 100644 index 00000000..f2899dfa --- /dev/null +++ b/test/usecases/odusliceassurance/goversion/internal/restclient/client_test.go @@ -0,0 +1,210 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package restclient + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewRequest(t *testing.T) { + assertions := require.New(t) + + bodyBytes, _ := json.Marshal("body") + succesfullReq, _ := http.NewRequest(http.MethodGet, "url", bytes.NewReader(bodyBytes)) + + type args struct { + method string + path string + payload interface{} + } + tests := []struct { + name string + args args + want *http.Request + wantErr error + }{ + { + name: "succesfull newRequest", + args: args{ + method: http.MethodGet, + path: "url", + payload: "body", + }, + want: succesfullReq, + wantErr: nil, + }, + { + name: "request failed json marshal", + args: args{ + method: http.MethodGet, + path: "url", + payload: map[string]interface{}{ + "foo": make(chan int), + }, + }, + want: nil, + wantErr: fmt.Errorf("failed to marshal request body: json: unsupported type: chan int"), + }, + { + name: "request failed calling newRequest", + args: args{ + method: "*?", + path: "url", + payload: "body", + }, + want: nil, + wantErr: fmt.Errorf("failed to create HTTP request: net/http: invalid method \"*?\""), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := New(&http.Client{}) + + req, err := client.newRequest(tt.args.method, tt.args.path, tt.args.payload) + if tt.wantErr != nil { + assertions.Equal(tt.want, req) + assertions.EqualError(tt.wantErr, err.Error()) + } else { + assertions.Equal("url", req.URL.Path) + assertions.Equal("application/json; charset=utf-8", req.Header.Get("Content-Type")) + assertions.Empty(req.Header.Get("Authorization")) + assertions.Nil(err) + } + + }) + } +} + +func TestGet(t *testing.T) { + assertions := require.New(t) + type args struct { + header string + respCode int + resp interface{} + } + tests := []struct { + name string + args args + wantErr string + }{ + { + name: "successful GET request", + args: args{ + header: "application/json", + respCode: http.StatusOK, + resp: "Success!", + }, + wantErr: "", + }, + { + name: "error GET request", + args: args{ + header: "application/json", + respCode: http.StatusBadRequest, + resp: nil, + }, + wantErr: "failed to do request, 400 status code received", + }, + } + + for _, tt := range tests { + + t.Run(tt.name, func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + response, _ := json.Marshal(tt.args.resp) + w.Header().Set("Content-Type", tt.args.header) + w.WriteHeader(tt.args.respCode) + w.Write(response) + })) + defer srv.Close() + + client := New(&http.Client{}) + var res interface{} + err := client.Get(srv.URL, &res) + + if err != nil { + assertions.Equal(tt.wantErr, err.Error()) + } + assertions.Equal(tt.args.resp, res) + }) + } +} + +func TestPost(t *testing.T) { + assertions := require.New(t) + type args struct { + header string + respCode int + resp interface{} + } + tests := []struct { + name string + args args + wantErr string + }{ + { + name: "successful Post request", + args: args{ + header: "application/json", + respCode: http.StatusOK, + resp: "Success!", + }, + wantErr: "", + }, + } + + for _, tt := range tests { + + t.Run(tt.name, func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + assertions.Equal(http.MethodPost, r.Method) + assertions.Contains(r.Header.Get("Content-Type"), "application/json") + + var reqBody interface{} + decoder := json.NewDecoder(r.Body) + decoder.Decode(&reqBody) + assertions.Equal(reqBody, `json:"example"`) + + response, _ := json.Marshal(tt.args.resp) + w.Header().Set("Content-Type", tt.args.header) + w.WriteHeader(tt.args.respCode) + w.Write(response) + })) + defer srv.Close() + + client := New(&http.Client{}) + payload := `json:"example"` + err := client.Post(srv.URL, payload, nil) + + if err != nil { + assertions.Equal(tt.wantErr, err.Error()) + } + }) + } +} diff --git a/test/usecases/odusliceassurance/goversion/internal/sliceassurance/app.go b/test/usecases/odusliceassurance/goversion/internal/sliceassurance/app.go index 7dc84b1f..2cef2778 100644 --- a/test/usecases/odusliceassurance/goversion/internal/sliceassurance/app.go +++ b/test/usecases/odusliceassurance/goversion/internal/sliceassurance/app.go @@ -39,7 +39,7 @@ const ( ) type App struct { - client restclient.HTTPClient + client *restclient.Client metricsPolicies *structures.SliceAssuranceMeas } diff --git a/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance.go b/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance.go index c243d185..7cefcaf6 100644 --- a/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance.go +++ b/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance.go @@ -73,19 +73,19 @@ func (sa *SliceAssuranceMeas) AddOrUpdateMetric(meas messages.Measurement) (stri var duid string var sd, sst int - regex := *regexp.MustCompile(`\/network-function\/distributed-unit-functions\[id=\'(.*)\'\]/cell\[id=\'(.*)\'\]/supported-measurements\/performance-measurement-type\[\.=\'(.*)\'\]\/supported-snssai-subcounter-instances\/slice-differentiator\[\.=(\d)\]\[slice-service-type=(\d+)\]`) + regex := *regexp.MustCompile(`\/(.*)network-function\/distributed-unit-functions\[id=\'(.*)\'\]\/cell\[id=\'(.*)\'\]\/supported-measurements\[performance-measurement-type=\'(.*)\'\]\/supported-snssai-subcounter-instances\[slice-differentiator=\'(\d+)\'\]\[slice-service-type=\'(\d+)\'\]`) res := regex.FindAllStringSubmatch(meas.MeasurementTypeInstanceReference, -1) - if res != nil && len(res[0]) == 6 { - duid = res[0][1] - sd = toInt(res[0][4]) - sst = toInt(res[0][5]) + if res != nil && len(res[0]) == 7 { + duid = res[0][2] + sd = toInt(res[0][5]) + sst = toInt(res[0][6]) key := MapKey{duid, sd, sst} value, check := sa.Metrics[key] if check { - sa.updateMetric(key, value, res[0][3], meas.Value) + sa.updateMetric(key, value, res[0][4], meas.Value) } else { // Only add new one if value exceeds threshold sa.addMetric(res, meas.Value) @@ -98,9 +98,9 @@ func (sa *SliceAssuranceMeas) AddOrUpdateMetric(meas messages.Measurement) (stri func (sa *SliceAssuranceMeas) addMetric(res [][]string, metricValue int) { if metricValue > 700 { - metric := NewSliceMetric(res[0][1], res[0][2], toInt(res[0][4]), toInt(res[0][5])) + metric := NewSliceMetric(res[0][2], res[0][3], toInt(res[0][5]), toInt(res[0][6])) metric.PM[res[0][3]] = metricValue - key := MapKey{res[0][1], toInt(res[0][4]), toInt(res[0][5])} + key := MapKey{res[0][2], toInt(res[0][5]), toInt(res[0][6])} sa.Metrics[key] = metric } } diff --git a/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance_test.go b/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance_test.go new file mode 100644 index 00000000..9ed35fb2 --- /dev/null +++ b/test/usecases/odusliceassurance/goversion/internal/structures/sliceassurance_test.go @@ -0,0 +1,172 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "oransc.org/usecase/oduclosedloop/messages" +) + +func TestAddMetric(t *testing.T) { + assertions := require.New(t) + type args struct { + meas messages.Measurement + } + tests := []struct { + name string + args args + }{ + { + name: "Test adding new metric", + args: args{ + meas: messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + }, + }, + }, + { + name: "Test with invalid input", + args: args{ + meas: messages.Measurement{ + MeasurementTypeInstanceReference: "/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + }, + }, + }, + } + + sliceAssuranceMeas := NewSliceAssuranceMeas() + assertions.Equal(0, len(sliceAssuranceMeas.Metrics), "Metrics is not empty, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 0) + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + if i == 0 { + sliceAssuranceMeas.AddOrUpdateMetric(tt.args.meas) + assertions.Equal(1, len(sliceAssuranceMeas.Metrics), "Metrics must have one new metric, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 1) + + testMapKey := MapKey{"O-DU-1211", 1, 1} + assertions.Contains(sliceAssuranceMeas.Metrics, testMapKey, "Metric added with wrong values , got: %v.", sliceAssuranceMeas.Metrics[testMapKey]) + } + if i == 1 { + _, got := sliceAssuranceMeas.AddOrUpdateMetric(tt.args.meas) + assertions.EqualError(got, " wrong format for MeasurementTypeInstanceReference") + } + }) + } +} + +func TestUpdateExistingMetric(t *testing.T) { + assertions := require.New(t) + meas := messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + } + + updateMeas := messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 897, + Unit: "kbit/s", + } + + sliceAssuranceMeas := NewSliceAssuranceMeas() + assertions.Equal(0, len(sliceAssuranceMeas.Metrics), "Metrics is not empty, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 0) + + sliceAssuranceMeas.AddOrUpdateMetric(meas) + assertions.Equal(1, len(sliceAssuranceMeas.Metrics), "Metrics must have one new metric, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 1) + + sliceAssuranceMeas.AddOrUpdateMetric(updateMeas) + assertions.Equal(1, len(sliceAssuranceMeas.Metrics), "Metrics must have one updated metric, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 1) + + testMapKey := MapKey{"O-DU-1211", 1, 1} + metricName := "user-equipment-average-throughput-uplink" + newMetricValue := 897 + if sliceAssuranceMeas.Metrics[testMapKey].PM[metricName] != newMetricValue { + t.Errorf("Metric value was not update properly, got: %d, want: %d.", sliceAssuranceMeas.Metrics[testMapKey].PM[metricName], newMetricValue) + } + +} + +func TestDeleteMetricWhenValueLessThanThreshold(t *testing.T) { + + meas := messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + } + + newMeas := messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 50, + Unit: "kbit/s", + } + + sliceAssuranceMeas := NewSliceAssuranceMeas() + assert.Equal(t, 0, len(sliceAssuranceMeas.Metrics), "Metrics is not empty, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 0) + + sliceAssuranceMeas.AddOrUpdateMetric(meas) + assert.Equal(t, 1, len(sliceAssuranceMeas.Metrics), "Metrics must have one new metric, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 1) + + sliceAssuranceMeas.AddOrUpdateMetric(newMeas) + assert.Equal(t, 0, len(sliceAssuranceMeas.Metrics), "Metrics must have been deleted, got: %d, want: %d.", len(sliceAssuranceMeas.Metrics), 0) + +} + +func TestAddPolicy(t *testing.T) { + + meas := messages.Measurement{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + } + sliceAssuranceMeas := NewSliceAssuranceMeas() + sliceAssuranceMeas.AddOrUpdateMetric(meas) + + duid := "O-DU-1211" + rrmPolicyRatio := messages.RRMPolicyRatio{ + Id: "id", + AdmState: "locked", + UserLabel: "user_label", + RRMPolicyMaxRatio: 0, + RRMPolicyMinRatio: 0, + RRMPolicyDedicatedRatio: 0, + ResourceType: "prb", + RRMPolicyMembers: []messages.RRMPolicyMember{{ + MobileCountryCode: "046", + MobileNetworkCode: "651", + SliceDifferentiator: 1, + SliceServiceType: 1, + }}, + } + assert.Equal(t, 0, len(sliceAssuranceMeas.Policies), "Policies is not empty, got: %d, want: %d.", len(sliceAssuranceMeas.Policies), 0) + + sliceAssuranceMeas.AddNewPolicy(duid, rrmPolicyRatio) + assert.Equal(t, 1, len(sliceAssuranceMeas.Policies), "Policies must have one new policy, got: %d, want: %d.", len(sliceAssuranceMeas.Policies), 1) + + sliceAssuranceMeas.PrintStructures() +} diff --git a/test/usecases/odusliceassurance/goversion/main.go b/test/usecases/odusliceassurance/goversion/main.go index b530c6be..f1c8d426 100644 --- a/test/usecases/odusliceassurance/goversion/main.go +++ b/test/usecases/odusliceassurance/goversion/main.go @@ -22,13 +22,14 @@ package main import ( "fmt" + "net/http" log "github.com/sirupsen/logrus" "oransc.org/usecase/oduclosedloop/internal/config" "oransc.org/usecase/oduclosedloop/internal/sliceassurance" ) -const TOPIC string = "/events/unauthenticated.PERFORMANCE_MEASUREMENTS" +const TOPIC string = "unauthenticated.VES_O_RAN_SC_HELLO_WORLD_PM_STREAMING_OUTPUT" var configuration *config.Config @@ -48,8 +49,11 @@ func main() { a := sliceassurance.App{} a.Initialize(dmaapUrl, configuration.SDNRAddress) - a.Run(TOPIC, configuration.Polltime) + go a.Run(TOPIC, configuration.Polltime) + http.HandleFunc("/status", statusHandler) + + log.Fatal(http.ListenAndServe(":40936", nil)) } func validateConfiguration(configuration *config.Config) error { @@ -58,3 +62,7 @@ func validateConfiguration(configuration *config.Config) error { } return nil } + +func statusHandler(w http.ResponseWriter, r *http.Request) { + // Just respond OK to show the service is alive for now. Might be extended later. +} diff --git a/test/usecases/odusliceassurance/goversion/messages/stdVesMessage_test.go b/test/usecases/odusliceassurance/goversion/messages/stdVesMessage_test.go new file mode 100644 index 00000000..2904d49f --- /dev/null +++ b/test/usecases/odusliceassurance/goversion/messages/stdVesMessage_test.go @@ -0,0 +1,76 @@ +// - +// ========================LICENSE_START================================= +// O-RAN-SC +// %% +// Copyright (C) 2021: Nordix Foundation +// %% +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========================LICENSE_END=================================== +// + +package messages + +import ( + "testing" +) + +func TestGetMeasurements(t *testing.T) { + type fields struct { + Event Event + } + tests := []struct { + name string + fields fields + want []Measurement + }{ + { + name: "get measurements message", + fields: fields{ + Event: Event{ + CommonEventHeader: CommonEventHeader{ + Domain: "stndDefined", + StndDefinedNamespace: "o-ran-sc-du-hello-world-pm-streaming-oas3", + }, + StndDefinedFields: StndDefinedFields{ + StndDefinedFieldsVersion: "1.0", + SchemaReference: "https://gerrit.o-ran-sc.org/r/gitweb?p=scp/oam/modeling.git;a=blob_plain;f=data-model/oas3/experimental/o-ran-sc-du-hello-world-oas3.json;hb=refs/heads/master", + Data: Data{ + DataId: "id", + Measurements: []Measurement{{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + }}, + }, + }, + }, + }, + want: []Measurement{{ + MeasurementTypeInstanceReference: "/o-ran-sc-du-hello-world:network-function/distributed-unit-functions[id='O-DU-1211']/cell[id='cell-1']/supported-measurements[performance-measurement-type='user-equipment-average-throughput-uplink']/supported-snssai-subcounter-instances[slice-differentiator='1'][slice-service-type='1']", + Value: 51232, + Unit: "kbit/s", + }}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + message := StdDefinedMessage{ + Event: tt.fields.Event, + } + if got := message.GetMeasurements(); len(got) != len(tt.want) { + t.Errorf("Message.GetMeasurements() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/test/usecases/odusliceassurance/goversion/pom.xml b/test/usecases/odusliceassurance/goversion/pom.xml deleted file mode 100644 index b882e95d..00000000 --- a/test/usecases/odusliceassurance/goversion/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - 4.0.0 - - oransc.org - o-du-slice-assurance - 1.0.0 - - 0.30.0 - - - - - - io.fabric8 - docker-maven-plugin - ${docker-maven-plugin.version} - false - - - generate-nonrtric-o-du-slice-assurance-image - package - - build - - - ${env.CONTAINER_PULL_REGISTRY} - - - o-ran-sc/nonrtric-o-du-slice-assurance:${project.version} - - try - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - - - - - - - - push-nonrtric-o-du-slice-assurance-image - - build - push - - - ${env.CONTAINER_PULL_REGISTRY} - ${env.CONTAINER_PUSH_REGISTRY} - - - o-ran-sc/nonrtric-o-du-slice-assurance:${project.version} - - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - latest - - - - - - - - - - - diff --git a/test/usecases/odusliceassurance/goversion/stub/sdnr/sdnrstub.go b/test/usecases/odusliceassurance/goversion/stub/sdnr/sdnrstub.go index b8f80be3..41cc928f 100644 --- a/test/usecases/odusliceassurance/goversion/stub/sdnr/sdnrstub.go +++ b/test/usecases/odusliceassurance/goversion/stub/sdnr/sdnrstub.go @@ -55,8 +55,8 @@ func getDistributedUnitFunctions(w http.ResponseWriter, r *http.Request) { AdmState: "locked", UserLabel: "rrm-pol-1", RRMPolicyMaxRatio: 100, - RRMPolicyMinRatio: "0", - RRMPolicyDedicatedRatio: "0", + RRMPolicyMinRatio: 0, + RRMPolicyDedicatedRatio: 0, ResourceType: "prb", RRMPolicyMembers: []messages.RRMPolicyMember{ { @@ -72,8 +72,8 @@ func getDistributedUnitFunctions(w http.ResponseWriter, r *http.Request) { AdmState: "unlocked", UserLabel: "rrm-pol-2", RRMPolicyMaxRatio: 20, - RRMPolicyMinRatio: "10", - RRMPolicyDedicatedRatio: "15", + RRMPolicyMinRatio: 10, + RRMPolicyDedicatedRatio: 15, ResourceType: "prb", RRMPolicyMembers: []messages.RRMPolicyMember{ { @@ -89,8 +89,8 @@ func getDistributedUnitFunctions(w http.ResponseWriter, r *http.Request) { AdmState: "unlocked", UserLabel: "rrm-pol-3", RRMPolicyMaxRatio: 30, - RRMPolicyMinRatio: "10", - RRMPolicyDedicatedRatio: "5", + RRMPolicyMinRatio: 10, + RRMPolicyDedicatedRatio: 5, ResourceType: "prb", RRMPolicyMembers: []messages.RRMPolicyMember{ { @@ -109,8 +109,6 @@ func getDistributedUnitFunctions(w http.ResponseWriter, r *http.Request) { } func updateRRMPolicyDedicatedRatio(w http.ResponseWriter, r *http.Request) { - //vars := mux.Vars(r) - fmt.Println("::updateRRMPolicyDedicatedRatio::") var prMessage messages.DistributedUnitFunction decoder := json.NewDecoder(r.Body) @@ -121,7 +119,6 @@ func updateRRMPolicyDedicatedRatio(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() fmt.Println("prMessage: ", prMessage) - //prMessage.Id = vars["POLICY-ID"] respondWithJSON(w, http.StatusOK, map[string]string{"status": "200"}) } diff --git a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json old mode 100644 new mode 100755 index 837d187d..56d204b4 --- a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json +++ b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json @@ -22,16 +22,16 @@ "taskParameters": [ { "key": "ORU-ODU-Map", - "value": "{\"ERICSSON-O-RU-11220\": \"HCL-O-DU-1122\", - \"ERICSSON-O-RU-11221\": \"HCL-O-DU-1122\", - \"ERICSSON-O-RU-11222\": \"HCL-O-DU-1122\", - \"ERICSSON-O-RU-11223\": \"HCL-O-DU-1122\", - \"ERICSSON-O-RU-11224\": \"HCL-O-DU-1123\", - \"ERICSSON-O-RU-11225\": \"HCL-O-DU-1123\", - \"ERICSSON-O-RU-11226\": \"HCL-O-DU-1123\", - \"ERICSSON-O-RU-11227\": \"HCL-O-DU-1124\", - \"ERICSSON-O-RU-11228\": \"HCL-O-DU-1125\", - \"ERICSSON-O-RU-11229\": \"HCL-O-DU-1125\"}" + "value": "{\"ERICSSON-O-RU-11220\": \"O-DU-1122\", + \"ERICSSON-O-RU-11221\": \"O-DU-1122\", + \"ERICSSON-O-RU-11222\": \"O-DU-1122\", + \"ERICSSON-O-RU-11223\": \"O-DU-1122\", + \"ERICSSON-O-RU-11224\": \"O-DU-1123\", + \"ERICSSON-O-RU-11225\": \"O-DU-1123\", + \"ERICSSON-O-RU-11226\": \"O-DU-1123\", + \"ERICSSON-O-RU-11227\": \"O-DU-1124\", + \"ERICSSON-O-RU-11228\": \"O-DU-1125\", + \"ERICSSON-O-RU-11229\": \"O-DU-1125\"}" } ] } @@ -42,7 +42,7 @@ "carrierTechnology": "RESTCLIENT", "parameterClassName": "org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters", "parameters": { - "url": "http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection={OruId}", + "url": "http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions={OduId}/radio-resource-management-policy-ratio=rrm-pol-1", "httpMethod" : "PUT", "httpHeaders" : [ ["Authorization", "Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="] diff --git a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json index 43af8ce5..f2fea50e 100644 --- a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json +++ b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json @@ -1 +1 @@ -{"tosca_definitions_version":"tosca_simple_yaml_1_1_0","topology_template":{"policies":[{"onap.policies.native.apex.LinkMonitor":{"type":"onap.policies.native.Apex","type_version":"1.0.0","name":"onap.policies.native.apex.LinkMonitor","version":"1.0.0","properties":{"engineServiceParameters":{"name":"LinkMonitorApexEngine","version":"0.0.1","id":101,"instanceCount":1,"deploymentPort":12345,"engineParameters":{"executorParameters":{"JAVASCRIPT":{"parameterClassName":"org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"}},"contextParameters":{"parameterClassName":"org.onap.policy.apex.context.parameters.ContextParameters","schemaParameters":{"Avro":{"parameterClassName":"org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"}}},"taskParameters":[{"key":"ORU-ODU-Map","value":"{\"ERICSSON-O-RU-11220\": \"HCL-O-DU-1122\",\n \"ERICSSON-O-RU-11221\": \"HCL-O-DU-1122\",\n \"ERICSSON-O-RU-11222\": \"HCL-O-DU-1122\",\n \"ERICSSON-O-RU-11223\": \"HCL-O-DU-1122\",\n \"ERICSSON-O-RU-11224\": \"HCL-O-DU-1123\",\n \"ERICSSON-O-RU-11225\": \"HCL-O-DU-1123\",\n \"ERICSSON-O-RU-11226\": \"HCL-O-DU-1123\",\n \"ERICSSON-O-RU-11227\": \"HCL-O-DU-1124\",\n \"ERICSSON-O-RU-11228\": \"HCL-O-DU-1125\",\n \"ERICSSON-O-RU-11229\": \"HCL-O-DU-1125\"}"}]},"policy_type_impl":{"apexPolicyModel":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"keyInformation":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"keyInfoMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"UUID":"cca47d74-7754-4a61-b163-ca31f66b157b","description":"Generated description for concept referred to by key \"ApexMessageOutputEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"UUID":"a295d6a3-1b73-387e-abba-b41e9b608802","description":"Generated description for concept referred to by key \"CreateLinkClearedOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"UUID":"fd594e88-411d-4a94-b2be-697b3a0d7adf","description":"This task creates the output fields when link failure is cleared."}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"UUID":"02be2b5d-45b7-3c54-ae54-97f2b5c30125","description":"Generated description for concept referred to by key \"CreateLinkFailureOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"UUID":"ac3d9842-80af-4a98-951c-bd79a431c613","description":"This task the output fields when link failure is detected."}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"UUID":"eecfde90-896c-4343-8f9c-2603ced94e2d","description":"This task sends a message to the output when link failure is cleared."}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"UUID":"c4500941-3f98-4080-a9cc-5b9753ed050b","description":"Generated description for concept referred to by key \"LinkFailureInputEvent:0.0.1\""}},{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"UUID":"3b3974fc-3012-3b02-9f33-c9d8eefe4dc1","description":"Generated description for concept referred to by key \"LinkFailureInputSchema:0.0.1\""}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"UUID":"4f04aa98-e917-4f4a-882a-c75ba5a99374","description":"Generated description for concept referred to by key \"LinkFailureOutputEvent:0.0.1\""}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"UUID":"2d1a7f6e-eb9a-3984-be1f-283d98111b84","description":"Generated description for concept referred to by key \"LinkFailureOutputSchema:0.0.1\""}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"UUID":"3351b0f4-cf06-4fa2-8823-edf67bd30223","description":"This task updates the config for O-RU when link failure is detected."}},{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"UUID":"540226fb-55ee-4f0e-a444-983a0494818e","description":"This is the Apex Policy Model for link monitoring."}},{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"UUID":"27ad3e7e-fe3b-3bd6-9081-718705c2bcea","description":"Generated description for concept referred to by key \"LinkMonitorModel_Events:0.0.1\""}},{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"UUID":"ea0b5f58-eefd-358a-9660-840c640bf981","description":"Generated description for concept referred to by key \"LinkMonitorModel_KeyInfo:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"UUID":"ee9e0b0f-2b7d-3ab7-9a98-c5ec05ed823d","description":"Generated description for concept referred to by key \"LinkMonitorModel_Policies:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"UUID":"fa5f9b8f-796c-3c70-84e9-5140c958c4bb","description":"Generated description for concept referred to by key \"LinkMonitorModel_Schemas:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"UUID":"eec592f7-69d5-39a9-981a-e552f787ed01","description":"Generated description for concept referred to by key \"LinkMonitorModel_Tasks:0.0.1\""}},{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"UUID":"6c5e410f-489a-46ff-964e-982ce6e8b6d0","description":"Generated description for concept referred to by key \"LinkMonitorPolicy:0.0.1\""}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"UUID":"ac4b34ac-39d6-3393-a267-8d5b84854018","description":"A schema for messages from apex"}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"UUID":"d48b619e-d00d-4008-b884-02d76ea4350b","description":"This task sends a message to the output when an event is received for which no policy has been defined."}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"UUID":"50662174-a88b-3cbd-91bd-8e91b40b2660","description":"A schema for O-DU-ID"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"UUID":"54daf32b-015f-39cd-8530-a1175c5553e9","description":"A schema for O-RU-ID"}}]}},"policies":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"policyMap":{"entry":[{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"policyKey":{"name":"LinkMonitorPolicy","version":"0.0.1"},"template":"Freestyle","state":{"entry":[{"key":"LinkClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"},"trigger":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkClearedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkClearedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureOrClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureOrClearedState"},"trigger":{"name":"LinkFailureInputEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"CreateLinkClearedOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"}}},{"key":"CreateLinkFailureOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"}}},{"key":"NoPolicyDefinedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"TaskSelectionLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Selection Execution: '\"+executor.subject.id+\n \"'. InputFields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar commonEventHeader = linkFailureInput.get(\"event\").get(\"commonEventHeader\");\nvar domain = commonEventHeader.get(\"domain\");\n\ntaskFailure = executor.subject.getTaskKey(\"CreateLinkFailureOutfieldsTask\");\ntaskCleared = executor.subject.getTaskKey(\"CreateLinkClearedOutfieldsTask\");\ntaskDefault = executor.subject.getDefaultTaskKey();\n\nif (domain == \"fault\") {\n var faultFields = linkFailureInput.get(\"event\").get(\"faultFields\");\n var alarmCondition = faultFields.get(\"alarmCondition\");\n var eventSeverity = faultFields.get(\"eventSeverity\");\n if (alarmCondition == \"28\" && eventSeverity != \"NORMAL\") {\n taskFailure.copyTo(executor.selectedTask);\n } else if (alarmCondition == \"28\" && eventSeverity == \"NORMAL\") {\n taskCleared.copyTo(executor.selectedTask);\n } else {\n taskDefault.copyTo(executor.selectedTask);\n }\n} else {\n taskDefault.copyTo(executor.selectedTask);\n}\n\ntrue;"},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"},"trigger":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkFailureLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"},"outgoingEvent":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkFailureTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"}}}]}}}]},"firstState":"LinkFailureOrClearedState"}}]}},"tasks":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"taskMap":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\n\nexecutor.outFields.put(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar returnValue = true;\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\nvar oruOduMap = JSON.parse(executor.parameters.get(\"ORU-ODU-Map\"));\n\nif (oruId in oruOduMap) {\n var oduId = oruOduMap[oruId];\n executor.outFields.put(\"OruId\", oruId);\n executor.outFields.put(\"OduId\", oduId);\n executor.logger.info(executor.outFields);\n} else {\n executor.message = \"No O-RU found in the config with this ID: \" + oruId;\n returnValue = false;\n}\n\nreturnValue;"}}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar oruId = executor.inFields.get(\"OruId\");\n\nexecutor.outFields.put(\"message\", \"CLEARED link failure for O-RU: \" + oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureOutput = executor.subject.getOutFieldSchemaHelper(\"LinkFailureOutput\").createNewInstance();\n\nvar oruId = executor.inFields.get(\"OruId\");\nvar oduId = executor.inFields.get(\"OduId\");\n\nvar unlockMessageArray = new java.util.ArrayList();\nfor (var i = 0; i < 1; i++) {\n unlockMessageArray.add({\n \"name\" : oruId,\n \"administrative_DasH_state\" : \"UNLOCKED\"\n });\n}\n\nlinkFailureOutput.put(\"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection\", unlockMessageArray);\nexecutor.outFields.put(\"LinkFailureOutput\", linkFailureOutput.toString());\n\nexecutor.getExecutionProperties().setProperty(\"OduId\", oduId);\nexecutor.getExecutionProperties().setProperty(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nexecutor.outFields.put(\"message\", \"No policy defined for this event\");\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}}]}},"events":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"eventMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"DMAAP","target":"APEX","parameter":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"OAM","parameter":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]}}}]}},"schemas":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"schemas":{"entry":[{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n \"type\": \"record\",\n \"name\": \"Link_Failure_Input\",\n \"fields\": [\n {\n \"name\": \"event\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Event_Type\",\n \"fields\": [\n {\n \"name\": \"commonEventHeader\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Common_Event_Header_Type\",\n \"fields\": [\n {\n \"name\": \"domain\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sequence\",\n \"type\": \"int\"\n },\n {\n \"name\": \"priority\",\n \"type\": \"string\"\n },\n {\n \"name\": \"reportingEntityId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"reportingEntityName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sourceId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sourceName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"startEpochMicrosec\",\n \"type\": \"string\"\n },\n {\n \"name\": \"lastEpochMicrosec\",\n \"type\": \"string\"\n },\n {\n \"name\": \"nfNamingCode\",\n \"type\": \"string\"\n },\n {\n \"name\": \"nfVendorName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"timeZoneOffset\",\n \"type\": \"string\"\n },\n {\n \"name\": \"version\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vesEventListenerVersion\",\n \"type\": \"string\"\n }\n ]\n }\n },\n {\n \"name\": \"faultFields\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Fault_Fields_Type\",\n \"fields\": [\n {\n \"name\": \"faultFieldsVersion\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmCondition\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmInterfaceA\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventSourceType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"specificProblem\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventSeverity\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vfStatus\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmAdditionalInformation\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Alarm_Additional_Information_Type\",\n \"fields\": [\n {\n \"name\": \"eventTime\",\n \"type\": \"string\"\n },\n {\n \"name\": \"equipType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vendor\",\n \"type\": \"string\"\n },\n {\n \"name\": \"model\",\n \"type\": \"string\"\n }\n ]\n }\n }\n ]\n }\n }\n ]\n }\n }\n ]\n}"}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n \"type\": \"record\",\n \"name\": \"Link_Failure_Output\",\n \"fields\": [\n {\n \"name\": \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection\",\n \"type\": {\n \t\"type\": \"array\",\n \t\"items\": {\n\t\t \"name\": \"Config_Change_Message\",\n \"type\": \"record\",\n \"fields\": [\n {\n \"name\": \"name\",\n \"type\": \"string\"\n },\n\t\t\t{\n \"name\": \"administrative_DasH_state\",\n \"type\": \"string\"\n }\n ]\n }\n\t }\n }\n ]\n}"}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}}]}}}}},"eventOutputParameters":{"RestProducer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection={OruId}","httpMethod":"PUT","httpHeaders":[["Authorization","Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="]]}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"LinkFailureOutput"}},"eventNameFilter":"LinkFailureOutputEvent"},"StdOutProducer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"message"}},"eventNameFilter":"ApexMessageOutputEvent"}},"eventInputParameters":{"DMaaPConsumer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://onap-dmaap:3904/events/unauthenticated.SEC_FAULT_OUTPUT/users/link-monitor-nonrtric?timeout=15000&limit=100"}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"versionAlias":"version","pojoField":"LinkFailureInput"}},"eventName":"LinkFailureInputEvent"}}}}}]}} \ No newline at end of file +{"tosca_definitions_version":"tosca_simple_yaml_1_1_0","topology_template":{"policies":[{"onap.policies.native.apex.LinkMonitor":{"type":"onap.policies.native.Apex","type_version":"1.0.0","name":"onap.policies.native.apex.LinkMonitor","version":"1.0.0","properties":{"engineServiceParameters":{"name":"LinkMonitorApexEngine","version":"0.0.1","id":101,"instanceCount":1,"deploymentPort":12345,"engineParameters":{"executorParameters":{"JAVASCRIPT":{"parameterClassName":"org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"}},"contextParameters":{"parameterClassName":"org.onap.policy.apex.context.parameters.ContextParameters","schemaParameters":{"Avro":{"parameterClassName":"org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"}}},"taskParameters":[{"key":"ORU-ODU-Map","value":"{\"ERICSSON-O-RU-11220\": \"O-DU-1122\",\r\n \"ERICSSON-O-RU-11221\": \"O-DU-1122\",\r\n \"ERICSSON-O-RU-11222\": \"O-DU-1122\",\r\n \"ERICSSON-O-RU-11223\": \"O-DU-1122\",\r\n \"ERICSSON-O-RU-11224\": \"O-DU-1123\",\r\n \"ERICSSON-O-RU-11225\": \"O-DU-1123\",\r\n \"ERICSSON-O-RU-11226\": \"O-DU-1123\",\r\n \"ERICSSON-O-RU-11227\": \"O-DU-1124\",\r\n \"ERICSSON-O-RU-11228\": \"O-DU-1125\",\r\n \"ERICSSON-O-RU-11229\": \"O-DU-1125\"}"}]},"policy_type_impl":{"apexPolicyModel":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"keyInformation":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"keyInfoMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"UUID":"cca47d74-7754-4a61-b163-ca31f66b157b","description":"Generated description for concept referred to by key \"ApexMessageOutputEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"UUID":"a295d6a3-1b73-387e-abba-b41e9b608802","description":"Generated description for concept referred to by key \"CreateLinkClearedOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"UUID":"fd594e88-411d-4a94-b2be-697b3a0d7adf","description":"This task creates the output fields when link failure is cleared."}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"UUID":"02be2b5d-45b7-3c54-ae54-97f2b5c30125","description":"Generated description for concept referred to by key \"CreateLinkFailureOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"UUID":"ac3d9842-80af-4a98-951c-bd79a431c613","description":"This task the output fields when link failure is detected."}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"UUID":"eecfde90-896c-4343-8f9c-2603ced94e2d","description":"This task sends a message to the output when link failure is cleared."}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"UUID":"c4500941-3f98-4080-a9cc-5b9753ed050b","description":"Generated description for concept referred to by key \"LinkFailureInputEvent:0.0.1\""}},{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"UUID":"3b3974fc-3012-3b02-9f33-c9d8eefe4dc1","description":"Generated description for concept referred to by key \"LinkFailureInputSchema:0.0.1\""}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"UUID":"4f04aa98-e917-4f4a-882a-c75ba5a99374","description":"Generated description for concept referred to by key \"LinkFailureOutputEvent:0.0.1\""}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"UUID":"2d1a7f6e-eb9a-3984-be1f-283d98111b84","description":"Generated description for concept referred to by key \"LinkFailureOutputSchema:0.0.1\""}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"UUID":"3351b0f4-cf06-4fa2-8823-edf67bd30223","description":"This task updates the config for O-RU when link failure is detected."}},{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"UUID":"540226fb-55ee-4f0e-a444-983a0494818e","description":"This is the Apex Policy Model for link monitoring."}},{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"UUID":"27ad3e7e-fe3b-3bd6-9081-718705c2bcea","description":"Generated description for concept referred to by key \"LinkMonitorModel_Events:0.0.1\""}},{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"UUID":"ea0b5f58-eefd-358a-9660-840c640bf981","description":"Generated description for concept referred to by key \"LinkMonitorModel_KeyInfo:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"UUID":"ee9e0b0f-2b7d-3ab7-9a98-c5ec05ed823d","description":"Generated description for concept referred to by key \"LinkMonitorModel_Policies:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"UUID":"fa5f9b8f-796c-3c70-84e9-5140c958c4bb","description":"Generated description for concept referred to by key \"LinkMonitorModel_Schemas:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"UUID":"eec592f7-69d5-39a9-981a-e552f787ed01","description":"Generated description for concept referred to by key \"LinkMonitorModel_Tasks:0.0.1\""}},{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"UUID":"6c5e410f-489a-46ff-964e-982ce6e8b6d0","description":"Generated description for concept referred to by key \"LinkMonitorPolicy:0.0.1\""}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"UUID":"ac4b34ac-39d6-3393-a267-8d5b84854018","description":"A schema for messages from apex"}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"UUID":"d48b619e-d00d-4008-b884-02d76ea4350b","description":"This task sends a message to the output when an event is received for which no policy has been defined."}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"UUID":"50662174-a88b-3cbd-91bd-8e91b40b2660","description":"A schema for O-DU-ID"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"UUID":"54daf32b-015f-39cd-8530-a1175c5553e9","description":"A schema for O-RU-ID"}}]}},"policies":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"policyMap":{"entry":[{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"policyKey":{"name":"LinkMonitorPolicy","version":"0.0.1"},"template":"Freestyle","state":{"entry":[{"key":"LinkClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"},"trigger":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkClearedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkClearedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureOrClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureOrClearedState"},"trigger":{"name":"LinkFailureInputEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"CreateLinkClearedOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"}}},{"key":"CreateLinkFailureOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"}}},{"key":"NoPolicyDefinedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"TaskSelectionLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Selection Execution: '\"+executor.subject.id+\n \"'. InputFields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar commonEventHeader = linkFailureInput.get(\"event\").get(\"commonEventHeader\");\nvar domain = commonEventHeader.get(\"domain\");\n\ntaskFailure = executor.subject.getTaskKey(\"CreateLinkFailureOutfieldsTask\");\ntaskCleared = executor.subject.getTaskKey(\"CreateLinkClearedOutfieldsTask\");\ntaskDefault = executor.subject.getDefaultTaskKey();\n\nif (domain == \"fault\") {\n var faultFields = linkFailureInput.get(\"event\").get(\"faultFields\");\n var alarmCondition = faultFields.get(\"alarmCondition\");\n var eventSeverity = faultFields.get(\"eventSeverity\");\n if (alarmCondition == \"28\" && eventSeverity != \"NORMAL\") {\n taskFailure.copyTo(executor.selectedTask);\n } else if (alarmCondition == \"28\" && eventSeverity == \"NORMAL\") {\n taskCleared.copyTo(executor.selectedTask);\n } else {\n taskDefault.copyTo(executor.selectedTask);\n }\n} else {\n taskDefault.copyTo(executor.selectedTask);\n}\n\ntrue;"},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"},"trigger":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkFailureLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"},"outgoingEvent":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkFailureTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"}}}]}}}]},"firstState":"LinkFailureOrClearedState"}}]}},"tasks":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"taskMap":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\n\nexecutor.outFields.put(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar returnValue = true;\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\nvar oruOduMap = JSON.parse(executor.parameters.get(\"ORU-ODU-Map\"));\n\nif (oruId in oruOduMap) {\n var oduId = oruOduMap[oruId];\n executor.outFields.put(\"OruId\", oruId);\n executor.outFields.put(\"OduId\", oduId);\n executor.logger.info(executor.outFields);\n} else {\n executor.message = \"No O-RU found in the config with this ID: \" + oruId;\n returnValue = false;\n}\n\nreturnValue;"}}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar oruId = executor.inFields.get(\"OruId\");\n\nexecutor.outFields.put(\"message\", \"CLEARED link failure for O-RU: \" + oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureOutput = executor.subject.getOutFieldSchemaHelper(\"LinkFailureOutput\").createNewInstance();\n\nvar oruId = executor.inFields.get(\"OruId\");\nvar oduId = executor.inFields.get(\"OduId\");\n\nvar unlockMessageArray = new java.util.ArrayList();\nfor (var i = 0; i < 1; i++) {\n unlockMessageArray.add({\n \"id\":\"rrm-pol-1\",\n \"radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio\":25,\n \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members\":\n [\n {\n \"mobile_DasH_country_DasH_code\":\"310\",\n \"mobile_DasH_network_DasH_code\":\"150\",\n \"slice_DasH_differentiator\":1,\n \"slice_DasH_service_DasH_type\":1\n }\n ],\n \"radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio\":15,\n \"user_DasH_label\":\"rrm-pol-1\",\n \"resource_DasH_type\":\"prb\",\n \"radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio\":20,\n \"administrative_DasH_state\":\"unlocked\"\n });\n}\n\nlinkFailureOutput.put(\"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio\", unlockMessageArray);\nexecutor.outFields.put(\"LinkFailureOutput\", linkFailureOutput.toString());\n\nexecutor.getExecutionProperties().setProperty(\"OduId\", oduId);\nexecutor.getExecutionProperties().setProperty(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nexecutor.outFields.put(\"message\", \"No policy defined for this event\");\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}}]}},"events":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"eventMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"DMAAP","target":"APEX","parameter":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"OAM","parameter":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]}}}]}},"schemas":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"schemas":{"entry":[{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n \"type\": \"record\",\n \"name\": \"Link_Failure_Input\",\n \"fields\": [\n {\n \"name\": \"event\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Event_Type\",\n \"fields\": [\n {\n \"name\": \"commonEventHeader\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Common_Event_Header_Type\",\n \"fields\": [\n {\n \"name\": \"domain\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sequence\",\n \"type\": \"int\"\n },\n {\n \"name\": \"priority\",\n \"type\": \"string\"\n },\n {\n \"name\": \"reportingEntityId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"reportingEntityName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sourceId\",\n \"type\": \"string\"\n },\n {\n \"name\": \"sourceName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"startEpochMicrosec\",\n \"type\": \"string\"\n },\n {\n \"name\": \"lastEpochMicrosec\",\n \"type\": \"string\"\n },\n {\n \"name\": \"nfNamingCode\",\n \"type\": \"string\"\n },\n {\n \"name\": \"nfVendorName\",\n \"type\": \"string\"\n },\n {\n \"name\": \"timeZoneOffset\",\n \"type\": \"string\"\n },\n {\n \"name\": \"version\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vesEventListenerVersion\",\n \"type\": \"string\"\n }\n ]\n }\n },\n {\n \"name\": \"faultFields\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Fault_Fields_Type\",\n \"fields\": [\n {\n \"name\": \"faultFieldsVersion\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmCondition\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmInterfaceA\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventSourceType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"specificProblem\",\n \"type\": \"string\"\n },\n {\n \"name\": \"eventSeverity\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vfStatus\",\n \"type\": \"string\"\n },\n {\n \"name\": \"alarmAdditionalInformation\",\n \"type\": {\n \"type\": \"record\",\n \"name\": \"Alarm_Additional_Information_Type\",\n \"fields\": [\n {\n \"name\": \"eventTime\",\n \"type\": \"string\"\n },\n {\n \"name\": \"equipType\",\n \"type\": \"string\"\n },\n {\n \"name\": \"vendor\",\n \"type\": \"string\"\n },\n {\n \"name\": \"model\",\n \"type\": \"string\"\n }\n ]\n }\n }\n ]\n }\n }\n ]\n }\n }\n ]\n}"}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n \"name\": \"Link_Failure_Output\",\n \"type\": \"record\",\n \"fields\": [\n {\n \"name\": \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio\",\n \"type\": {\n \"type\": \"array\",\n \"items\": {\n \"name\": \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio_record\",\n \"type\": \"record\",\n \"fields\": [\n {\n \"name\": \"id\",\n \"type\": \"string\"\n },\n {\n \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio\",\n \"type\": \"int\"\n },\n {\n \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members\",\n \"type\": {\n \"type\": \"array\",\n \"items\": {\n \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members_record\",\n \"type\": \"record\",\n \"fields\": [\n {\n \"name\": \"mobile_DasH_country_DasH_code\",\n \"type\": \"string\"\n },\n {\n \"name\": \"mobile_DasH_network_DasH_code\",\n \"type\": \"string\"\n },\n {\n \"name\": \"slice_DasH_differentiator\",\n \"type\": \"int\"\n },\n {\n \"name\": \"slice_DasH_service_DasH_type\",\n \"type\": \"int\"\n }\n ]\n }\n }\n },\n {\n \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio\",\n \"type\": \"int\"\n },\n {\n \"name\": \"user_DasH_label\",\n \"type\": \"string\"\n },\n {\n \"name\": \"resource_DasH_type\",\n \"type\": \"string\"\n },\n {\n \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio\",\n \"type\": \"int\"\n },\n {\n \"name\": \"administrative_DasH_state\",\n \"type\": \"string\"\n }\n ]\n }\n }\n }\n ]\n}"}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}}]}}}}},"eventOutputParameters":{"RestProducer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions={OduId}/radio-resource-management-policy-ratio=rrm-pol-1","httpMethod":"PUT","httpHeaders":[["Authorization","Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="]]}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"LinkFailureOutput"}},"eventNameFilter":"LinkFailureOutputEvent"},"StdOutProducer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"message"}},"eventNameFilter":"ApexMessageOutputEvent"}},"eventInputParameters":{"DMaaPConsumer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://onap-dmaap:3904/events/unauthenticated.SEC_FAULT_OUTPUT/users/link-monitor-nonrtric?timeout=15000&limit=100"}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"versionAlias":"version","pojoField":"LinkFailureInput"}},"eventName":"LinkFailureInputEvent"}}}}}]}} \ No newline at end of file diff --git a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js old mode 100644 new mode 100755 index 16fd06ae..ea79c336 --- a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js +++ b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js @@ -28,12 +28,26 @@ var oduId = executor.inFields.get("OduId"); var unlockMessageArray = new java.util.ArrayList(); for (var i = 0; i < 1; i++) { unlockMessageArray.add({ - "name" : oruId, - "administrative_DasH_state" : "UNLOCKED" - }); + "id":"rrm-pol-1", + "radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio":25, + "radio_DasH_resource_DasH_management_DasH_policy_DasH_members": + [ + { + "mobile_DasH_country_DasH_code":"310", + "mobile_DasH_network_DasH_code":"150", + "slice_DasH_differentiator":1, + "slice_DasH_service_DasH_type":1 + } + ], + "radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio":15, + "user_DasH_label":"rrm-pol-1", + "resource_DasH_type":"prb", + "radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio":20, + "administrative_DasH_state":"unlocked" + }); } -linkFailureOutput.put("o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection", unlockMessageArray); +linkFailureOutput.put("o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio", unlockMessageArray); executor.outFields.put("LinkFailureOutput", linkFailureOutput.toString()); executor.getExecutionProperties().setProperty("OduId", oduId); diff --git a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc old mode 100644 new mode 100755 index fb144a1d..c423047f --- a/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc +++ b/test/usecases/oruclosedlooprecovery/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc @@ -1,26 +1,74 @@ { - "type": "record", - "name": "Link_Failure_Output", - "fields": [ - { - "name": "o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection", - "type": { - "type": "array", - "items": { - "name": "Config_Change_Message", - "type": "record", - "fields": [ - { - "name": "name", - "type": "string" - }, - { - "name": "administrative_DasH_state", - "type": "string" - } - ] + "name": "Link_Failure_Output", + "type": "record", + "fields": [ + { + "name": "o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio", + "type": { + "type": "array", + "items": { + "name": "o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio_record", + "type": "record", + "fields": [ + { + "name": "id", + "type": "string" + }, + { + "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio", + "type": "int" + }, + { + "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_members", + "type": { + "type": "array", + "items": { + "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_members_record", + "type": "record", + "fields": [ + { + "name": "mobile_DasH_country_DasH_code", + "type": "string" + }, + { + "name": "mobile_DasH_network_DasH_code", + "type": "string" + }, + { + "name": "slice_DasH_differentiator", + "type": "int" + }, + { + "name": "slice_DasH_service_DasH_type", + "type": "int" + } + ] } - } + } + }, + { + "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio", + "type": "int" + }, + { + "name": "user_DasH_label", + "type": "string" + }, + { + "name": "resource_DasH_type", + "type": "string" + }, + { + "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio", + "type": "int" + }, + { + "name": "administrative_DasH_state", + "type": "string" + } + ] } - ] -} + } + } + ] +} \ No newline at end of file diff --git a/test/usecases/oruclosedlooprecovery/goversion/README.md b/test/usecases/oruclosedlooprecovery/goversion/README.md index b5b93553..06c44b29 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/README.md +++ b/test/usecases/oruclosedlooprecovery/goversion/README.md @@ -25,13 +25,16 @@ The configured public key and cerificate shall be PEM-encoded. A self signed cer ## Functionality -The creation of the job is not done when the consumer is started. Instead the consumer provides a REST API where it can be started and stopped, described below. +The creation of the job is not done when the consumer is started. Instead the consumer provides a REST API where it can be started and stopped, described below. The API is available on the host and port configured for the consumer ->- /start Creates the job in ICS. ->- /stop Deletes the job in ICS. +>- /admin/start Creates the job in ICS. +>- /admin/stop Deletes the job in ICS. If the consumer is shut down with a SIGTERM, it will also delete the job before exiting. +There is also a status call provided in the REST API. This will return the running status of the consumer as JSON. +>- /status {"status": "started/stopped"} + ## Development To make it easy to test during development of the consumer, three stubs are provided in the `stub` folder. diff --git a/test/usecases/oruclosedlooprecovery/goversion/container-tag.yaml b/test/usecases/oruclosedlooprecovery/goversion/container-tag.yaml index 6b1c9db7..5b018097 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/container-tag.yaml +++ b/test/usecases/oruclosedlooprecovery/goversion/container-tag.yaml @@ -2,4 +2,4 @@ # By default this file is in the docker build directory, # but the location can configured in the JJB template. --- -tag: 1.0.0 +tag: 1.0.1 diff --git a/test/usecases/oruclosedlooprecovery/goversion/internal/config/config.go b/test/usecases/oruclosedlooprecovery/goversion/internal/config/config.go index 718f435f..52331283 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/internal/config/config.go +++ b/test/usecases/oruclosedlooprecovery/goversion/internal/config/config.go @@ -57,7 +57,7 @@ func New() *Config { } func (c Config) String() string { - return fmt.Sprintf("ConsumerHost: %v, ConsumerPort: %v, InfoCoordinatorAddress: %v, SDNRAddress: %v, SDNRUser: %v, SDNRPassword: %v, ORUToODUMapFile: %v, ConsumerCertPath: %v, ConsumerKeyPath: %v, LogLevel: %v", c.ConsumerHost, c.ConsumerPort, c.InfoCoordinatorAddress, c.SDNRAddress, c.SDNRUser, c.SDNPassword, c.ORUToODUMapFile, c.ConsumerCertPath, c.ConsumerKeyPath, c.LogLevel) + return fmt.Sprintf("{ConsumerHost: %v, ConsumerPort: %v, InfoCoordinatorAddress: %v, SDNRAddress: %v, SDNRUser: %v, SDNRPassword: %v, ORUToODUMapFile: %v, ConsumerCertPath: %v, ConsumerKeyPath: %v, LogLevel: %v}", c.ConsumerHost, c.ConsumerPort, c.InfoCoordinatorAddress, c.SDNRAddress, c.SDNRUser, c.SDNPassword, c.ORUToODUMapFile, c.ConsumerCertPath, c.ConsumerKeyPath, c.LogLevel) } func getEnv(key string, defaultVal string) string { diff --git a/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler.go b/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler.go index 3aecf45c..26b3ab32 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler.go +++ b/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler.go @@ -37,8 +37,8 @@ type Configuration struct { SDNRPassword string } -const rawSdnrPath = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection=[O-RU-ID]" -const unlockMessage = `{"o-ran-sc-du-hello-world:du-to-ru-connection": [{"name":"[O-RU-ID]","administrative-state":"UNLOCKED"}]}` +const rawSdnrPath = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=[O-DU-ID]/radio-resource-management-policy-ratio=rrm-pol-1" +const unlockMessage = `{"o-ran-sc-du-hello-world:radio-resource-management-policy-ratio":[{"id":"rrm-pol-1","radio-resource-management-policy-max-ratio":25,"radio-resource-management-policy-members":[{"mobile-country-code":"310","mobile-network-code":"150","slice-differentiator":1,"slice-service-type":1}],"radio-resource-management-policy-min-ratio":15,"user-label":"rrm-pol-1","resource-type":"prb","radio-resource-management-policy-dedicated-ratio":20,"administrative-state":"unlocked"}]}` type LinkFailureHandler struct { lookupService repository.LookupService @@ -71,8 +71,7 @@ func (lfh LinkFailureHandler) MessagesHandler(w http.ResponseWriter, r *http.Req func (lfh LinkFailureHandler) sendUnlockMessage(oRuId string) { if oDuId, err := lfh.lookupService.GetODuID(oRuId); err == nil { - sdnrPath := getSdnrPath(oRuId, oDuId) - unlockMessage := lfh.getUnlockMessage(oRuId) + sdnrPath := getSdnrPath(oDuId) if error := restclient.Put(lfh.config.SDNRAddress+sdnrPath, unlockMessage, lfh.client, lfh.config.SDNRUser, lfh.config.SDNRPassword); error == nil { log.Debugf("Sent unlock message for O-RU: %v to O-DU: %v.", oRuId, oDuId) } else { @@ -84,12 +83,7 @@ func (lfh LinkFailureHandler) sendUnlockMessage(oRuId string) { } -func getSdnrPath(oRuId string, oDuId string) string { - sdnrPath := strings.Replace(rawSdnrPath, "[O-DU-ID]", oDuId, 1) - sdnrPath = strings.Replace(sdnrPath, "[O-RU-ID]", oRuId, 1) +func getSdnrPath(oDuId string) string { + sdnrPath := strings.Replace(rawSdnrPath, "[O-DU-ID]", oDuId, -1) return sdnrPath } - -func (lfh LinkFailureHandler) getUnlockMessage(oRuId string) string { - return strings.Replace(unlockMessage, "[O-RU-ID]", oRuId, 1) -} diff --git a/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler_test.go b/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler_test.go index a3df7044..050417f5 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler_test.go +++ b/test/usecases/oruclosedlooprecovery/goversion/internal/linkfailure/linkfailurehandler_test.go @@ -56,7 +56,7 @@ func Test_MessagesHandlerWithLinkFailure(t *testing.T) { lookupServiceMock := mocks.LookupService{} - lookupServiceMock.On("GetODuID", mock.Anything).Return("HCL-O-DU-1122", nil) + lookupServiceMock.On("GetODuID", mock.Anything).Return("O-DU-1122", nil) handlerUnderTest := NewLinkFailureHandler(&lookupServiceMock, Configuration{ SDNRAddress: "http://localhost:9990", @@ -78,21 +78,21 @@ func Test_MessagesHandlerWithLinkFailure(t *testing.T) { assertions.Equal(http.MethodPut, actualRequest.Method) assertions.Equal("http", actualRequest.URL.Scheme) assertions.Equal("localhost:9990", actualRequest.URL.Host) - expectedSdnrPath := "/rests/data/network-topology:network-topology/topology=topology-netconf/node=HCL-O-DU-1122/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection=ERICSSON-O-RU-11220" + expectedSdnrPath := "/rests/data/network-topology:network-topology/topology=topology-netconf/node=O-DU-1122/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=O-DU-1122/radio-resource-management-policy-ratio=rrm-pol-1" assertions.Equal(expectedSdnrPath, actualRequest.URL.Path) assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type")) tempRequest, _ := http.NewRequest("", "", nil) tempRequest.SetBasicAuth("admin", "pwd") assertions.Equal(tempRequest.Header.Get("Authorization"), actualRequest.Header.Get("Authorization")) body, _ := ioutil.ReadAll(actualRequest.Body) - expectedBody := []byte(`{"o-ran-sc-du-hello-world:du-to-ru-connection": [{"name":"ERICSSON-O-RU-11220","administrative-state":"UNLOCKED"}]}`) + expectedBody := []byte(`{"o-ran-sc-du-hello-world:radio-resource-management-policy-ratio":[{"id":"rrm-pol-1","radio-resource-management-policy-max-ratio":25,"radio-resource-management-policy-members":[{"mobile-country-code":"310","mobile-network-code":"150","slice-differentiator":1,"slice-service-type":1}],"radio-resource-management-policy-min-ratio":15,"user-label":"rrm-pol-1","resource-type":"prb","radio-resource-management-policy-dedicated-ratio":20,"administrative-state":"unlocked"}]}`) assertions.Equal(expectedBody, body) clientMock.AssertNumberOfCalls(t, "Do", 1) logString := buf.String() assertions.Contains(logString, "Sent unlock message") assertions.Contains(logString, "O-RU: ERICSSON-O-RU-11220") - assertions.Contains(logString, "O-DU: HCL-O-DU-1122") + assertions.Contains(logString, "O-DU: O-DU-1122") } func newRequest(method string, url string, bodyAsBytes []byte, t *testing.T) *http.Request { @@ -117,7 +117,7 @@ func Test_MessagesHandlerWithClearLinkFailure(t *testing.T) { lookupServiceMock := mocks.LookupService{} - lookupServiceMock.On("GetODuID", mock.Anything).Return("HCL-O-DU-1122", nil) + lookupServiceMock.On("GetODuID", mock.Anything).Return("O-DU-1122", nil) handlerUnderTest := NewLinkFailureHandler(&lookupServiceMock, Configuration{}, nil) diff --git a/test/usecases/oruclosedlooprecovery/goversion/main.go b/test/usecases/oruclosedlooprecovery/goversion/main.go index 4bf4ec63..c3d731f4 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/main.go +++ b/test/usecases/oruclosedlooprecovery/goversion/main.go @@ -56,6 +56,7 @@ var configuration *config.Config var linkfailureConfig linkfailure.Configuration var lookupService repository.LookupService var consumerPort string +var started bool func init() { doInit() @@ -130,6 +131,7 @@ func getRouter() *mux.Router { r := mux.NewRouter() r.HandleFunc("/", messageHandler.MessagesHandler).Methods(http.MethodPost).Name("messageHandler") + r.HandleFunc("/status", statusHandler).Methods(http.MethodGet).Name("status") r.HandleFunc("/admin/start", startHandler).Methods(http.MethodPost).Name("start") r.HandleFunc("/admin/stop", stopHandler).Methods(http.MethodPost).Name("stop") @@ -164,6 +166,7 @@ func startHandler(w http.ResponseWriter, r *http.Request) { return } log.Debug("Registered job.") + started = true } func stopHandler(w http.ResponseWriter, r *http.Request) { @@ -173,6 +176,15 @@ func stopHandler(w http.ResponseWriter, r *http.Request) { return } log.Debug("Deleted job.") + started = false +} + +func statusHandler(w http.ResponseWriter, r *http.Request) { + runStatus := "started" + if !started { + runStatus = "stopped" + } + fmt.Fprintf(w, `{"status": "%v"}`, runStatus) } func deleteOnShutdown(s chan os.Signal) { diff --git a/test/usecases/oruclosedlooprecovery/goversion/main_test.go b/test/usecases/oruclosedlooprecovery/goversion/main_test.go index 6b1b0e51..c0e29731 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/main_test.go +++ b/test/usecases/oruclosedlooprecovery/goversion/main_test.go @@ -189,6 +189,14 @@ func Test_getRouter_shouldContainAllPathsWithHandlers(t *testing.T) { assertions.Nil(err) path, _ = stopHandlerRoute.GetPathTemplate() assertions.Equal("/admin/stop", path) + + statusHandlerRoute := r.Get("status") + assertions.NotNil(statusHandlerRoute) + supportedMethods, err = statusHandlerRoute.GetMethods() + assertions.Equal([]string{http.MethodGet}, supportedMethods) + assertions.Nil(err) + path, _ = statusHandlerRoute.GetPathTemplate() + assertions.Equal("/status", path) } func Test_startHandler(t *testing.T) { @@ -264,6 +272,16 @@ func Test_startHandler(t *testing.T) { expectedBody := wantedBody assertions.Equal(expectedBody, body) clientMock.AssertNumberOfCalls(t, "Do", 1) + + // Check that the running status is "started" + statusHandler := http.HandlerFunc(statusHandler) + statusResponseRecorder := httptest.NewRecorder() + statusRequest, _ := http.NewRequest(http.MethodGet, "/status", nil) + + statusHandler.ServeHTTP(statusResponseRecorder, statusRequest) + + assertions.Equal(http.StatusOK, statusResponseRecorder.Code) + assertions.Equal(`{"status": "started"}`, statusResponseRecorder.Body.String()) }) } } @@ -324,6 +342,16 @@ func Test_stopHandler(t *testing.T) { assertions.Equal("enrichmentservice:8083", actualRequest.URL.Host) assertions.Equal("/data-consumer/v1/info-jobs/14e7bb84-a44d-44c1-90b7-6995a92ad43c", actualRequest.URL.Path) clientMock.AssertNumberOfCalls(t, "Do", 1) + + // Check that the running status is "stopped" + statusHandler := http.HandlerFunc(statusHandler) + statusResponseRecorder := httptest.NewRecorder() + statusRequest, _ := http.NewRequest(http.MethodGet, "/status", nil) + + statusHandler.ServeHTTP(statusResponseRecorder, statusRequest) + + assertions.Equal(http.StatusOK, statusResponseRecorder.Code) + assertions.Equal(`{"status": "stopped"}`, statusResponseRecorder.Body.String()) }) } } diff --git a/test/usecases/oruclosedlooprecovery/goversion/o-ru-to-o-du-map.csv b/test/usecases/oruclosedlooprecovery/goversion/o-ru-to-o-du-map.csv index 951337af..2c5417d8 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/o-ru-to-o-du-map.csv +++ b/test/usecases/oruclosedlooprecovery/goversion/o-ru-to-o-du-map.csv @@ -1,11 +1,11 @@ -ERICSSON-O-RU-11220,HCL-O-DU-1122 -ERICSSON-O-RU-11221,HCL-O-DU-1122 -ERICSSON-O-RU-11222,HCL-O-DU-1122 -ERICSSON-O-RU-11223,HCL-O-DU-1122 -ERICSSON-O-RU-11223,HCL-O-DU-1122 -ERICSSON-O-RU-11224,HCL-O-DU-1123 -ERICSSON-O-RU-11225,HCL-O-DU-1123 -ERICSSON-O-RU-11226,HCL-O-DU-1123 -ERICSSON-O-RU-11227,HCL-O-DU-1124 -ERICSSON-O-RU-11228,HCL-O-DU-1125 -ERICSSON-O-RU-11229,HCL-O-DU-1125 \ No newline at end of file +ERICSSON-O-RU-11220,O-DU-1122 +ERICSSON-O-RU-11221,O-DU-1122 +ERICSSON-O-RU-11222,O-DU-1122 +ERICSSON-O-RU-11223,O-DU-1122 +ERICSSON-O-RU-11223,O-DU-1122 +ERICSSON-O-RU-11224,O-DU-1123 +ERICSSON-O-RU-11225,O-DU-1123 +ERICSSON-O-RU-11226,O-DU-1123 +ERICSSON-O-RU-11227,O-DU-1124 +ERICSSON-O-RU-11228,O-DU-1125 +ERICSSON-O-RU-11229,O-DU-1125 \ No newline at end of file diff --git a/test/usecases/oruclosedlooprecovery/goversion/pom.xml b/test/usecases/oruclosedlooprecovery/goversion/pom.xml deleted file mode 100644 index 60cf9ffc..00000000 --- a/test/usecases/oruclosedlooprecovery/goversion/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - 4.0.0 - - oransc.org - o-ru-closed-loop-consumer - 1.0.0 - - 0.30.0 - - - - - - exec-maven-plugin - org.codehaus.mojo - - - Build Go binary - generate-sources - - exec - - - ${basedir}/build_and_test.sh - - - - - - io.fabric8 - docker-maven-plugin - ${docker-maven-plugin.version} - false - - - generate-nonrtric-o-ru-closed-loop-consumer-image - package - - build - - - ${env.CONTAINER_PULL_REGISTRY} - - - o-ran-sc/nonrtric-o-ru-closed-loop-consumer:${project.version} - - try - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - - - - - - - - push-nonrtric-o-ru-closed-loop-consumer-image - - build - push - - - ${env.CONTAINER_PULL_REGISTRY} - ${env.CONTAINER_PUSH_REGISTRY} - - - o-ran-sc/nonrtric-o-ru-closed-loop-consumer:${project.version} - - ${basedir} - Dockerfile - - ${project.build.finalName}.jar - - - ${project.version} - latest - - - - - - - - - - - diff --git a/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go b/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go index c2d9e73f..83170e0e 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go +++ b/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go @@ -36,7 +36,7 @@ var client = &http.Client{ func main() { port := flag.Int("port", 8083, "The port this consumer will listen on") flag.Parse() - fmt.Println("Starting SDNR stub on port ", *port) + fmt.Println("Starting ICS stub on port ", *port) r := mux.NewRouter() r.HandleFunc("/data-consumer/v1/info-jobs/{jobId}", handleCalls).Methods(http.MethodPut, http.MethodDelete) diff --git a/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go b/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go index 4af16cf5..e219e19d 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go +++ b/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go @@ -52,7 +52,7 @@ func createJobHandler(w http.ResponseWriter, r *http.Request) { started = true fmt.Println("Start pushing messages for job: ", id) - startPushingMessages() + go startPushingMessages() } func deleteJobHandler(w http.ResponseWriter, r *http.Request) { diff --git a/test/usecases/oruclosedlooprecovery/goversion/stub/sdnr/sdnrstub.go b/test/usecases/oruclosedlooprecovery/goversion/stub/sdnr/sdnrstub.go index fd0af03b..0bcd0f4b 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/stub/sdnr/sdnrstub.go +++ b/test/usecases/oruclosedlooprecovery/goversion/stub/sdnr/sdnrstub.go @@ -34,7 +34,7 @@ func main() { flag.Parse() r := mux.NewRouter() - r.HandleFunc("/rests/data/network-topology:network-topology/topology=topology-netconf/node={O-DU-ID}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection={O-RU-ID}", handleData) + r.HandleFunc("/rests/data/network-topology:network-topology/topology=topology-netconf/node={O-DU-ID}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions={O-DU-ID}/radio-resource-management-policy-ratio=rrm-pol-1", handleData) fmt.Println("Starting SDNR on port: ", *port) fmt.Println(http.ListenAndServe(fmt.Sprintf(":%v", *port), r)) diff --git a/test/usecases/oruclosedlooprecovery/scriptversion/app/Dockerfile b/test/usecases/oruclosedlooprecovery/scriptversion/app/Dockerfile index 4cb03c74..21b24b17 100644 --- a/test/usecases/oruclosedlooprecovery/scriptversion/app/Dockerfile +++ b/test/usecases/oruclosedlooprecovery/scriptversion/app/Dockerfile @@ -29,4 +29,13 @@ RUN apt-get install iputils-ping -y RUN pip install -r requirements.txt +ARG user=nonrtric +ARG group=nonrtric + +RUN groupadd $user && \ + useradd -r -g $group $user +RUN chown -R $user:$group /usr/src/app/ + +USER ${user} + CMD [ "python3", "-u", "main.py" ] diff --git a/test/usecases/oruclosedlooprecovery/scriptversion/app/main.py b/test/usecases/oruclosedlooprecovery/scriptversion/app/main.py index 8f5b2443..52f0ca85 100644 --- a/test/usecases/oruclosedlooprecovery/scriptversion/app/main.py +++ b/test/usecases/oruclosedlooprecovery/scriptversion/app/main.py @@ -24,14 +24,29 @@ import requests import time MR_PATH = "/events/[TOPIC]/users/test/" -SDNR_PATH = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection=[O-RU-ID]" +SDNR_PATH = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=[O-DU-ID]/radio-resource-management-policy-ratio=rrm-pol-1" FAUILT_ID = "28" UNLOCK_MESSAGE = { - "o-ran-sc-du-hello-world:du-to-ru-connection": [ + "o-ran-sc-du-hello-world:radio-resource-management-policy-ratio": + [ { - "name":"", - "administrative-state":"UNLOCKED" + "id":"rrm-pol-1", + "radio-resource-management-policy-max-ratio":25, + "radio-resource-management-policy-members": + [ + { + "mobile-country-code":"310", + "mobile-network-code":"150", + "slice-differentiator":1, + "slice-service-type":1 + } + ], + "radio-resource-management-policy-min-ratio":15, + "user-label":"rrm-pol-1", + "resource-type":"prb", + "radio-resource-management-policy-dedicated-ratio":20, + "administrative-state":"unlocked" } ] } @@ -71,8 +86,7 @@ def handle_link_failure(message, o_ru_to_o_du_map, sdnr_address, sdnr_user, sdnr o_du_id = o_ru_to_o_du_map[o_ru_id] verboseprint("O-DU ID: " + o_du_id) unlock_msg = json.loads(json.dumps(UNLOCK_MESSAGE)) - unlock_msg["o-ran-sc-du-hello-world:du-to-ru-connection"][0]["name"] = o_ru_id - send_path = SDNR_PATH.replace("[O-DU-ID]", o_du_id).replace("[O-RU-ID]", o_ru_id) + send_path = SDNR_PATH.replace("[O-DU-ID]", o_du_id) requests.put(sdnr_address + send_path, auth=(sdnr_user, sdnr_pwd), json=unlock_msg) else: print("ERROR: No mapping for O-RU ID: " + o_ru_id) diff --git a/test/usecases/oruclosedlooprecovery/scriptversion/app/o-ru-to-o-du-map.txt b/test/usecases/oruclosedlooprecovery/scriptversion/app/o-ru-to-o-du-map.txt index c9ec8eae..314495cf 100644 --- a/test/usecases/oruclosedlooprecovery/scriptversion/app/o-ru-to-o-du-map.txt +++ b/test/usecases/oruclosedlooprecovery/scriptversion/app/o-ru-to-o-du-map.txt @@ -1,13 +1,13 @@ { - "ERICSSON-O-RU-11220": "HCL-O-DU-1122", - "ERICSSON-O-RU-11221": "HCL-O-DU-1122", - "ERICSSON-O-RU-11222": "HCL-O-DU-1122", - "ERICSSON-O-RU-11223": "HCL-O-DU-1122", - "ERICSSON-O-RU-11223": "HCL-O-DU-1122", - "ERICSSON-O-RU-11224": "HCL-O-DU-1123", - "ERICSSON-O-RU-11225": "HCL-O-DU-1123", - "ERICSSON-O-RU-11226": "HCL-O-DU-1123", - "ERICSSON-O-RU-11227": "HCL-O-DU-1124", - "ERICSSON-O-RU-11228": "HCL-O-DU-1125", - "ERICSSON-O-RU-11229": "HCL-O-DU-1125", + "ERICSSON-O-RU-11220": "O-DU-1122", + "ERICSSON-O-RU-11221": "O-DU-1122", + "ERICSSON-O-RU-11222": "O-DU-1122", + "ERICSSON-O-RU-11223": "O-DU-1122", + "ERICSSON-O-RU-11223": "O-DU-1122", + "ERICSSON-O-RU-11224": "O-DU-1123", + "ERICSSON-O-RU-11225": "O-DU-1123", + "ERICSSON-O-RU-11226": "O-DU-1123", + "ERICSSON-O-RU-11227": "O-DU-1124", + "ERICSSON-O-RU-11228": "O-DU-1125", + "ERICSSON-O-RU-11229": "O-DU-1125", } \ No newline at end of file diff --git a/test/usecases/oruclosedlooprecovery/scriptversion/simulators/sdnr_simulator.py b/test/usecases/oruclosedlooprecovery/scriptversion/simulators/sdnr_simulator.py index 535c3ee0..a44c0734 100644 --- a/test/usecases/oruclosedlooprecovery/scriptversion/simulators/sdnr_simulator.py +++ b/test/usecases/oruclosedlooprecovery/scriptversion/simulators/sdnr_simulator.py @@ -39,7 +39,7 @@ MR_PATH = "/events/unauthenticated.SEC_FAULT_OUTPUT" # Server info HOST_IP = "::" HOST_PORT = 9990 -APP_URL = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection=" +APP_URL = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=/radio-resource-management-policy-ratio=rrm-pol-1" USERNAME = "admin" PASSWORD = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U" @@ -88,17 +88,17 @@ linkFailureMessage = { class AlarmClearThread (threading.Thread): - def __init__(self, sleep_time, o_ru_id): + def __init__(self, sleep_time, o_du_id): threading.Thread.__init__(self) self.sleep_time = sleep_time - self.o_ru_id = o_ru_id + self.o_du_id = o_du_id def run(self): - print(f'Sleeping: {self.sleep_time} before clearing O-DU: {self.o_ru_id}') + print(f'Sleeping: {self.sleep_time} before clearing O-DU: {self.o_du_id}') time.sleep(self.sleep_time) msg_as_json = json.loads(json.dumps(linkFailureMessage)) - msg_as_json["event"]["commonEventHeader"]["sourceName"] = self.o_ru_id - print("Sedning alarm clear for O-RU: " + self.o_ru_id) + msg_as_json["event"]["commonEventHeader"]["sourceName"] = self.o_du_id + print("Sedning alarm clear for O-DU: " + self.o_du_id) requests.post(mr_host + ":" + mr_port + MR_PATH, json=msg_as_json); @@ -118,10 +118,10 @@ def verify_password(username, password): @app.route(APP_URL, methods=['PUT']) @auth.login_required -def sendrequest(o_du_id, o_ru_id): - print("Got request with O-DU ID: " + o_du_id + " and O-RU ID: " + o_ru_id) +def sendrequest(o_du_id, o_du_id2): + print("Got request with O-DU ID: " + o_du_id) random_time = int(10 * random.random()) - alarm_clear_thread = AlarmClearThread(random_time, o_ru_id) + alarm_clear_thread = AlarmClearThread(random_time, o_du_id) alarm_clear_thread.start() return Response(status=200) -- 2.16.6