summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorSirisha_Manchikanti <sirisha.manchikanti@est.tech>2021-05-07 15:17:52 +0100
committerSirisha_Manchikanti <sirisha.manchikanti@est.tech>2021-05-13 09:00:52 +0100
commitf83411a86e2277adae69e780e8511913d61a0f17 (patch)
treed75f197e703270cda608c9bd0d236f7ce8c12e13 /runtime
parentcac5cc982413ab9593186d308eda8936e9603ad9 (diff)
Modular structure of clamp including controlloop
This commit is the first commit that puts in multi module structure while changing the existing CLAMP code as little as possible. It adds a structure where common, models, participant and runtime are direct children under clamp, and current clamp code is moved under runtime. This runtime directory will host controlloop runtime code in later commits. Issue-ID: POLICY-3215 Signed-off-by: Sirisha_Manchikanti <sirisha.manchikanti@est.tech> Change-Id: I15bc8be92ed020343bff4024c4718fec462c40d7 Signed-off-by: liamfallon <liam.fallon@est.tech>
Diffstat (limited to 'runtime')
-rwxr-xr-xruntime/extra/bin-for-dev/start-backend.sh28
-rwxr-xr-xruntime/extra/bin-for-dev/start-db.sh35
-rwxr-xr-xruntime/extra/bin-for-dev/start-emulator.sh26
-rwxr-xr-xruntime/extra/bin-for-dev/start-frontend.sh27
-rw-r--r--runtime/extra/docker/clamp/clamp.env2
-rw-r--r--runtime/extra/docker/clamp/docker-compose.yml38
-rw-r--r--runtime/extra/docker/mariadb/conf1/my.cnf194
-rw-r--r--runtime/extra/docker/mariadb/conf2/my.cnf193
-rw-r--r--runtime/extra/docker/mariadb/conf3/my.cnf193
-rwxr-xr-xruntime/extra/sql/bootstrap-database.sh28
-rw-r--r--runtime/extra/sql/bulkload/create-db.sql11
-rw-r--r--runtime/extra/sql/bulkload/create-tables.sql255
-rwxr-xr-xruntime/extra/sql/dump/backup-data-only.sh26
-rwxr-xr-xruntime/extra/sql/dump/backup-database.sh26
-rwxr-xr-xruntime/extra/sql/dump/load-fake-data.sh26
-rw-r--r--runtime/extra/sql/dump/test-data.sql218
-rw-r--r--runtime/pom.xml1250
-rw-r--r--runtime/runtime/src/main/resources/META-INF/resources/swagger.html454
-rw-r--r--runtime/src/main/docker/backend/Dockerfile53
-rw-r--r--runtime/src/main/docker/backend/backend-files.xml43
-rw-r--r--runtime/src/main/docker/frontend/Dockerfile71
-rw-r--r--runtime/src/main/docker/frontend/frontend-files.xml48
-rw-r--r--runtime/src/main/docker/frontend/nginx/default.conf25
-rw-r--r--runtime/src/main/docker/frontend/nginx/nginx.conf18
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java182
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java97
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java203
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java46
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java43
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/Application.java195
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java40
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java160
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java53
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java229
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java144
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java67
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java166
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java105
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java74
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java167
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java140
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java97
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java46
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java100
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java272
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java55
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java110
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java61
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java61
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java61
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java53
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java61
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java190
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java62
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java60
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java66
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java62
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java102
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java60
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java88
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java84
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java438
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java28
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java70
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java93
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java220
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java90
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java219
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java81
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java86
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java83
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java105
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java34
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java72
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java222
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java121
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java135
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java75
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java43
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java49
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java229
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java353
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java103
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java32
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java211
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java223
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java149
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java185
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java61
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java53
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java36
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java418
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java304
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java89
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java173
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java46
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java40
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java108
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java105
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java51
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java101
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java209
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java389
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java204
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java190
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java28
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java36
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java172
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java146
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java266
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java58
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java128
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java128
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java112
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java28
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java193
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java32
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java51
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java129
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java169
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java31
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java295
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java31
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java341
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java192
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java100
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java36
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java67
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java42
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java52
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java282
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java92
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java37
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java138
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java255
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java223
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java91
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java35
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java76
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java276
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java32
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java112
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java219
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java32
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java348
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java94
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java141
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java54
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java180
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java104
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java219
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java254
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java32
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java40
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java141
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java66
-rw-r--r--runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java91
-rw-r--r--runtime/src/main/resources/META-INF/resources/swagger.html4508
-rw-r--r--runtime/src/main/resources/META-INF/services/org/apache/camel/dataformat/clamp-gson23
-rw-r--r--runtime/src/main/resources/application-noaaf.properties190
-rw-r--r--runtime/src/main/resources/application.properties203
-rw-r--r--runtime/src/main/resources/asciidoc/swagger.adoc4
-rw-r--r--runtime/src/main/resources/boot-message.txt16
-rw-r--r--runtime/src/main/resources/clds-version.properties24
-rw-r--r--runtime/src/main/resources/clds/aaf/org.onap.clamp.keyfile27
-rw-r--r--runtime/src/main/resources/clds/aaf/ssl/ca-certs.pem32
-rw-r--r--runtime/src/main/resources/clds/aaf/ssl/clamp.key32
-rw-r--r--runtime/src/main/resources/clds/aaf/ssl/clamp.pem33
-rw-r--r--runtime/src/main/resources/clds/aaf/truststoreONAPall.jksbin0 -> 117990 bytes
-rw-r--r--runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml1472
-rw-r--r--runtime/src/main/resources/clds/camel/rest/clds-services.xml24
-rw-r--r--runtime/src/main/resources/clds/camel/routes/cds-flows.xml64
-rw-r--r--runtime/src/main/resources/clds/camel/routes/dcae-flows.xml501
-rw-r--r--runtime/src/main/resources/clds/camel/routes/loop-flows.xml256
-rw-r--r--runtime/src/main/resources/clds/camel/routes/policy-flows.xml654
-rw-r--r--runtime/src/main/resources/clds/camel/routes/utils-flows.xml28
-rw-r--r--runtime/src/main/resources/clds/clds-users.json33
-rw-r--r--runtime/src/main/resources/clds/json-schema/operational_policies/operational_policy.json320
-rw-r--r--runtime/src/main/resources/clds/sdc-controllers-config.json18
-rw-r--r--runtime/src/main/resources/clds/tosca-converter/default-tosca-types.yaml87
-rw-r--r--runtime/src/main/resources/clds/tosca-converter/templates.json398
-rw-r--r--runtime/src/main/resources/logback-default.xml329
-rw-r--r--runtime/src/main/resources/logback-spring.xml19
-rw-r--r--runtime/src/main/resources/logmessages.properties27
-rw-r--r--runtime/src/main/resources/system.properties27
-rw-r--r--runtime/src/main/script/SelectNpmRepo.groovy34
-rw-r--r--runtime/src/main/script/TagVersion.groovy40
-rw-r--r--runtime/src/main/script/checkLibIndex.sh122
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/client/CdsServicesTest.java56
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoderTest.java99
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfigurationTest.java108
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/AuthorizationControllerItCase.java137
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/CldsHealthcheckServiceItCase.java55
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/HttpsItCase.java106
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/RobotItCase.java131
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/config/CldsReferencePropertiesItCase.java64
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/config/SdcControllersConfigurationItCase.java88
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/it/sdc/controller/SdcSingleControllerItCase.java152
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseCacheTestItCase.java127
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseTest.java59
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/model/jsontype/JsonTypeDescriptorTest.java95
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParserTest.java208
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGeneratorTest.java77
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandlerTest.java199
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/DictionaryRepositoriesTestItCase.java88
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ArrayFieldTest.java55
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ConstraintTest.java106
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateFieldTest.java69
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateManagerTest.java203
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateTest.java69
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupportItCase.java147
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementPropertyTest.java79
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementTest.java52
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/util/JsonUtilsTest.java77
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/util/LoggingUtilsTest.java138
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject.java45
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject2.java44
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/flow/FlowLogOperationTest.java102
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/CsarInstallerItCase.java322
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/DcaeComponentTest.java189
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/DeployFlowTestItCase.java321
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/ExternalComponentStateTest.java82
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopControllerTestItCase.java175
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopLogServiceTestItCase.java96
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopRepositoriesItCase.java258
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopServiceTestItCase.java381
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplateLoopElementModelTest.java105
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplatesServiceItCase.java146
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/LoopToJsonTest.java173
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/PolicyComponentTest.java296
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/PolicyModelServiceItCase.java300
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/ServiceTest.java54
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/loop/deploy/BlueprintInputParametersTest.java125
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/downloader/PolicyEngineControllerTestItCase.java117
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/microservice/MicroServicePayloadTest.java47
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java67
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupAnalyzerTest.java231
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadExceptionTest.java33
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadTest.java75
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java102
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/tosca/DictionaryServiceItCase.java247
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/util/PassDecoderTest.java55
-rw-r--r--runtime/src/test/java/org/onap/policy/clamp/util/SemanticVersioningTest.java91
-rw-r--r--runtime/src/test/resources/application.properties180
-rw-r--r--runtime/src/test/resources/clds/blueprint-with-microservice-chain.yaml202
-rw-r--r--runtime/src/test/resources/clds/clds-parse-exception.json1
-rw-r--r--runtime/src/test/resources/clds/clds-users-incomplete-permissions.json14
-rw-r--r--runtime/src/test/resources/clds/clds-users-no-permission.json7
-rw-r--r--runtime/src/test/resources/clds/clds-users-two-users.json26
-rw-r--r--runtime/src/test/resources/clds/new-microservice.yaml46
-rw-r--r--runtime/src/test/resources/clds/policy-merger.json215
-rw-r--r--runtime/src/test/resources/clds/sdc-controller-config-NULL.json11
-rw-r--r--runtime/src/test/resources/clds/sdc-controller-config-TLS.json14
-rw-r--r--runtime/src/test/resources/clds/sdc-controller-config-bad.json13
-rw-r--r--runtime/src/test/resources/clds/sdc-controller-config-empty-encrypted.json14
-rw-r--r--runtime/src/test/resources/clds/sdc-controllers-config-bad.json26
-rw-r--r--runtime/src/test/resources/clds/sdc-controllers-config-missing-param.json13
-rw-r--r--runtime/src/test/resources/clds/sdc-controllers-config.json30
-rw-r--r--runtime/src/test/resources/clds/single-microservice-fragment-invalid.yaml25
-rw-r--r--runtime/src/test/resources/clds/single-microservice-fragment-valid-with-version.yaml21
-rw-r--r--runtime/src/test/resources/clds/single-microservice-fragment-without-name.yaml22
-rw-r--r--runtime/src/test/resources/clds/single-microservice-fragment-without-properties.yaml18
-rw-r--r--runtime/src/test/resources/clds/single-microservice-fragment-without-relationships.yaml18
-rw-r--r--runtime/src/test/resources/clds/templates/dcae-deployment-template.json9
-rw-r--r--runtime/src/test/resources/clds/templates/dcae-template.json26
-rw-r--r--runtime/src/test/resources/clds/templates/globalProperties.json104
-rw-r--r--runtime/src/test/resources/clds/templates/sdc-decode-service_ids.json1
-rw-r--r--runtime/src/test/resources/clds/templates/sdc-template.json1
-rw-r--r--runtime/src/test/resources/clds/templates/tca-policy-template.json19
-rw-r--r--runtime/src/test/resources/clds/templates/tca-template.json14
-rw-r--r--runtime/src/test/resources/clds/templates/tca-thresholds-template.json9
-rw-r--r--runtime/src/test/resources/clds/templates/ui-location-default.json5
-rw-r--r--runtime/src/test/resources/clds/util/file.xml6
-rw-r--r--runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-wf-expected-result.json30
-rw-r--r--runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-workflow.json78
-rw-r--r--runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-wf-expected-result.json40
-rw-r--r--runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-workflow.json80
-rw-r--r--runtime/src/test/resources/example/dcae/inventory-response.json78
-rw-r--r--runtime/src/test/resources/example/policy/pdp-deployment-testos-1_0_0.json30
-rw-r--r--runtime/src/test/resources/example/policy/pdp-deployment-testos-2_0_0.json204
-rw-r--r--runtime/src/test/resources/example/policy/pdp-group-multi-policies-payload.json74
-rw-r--r--runtime/src/test/resources/example/policy/pdp-group-policy-payload.json54
-rw-r--r--runtime/src/test/resources/example/policy/policy-merger.json269
-rw-r--r--runtime/src/test/resources/example/policy/single-policy-enriched.json47
-rw-r--r--runtime/src/test/resources/example/sdc/blueprint-dcae/tca-bad-policy.yaml141
-rw-r--r--runtime/src/test/resources/example/sdc/blueprint-dcae/tca-guilin.yaml141
-rw-r--r--runtime/src/test/resources/example/sdc/blueprint-dcae/tca.yaml105
-rw-r--r--runtime/src/test/resources/example/sdc/blueprint-dcae/tca_2.yaml174
-rw-r--r--runtime/src/test/resources/example/sdc/blueprint-dcae/tca_3.yaml171
-rw-r--r--runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-multi-blueprints.json43
-rw-r--r--runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-single-blueprint.json9
-rw-r--r--runtime/src/test/resources/example/sdc/expected-result/policy-data.yaml2859
-rw-r--r--runtime/src/test/resources/example/sdc/service-Simsfoimap0112.csarbin0 -> 52568 bytes
-rw-r--r--runtime/src/test/resources/example/sdc/service-without-policy.csarbin0 -> 56126 bytes
-rw-r--r--runtime/src/test/resources/example/sdc/service_Vloadbalancerms_cds.csarbin0 -> 115771 bytes
-rw-r--r--runtime/src/test/resources/example/sdc/service_Vloadbalancerms_no_cds.csarbin0 -> 115690 bytes
-rw-r--r--runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.file96
-rw-r--r--runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.file12
-rw-r--r--runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.file197
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.file53
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.file101
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.file38
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.file47
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.file80
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.file40
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.file360
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.file150
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file158
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.file160
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.header1
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.file104
-rw-r--r--runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.header1
-rwxr-xr-xruntime/src/test/resources/http-cache/start_http_cache.sh52
-rw-r--r--runtime/src/test/resources/http-cache/third_party_proxy.py497
-rw-r--r--runtime/src/test/resources/https/https-test.properties135
-rw-r--r--runtime/src/test/resources/https/keystore-test.jksbin0 -> 2244 bytes
-rw-r--r--runtime/src/test/resources/logback.xml95
-rw-r--r--runtime/src/test/resources/robotframework/Dockerfile6
-rw-r--r--runtime/src/test/resources/robotframework/requirements.txt6
-rw-r--r--runtime/src/test/resources/robotframework/robotframework-test.properties180
-rw-r--r--runtime/src/test/resources/robotframework/tests/01_healthcheck.robot19
-rw-r--r--runtime/src/test/resources/robotframework/tests/02_policy_queries.robot21
-rw-r--r--runtime/src/test/resources/tosca/micro-service-policy-payload.json42
-rw-r--r--runtime/src/test/resources/tosca/micro-service-policy-properties.json25
-rw-r--r--runtime/src/test/resources/tosca/model-properties-cds.json154
-rw-r--r--runtime/src/test/resources/tosca/model-properties-operational-policy.json353
-rw-r--r--runtime/src/test/resources/tosca/model-properties.json353
-rw-r--r--runtime/src/test/resources/tosca/new-converter/constraints.yaml60
-rw-r--r--runtime/src/test/resources/tosca/new-converter/sampleOperationalPolicies.yaml160
-rw-r--r--runtime/src/test/resources/tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml174
-rw-r--r--runtime/src/test/resources/tosca/new-converter/tca-with-metadata.json224
-rw-r--r--runtime/src/test/resources/tosca/new-converter/tosca_apex_with_metadata.json577
-rw-r--r--runtime/src/test/resources/tosca/new-converter/tosca_metadata_clamp_possible_values.yaml184
-rw-r--r--runtime/src/test/resources/tosca/operational-policy-cds-payload-with-list.json590
-rw-r--r--runtime/src/test/resources/tosca/operational-policy-json-schema.json936
-rw-r--r--runtime/src/test/resources/tosca/operational-policy-no-guard-properties.json35
-rw-r--r--runtime/src/test/resources/tosca/operational-policy-properties.json132
-rw-r--r--runtime/src/test/resources/tosca/resource-details-cds.json336
-rw-r--r--runtime/src/test/resources/tosca/resource-details.json336
-rw-r--r--runtime/src/test/resources/tosca/service-details.json15
-rw-r--r--runtime/src/test/resources/tosca/tca_hi_lo.json179
-rw-r--r--runtime/src/test/resources/tosca/tosca_example.yaml158
-rw-r--r--runtime/src/test/resources/tosca/tosca_with_date_time_json_schema.json240
-rw-r--r--runtime/src/test/resources/tosca/tosca_with_metadata.yaml162
-rw-r--r--runtime/ui-react-lib/libExportExclusions.dat4
-rwxr-xr-xruntime/ui-react-lib/libIndex.js56
-rwxr-xr-xruntime/ui-react-lib/package.json54
-rwxr-xr-xruntime/ui-react-lib/rollup.config.js48
-rw-r--r--runtime/ui-react/package.json100
-rw-r--r--runtime/ui-react/public/index.html40
-rw-r--r--runtime/ui-react/public/manifest.json15
-rw-r--r--runtime/ui-react/public/onap.icobin0 -> 18046 bytes
-rw-r--r--runtime/ui-react/src/LoopUI.js419
-rw-r--r--runtime/ui-react/src/LoopUI.test.js171
-rw-r--r--runtime/ui-react/src/NotFound.js36
-rw-r--r--runtime/ui-react/src/NotFound.test.js36
-rw-r--r--runtime/ui-react/src/OnapClamp.js39
-rw-r--r--runtime/ui-react/src/OnapClamp.test.js36
-rw-r--r--runtime/ui-react/src/__snapshots__/LoopUI.test.js.snap188
-rw-r--r--runtime/ui-react/src/__snapshots__/NotFound.test.js.snap26
-rw-r--r--runtime/ui-react/src/__snapshots__/OnapClamp.test.js.snap216
-rw-r--r--runtime/ui-react/src/api/LoopActionService.js74
-rw-r--r--runtime/ui-react/src/api/LoopCache.js252
-rw-r--r--runtime/ui-react/src/api/LoopCache.test.js305
-rw-r--r--runtime/ui-react/src/api/LoopCacheMockFile.json125
-rw-r--r--runtime/ui-react/src/api/LoopService.js244
-rw-r--r--runtime/ui-react/src/api/PoliciesListCacheMockFile.json215
-rw-r--r--runtime/ui-react/src/api/PolicyService.js148
-rw-r--r--runtime/ui-react/src/api/PolicyToscaService.js80
-rw-r--r--runtime/ui-react/src/api/TemplateService.js197
-rw-r--r--runtime/ui-react/src/api/UserService.js74
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.js190
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js143
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.js173
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.test.js112
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.js118
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.test.js108
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js247
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.test.js109
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.js137
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.test.js92
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/__snapshots__/CreateLoopModal.test.js.snap167
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap88
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/__snapshots__/LoopPropertiesModal.test.js.snap61
-rw-r--r--runtime/ui-react/src/components/dialogs/Loop/__snapshots__/OpenLoopModal.test.js.snap137
-rw-r--r--runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js631
-rw-r--r--runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js462
-rw-r--r--runtime/ui-react/src/components/dialogs/ManageDictionaries/__snapshots__/ManageDictionaries.test.js.snap196
-rw-r--r--runtime/ui-react/src/components/dialogs/PerformActions.js95
-rw-r--r--runtime/ui-react/src/components/dialogs/PerformActions.test.js90
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js109
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js176
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js192
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js71
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js345
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js135
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js128
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js66
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js54
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js473
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap788
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap159
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap30
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json179
-rw-r--r--runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml13
-rw-r--r--runtime/ui-react/src/components/dialogs/RefreshStatus.js65
-rw-r--r--runtime/ui-react/src/components/dialogs/RefreshStatus.test.js71
-rw-r--r--runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js163
-rw-r--r--runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.test.js162
-rw-r--r--runtime/ui-react/src/components/dialogs/Tosca/__snapshots__/ViewLoopTemplatesModal.test.js.snap157
-rw-r--r--runtime/ui-react/src/components/dialogs/UserInfoModal.js110
-rw-r--r--runtime/ui-react/src/components/dialogs/UserInfoModal.test.js78
-rw-r--r--runtime/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap119
-rw-r--r--runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.js96
-rw-r--r--runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.test.js70
-rw-r--r--runtime/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap62
-rw-r--r--runtime/ui-react/src/components/loop_viewer/status/LoopStatus.js106
-rw-r--r--runtime/ui-react/src/components/loop_viewer/status/LoopStatus.test.js78
-rw-r--r--runtime/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap66
-rw-r--r--runtime/ui-react/src/components/loop_viewer/svg/SvgGenerator.js246
-rw-r--r--runtime/ui-react/src/components/menu/MenuBar.js123
-rw-r--r--runtime/ui-react/src/components/menu/MenuBar.test.js46
-rw-r--r--runtime/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap1070
-rw-r--r--runtime/ui-react/src/index.js38
-rw-r--r--runtime/ui-react/src/logo.pngbin0 -> 21360 bytes
-rw-r--r--runtime/ui-react/src/setupTests.js28
-rw-r--r--runtime/ui-react/src/theme/globalStyle.js98
-rw-r--r--runtime/ui-react/src/utils/CsvToJson.js204
-rw-r--r--runtime/ui-react/src/utils/CsvToJson.test.js268
-rw-r--r--runtime/ui-react/src/utils/OnapConstants.js32
-rw-r--r--runtime/ui-react/src/utils/OnapUtils.js65
449 files changed, 63871 insertions, 0 deletions
diff --git a/runtime/extra/bin-for-dev/start-backend.sh b/runtime/extra/bin-for-dev/start-backend.sh
new file mode 100755
index 000000000..df513d263
--- /dev/null
+++ b/runtime/extra/bin-for-dev/start-backend.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+# Start Clamp backend in DEBUG mode
+mkdir -p /var/log/onap
+java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9999 -jar ../../target/policy-clamp-backend.jar --spring.config.name=application-noaaf
diff --git a/runtime/extra/bin-for-dev/start-db.sh b/runtime/extra/bin-for-dev/start-db.sh
new file mode 100755
index 000000000..97f8de1f5
--- /dev/null
+++ b/runtime/extra/bin-for-dev/start-db.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+docker-compose -f ../docker/clamp/docker-compose.yml up -d db
+
+if [ "$1" = "test" ]; then
+ while ! (docker logs clamp_db_1 2>&1 | grep "socket: '/run/mysqld/mysqld.sock' port: 3306 mariadb.org binary distribution" > /dev/null);
+ do
+ echo "Waiting Mysql to be up with CLDSDB4 db loaded before loading the TEST DATA ..."
+ sleep 3
+ done
+ docker exec -it clamp_db_1 /docker-entrypoint-initdb.d/dump/load-fake-data.sh
+fi;
diff --git a/runtime/extra/bin-for-dev/start-emulator.sh b/runtime/extra/bin-for-dev/start-emulator.sh
new file mode 100755
index 000000000..274d88939
--- /dev/null
+++ b/runtime/extra/bin-for-dev/start-emulator.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+docker-compose -f ../docker/clamp/docker-compose.yml up -d third-party-proxy
diff --git a/runtime/extra/bin-for-dev/start-frontend.sh b/runtime/extra/bin-for-dev/start-frontend.sh
new file mode 100755
index 000000000..d5f4d2414
--- /dev/null
+++ b/runtime/extra/bin-for-dev/start-frontend.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+cd ../../target/ui-react
+node/npm start --scripts-prepend-node-path
diff --git a/runtime/extra/docker/clamp/clamp.env b/runtime/extra/docker/clamp/clamp.env
new file mode 100644
index 000000000..5d31aa42e
--- /dev/null
+++ b/runtime/extra/docker/clamp/clamp.env
@@ -0,0 +1,2 @@
+### Be careful, this must be in one line only ###
+SPRING_APPLICATION_JSON={"spring.datasource.url":"jdbc:mariadb:sequential://db:3306/cldsdb4?autoReconnect=true&connectTimeout=10000&socketTimeout=10000&retriesAllDown=3","spring.profiles.active":"clamp-default,clamp-default-user,clamp-sdc-controller,clamp-ssl-config,clamp-policy-controller,default-dictionary-elements","clamp.config.policy.api.url":"http://third-party-proxy:8085","clamp.config.policy.pap.url":"http://third-party-proxy:8085","clamp.config.dcae.inventory.url":"http://third-party-proxy:8085","clamp.config.dcae.deployment.url":"http://third-party-proxy:8085"}
diff --git a/runtime/extra/docker/clamp/docker-compose.yml b/runtime/extra/docker/clamp/docker-compose.yml
new file mode 100644
index 000000000..c56be0aae
--- /dev/null
+++ b/runtime/extra/docker/clamp/docker-compose.yml
@@ -0,0 +1,38 @@
+version: '3.1'
+
+services:
+ policy-clamp-frontend:
+ image: onap/policy-clamp-frontend
+ depends_on:
+ - policy-clamp-backend
+ ports:
+ - "2443:2443"
+ db:
+ image: mariadb:10.5.4
+ volumes:
+ - "/var/lib/mysql"
+ - "../mariadb/conf1:/etc/mysql/conf.d:ro"
+ - "../../sql/:/docker-entrypoint-initdb.d:rw"
+ environment:
+ - MYSQL_ROOT_PASSWORD=strong_pitchou
+ ports:
+ - "3306:3306"
+
+ policy-clamp-backend:
+ image: onap/policy-clamp-backend
+ depends_on:
+ - db
+ - third-party-proxy
+ env_file:
+ - clamp.env
+ ports:
+ - "10443:8443"
+
+ third-party-proxy:
+ image: python:2-slim
+ volumes:
+ - "../../../src/test/resources/http-cache/example/:/thirdparty:rw"
+ - "../../../src/test/resources/http-cache/:/script/:ro"
+ ports:
+ - "8085:8085"
+ command: /bin/sh -c "pip install --no-cache-dir requests && pip install --no-cache-dir simplejson && python -u /script/third_party_proxy.py -v true --port 8085 --root /thirdparty --proxyaddress third-party-proxy:8085"
diff --git a/runtime/extra/docker/mariadb/conf1/my.cnf b/runtime/extra/docker/mariadb/conf1/my.cnf
new file mode 100644
index 000000000..c6631fb4e
--- /dev/null
+++ b/runtime/extra/docker/mariadb/conf1/my.cnf
@@ -0,0 +1,194 @@
+# Example MySQL config file for medium systems.
+#
+# This is for a system with memory 8G where MySQL plays
+# an important part, or systems up to 128M where MySQL is used together with
+# other programs (such as a web server)
+#
+# In this file, you can use all long options that a program supports.
+# If you want to know which options a program supports, run the program
+# with the "--help" option.
+
+# The following options will be passed to all MySQL clients
+##[client]
+##user = root
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+##performance_schema
+
+slow_query_log =ON
+long_query_time =2
+slow_query_log_file =//var/lib/mysql/slow_query.log
+##basedir = //opt/app/mysql/product/mariadb-10.1.11-linux-x86_64
+##datadir = //opt/app/mysql/data
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+skip-external-locking
+explicit_defaults_for_timestamp = true
+skip-symbolic-links
+local-infile = 0
+#ignore_db_dir=lost+found
+key_buffer_size = 16M
+max_allowed_packet = 4M
+table_open_cache = 100
+sort_buffer_size = 512K
+net_buffer_length = 8K
+read_buffer_size = 256K
+read_rnd_buffer_size = 512K
+myisam_sort_buffer_size = 8M
+max_connections = 500
+lower_case_table_names = 1
+thread_stack = 256K
+thread_cache_size = 25
+query_cache_size = 8M
+query_cache_type = 0
+query_prealloc_size = 512K
+query_cache_limit = 1M
+
+# Password validation
+##plugin-load-add=simple_password_check.so
+##simple_password_check_other_characters=0
+
+# Audit Log settings
+plugin-load-add=server_audit.so
+server_audit=FORCE_PLUS_PERMANENT
+server_audit_file_path=//var/lib/mysql/audit.log
+server_audit_file_rotate_size=50M
+server_audit_events=CONNECT,QUERY,TABLE
+server_audit_logging=on
+
+# Don't listen on a TCP/IP port at all. This can be a security enhancement,
+# if all processes that need to connect to mysqld run on the same host.
+# All interaction with mysqld must be made via Unix sockets or named pipes.
+# Note that using this option without enabling named pipes on Windows
+# (via the "enable-named-pipe" option) will render mysqld useless!
+#
+#skip-networking
+
+# Replication Master Server (default)
+# binary logging is required for replication
+##log-bin=//var/lib/mysql/mysql-bin
+
+# binary logging format - mixed recommended
+binlog_format=row
+
+# required unique id between 1 and 2^32 - 1
+# defaults to 1 if master-host is not set
+# but will not function as a master if omitted
+
+# Replication Slave (comment out master section to use this)
+#
+# To configure this host as a replication slave, you can choose between
+# two methods :
+#
+# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
+# the syntax is:
+#
+# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
+# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
+#
+# where you replace <host>, <user>, <password> by quoted strings and
+# <port> by the master's port number (3306 by default).
+#
+# Example:
+#
+# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
+# MASTER_USER='joe', MASTER_PASSWORD='secret';
+#
+# OR
+#
+# 2) Set the variables below. However, in case you choose this method, then
+# start replication for the first time (even unsuccessfully, for example
+# if you mistyped the password in master-password and the slave fails to
+# connect), the slave will create a master.info file, and any later
+# change in this file to the variables' values below will be ignored and
+# overridden by the content of the master.info file, unless you shutdown
+# the slave server, delete master.info and restart the slaver server.
+# For that reason, you may want to leave the lines below untouched
+# (commented) and instead use CHANGE MASTER TO (see above)
+#
+# required unique id between 2 and 2^32 - 1
+# (and different from the master)
+# defaults to 2 if master-host is set
+# but will not function as a slave if omitted
+#server-id = 2
+#
+# The replication master for this slave - required
+#master-host = <hostname>
+#
+# The username the slave will use for authentication when connecting
+# to the master - required
+#master-user = <username>
+#
+# The password the slave will authenticate with when connecting to
+# the master - required
+#master-password = <password>
+#
+# The port the master is listening on.
+# optional - defaults to 3306
+#master-port = <port>
+#
+# binary logging - not required for slaves, but recommended
+#log-bin=mysql-bin
+
+# Uncomment the following if you are using InnoDB tables
+##innodb_data_home_dir = //opt/app/mysql/data
+##innodb_data_file_path = ibdata1:20M:autoextend:max:32G
+##innodb_log_group_home_dir = //opt/app/mysql/iblogs
+# You can set .._buffer_pool_size up to 50 - 80 %
+# of RAM but beware of setting memory usage too high
+innodb_buffer_pool_size = 128M
+#innodb_additional_mem_pool_size = 2M
+# Set .._log_file_size to 25 % of buffer pool size
+innodb_log_file_size = 10M
+innodb_log_files_in_group = 3
+innodb_log_buffer_size = 8M
+#innodb_flush_log_at_trx_commit = 1
+innodb_lock_wait_timeout = 50
+innodb_autoextend_increment = 100
+expire_logs_days = 8
+open_files_limit = 2000
+transaction-isolation=READ-COMMITTED
+####### Galera parameters #######
+## Galera Provider configuration
+wsrep_provider=/usr/lib/galera/libgalera_smm.so
+wsrep_provider_options="gcache.size=128M; gcache.page_size=10M"
+## Galera Cluster configuration
+wsrep_cluster_name="MSO-automated-tests-cluster"
+wsrep_cluster_address="gcomm://"
+#wsrep_cluster_address="gcomm://mariadb1,mariadb2,mariadb3"
+##wsrep_cluster_address="gcomm://192.169.3.184,192.169.3.185,192.169.3.186"
+## Galera Synchronization configuration
+wsrep_sst_method=rsync
+#wsrep_sst_method=xtrabackup-v2
+#wsrep_sst_auth="sstuser:Mon#2o!6"
+## Galera Node configuration
+wsrep_node_name="mariadb1"
+##wsrep_node_address="192.169.3.184"
+wsrep_on=OFF
+## Status notification
+#wsrep_notify_cmd=/opt/app/mysql/bin/wsrep_notify
+#######
+
+
+[mysqldump]
+quick
+max_allowed_packet = 16M
+
+[mysql]
+no-auto-rehash
+# Remove the next comment character if you are not familiar with SQL
+#safe-updates
+
+[myisamchk]
+key_buffer_size = 20971520
+
+##[mysqlhotcopy]
+##interactive-timeout
+##[mysqld_safe]
+##malloc-lib=//opt/app/mysql/local/lib/libjemalloc.so.1
+##log-error=//opt/app/mysql/log/mysqld.log \ No newline at end of file
diff --git a/runtime/extra/docker/mariadb/conf2/my.cnf b/runtime/extra/docker/mariadb/conf2/my.cnf
new file mode 100644
index 000000000..bf5f9c177
--- /dev/null
+++ b/runtime/extra/docker/mariadb/conf2/my.cnf
@@ -0,0 +1,193 @@
+# Example MySQL config file for medium systems.
+#
+# This is for a system with memory 8G where MySQL plays
+# an important part, or systems up to 128M where MySQL is used together with
+# other programs (such as a web server)
+#
+# In this file, you can use all long options that a program supports.
+# If you want to know which options a program supports, run the program
+# with the "--help" option.
+
+# The following options will be passed to all MySQL clients
+##[client]
+##user = root
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+##performance_schema
+
+slow_query_log =ON
+long_query_time =2
+slow_query_log_file =//var/lib/mysql/slow_query.log
+##basedir = //opt/app/mysql/product/mariadb-10.1.11-linux-x86_64
+##datadir = //opt/app/mysql/data
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+skip-external-locking
+explicit_defaults_for_timestamp = true
+skip-symbolic-links
+local-infile = 0
+#ignore_db_dir=lost+found
+key_buffer_size = 16M
+max_allowed_packet = 4M
+table_open_cache = 100
+sort_buffer_size = 512K
+net_buffer_length = 8K
+read_buffer_size = 256K
+read_rnd_buffer_size = 512K
+myisam_sort_buffer_size = 8M
+max_connections = 500
+lower_case_table_names = 1
+thread_stack = 256K
+thread_cache_size = 25
+query_cache_size = 8M
+query_cache_type = 0
+query_prealloc_size = 512K
+query_cache_limit = 1M
+
+# Password validation
+##plugin-load-add=simple_password_check.so
+##simple_password_check_other_characters=0
+
+# Audit Log settings
+plugin-load-add=server_audit.so
+server_audit=FORCE_PLUS_PERMANENT
+server_audit_file_path=//var/lib/mysql/audit.log
+server_audit_file_rotate_size=50M
+server_audit_events=CONNECT,QUERY,TABLE
+server_audit_logging=on
+
+# Don't listen on a TCP/IP port at all. This can be a security enhancement,
+# if all processes that need to connect to mysqld run on the same host.
+# All interaction with mysqld must be made via Unix sockets or named pipes.
+# Note that using this option without enabling named pipes on Windows
+# (via the "enable-named-pipe" option) will render mysqld useless!
+#
+#skip-networking
+
+# Replication Master Server (default)
+# binary logging is required for replication
+##log-bin=//var/lib/mysql/mysql-bin
+
+# binary logging format - mixed recommended
+binlog_format=row
+
+# required unique id between 1 and 2^32 - 1
+# defaults to 1 if master-host is not set
+# but will not function as a master if omitted
+
+# Replication Slave (comment out master section to use this)
+#
+# To configure this host as a replication slave, you can choose between
+# two methods :
+#
+# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
+# the syntax is:
+#
+# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
+# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
+#
+# where you replace <host>, <user>, <password> by quoted strings and
+# <port> by the master's port number (3306 by default).
+#
+# Example:
+#
+# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
+# MASTER_USER='joe', MASTER_PASSWORD='secret';
+#
+# OR
+#
+# 2) Set the variables below. However, in case you choose this method, then
+# start replication for the first time (even unsuccessfully, for example
+# if you mistyped the password in master-password and the slave fails to
+# connect), the slave will create a master.info file, and any later
+# change in this file to the variables' values below will be ignored and
+# overridden by the content of the master.info file, unless you shutdown
+# the slave server, delete master.info and restart the slaver server.
+# For that reason, you may want to leave the lines below untouched
+# (commented) and instead use CHANGE MASTER TO (see above)
+#
+# required unique id between 2 and 2^32 - 1
+# (and different from the master)
+# defaults to 2 if master-host is set
+# but will not function as a slave if omitted
+#server-id = 2
+#
+# The replication master for this slave - required
+#master-host = <hostname>
+#
+# The username the slave will use for authentication when connecting
+# to the master - required
+#master-user = <username>
+#
+# The password the slave will authenticate with when connecting to
+# the master - required
+#master-password = <password>
+#
+# The port the master is listening on.
+# optional - defaults to 3306
+#master-port = <port>
+#
+# binary logging - not required for slaves, but recommended
+#log-bin=mysql-bin
+
+# Uncomment the following if you are using InnoDB tables
+##innodb_data_home_dir = //opt/app/mysql/data
+##innodb_data_file_path = ibdata1:20M:autoextend:max:32G
+##innodb_log_group_home_dir = //opt/app/mysql/iblogs
+# You can set .._buffer_pool_size up to 50 - 80 %
+# of RAM but beware of setting memory usage too high
+innodb_buffer_pool_size = 6380M
+#innodb_additional_mem_pool_size = 2M
+# Set .._log_file_size to 25 % of buffer pool size
+innodb_log_file_size = 150M
+innodb_log_files_in_group = 3
+innodb_log_buffer_size = 8M
+#innodb_flush_log_at_trx_commit = 1
+innodb_lock_wait_timeout = 50
+innodb_autoextend_increment = 100
+expire_logs_days = 8
+open_files_limit = 2000
+transaction-isolation=READ-COMMITTED
+####### Galera parameters #######
+## Galera Provider configuration
+wsrep_provider=/usr/lib/galera/libgalera_smm.so
+wsrep_provider_options="gcache.size=2G; gcache.page_size=1G"
+## Galera Cluster configuration
+wsrep_cluster_name="MSO-automated-tests-cluster"
+wsrep_cluster_address="gcomm://mariadb1,mariadb2,mariadb3"
+##wsrep_cluster_address="gcomm://192.169.3.184,192.169.3.185,192.169.3.186"
+## Galera Synchronization configuration
+wsrep_sst_method=rsync
+#wsrep_sst_method=xtrabackup-v2
+#wsrep_sst_auth="sstuser:Mon#2o!6"
+## Galera Node configuration
+wsrep_node_name="mariadb2"
+##wsrep_node_address="192.169.3.184"
+wsrep_on=ON
+## Status notification
+#wsrep_notify_cmd=/opt/app/mysql/bin/wsrep_notify
+#######
+
+
+[mysqldump]
+quick
+max_allowed_packet = 16M
+
+[mysql]
+no-auto-rehash
+# Remove the next comment character if you are not familiar with SQL
+#safe-updates
+
+[myisamchk]
+key_buffer_size = 20971520
+
+##[mysqlhotcopy]
+##interactive-timeout
+##[mysqld_safe]
+##malloc-lib=//opt/app/mysql/local/lib/libjemalloc.so.1
+##log-error=//opt/app/mysql/log/mysqld.log \ No newline at end of file
diff --git a/runtime/extra/docker/mariadb/conf3/my.cnf b/runtime/extra/docker/mariadb/conf3/my.cnf
new file mode 100644
index 000000000..74f7a31b0
--- /dev/null
+++ b/runtime/extra/docker/mariadb/conf3/my.cnf
@@ -0,0 +1,193 @@
+# Example MySQL config file for medium systems.
+#
+# This is for a system with memory 8G where MySQL plays
+# an important part, or systems up to 128M where MySQL is used together with
+# other programs (such as a web server)
+#
+# In this file, you can use all long options that a program supports.
+# If you want to know which options a program supports, run the program
+# with the "--help" option.
+
+# The following options will be passed to all MySQL clients
+##[client]
+##user = root
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+##performance_schema
+
+slow_query_log =ON
+long_query_time =2
+slow_query_log_file =//var/lib/mysql/slow_query.log
+##basedir = //opt/app/mysql/product/mariadb-10.1.11-linux-x86_64
+##datadir = //opt/app/mysql/data
+##port = 3306
+##socket = //opt/app/mysql/mysql.sock
+skip-external-locking
+explicit_defaults_for_timestamp = true
+skip-symbolic-links
+local-infile = 0
+#ignore_db_dir=lost+found
+key_buffer_size = 16M
+max_allowed_packet = 4M
+table_open_cache = 100
+sort_buffer_size = 512K
+net_buffer_length = 8K
+read_buffer_size = 256K
+read_rnd_buffer_size = 512K
+myisam_sort_buffer_size = 8M
+max_connections = 500
+lower_case_table_names = 1
+thread_stack = 256K
+thread_cache_size = 25
+query_cache_size = 8M
+query_cache_type = 0
+query_prealloc_size = 512K
+query_cache_limit = 1M
+
+# Password validation
+##plugin-load-add=simple_password_check.so
+##simple_password_check_other_characters=0
+
+# Audit Log settings
+plugin-load-add=server_audit.so
+server_audit=FORCE_PLUS_PERMANENT
+server_audit_file_path=//var/lib/mysql/audit.log
+server_audit_file_rotate_size=50M
+server_audit_events=CONNECT,QUERY,TABLE
+server_audit_logging=on
+
+# Don't listen on a TCP/IP port at all. This can be a security enhancement,
+# if all processes that need to connect to mysqld run on the same host.
+# All interaction with mysqld must be made via Unix sockets or named pipes.
+# Note that using this option without enabling named pipes on Windows
+# (via the "enable-named-pipe" option) will render mysqld useless!
+#
+#skip-networking
+
+# Replication Master Server (default)
+# binary logging is required for replication
+##log-bin=//var/lib/mysql/mysql-bin
+
+# binary logging format - mixed recommended
+binlog_format=row
+
+# required unique id between 1 and 2^32 - 1
+# defaults to 1 if master-host is not set
+# but will not function as a master if omitted
+
+# Replication Slave (comment out master section to use this)
+#
+# To configure this host as a replication slave, you can choose between
+# two methods :
+#
+# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
+# the syntax is:
+#
+# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
+# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
+#
+# where you replace <host>, <user>, <password> by quoted strings and
+# <port> by the master's port number (3306 by default).
+#
+# Example:
+#
+# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
+# MASTER_USER='joe', MASTER_PASSWORD='secret';
+#
+# OR
+#
+# 2) Set the variables below. However, in case you choose this method, then
+# start replication for the first time (even unsuccessfully, for example
+# if you mistyped the password in master-password and the slave fails to
+# connect), the slave will create a master.info file, and any later
+# change in this file to the variables' values below will be ignored and
+# overridden by the content of the master.info file, unless you shutdown
+# the slave server, delete master.info and restart the slaver server.
+# For that reason, you may want to leave the lines below untouched
+# (commented) and instead use CHANGE MASTER TO (see above)
+#
+# required unique id between 2 and 2^32 - 1
+# (and different from the master)
+# defaults to 2 if master-host is set
+# but will not function as a slave if omitted
+#server-id = 2
+#
+# The replication master for this slave - required
+#master-host = <hostname>
+#
+# The username the slave will use for authentication when connecting
+# to the master - required
+#master-user = <username>
+#
+# The password the slave will authenticate with when connecting to
+# the master - required
+#master-password = <password>
+#
+# The port the master is listening on.
+# optional - defaults to 3306
+#master-port = <port>
+#
+# binary logging - not required for slaves, but recommended
+#log-bin=mysql-bin
+
+# Uncomment the following if you are using InnoDB tables
+##innodb_data_home_dir = //opt/app/mysql/data
+##innodb_data_file_path = ibdata1:20M:autoextend:max:32G
+##innodb_log_group_home_dir = //opt/app/mysql/iblogs
+# You can set .._buffer_pool_size up to 50 - 80 %
+# of RAM but beware of setting memory usage too high
+innodb_buffer_pool_size = 6380M
+#innodb_additional_mem_pool_size = 2M
+# Set .._log_file_size to 25 % of buffer pool size
+innodb_log_file_size = 150M
+innodb_log_files_in_group = 3
+innodb_log_buffer_size = 8M
+#innodb_flush_log_at_trx_commit = 1
+innodb_lock_wait_timeout = 50
+innodb_autoextend_increment = 100
+expire_logs_days = 8
+open_files_limit = 2000
+transaction-isolation=READ-COMMITTED
+####### Galera parameters #######
+## Galera Provider configuration
+wsrep_provider=/usr/lib/galera/libgalera_smm.so
+wsrep_provider_options="gcache.size=2G; gcache.page_size=1G"
+## Galera Cluster configuration
+wsrep_cluster_name="MSO-automated-tests-cluster"
+wsrep_cluster_address="gcomm://mariadb1,mariadb2,mariadb3"
+##wsrep_cluster_address="gcomm://192.169.3.184,192.169.3.185,192.169.3.186"
+## Galera Synchronization configuration
+wsrep_sst_method=rsync
+#wsrep_sst_method=xtrabackup-v2
+#wsrep_sst_auth="sstuser:Mon#2o!6"
+## Galera Node configuration
+wsrep_node_name="mariadb3"
+##wsrep_node_address="192.169.3.184"
+wsrep_on=ON
+## Status notification
+#wsrep_notify_cmd=/opt/app/mysql/bin/wsrep_notify
+#######
+
+
+[mysqldump]
+quick
+max_allowed_packet = 16M
+
+[mysql]
+no-auto-rehash
+# Remove the next comment character if you are not familiar with SQL
+#safe-updates
+
+[myisamchk]
+key_buffer_size = 20971520
+
+##[mysqlhotcopy]
+##interactive-timeout
+##[mysqld_safe]
+##malloc-lib=//opt/app/mysql/local/lib/libjemalloc.so.1
+##log-error=//opt/app/mysql/log/mysqld.log \ No newline at end of file
diff --git a/runtime/extra/sql/bootstrap-database.sh b/runtime/extra/sql/bootstrap-database.sh
new file mode 100755
index 000000000..224a813db
--- /dev/null
+++ b/runtime/extra/sql/bootstrap-database.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+mysql -uroot -p$MYSQL_ROOT_PASSWORD -f < /docker-entrypoint-initdb.d/bulkload/create-db.sql
+## New model creation
+mysql -uroot -p$MYSQL_ROOT_PASSWORD -f cldsdb4 < /docker-entrypoint-initdb.d/bulkload/create-tables.sql
diff --git a/runtime/extra/sql/bulkload/create-db.sql b/runtime/extra/sql/bulkload/create-db.sql
new file mode 100644
index 000000000..ea4d97c1b
--- /dev/null
+++ b/runtime/extra/sql/bulkload/create-db.sql
@@ -0,0 +1,11 @@
+#
+# Create CLDS database objects (tables, etc.)
+#
+#
+CREATE DATABASE `cldsdb4`;
+USE `cldsdb4`;
+DROP USER 'clds';
+CREATE USER 'clds';
+GRANT ALL on cldsdb4.* to 'clds' identified by 'sidnnd83K' with GRANT OPTION;
+FLUSH PRIVILEGES;
+
diff --git a/runtime/extra/sql/bulkload/create-tables.sql b/runtime/extra/sql/bulkload/create-tables.sql
new file mode 100644
index 000000000..111a4058e
--- /dev/null
+++ b/runtime/extra/sql/bulkload/create-tables.sql
@@ -0,0 +1,255 @@
+
+ create table dictionary (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ dictionary_second_level integer,
+ dictionary_type varchar(255),
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table dictionary_elements (
+ short_name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ description varchar(255) not null,
+ name varchar(255) not null,
+ subdictionary_name varchar(255),
+ type varchar(255) not null,
+ primary key (short_name)
+ ) engine=InnoDB;
+
+ create table dictionary_to_dictionaryelements (
+ dictionary_name varchar(255) not null,
+ dictionary_element_short_name varchar(255) not null,
+ primary key (dictionary_name, dictionary_element_short_name)
+ ) engine=InnoDB;
+
+ create table hibernate_sequence (
+ next_val bigint
+ ) engine=InnoDB;
+
+ insert into hibernate_sequence values ( 1 );
+
+ create table loop_element_models (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ blueprint_yaml MEDIUMTEXT,
+ dcae_blueprint_id varchar(255),
+ loop_element_type varchar(255) not null,
+ short_name varchar(255),
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table loop_logs (
+ id bigint not null,
+ log_component varchar(255) not null,
+ log_instant datetime(6) not null,
+ log_type varchar(255) not null,
+ message MEDIUMTEXT not null,
+ loop_id varchar(255) not null,
+ primary key (id)
+ ) engine=InnoDB;
+
+ create table loop_templates (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ allowed_loop_type varchar(255),
+ blueprint_yaml MEDIUMTEXT,
+ dcae_blueprint_id varchar(255),
+ maximum_instances_allowed integer,
+ unique_blueprint boolean default false,
+ service_uuid varchar(255),
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table loopelementmodels_to_policymodels (
+ loop_element_name varchar(255) not null,
+ policy_model_type varchar(255) not null,
+ policy_model_version varchar(255) not null,
+ primary key (loop_element_name, policy_model_type, policy_model_version)
+ ) engine=InnoDB;
+
+ create table loops (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ dcae_deployment_id varchar(255),
+ dcae_deployment_status_url varchar(255),
+ global_properties_json json,
+ last_computed_state varchar(255) not null,
+ loop_template_name varchar(255) not null,
+ service_uuid varchar(255),
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table loops_to_microservicepolicies (
+ loop_name varchar(255) not null,
+ microservicepolicy_name varchar(255) not null,
+ primary key (loop_name, microservicepolicy_name)
+ ) engine=InnoDB;
+
+ create table looptemplates_to_loopelementmodels (
+ loop_element_model_name varchar(255) not null,
+ loop_template_name varchar(255) not null,
+ flow_order integer not null,
+ primary key (loop_element_model_name, loop_template_name)
+ ) engine=InnoDB;
+
+ create table micro_service_policies (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ configurations_json json,
+ json_representation json not null,
+ pdp_group varchar(255),
+ pdp_sub_group varchar(255),
+ context varchar(255),
+ dcae_blueprint_id varchar(255),
+ dcae_deployment_id varchar(255),
+ dcae_deployment_status_url varchar(255),
+ device_type_scope varchar(255),
+ shared bit not null,
+ loop_element_model_id varchar(255),
+ policy_model_type varchar(255),
+ policy_model_version varchar(255),
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table operational_policies (
+ name varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ configurations_json json,
+ json_representation json not null,
+ pdp_group varchar(255),
+ pdp_sub_group varchar(255),
+ loop_element_model_id varchar(255),
+ policy_model_type varchar(255),
+ policy_model_version varchar(255),
+ loop_id varchar(255) not null,
+ primary key (name)
+ ) engine=InnoDB;
+
+ create table policy_models (
+ policy_model_type varchar(255) not null,
+ version varchar(255) not null,
+ created_by varchar(255),
+ created_timestamp datetime(6) not null,
+ updated_by varchar(255),
+ updated_timestamp datetime(6) not null,
+ policy_acronym varchar(255),
+ policy_tosca MEDIUMTEXT,
+ policy_pdp_group json,
+ primary key (policy_model_type, version)
+ ) engine=InnoDB;
+
+ create table services (
+ service_uuid varchar(255) not null,
+ name varchar(255) not null,
+ resource_details json,
+ service_details json,
+ version varchar(255),
+ primary key (service_uuid)
+ ) engine=InnoDB;
+
+ alter table dictionary_to_dictionaryelements
+ add constraint FK68hjjinnm8nte2owstd0xwp23
+ foreign key (dictionary_element_short_name)
+ references dictionary_elements (short_name);
+
+ alter table dictionary_to_dictionaryelements
+ add constraint FKtqfxg46gsxwlm2gkl6ne3cxfe
+ foreign key (dictionary_name)
+ references dictionary (name);
+
+ alter table loop_logs
+ add constraint FK1j0cda46aickcaoxqoo34khg2
+ foreign key (loop_id)
+ references loops (name);
+
+ alter table loop_templates
+ add constraint FKn692dk6281wvp1o95074uacn6
+ foreign key (service_uuid)
+ references services (service_uuid);
+
+ alter table loopelementmodels_to_policymodels
+ add constraint FK23j2q74v6kaexefy0tdabsnda
+ foreign key (policy_model_type, policy_model_version)
+ references policy_models (policy_model_type, version);
+
+ alter table loopelementmodels_to_policymodels
+ add constraint FKjag1iu0olojfwryfkvb5o0rk5
+ foreign key (loop_element_name)
+ references loop_element_models (name);
+
+ alter table loops
+ add constraint FK844uwy82wt0l66jljkjqembpj
+ foreign key (loop_template_name)
+ references loop_templates (name);
+
+ alter table loops
+ add constraint FK4b9wnqopxogwek014i1shqw7w
+ foreign key (service_uuid)
+ references services (service_uuid);
+
+ alter table loops_to_microservicepolicies
+ add constraint FKle255jmi7b065fwbvmwbiehtb
+ foreign key (microservicepolicy_name)
+ references micro_service_policies (name);
+
+ alter table loops_to_microservicepolicies
+ add constraint FK8avfqaf7xl71l7sn7a5eri68d
+ foreign key (loop_name)
+ references loops (name);
+
+ alter table looptemplates_to_loopelementmodels
+ add constraint FK1k7nbrbugvqa0xfxkq3cj1yn9
+ foreign key (loop_element_model_name)
+ references loop_element_models (name);
+
+ alter table looptemplates_to_loopelementmodels
+ add constraint FKj29yxyw0x7ue6mwgi6d3qg748
+ foreign key (loop_template_name)
+ references loop_templates (name);
+
+ alter table micro_service_policies
+ add constraint FKqvvdypacbww07fuv8xvlvdjgl
+ foreign key (loop_element_model_id)
+ references loop_element_models (name);
+
+ alter table micro_service_policies
+ add constraint FKn17j9ufmyhqicb6cvr1dbjvkt
+ foreign key (policy_model_type, policy_model_version)
+ references policy_models (policy_model_type, version);
+
+ alter table operational_policies
+ add constraint FKi9kh7my40737xeuaye9xwbnko
+ foreign key (loop_element_model_id)
+ references loop_element_models (name);
+
+ alter table operational_policies
+ add constraint FKlsyhfkoqvkwj78ofepxhoctip
+ foreign key (policy_model_type, policy_model_version)
+ references policy_models (policy_model_type, version);
+
+ alter table operational_policies
+ add constraint FK1ddoggk9ni2bnqighv6ecmuwu
+ foreign key (loop_id)
+ references loops (name);
diff --git a/runtime/extra/sql/dump/backup-data-only.sh b/runtime/extra/sql/dump/backup-data-only.sh
new file mode 100755
index 000000000..8ebebf91d
--- /dev/null
+++ b/runtime/extra/sql/dump/backup-data-only.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+mysqldump -uroot -p$MYSQL_ROOT_PASSWORD -v --extended-insert=FALSE --complete-insert --no-create-db --no-create-info --databases cldsdb4 > /docker-entrypoint-initdb.d/dump/test-data.sql \ No newline at end of file
diff --git a/runtime/extra/sql/dump/backup-database.sh b/runtime/extra/sql/dump/backup-database.sh
new file mode 100755
index 000000000..1ae7ee2b7
--- /dev/null
+++ b/runtime/extra/sql/dump/backup-database.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+mysqldump -uroot -p$MYSQL_ROOT_PASSWORD -v --extended-insert=FALSE --databases cldsdb4 > $1 \ No newline at end of file
diff --git a/runtime/extra/sql/dump/load-fake-data.sh b/runtime/extra/sql/dump/load-fake-data.sh
new file mode 100755
index 000000000..572972683
--- /dev/null
+++ b/runtime/extra/sql/dump/load-fake-data.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+mysql -uroot -p$MYSQL_ROOT_PASSWORD -v -f cldsdb4 < /docker-entrypoint-initdb.d/dump/test-data.sql \ No newline at end of file
diff --git a/runtime/extra/sql/dump/test-data.sql b/runtime/extra/sql/dump/test-data.sql
new file mode 100644
index 000000000..367ddb61d
--- /dev/null
+++ b/runtime/extra/sql/dump/test-data.sql
@@ -0,0 +1,218 @@
+-- MariaDB dump 10.17 Distrib 10.5.4-MariaDB, for debian-linux-gnu (x86_64)
+--
+-- Host: localhost Database: cldsdb4
+-- ------------------------------------------------------
+-- Server version 10.5.4-MariaDB-1:10.5.4+maria~focal-log
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Current Database: `cldsdb4`
+--
+
+USE `cldsdb4`;
+
+--
+-- Dumping data for table `dictionary`
+--
+
+LOCK TABLES `dictionary` WRITE;
+/*!40000 ALTER TABLE `dictionary` DISABLE KEYS */;
+INSERT INTO `dictionary` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `dictionary_second_level`, `dictionary_type`) VALUES ('DefaultActors','Not found','2021-03-05 17:10:52.561538','Not found','2021-03-05 17:10:52.561538',0,'');
+INSERT INTO `dictionary` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `dictionary_second_level`, `dictionary_type`) VALUES ('DefaultOperations','Not found','2021-03-05 17:10:52.579372','Not found','2021-03-05 17:10:52.579372',0,'');
+/*!40000 ALTER TABLE `dictionary` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `dictionary_elements`
+--
+
+LOCK TABLES `dictionary_elements` WRITE;
+/*!40000 ALTER TABLE `dictionary_elements` DISABLE KEYS */;
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('APPC','Not found','2021-03-05 17:10:52.570617','Not found','2021-03-05 17:10:52.570617','APPC component','APPC',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('BandwidthOnDemand (SDNC operation)','Not found','2021-03-05 17:10:52.580331','Not found','2021-03-05 17:10:52.580331','SDNC operation','BandwidthOnDemand',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('Health-Check (APPC operation)','Not found','2021-03-05 17:10:52.587614','Not found','2021-03-05 17:10:52.587614','APPC operation','Health-Check',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('Migrate (APPC operation)','Not found','2021-03-05 17:10:52.586285','Not found','2021-03-05 17:10:52.586285','APPC operation','Migrate',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('ModifyConfig (APPC/VFC operation)','Not found','2021-03-05 17:10:52.584261','Not found','2021-03-05 17:10:52.584261','APPC/VFC operation','ModifyConfig',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('Rebuild (APPC operation)','Not found','2021-03-05 17:10:52.583480','Not found','2021-03-05 17:10:52.583480','APPC operation','Rebuild',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('Reroute (SDNC operation)','Not found','2021-03-05 17:10:52.581911','Not found','2021-03-05 17:10:52.581911','SDNC operation','Reroute',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('Restart (APPC operation)','Not found','2021-03-05 17:10:52.585115','Not found','2021-03-05 17:10:52.585115','APPC operation','Restart',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('SDNC','Not found','2021-03-05 17:10:52.567645','Not found','2021-03-05 17:10:52.567645','SDNC component','SDNC',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('SDNR','Not found','2021-03-05 17:10:52.566004','Not found','2021-03-05 17:10:52.566004','SDNR component','SDNR',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('SO','Not found','2021-03-05 17:10:52.569719','Not found','2021-03-05 17:10:52.569719','SO component','SO',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('VF Module Create (SO operation)','Not found','2021-03-05 17:10:52.582689','Not found','2021-03-05 17:10:52.582689','SO operation','VF Module Create',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('VF Module Delete (SO operation)','Not found','2021-03-05 17:10:52.581150','Not found','2021-03-05 17:10:52.581150','SO operation','VF Module Delete',NULL,'string');
+INSERT INTO `dictionary_elements` (`short_name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `description`, `name`, `subdictionary_name`, `type`) VALUES ('VFC','Not found','2021-03-05 17:10:52.568756','Not found','2021-03-05 17:10:52.568756','VFC component','VFC',NULL,'string');
+/*!40000 ALTER TABLE `dictionary_elements` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `dictionary_to_dictionaryelements`
+--
+
+LOCK TABLES `dictionary_to_dictionaryelements` WRITE;
+/*!40000 ALTER TABLE `dictionary_to_dictionaryelements` DISABLE KEYS */;
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultActors','APPC');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultActors','SDNC');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultActors','SDNR');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultActors','SO');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultActors','VFC');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','BandwidthOnDemand (SDNC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','Health-Check (APPC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','Migrate (APPC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','ModifyConfig (APPC/VFC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','Rebuild (APPC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','Reroute (SDNC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','Restart (APPC operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','VF Module Create (SO operation)');
+INSERT INTO `dictionary_to_dictionaryelements` (`dictionary_name`, `dictionary_element_short_name`) VALUES ('DefaultOperations','VF Module Delete (SO operation)');
+/*!40000 ALTER TABLE `dictionary_to_dictionaryelements` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `hibernate_sequence`
+--
+
+LOCK TABLES `hibernate_sequence` WRITE;
+/*!40000 ALTER TABLE `hibernate_sequence` DISABLE KEYS */;
+INSERT INTO `hibernate_sequence` (`next_val`) VALUES (11);
+/*!40000 ALTER TABLE `hibernate_sequence` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loop_element_models`
+--
+
+LOCK TABLES `loop_element_models` WRITE;
+/*!40000 ALTER TABLE `loop_element_models` DISABLE KEYS */;
+INSERT INTO `loop_element_models` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `blueprint_yaml`, `dcae_blueprint_id`, `loop_element_type`, `short_name`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app',NULL,'2021-03-05 17:10:19.722143','Not found','2021-03-05 17:10:19.852676',NULL,NULL,'MICRO_SERVICE_TYPE',NULL);
+INSERT INTO `loop_element_models` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `blueprint_yaml`, `dcae_blueprint_id`, `loop_element_type`, `short_name`) VALUES ('onap.policies.monitoring.tcagen2','Not found','2021-03-05 17:10:19.837051','Not found','2021-03-05 17:10:19.837051',NULL,NULL,'MICRO_SERVICE_TYPE',NULL);
+/*!40000 ALTER TABLE `loop_element_models` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loop_logs`
+--
+
+LOCK TABLES `loop_logs` WRITE;
+/*!40000 ALTER TABLE `loop_logs` DISABLE KEYS */;
+/*!40000 ALTER TABLE `loop_logs` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loop_templates`
+--
+
+LOCK TABLES `loop_templates` WRITE;
+/*!40000 ALTER TABLE `loop_templates` DISABLE KEYS */;
+INSERT INTO `loop_templates` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `allowed_loop_type`, `blueprint_yaml`, `dcae_blueprint_id`, `maximum_instances_allowed`, `unique_blueprint`, `service_uuid`) VALUES ('LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca','Not found','2021-03-05 17:10:19.774034','Not found','2021-03-05 17:10:19.774034','CLOSED','tosca_definitions_version: cloudify_dsl_1_3\nimports:\n- http://www.getcloudify.org/spec/cloudify/3.4/types.yaml\n- https://onap.org:8443/repository/solutioning01-mte2-raw/type_files/docker/2.2.0/node-type.yaml\n- https://onap.org:8443/repository/solutioning01-mte2-raw/type_files/relationship/1.0.0/node-type.yaml\n- http://onap.org:8081/repository/solutioning01-mte2-raw/type_files/dmaap/dmaap_mr.yaml\ninputs:\n location_id:\n type: string\n service_id:\n type: string\n policy_id:\n type: string\nnode_templates:\n policy_0:\n type: dcae.nodes.policy\n properties:\n policy_id: \n get_input: policy_id\n policy_model_id: \"onap.policies.monitoring.cdap.tca.hi.lo.app\"\n cdap_host_host:\n type: dcae.nodes.StreamingAnalytics.SelectedCDAPInfrastructure\n properties:\n location_id:\n get_input: location_id\n scn_override: cdap_broker.solutioning-central.dcae.onap.org\n interfaces:\n cloudify.interfaces.lifecycle: {\n }\n tca_tca:\n type: dcae.nodes.MicroService.cdap\n properties:\n app_config:\n appDescription: DCAE Analytics Threshold Crossing Alert Application\n appName: dcae-tca\n tcaSubscriberOutputStreamName: TCASubscriberOutputStream\n tcaVESAlertsTableName: TCAVESAlertsTable\n tcaVESAlertsTableTTLSeconds: \'1728000\'\n tcaVESMessageStatusTableName: TCAVESMessageStatusTable\n tcaVESMessageStatusTableTTLSeconds: \'86400\'\n thresholdCalculatorFlowletInstances: \'2\'\n app_preferences:\n publisherContentType: application/json\n publisherHostName: mrlocal-mtnjftle01.onap.org\n publisherHostPort: \'3905\'\n publisherMaxBatchSize: \'10\'\n publisherMaxRecoveryQueueSize: \'100000\'\n publisherPollingInterval: \'20000\'\n publisherProtocol: https\n publisherTopicName: org.onap.dcae.dmaap.mtnje2.DcaeTestVESPub\n publisherUserName: test@tca.af.dcae.onap.org\n publisherUserPassword: password\n subscriberConsumerGroup: OpenDCAE-c12\n subscriberConsumerId: c12\n subscriberContentType: application/json\n subscriberHostName: mrlocal-mtnjftle01.onap.org\n subscriberHostPort: \'3905\'\n subscriberMessageLimit: \'-1\'\n subscriberPollingInterval: \'20000\'\n subscriberProtocol: https\n subscriberTimeoutMS: \'-1\'\n subscriberTopicName: org.onap.dcae.dmaap.mtnje2.DcaeTestVESSub\n subscriberUserName: test@tca.af.dcae.onap.org\n subscriberUserPassword: password\n tca_policy: null\n artifact_name: dcae-analytics-tca\n artifact_version: 1.0.0\n connections:\n streams_publishes: [\n ]\n streams_subscribes: [\n ]\n jar_url: http://somejar\n location_id:\n get_input: location_id\n namespace: cdap_tca_hi_lo\n programs:\n - program_id: TCAVESCollectorFlow\n program_type: flows\n - program_id: TCADMaaPMRSubscriberWorker\n program_type: workers\n - program_id: TCADMaaPMRPublisherWorker\n program_type: workers\n service_component_type: cdap_app_tca\n service_id:\n get_input: service_id\n streamname: TCASubscriberOutputStream\n relationships:\n - target: topic0\n type: dcae.relationships.subscribe_to_events\n - target: topic1\n type: dcae.relationships.publish_events\n - target: cdap_host_host\n type: dcae.relationships.component_contained_in\n - target: policy_0\n type: dcae.relationships.depends_on\n topic0:\n type: dcae.nodes.Topic\n properties:\n topic_name: \'\'\n topic1:\n type: dcae.nodes.Topic\n properties:\n topic_name: \'\'\n \n','typeId-7e039b4b-8ab4-47f2-9dd4-2cbe584105a6',0,1,'63cac700-ab9a-4115-a74f-7eac85e3fce0');
+INSERT INTO `loop_templates` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `allowed_loop_type`, `blueprint_yaml`, `dcae_blueprint_id`, `maximum_instances_allowed`, `unique_blueprint`, `service_uuid`) VALUES ('LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca-guilin','Not found','2021-03-05 17:10:19.833813','Not found','2021-03-05 17:10:19.833813','CLOSED','# ============LICENSE_START====================================================\n# =============================================================================\n# Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.\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# ============LICENSE_END======================================================\n#k8s-tca-gen2-v3.yaml\n\ntosca_definitions_version: cloudify_dsl_1_3\nimports:\n - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml\n - plugin:k8splugin?version=3.4.2\n - plugin:clamppolicyplugin?version=1.1.0\ninputs:\n service_name:\n type: string\n default: \'dcae-tcagen2\'\n log_directory:\n type: string\n default: \"/opt/logs/dcae-analytics-tca\"\n replicas:\n type: integer\n description: number of instances\n default: 1\n spring.data.mongodb.uri:\n type: string\n default: \"mongodb://dcae-mongohost/dcae-tcagen2\"\n tag_version:\n type: string\n default: \"nexus3.onap.org:10001/onap/org.onap.dcaegen2.analytics.tca-gen2.dcae-analytics-tca-web:1.2.1\"\n tca.aai.password:\n type: string\n default: \"DCAE\"\n tca.aai.url:\n type: string\n default: \"http://aai.onap.svc.cluster.local\"\n tca.aai.username:\n type: string\n default: \"DCAE\"\n tca_handle_in_subscribe_url:\n type: string\n default: \"http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.VES_MEASUREMENT_OUTPUT\"\n tca_handle_out_publish_url:\n type: string\n default: \"http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.DCAE_CL_OUTPUT\"\n tca_consumer_group:\n type: string\n default: \"cg1\"\n policy_model_id:\n type: string\n default: \"onap.policies.monitoring.tcagen2\"\n policy_id:\n type: string\n default: \"onap.restart.tca\"\nnode_templates:\n docker.tca:\n type: dcae.nodes.ContainerizedServiceComponent\n relationships:\n - target: tcagen2_policy\n type: cloudify.relationships.depends_on\n interfaces:\n cloudify.interfaces.lifecycle:\n start:\n inputs:\n ports:\n - concat: [\"9091:\", \"0\"]\n properties:\n application_config:\n service_calls: []\n streams_publishes:\n tca_handle_out:\n dmaap_info:\n topic_url:\n get_input: tca_handle_out_publish_url\n type: message_router\n streams_subscribes:\n tca_handle_in:\n dmaap_info:\n topic_url:\n get_input: tca_handle_in_subscribe_url\n type: message_router\n spring.data.mongodb.uri:\n get_input: spring.data.mongodb.uri\n streams_subscribes.tca_handle_in.consumer_group:\n get_input: tca_consumer_group\n streams_subscribes.tca_handle_in.consumer_ids[0]: c0\n streams_subscribes.tca_handle_in.consumer_ids[1]: c1\n streams_subscribes.tca_handle_in.message_limit: 50000\n streams_subscribes.tca_handle_in.polling.auto_adjusting.max: 60000\n streams_subscribes.tca_handle_in.polling.auto_adjusting.min: 30000\n streams_subscribes.tca_handle_in.polling.auto_adjusting.step_down: 30000\n streams_subscribes.tca_handle_in.polling.auto_adjusting.step_up: 10000\n streams_subscribes.tca_handle_in.polling.fixed_rate: 0\n streams_subscribes.tca_handle_in.timeout: -1\n tca.aai.enable_enrichment: true\n tca.aai.generic_vnf_path: aai/v11/network/generic-vnfs/generic-vnf\n tca.aai.node_query_path: aai/v11/search/nodes-query\n tca.aai.password:\n get_input: tca.aai.password\n tca.aai.url:\n get_input: tca.aai.url\n tca.aai.username:\n get_input: tca.aai.username\n tca.policy: \'{\"domain\":\"measurementsForVfScaling\",\"metricsPerEventName\":[{\"eventName\":\"vFirewallBroadcastPackets\",\"controlLoopSchemaType\":\"VM\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"LESS_OR_EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ONSET\"},{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":700,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"vLoadBalancer\",\"controlLoopSchemaType\":\"VM\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"Measurement_vGMUX\",\"controlLoopSchemaType\":\"VNF\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ABATED\"},{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"GREATER\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]}]}\'\n tca.processing_batch_size: 10000\n tca.enable_abatement: true\n tca.enable_ecomp_logging: true\n docker_config:\n healthcheck:\n endpoint: /actuator/health\n interval: 30s\n timeout: 10s\n type: http\n image:\n get_input: tag_version\n log_info:\n log_directory:\n get_input: log_directory\n tls_info:\n use_tls: true\n cert_directory: \'/etc/tca-gen2/ssl\'\n replicas:\n get_input: replicas\n service_component_type: { get_input: service_name }\n tcagen2_policy:\n type: clamp.nodes.policy\n properties:\n policy_id:\n get_input: policy_id\n policy_model_id:\n get_input: policy_model_id\n','typeId-9355082c-7e22-47aa-963e-3236a0221ac9',0,1,'63cac700-ab9a-4115-a74f-7eac85e3fce0');
+INSERT INTO `loop_templates` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `allowed_loop_type`, `blueprint_yaml`, `dcae_blueprint_id`, `maximum_instances_allowed`, `unique_blueprint`, `service_uuid`) VALUES ('LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca_3','Not found','2021-03-05 17:10:19.748910','Not found','2021-03-05 17:10:19.748910','CLOSED','#\n# ============LICENSE_START====================================================\n# =============================================================================\n# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.\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# ============LICENSE_END======================================================\n\ntosca_definitions_version: cloudify_dsl_1_3\n\ndescription: >\n This blueprint deploys/manages the TCA module as a Docker container\n\nimports:\n - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml\n - \"https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/k8splugin/1.7.2/k8splugin_types.yaml\"\n - \"https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/clamppolicyplugin/1.1.0/clamppolicyplugin_types.yaml\"\ninputs:\n aaiEnrichmentHost:\n type: string\n default: \"aai.onap.svc.cluster.local\"\n aaiEnrichmentPort:\n type: string\n default: \"8443\"\n enableAAIEnrichment:\n type: string\n default: \"true\"\n dmaap_host:\n type: string\n default: \"message-router.onap.svc.cluster.local\"\n dmaap_port:\n type: string\n default: \"3904\"\n enableRedisCaching:\n type: string\n default: \"false\"\n redisHosts:\n type: string\n default: \"dcae-redis.onap.svc.cluster.local:6379\"\n tag_version:\n type: string\n default: \"nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.2.2\"\n consul_host:\n type: string\n default: \"consul-server.onap\"\n consul_port:\n type: string\n default: \"8500\"\n cbs_host:\n type: string\n default: \"config-binding-service\"\n cbs_port:\n type: string\n default: \"10000\"\n policy_id:\n type: string\n default: \"onap.restart.tca\"\n external_port:\n type: string\n description: Kubernetes node port on which CDAPgui is exposed\n default: \"32012\"\n policy_model_id:\n type: string\n default: \"onap.policies.monitoring.cdap.tca.hi.lo.app\"\nnode_templates:\n tca_k8s:\n type: dcae.nodes.ContainerizedServiceComponent\n relationships:\n - target: tca_policy\n type: cloudify.relationships.depends_on\n properties:\n service_component_type: \'dcaegen2-analytics-tca\'\n application_config: {}\n docker_config: {}\n image:\n get_input: tag_version\n log_info:\n log_directory: \"/opt/app/TCAnalytics/logs\"\n application_config:\n app_config:\n appDescription: DCAE Analytics Threshold Crossing Alert Application\n appName: dcae-tca\n tcaAlertsAbatementTableName: TCAAlertsAbatementTable\n tcaAlertsAbatementTableTTLSeconds: \'1728000\'\n tcaSubscriberOutputStreamName: TCASubscriberOutputStream\n tcaVESAlertsTableName: TCAVESAlertsTable\n tcaVESAlertsTableTTLSeconds: \'1728000\'\n tcaVESMessageStatusTableName: TCAVESMessageStatusTable\n tcaVESMessageStatusTableTTLSeconds: \'86400\'\n thresholdCalculatorFlowletInstances: \'2\'\n app_preferences:\n aaiEnrichmentHost:\n get_input: aaiEnrichmentHost\n aaiEnrichmentIgnoreSSLCertificateErrors: \'true\'\n aaiEnrichmentPortNumber: \'8443\'\n aaiEnrichmentProtocol: https\n aaiEnrichmentUserName: dcae@dcae.onap.org\n aaiEnrichmentUserPassword: demo123456!\n aaiVMEnrichmentAPIPath: /aai/v11/search/nodes-query\n aaiVNFEnrichmentAPIPath: /aai/v11/network/generic-vnfs/generic-vnf\n enableAAIEnrichment:\n get_input: enableAAIEnrichment\n enableRedisCaching:\n get_input: enableRedisCaching\n redisHosts:\n get_input: redisHosts\n enableAlertCEFFormat: \'false\'\n publisherContentType: application/json\n publisherHostName:\n get_input: dmaap_host\n publisherHostPort:\n get_input: dmaap_port\n publisherMaxBatchSize: \'1\'\n publisherMaxRecoveryQueueSize: \'100000\'\n publisherPollingInterval: \'20000\'\n publisherProtocol: http\n publisherTopicName: unauthenticated.DCAE_CL_OUTPUT\n subscriberConsumerGroup: OpenDCAE-clamp\n subscriberConsumerId: c12\n subscriberContentType: application/json\n subscriberHostName:\n get_input: dmaap_host\n subscriberHostPort:\n get_input: dmaap_port\n subscriberMessageLimit: \'-1\'\n subscriberPollingInterval: \'30000\'\n subscriberProtocol: http\n subscriberTimeoutMS: \'-1\'\n subscriberTopicName: unauthenticated.VES_MEASUREMENT_OUTPUT\n #tca_policy: \'{\"domain\":\"measurementsForVfScaling\",\"metricsPerEventName\":[{\"eventName\":\"vFirewallBroadcastPackets\",\"controlLoopSchemaType\":\"VM\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"LESS_OR_EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ONSET\"},{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":700,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"vLoadBalancer\",\"controlLoopSchemaType\":\"VM\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"Measurement_vGMUX\",\"controlLoopSchemaType\":\"VNF\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ABATED\"},{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"GREATER\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]}]}\'\n tca_policy: \'\'\n service_component_type: dcaegen2-analytics_tca\n interfaces:\n cloudify.interfaces.lifecycle:\n start:\n inputs:\n envs:\n DMAAPHOST:\n { get_input: dmaap_host }\n DMAAPPORT: \"3904\"\n DMAAPPUBTOPIC: \"unauthenticated.DCAE_CL_OUTPUT\"\n DMAAPSUBTOPIC: \"unauthenticated.VES_MEASUREMENT_OUTPUT\"\n AAIHOST:\n { get_input: aaiEnrichmentHost }\n AAIPORT: \"8443\"\n CONSUL_HOST:\n { get_input: consul_host }\n CONSUL_PORT: \"8500\"\n CBS_HOST:\n { get_input: cbs_host }\n CBS_PORT: \"10000\"\n CONFIG_BINDING_SERVICE: \"config_binding_service\"\n ports:\n - concat: [\"11011:\", { get_input: external_port }]\n tca_policy:\n type: clamp.nodes.policy\n properties:\n policy_id:\n get_input: policy_id\n policy_model_id:\n get_input: policy_model_id\n','typeId-239e94d1-f137-42bf-91d4-659e9a7f928e',0,1,'63cac700-ab9a-4115-a74f-7eac85e3fce0');
+INSERT INTO `loop_templates` (`name`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `allowed_loop_type`, `blueprint_yaml`, `dcae_blueprint_id`, `maximum_instances_allowed`, `unique_blueprint`, `service_uuid`) VALUES ('LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName2_tca_2','Not found','2021-03-05 17:10:19.715327','Not found','2021-03-05 17:10:19.715327','CLOSED','#\n# ============LICENSE_START====================================================\n# =============================================================================\n# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.\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# ============LICENSE_END======================================================\n\ntosca_definitions_version: cloudify_dsl_1_3\n\ndescription: >\n This blueprint deploys/manages the TCA module as a Docker container\n\nimports:\n - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml\n - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/k8splugin/1.4.12/k8splugin_types.yaml\n# - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/dcaepolicyplugin/2.3.0/dcaepolicyplugin_types.yaml\n - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/clamppolicyplugin/1.0.0/clamppolicyplugin_types.yaml\ninputs:\n aaiEnrichmentHost:\n type: string\n default: \"aai.onap.svc.cluster.local\"\n aaiEnrichmentPort:\n type: string\n default: \"8443\"\n enableAAIEnrichment:\n type: string\n default: true\n dmaap_host:\n type: string\n default: message-router.onap\n dmaap_port:\n type: string\n default: \"3904\"\n enableRedisCaching:\n type: string\n default: false\n redisHosts:\n type: string\n default: dcae-redis.onap.svc.cluster.local:6379\n tag_version:\n type: string\n default: \"nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.1.1\"\n consul_host:\n type: string\n default: consul-server.onap\n consul_port:\n type: string\n default: \"8500\"\n cbs_host:\n type: string\n default: \"config-binding-servicel\"\n cbs_port:\n type: string\n default: \"10000\"\n policy_id:\n type: string\n default: \"onap.restart.tca\"\n external_port:\n type: string\n description: Kubernetes node port on which CDAPgui is exposed\n default: \"32012\"\n policy_model_id:\n type: string\n default: \"onap.policies.monitoring.cdap.tca.hi.lo.app\"\nnode_templates:\n tca_k8s:\n type: dcae.nodes.ContainerizedServiceComponent\n relationships:\n - target: tca_policy\n type: cloudify.relationships.depends_on\n properties:\n service_component_type: \'dcaegen2-analytics-tca\'\n application_config: {}\n docker_config: {}\n image:\n get_input: tag_version\n log_info:\n log_directory: \"/opt/app/TCAnalytics/logs\"\n application_config:\n app_config:\n appDescription: DCAE Analytics Threshold Crossing Alert Application\n appName: dcae-tca\n tcaAlertsAbatementTableName: TCAAlertsAbatementTable\n tcaAlertsAbatementTableTTLSeconds: \'1728000\'\n tcaSubscriberOutputStreamName: TCASubscriberOutputStream\n tcaVESAlertsTableName: TCAVESAlertsTable\n tcaVESAlertsTableTTLSeconds: \'1728000\'\n tcaVESMessageStatusTableName: TCAVESMessageStatusTable\n tcaVESMessageStatusTableTTLSeconds: \'86400\'\n thresholdCalculatorFlowletInstances: \'2\'\n app_preferences:\n aaiEnrichmentHost:\n get_input: aaiEnrichmentHost\n aaiEnrichmentIgnoreSSLCertificateErrors: \'true\'\n aaiEnrichmentPortNumber: \'8443\'\n aaiEnrichmentProtocol: https\n aaiEnrichmentUserName: dcae@dcae.onap.org\n aaiEnrichmentUserPassword: demo123456!\n aaiVMEnrichmentAPIPath: /aai/v11/search/nodes-query\n aaiVNFEnrichmentAPIPath: /aai/v11/network/generic-vnfs/generic-vnf\n enableAAIEnrichment:\n get_input: enableAAIEnrichment\n enableRedisCaching:\n get_input: enableRedisCaching\n redisHosts:\n get_input: redisHosts\n enableAlertCEFFormat: \'false\'\n publisherContentType: application/json\n publisherHostName:\n get_input: dmaap_host\n publisherHostPort:\n get_input: dmaap_port\n publisherMaxBatchSize: \'1\'\n publisherMaxRecoveryQueueSize: \'100000\'\n publisherPollingInterval: \'20000\'\n publisherProtocol: http\n publisherTopicName: unauthenticated.DCAE_CL_OUTPUT\n subscriberConsumerGroup: OpenDCAE-clamp\n subscriberConsumerId: c12\n subscriberContentType: application/json\n subscriberHostName:\n get_input: dmaap_host\n subscriberHostPort:\n get_input: dmaap_port\n subscriberMessageLimit: \'-1\'\n subscriberPollingInterval: \'30000\'\n subscriberProtocol: http\n subscriberTimeoutMS: \'-1\'\n subscriberTopicName: unauthenticated.VES_MEASUREMENT_OUTPUT\n# tca_policy: \'{\"domain\":\"measurementsForVfScaling\",\"metricsPerEventName\":[{\"eventName\":\"vFirewallBroadcastPackets\",\"controlLoopSchemaType\":\"VNF\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"LESS_OR_EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ONSET\"},{\"closedLoopControlName\":\"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":700,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"vLoadBalancer\",\"controlLoopSchemaType\":\"VM\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\",\"thresholdValue\":300,\"direction\":\"GREATER_OR_EQUAL\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]},{\"eventName\":\"Measurement_vGMUX\",\"controlLoopSchemaType\":\"VNF\",\"policyScope\":\"DCAE\",\"policyName\":\"DCAE.Config_tca-hi-lo\",\"policyVersion\":\"v0.0.1\",\"thresholds\":[{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"EQUAL\",\"severity\":\"MAJOR\",\"closedLoopEventStatus\":\"ABATED\"},{\"closedLoopControlName\":\"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e\",\"version\":\"1.0.2\",\"fieldPath\":\"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\",\"thresholdValue\":0,\"direction\":\"GREATER\",\"severity\":\"CRITICAL\",\"closedLoopEventStatus\":\"ONSET\"}]}]}\'\n service_component_type: dcaegen2-analytics_tca\n interfaces:\n cloudify.interfaces.lifecycle:\n start:\n inputs:\n envs:\n DMAAPHOST:\n { get_input: dmaap_host }\n DMAAPPORT:\n { get_input: dmaap_port }\n DMAAPPUBTOPIC: \"unauthenticated.DCAE_CL_OUTPUT\"\n DMAAPSUBTOPIC: \"unauthenticated.VES_MEASUREMENT_OUTPUT\"\n AAIHOST:\n { get_input: aaiEnrichmentHost }\n AAIPORT:\n { get_input: aaiEnrichmentPort }\n CONSUL_HOST:\n { get_input: consul_host }\n CONSUL_PORT:\n { get_input: consul_port }\n CBS_HOST:\n { get_input: cbs_host }\n CBS_PORT:\n { get_input: cbs_port }\n CONFIG_BINDING_SERVICE: \"config_binding_service\"\n ports:\n - concat: [\"11011:\", { get_input: external_port }]\n tca_policy:\n type: clamp.nodes.policy\n properties:\n policy_id:\n get_input: policy_id\n policy_model_id: \"onap.policies.monitoring.cdap.tca.hi.lo.app\"\n','typeId-6c349c12-eabd-44a2-9b2d-e9115fb27655',0,1,'63cac700-ab9a-4115-a74f-7eac85e3fce0');
+/*!40000 ALTER TABLE `loop_templates` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loopelementmodels_to_policymodels`
+--
+
+LOCK TABLES `loopelementmodels_to_policymodels` WRITE;
+/*!40000 ALTER TABLE `loopelementmodels_to_policymodels` DISABLE KEYS */;
+INSERT INTO `loopelementmodels_to_policymodels` (`loop_element_name`, `policy_model_type`, `policy_model_version`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app','onap.policies.monitoring.cdap.tca.hi.lo.app','1.0.0');
+INSERT INTO `loopelementmodels_to_policymodels` (`loop_element_name`, `policy_model_type`, `policy_model_version`) VALUES ('onap.policies.monitoring.tcagen2','onap.policies.monitoring.tcagen2','1.0.0');
+/*!40000 ALTER TABLE `loopelementmodels_to_policymodels` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loops`
+--
+
+LOCK TABLES `loops` WRITE;
+/*!40000 ALTER TABLE `loops` DISABLE KEYS */;
+/*!40000 ALTER TABLE `loops` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `loops_to_microservicepolicies`
+--
+
+LOCK TABLES `loops_to_microservicepolicies` WRITE;
+/*!40000 ALTER TABLE `loops_to_microservicepolicies` DISABLE KEYS */;
+/*!40000 ALTER TABLE `loops_to_microservicepolicies` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `looptemplates_to_loopelementmodels`
+--
+
+LOCK TABLES `looptemplates_to_loopelementmodels` WRITE;
+/*!40000 ALTER TABLE `looptemplates_to_loopelementmodels` DISABLE KEYS */;
+INSERT INTO `looptemplates_to_loopelementmodels` (`loop_element_model_name`, `loop_template_name`, `flow_order`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app','LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca',0);
+INSERT INTO `looptemplates_to_loopelementmodels` (`loop_element_model_name`, `loop_template_name`, `flow_order`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app','LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca_3',0);
+INSERT INTO `looptemplates_to_loopelementmodels` (`loop_element_model_name`, `loop_template_name`, `flow_order`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app','LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName2_tca_2',0);
+INSERT INTO `looptemplates_to_loopelementmodels` (`loop_element_model_name`, `loop_template_name`, `flow_order`) VALUES ('onap.policies.monitoring.tcagen2','LOOP_TEMPLATE_RzsRR_v1_0_ResourceInstanceName1_tca-guilin',0);
+/*!40000 ALTER TABLE `looptemplates_to_loopelementmodels` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `micro_service_policies`
+--
+
+LOCK TABLES `micro_service_policies` WRITE;
+/*!40000 ALTER TABLE `micro_service_policies` DISABLE KEYS */;
+/*!40000 ALTER TABLE `micro_service_policies` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `operational_policies`
+--
+
+LOCK TABLES `operational_policies` WRITE;
+/*!40000 ALTER TABLE `operational_policies` DISABLE KEYS */;
+/*!40000 ALTER TABLE `operational_policies` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `policy_models`
+--
+
+LOCK TABLES `policy_models` WRITE;
+/*!40000 ALTER TABLE `policy_models` DISABLE KEYS */;
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.controlloop.guard.common.Blacklist','1.0.0','Not found','2021-03-05 17:10:27.333221','Not found','2021-03-05 17:10:27.473020','Blacklist','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.controlloop.guard.Common:\n derived_from: tosca.policies.Root\n version: 1.0.0\n description: |\n This is the base Policy Type for Guard policies that guard the execution of Operational\n Policies.\n properties:\n actor:\n type: string\n description: Specifies the Actor the guard applies to.\n required: true\n operation:\n type: string\n description: Specified the operation that the actor is performing\n the guard applies to.\n required: true\n timeRange:\n type: tosca.datatypes.TimeInterval\n description: |\n An optional range of time during the day the guard policy is valid for.\n required: false\n id:\n type: string\n description: The Control Loop id this applies to.\n required: false\n onap.policies.controlloop.guard.common.Blacklist:\n derived_from: onap.policies.controlloop.guard.Common\n type_version: 1.0.0\n version: 1.0.0\n description: Supports blacklist of entity id\'s from performing control loop\n actions on.\n properties:\n blacklist:\n type: list\n description: List of entity id\'s\n required: true\n entry_schema:\n type: string\n','{\n \"supportedPdpGroups\": [\n {\n \"controlloop\": [\n \"xacml\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.controlloop.guard.common.FrequencyLimiter','1.0.0','Not found','2021-03-05 17:10:27.311329','Not found','2021-03-05 17:10:27.473520','FrequencyLimiter','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.controlloop.guard.Common:\n derived_from: tosca.policies.Root\n version: 1.0.0\n description: |\n This is the base Policy Type for Guard policies that guard the execution of Operational\n Policies.\n properties:\n actor:\n type: string\n description: Specifies the Actor the guard applies to.\n required: true\n operation:\n type: string\n description: Specified the operation that the actor is performing\n the guard applies to.\n required: true\n timeRange:\n type: tosca.datatypes.TimeInterval\n description: |\n An optional range of time during the day the guard policy is valid for.\n required: false\n id:\n type: string\n description: The Control Loop id this applies to.\n required: false\n onap.policies.controlloop.guard.common.FrequencyLimiter:\n derived_from: onap.policies.controlloop.guard.Common\n type_version: 1.0.0\n version: 1.0.0\n description: Supports limiting the frequency of actions being taken by a Actor.\n properties:\n timeWindow:\n type: integer\n description: The time window to count the actions against.\n required: true\n timeUnits:\n type: string\n description: The units of time the window is counting.\n constraints:\n - valid_values:\n - second\n - minute\n - hour\n - day\n - week\n - month\n - year\n limit:\n type: integer\n description: The limit\n required: true\n constraints:\n - greater_than: 0\n','{\n \"supportedPdpGroups\": [\n {\n \"controlloop\": [\n \"xacml\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.controlloop.guard.common.MinMax','2.0.0','Not found','2021-03-05 17:10:27.377510','Not found','2021-03-05 17:10:27.377510','MinMax','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.controlloop.guard.Common:\n derived_from: tosca.policies.Root\n version: 1.0.0\n description: |\n This is the base Policy Type for Guard policies that guard the execution of Operational\n Policies.\n properties:\n actor:\n type: string\n description: Specifies the Actor the guard applies to.\n required: true\n operation:\n type: string\n description: Specified the operation that the actor is performing\n the guard applies to.\n required: true\n timeRange:\n type: tosca.datatypes.TimeInterval\n description: |\n An optional range of time during the day the guard policy is valid for.\n required: false\n id:\n type: string\n description: The Control Loop id this applies to.\n required: false\n onap.policies.controlloop.guard.common.MinMax:\n derived_from: onap.policies.controlloop.guard.Common\n type_version: 1.0.0\n version: 1.0.0\n description: Supports Min/Max number of entity for scaling operations\n properties:\n min:\n type: integer\n required: true\n description: The minimum instances of this entity\n max:\n type: integer\n required: false\n description: The maximum instances of this entity\n',NULL);
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.controlloop.operational.common.Apex','1.0.0','Not found','2021-03-05 17:10:27.289621','Not found','2021-03-05 17:10:27.473869','Apex','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.controlloop.operational.Common:\n properties:\n abatement:\n name: abatement\n type: boolean\n typeVersion: 0.0.0\n description: Whether an abatement event message will be expected for\n the control loop from DCAE.\n default: \'false\'\n required: true\n constraints: [\n ]\n metadata: {\n }\n operations:\n name: operations\n type: list\n typeVersion: 0.0.0\n description: List of operations to be performed when Control Loop\n is triggered.\n required: true\n constraints: [\n ]\n entry_schema:\n type: onap.datatype.controlloop.Operation\n typeVersion: 0.0.0\n constraints: [\n ]\n metadata: {\n }\n trigger:\n name: trigger\n type: string\n typeVersion: 0.0.0\n description: Initial operation to execute upon receiving an Onset\n event message for the Control Loop.\n required: true\n constraints: [\n ]\n metadata: {\n }\n timeout:\n name: timeout\n type: integer\n typeVersion: 0.0.0\n description: |\n Overall timeout for executing all the operations. This timeout should equal or exceed the total\n timeout for each operation listed.\n required: true\n constraints: [\n ]\n metadata: {\n }\n id:\n name: id\n type: string\n typeVersion: 0.0.0\n description: The unique control loop id.\n required: true\n constraints: [\n ]\n metadata: {\n }\n name: onap.policies.controlloop.operational.Common\n version: 1.0.0\n derived_from: tosca.policies.Root\n metadata: {\n }\n description: |\n Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant\n Policy Types. This does NOT support the legacy Policy YAML policy type.\n onap.policies.controlloop.operational.common.Apex:\n properties:\n engineServiceParameters:\n name: engineServiceParameters\n type: string\n typeVersion: 0.0.0\n description: The engine parameters like name, instanceCount, policy\n implementation, parameters etc.\n required: true\n constraints: [\n ]\n metadata: {\n }\n eventOutputParameters:\n name: eventOutputParameters\n type: string\n typeVersion: 0.0.0\n description: The event output parameters.\n required: true\n constraints: [\n ]\n metadata: {\n }\n javaProperties:\n name: javaProperties\n type: string\n typeVersion: 0.0.0\n description: Name/value pairs of properties to be set for APEX if\n needed.\n required: false\n constraints: [\n ]\n metadata: {\n }\n eventInputParameters:\n name: eventInputParameters\n type: string\n typeVersion: 0.0.0\n description: The event input parameters.\n required: true\n constraints: [\n ]\n metadata: {\n }\n name: onap.policies.controlloop.operational.common.Apex\n version: 1.0.0\n derived_from: onap.policies.controlloop.operational.Common\n metadata: {\n }\n description: Operational policies for Apex PDP\ndata_types:\n onap.datatype.controlloop.Actor:\n constraints: [\n ]\n properties:\n payload:\n name: payload\n type: map\n typeVersion: 0.0.0\n description: Name/value pairs of payload information passed by Policy\n to the actor\n required: false\n constraints: [\n ]\n entry_schema:\n type: string\n typeVersion: 0.0.0\n constraints: [\n ]\n metadata:\n clamp_possible_values: ClampExecution:CDS/payload\n target:\n name: target\n type: onap.datatype.controlloop.Target\n typeVersion: 0.0.0\n description: The resource the operation should be performed on.\n required: true\n constraints: [\n ]\n metadata: {\n }\n actor:\n name: actor\n type: string\n typeVersion: 0.0.0\n description: The actor performing the operation.\n required: true\n constraints: [\n ]\n metadata:\n clamp_possible_values: Dictionary:DefaultActors,ClampExecution:CDS/actor\n operation:\n name: operation\n type: string\n typeVersion: 0.0.0\n description: The operation the actor is performing.\n required: true\n constraints: [\n ]\n metadata:\n clamp_possible_values: Dictionary:DefaultOperations, ClampExecution:CDS/operation\n name: onap.datatype.controlloop.Actor\n version: 0.0.0\n derived_from: tosca.datatypes.Root\n metadata: {\n }\n description: An actor/operation/target definition\n onap.datatype.controlloop.Operation:\n constraints: [\n ]\n properties:\n failure_retries:\n name: failure_retries\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke when the current operation\n has exceeded its max retries.\n default: final_failure_retries\n required: false\n constraints: [\n ]\n metadata: {\n }\n id:\n name: id\n type: string\n typeVersion: 0.0.0\n description: Unique identifier for the operation\n required: true\n constraints: [\n ]\n metadata: {\n }\n failure_timeout:\n name: failure_timeout\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke when the time out for\n the operation occurs.\n default: final_failure_timeout\n required: false\n constraints: [\n ]\n metadata: {\n }\n failure:\n name: failure\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke on Actor operation\n failure.\n default: final_failure\n required: false\n constraints: [\n ]\n metadata: {\n }\n operation:\n name: operation\n type: onap.datatype.controlloop.Actor\n typeVersion: 0.0.0\n description: The definition of the operation to be performed.\n required: true\n constraints: [\n ]\n metadata: {\n }\n failure_guard:\n name: failure_guard\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke when the current operation\n is blocked due to guard policy enforcement.\n default: final_failure_guard\n required: false\n constraints: [\n ]\n metadata: {\n }\n retries:\n name: retries\n type: integer\n typeVersion: 0.0.0\n description: The number of retries the actor should attempt to perform\n the operation.\n default: \'0\'\n required: true\n constraints: [\n ]\n metadata: {\n }\n timeout:\n name: timeout\n type: integer\n typeVersion: 0.0.0\n description: The amount of time for the actor to perform the operation.\n required: true\n constraints: [\n ]\n metadata: {\n }\n failure_exception:\n name: failure_exception\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke when the current operation\n causes an exception.\n default: final_failure_exception\n required: false\n constraints: [\n ]\n metadata: {\n }\n description:\n name: description\n type: string\n typeVersion: 0.0.0\n description: A user-friendly description of the intent for the operation\n required: false\n constraints: [\n ]\n metadata: {\n }\n success:\n name: success\n type: string\n typeVersion: 0.0.0\n description: Points to the operation to invoke on success. A value\n of \"final_success\" indicates and end to the operation.\n default: final_success\n required: false\n constraints: [\n ]\n metadata: {\n }\n name: onap.datatype.controlloop.Operation\n version: 0.0.0\n derived_from: tosca.datatypes.Root\n metadata: {\n }\n description: An operation supported by an actor\n onap.datatype.controlloop.Target:\n constraints: [\n ]\n properties:\n entityIds:\n name: entityIds\n type: map\n typeVersion: 0.0.0\n description: |\n Map of values that identify the resource. If none are provided, it is assumed that the\n entity that generated the ONSET event will be the target.\n required: false\n constraints: [\n ]\n entry_schema:\n type: string\n typeVersion: 0.0.0\n constraints: [\n ]\n metadata:\n clamp_possible_values: ClampExecution:CSAR_RESOURCES\n targetType:\n name: targetType\n type: string\n typeVersion: 0.0.0\n description: Category for the target type\n required: true\n constraints:\n - valid_values:\n - VNF\n - VM\n - VFMODULE\n - PNF\n metadata: {\n }\n name: onap.datatype.controlloop.Target\n version: 0.0.0\n derived_from: tosca.datatypes.Root\n metadata: {\n }\n description: Definition for a entity in A&AI to perform a control loop operation\n on\nname: ToscaServiceTemplateSimple\nversion: 1.0.0\nmetadata: {\n }\n','{\n \"supportedPdpGroups\": [\n {\n \"controlloop\": [\n \"apex\",\n \"drools\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.controlloop.operational.common.Drools','1.0.0','Not found','2021-03-05 17:10:27.263600','Not found','2021-03-05 17:10:27.476583','Drools','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.controlloop.operational.common.Drools:\n derived_from: onap.policies.controlloop.operational.Common\n type_version: 1.0.0\n version: 1.0.0\n description: Operational policies for Drools PDP\n properties:\n controllerName:\n type: string\n description: Drools controller properties\n required: false\n onap.policies.controlloop.operational.Common:\n derived_from: tosca.policies.Root\n version: 1.0.0\n description: |\n Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant\n Policy Types. This does NOT support the legacy Policy YAML policy type.\n properties:\n id:\n type: string\n description: The unique control loop id.\n required: true\n timeout:\n type: integer\n description: |\n Overall timeout for executing all the operations. This timeout should equal or exceed the total\n timeout for each operation listed.\n required: true\n abatement:\n type: boolean\n description: Whether an abatement event message will be expected for\n the control loop from DCAE.\n required: true\n default: false\n trigger:\n type: string\n description: Initial operation to execute upon receiving an Onset\n event message for the Control Loop.\n required: true\n operations:\n type: list\n description: List of operations to be performed when Control Loop\n is triggered.\n required: true\n entry_schema:\n type: onap.datatype.controlloop.Operation\ndata_types:\n onap.datatype.controlloop.Target:\n derived_from: tosca.datatypes.Root\n description: Definition for a entity in A&AI to perform a control loop operation\n on\n properties:\n targetType:\n type: string\n description: Category for the target type\n required: true\n constraints:\n - valid_values:\n - VNF\n - VM\n - VFMODULE\n - PNF\n entityIds:\n type: map\n description: |\n Map of values that identify the resource. If none are provided, it is assumed that the\n entity that generated the ONSET event will be the target.\n required: false\n metadata:\n clamp_possible_values: ClampExecution:CSAR_RESOURCES\n entry_schema:\n type: string\n onap.datatype.controlloop.Actor:\n derived_from: tosca.datatypes.Root\n description: An actor/operation/target definition\n properties:\n actor:\n type: string\n description: The actor performing the operation.\n required: true\n metadata:\n clamp_possible_values: Dictionary:DefaultActors,ClampExecution:CDS/actor\n operation:\n type: string\n description: The operation the actor is performing.\n required: true\n metadata:\n clamp_possible_values: Dictionary:DefaultOperations, ClampExecution:CDS/operations\n target:\n type: onap.datatype.controlloop.Target\n description: The resource the operation should be performed on.\n required: true\n payload:\n type: map\n description: Name/value pairs of payload information passed by Policy\n to the actor\n required: false\n metadata:\n clamp_possible_values: ClampExecution:CDS/payload\n entry_schema:\n type: string\n onap.datatype.controlloop.Operation:\n derived_from: tosca.datatypes.Root\n description: An operation supported by an actor\n properties:\n id:\n type: string\n description: Unique identifier for the operation\n required: true\n description:\n type: string\n description: A user-friendly description of the intent for the operation\n required: false\n operation:\n type: onap.datatype.controlloop.Actor\n description: The definition of the operation to be performed.\n required: true\n timeout:\n type: integer\n description: The amount of time for the actor to perform the operation.\n required: true\n retries:\n type: integer\n description: The number of retries the actor should attempt to perform\n the operation.\n required: true\n default: 0\n success:\n type: string\n description: Points to the operation to invoke on success. A value\n of \"final_success\" indicates and end to the operation.\n required: false\n default: final_success\n failure:\n type: string\n description: Points to the operation to invoke on Actor operation\n failure.\n required: false\n default: final_failure\n failure_timeout:\n type: string\n description: Points to the operation to invoke when the time out for\n the operation occurs.\n required: false\n default: final_failure_timeout\n failure_retries:\n type: string\n description: Points to the operation to invoke when the current operation\n has exceeded its max retries.\n required: false\n default: final_failure_retries\n failure_exception:\n type: string\n description: Points to the operation to invoke when the current operation\n causes an exception.\n required: false\n default: final_failure_exception\n failure_guard:\n type: string\n description: Points to the operation to invoke when the current operation\n is blocked due to guard policy enforcement.\n required: false\n default: final_failure_guard\n','{\n \"supportedPdpGroups\": [\n {\n \"controlloop\": [\n \"apex\",\n \"drools\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.monitoring.cdap.tca.hi.lo.app','1.0.0','Not found','2021-03-05 17:10:19.671978','Not found','2021-03-05 17:10:27.477076','app','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.Monitoring:\n derived_from: tosca.policies.Root\n version: 1.0.0\n description: a base policy type for all policies that govern monitoring provisioning\n onap.policies.monitoring.cdap.tca.hi.lo.app:\n derived_from: onap.policies.Monitoring\n version: 1.0.0\n properties:\n tca_policy:\n type: onap.datatypes.monitoring.tca_policy\n description: TCA Policy JSON\n required: true\ndata_types:\n onap.datatypes.monitoring.metricsPerEventName:\n derived_from: tosca.datatypes.Root\n properties:\n controlLoopSchemaType:\n type: string\n required: true\n description: Specifies Control Loop Schema Type for the event Name\n e.g. VNF, VM\n constraints:\n - valid_values:\n - VM\n - VNF\n eventName:\n type: string\n required: true\n description: Event name to which thresholds need to be applied\n policyName:\n type: string\n required: true\n description: TCA Policy Scope Name\n policyScope:\n type: string\n required: true\n description: TCA Policy Scope\n policyVersion:\n type: string\n required: true\n description: TCA Policy Scope Version\n thresholds:\n type: list\n required: true\n description: Thresholds associated with eventName\n entry_schema:\n type: onap.datatypes.monitoring.thresholds\n onap.datatypes.monitoring.tca_policy:\n derived_from: tosca.datatypes.Root\n properties:\n domain:\n type: string\n required: true\n description: Domain name to which TCA needs to be applied\n default: measurementsForVfScaling\n constraints:\n - equal: measurementsForVfScaling\n metricsPerEventName:\n type: list\n required: true\n description: Contains eventName and threshold details that need to\n be applied to given eventName\n entry_schema:\n type: onap.datatypes.monitoring.metricsPerEventName\n onap.datatypes.monitoring.thresholds:\n derived_from: tosca.datatypes.Root\n properties:\n closedLoopControlName:\n type: string\n required: true\n description: Closed Loop Control Name associated with the threshold\n closedLoopEventStatus:\n type: string\n required: true\n description: Closed Loop Event Status of the threshold\n constraints:\n - valid_values:\n - ONSET\n - ABATED\n direction:\n type: string\n required: true\n description: Direction of the threshold\n constraints:\n - valid_values:\n - LESS\n - LESS_OR_EQUAL\n - GREATER\n - GREATER_OR_EQUAL\n - EQUAL\n fieldPath:\n type: string\n required: true\n description: Json field Path as per CEF message which needs to be\n analyzed for TCA\n constraints:\n - valid_values:\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage\n - $.event.measurementsForVfScalingFields.meanRequestLatency\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed\n - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\n severity:\n type: string\n required: true\n description: Threshold Event Severity\n constraints:\n - valid_values:\n - CRITICAL\n - MAJOR\n - MINOR\n - WARNING\n - NORMAL\n thresholdValue:\n type: integer\n required: true\n description: Threshold value for the field Path inside CEF message\n version:\n type: string\n required: true\n description: Version number associated with the threshold\n','{\n \"supportedPdpGroups\": [\n {\n \"monitoring\": [\n \"xacml\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.monitoring.tcagen2','1.0.0','Not found','2021-03-05 17:10:19.809945','Not found','2021-03-05 17:10:27.477416','tcagen2','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.Monitoring:\n derived_from: tosca.policies.Root\n version: 1.0.0\n name: onap.policies.Monitoring\n description: a base policy type for all policies that govern monitoring provisioning\n onap.policies.monitoring.tcagen2:\n derived_from: onap.policies.Monitoring\n version: 1.0.0\n name: onap.policies.monitoring.tcagen2\n properties:\n tca.policy:\n type: onap.datatypes.monitoring.tca_policy\n description: TCA Policy JSON\n required: true\ndata_types:\n onap.datatypes.monitoring.metricsPerEventName:\n derived_from: tosca.datatypes.Root\n properties:\n controlLoopSchemaType:\n type: string\n required: true\n description: Specifies Control Loop Schema Type for the event Name\n e.g. VNF, VM\n constraints:\n - valid_values:\n - VM\n - VNF\n eventName:\n type: string\n required: true\n description: Event name to which thresholds need to be applied\n policyName:\n type: string\n required: true\n description: TCA Policy Scope Name\n policyScope:\n type: string\n required: true\n description: TCA Policy Scope\n policyVersion:\n type: string\n required: true\n description: TCA Policy Scope Version\n thresholds:\n type: list\n required: true\n description: Thresholds associated with eventName\n entry_schema:\n type: onap.datatypes.monitoring.thresholds\n onap.datatypes.monitoring.tca_policy:\n derived_from: tosca.datatypes.Root\n properties:\n domain:\n type: string\n required: true\n description: Domain name to which TCA needs to be applied\n default: measurementsForVfScaling\n constraints:\n - equal: measurementsForVfScaling\n metricsPerEventName:\n type: list\n required: true\n description: Contains eventName and threshold details that need to\n be applied to given eventName\n entry_schema:\n type: onap.datatypes.monitoring.metricsPerEventName\n onap.datatypes.monitoring.thresholds:\n derived_from: tosca.datatypes.Root\n properties:\n closedLoopControlName:\n type: string\n required: true\n description: Closed Loop Control Name associated with the threshold\n closedLoopEventStatus:\n type: string\n required: true\n description: Closed Loop Event Status of the threshold\n constraints:\n - valid_values:\n - ONSET\n - ABATED\n direction:\n type: string\n required: true\n description: Direction of the threshold\n constraints:\n - valid_values:\n - LESS\n - LESS_OR_EQUAL\n - GREATER\n - GREATER_OR_EQUAL\n - EQUAL\n fieldPath:\n type: string\n required: true\n description: Json field Path as per CEF message which needs to be\n analyzed for TCA\n constraints:\n - valid_values:\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated\n - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait\n - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage\n - $.event.measurementsForVfScalingFields.meanRequestLatency\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree\n - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed\n - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value\n severity:\n type: string\n required: true\n description: Threshold Event Severity\n constraints:\n - valid_values:\n - CRITICAL\n - MAJOR\n - MINOR\n - WARNING\n - NORMAL\n thresholdValue:\n type: integer\n required: true\n description: Threshold value for the field Path inside CEF message\n version:\n type: string\n required: true\n description: Version number associated with the threshold\n','{\n \"supportedPdpGroups\": [\n {\n \"monitoring\": [\n \"xacml\"\n ]\n }\n ]\n}');
+INSERT INTO `policy_models` (`policy_model_type`, `version`, `created_by`, `created_timestamp`, `updated_by`, `updated_timestamp`, `policy_acronym`, `policy_tosca`, `policy_pdp_group`) VALUES ('onap.policies.Naming','1.0.0','Not found','2021-03-05 17:10:27.355402','Not found','2021-03-05 17:10:27.477691','Naming','tosca_definitions_version: tosca_simple_yaml_1_1_0\npolicy_types:\n onap.policies.Naming:\n derived_from: tosca.policies.Root\n version: 1.0.0\n name: onap.policies.Naming\n description: Virtual policy node for naming\n properties:\n policy-instance-name:\n type: string\n naming-models:\n type: list\n entry_schema:\n type: policy.data.naming-model-entity\ndata_types:\n policy.data.naming-model-entity:\n derived_from: tosca.datatypes.Root\n properties:\n nfRole:\n type: string\n required: false\n metadata:\n matchable: true\n naming-type:\n type: string\n required: true\n metadata:\n matchable: true\n naming-recipe:\n type: string\n required: true\n name-operation:\n type: string\n required: false\n naming-properties:\n type: list\n required: true\n entry_schema:\n type: policy.data.naming-property\n policy.data.naming-property:\n derived_from: tosca.datatypes.Root\n properties:\n property-name:\n type: string\n required: true\n metadata:\n matchable: true\n property-value:\n type: string\n required: false\n property-operation:\n type: string\n required: false\n source-system:\n type: string\n required: false\n source-endpoint:\n type: string\n required: false\n increment-sequence:\n type: policy.data.increment-sequence\n required: false\n policy.data.increment-sequence:\n derived_from: tosca.datatypes.Root\n properties:\n scope:\n type: list\n required: true\n entry_schema:\n type: string\n constraints:\n - valid_values:\n - CLOUD_REGION_ID\n - LOCATION_CLLI\n - VNF\n - VM\n - VFMODULE\n - PRECEEDING\n - TRAILING\n - ENTIRETY\n sequence-type:\n type: string\n require: true\n entry_schema:\n type: string\n constraints:\n - valid_values:\n - numeric\n - alpha-numeric\n start-value:\n type: string\n required: true\n max:\n type: string\n required: false\n increment:\n type: string\n required: true\n length:\n type: string\n required: true\n','{\n \"supportedPdpGroups\": [\n {\n \"monitoring\": [\n \"xacml\"\n ]\n }\n ]\n}');
+/*!40000 ALTER TABLE `policy_models` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Dumping data for table `services`
+--
+
+LOCK TABLES `services` WRITE;
+/*!40000 ALTER TABLE `services` DISABLE KEYS */;
+INSERT INTO `services` (`service_uuid`, `name`, `resource_details`, `service_details`, `version`) VALUES ('63cac700-ab9a-4115-a74f-7eac85e3fce0','vLoadBalancerMS','{\n \"CP\": {},\n \"VL\": {},\n \"VF\": {\n \"vLoadBalancerMS 0\": {\n \"resourceVendor\": \"Test\",\n \"name\": \"vLoadBalancerMS\",\n \"resourceVendorModelNumber\": \"\",\n \"description\": \"vLBMS\",\n \"invariantUUID\": \"1a31b9f2-e50d-43b7-89b3-a040250cf506\",\n \"UUID\": \"b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6\",\n \"type\": \"VF\",\n \"category\": \"Application L4+\",\n \"subcategory\": \"Load Balancer\",\n \"version\": \"1.0\",\n \"customizationUUID\": \"465246dc-7748-45f4-a013-308d92922552\",\n \"resourceVendorRelease\": \"1.0\",\n \"controllerProperties\": {\n \"sdnc_model_name\": \"baseconfiguration\",\n \"sdnc_model_version\": \"1.0.0\",\n \"workflows\": {\n \"resource-assignment\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n },\n \"activate\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n },\n \"activate-restconf\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n },\n \"activate-cli\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n },\n \"assign-activate\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n },\n \"imperative-test-wf\": {\n \"inputs\": {\n \"resource-assignment-properties\": {\n \"type\": \"object\",\n \"properties\": {\n \"request-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"service-instance-id\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"hostname\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"request-info\": {\n \"type\": \"object\",\n \"properties\": {\n \"prop1\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n },\n \"prop2\": {\n \"required\": true,\n \"type\": \"string\",\n \"input-param\": true\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n },\n \"CR\": {},\n \"VFC\": {},\n \"PNF\": {},\n \"Service\": {},\n \"CVFC\": {},\n \"Service Proxy\": {},\n \"Configuration\": {},\n \"AllottedResource\": {},\n \"VFModule\": {\n \"Vloadbalancerms..vpkg..module-1\": {\n \"vfModuleModelInvariantUUID\": \"ca052563-eb92-4b5b-ad41-9111768ce043\",\n \"vfModuleModelVersion\": \"1\",\n \"vfModuleModelName\": \"Vloadbalancerms..vpkg..module-1\",\n \"vfModuleModelUUID\": \"1e725ccc-b823-4f67-82b9-4f4367070dbc\",\n \"vfModuleModelCustomizationUUID\": \"1bffdc31-a37d-4dee-b65c-dde623a76e52\",\n \"min_vf_module_instances\": 0,\n \"vf_module_label\": \"vpkg\",\n \"max_vf_module_instances\": 1,\n \"vf_module_type\": \"Expansion\",\n \"isBase\": false,\n \"initial_count\": 0,\n \"volume_group\": false\n },\n \"Vloadbalancerms..vdns..module-3\": {\n \"vfModuleModelInvariantUUID\": \"4c10ba9b-f88f-415e-9de3-5d33336047fa\",\n \"vfModuleModelVersion\": \"1\",\n \"vfModuleModelName\": \"Vloadbalancerms..vdns..module-3\",\n \"vfModuleModelUUID\": \"4fa73b49-8a6c-493e-816b-eb401567b720\",\n \"vfModuleModelCustomizationUUID\": \"bafcdab0-801d-4d81-9ead-f464640a38b1\",\n \"min_vf_module_instances\": 0,\n \"vf_module_label\": \"vdns\",\n \"max_vf_module_instances\": 50,\n \"vf_module_type\": \"Expansion\",\n \"isBase\": false,\n \"initial_count\": 0,\n \"volume_group\": false\n },\n \"Vloadbalancerms..base_template..module-0\": {\n \"vfModuleModelInvariantUUID\": \"921f7c96-ebdd-42e6-81b9-1cfc0c9796f3\",\n \"vfModuleModelVersion\": \"1\",\n \"vfModuleModelName\": \"Vloadbalancerms..base_template..module-0\",\n \"vfModuleModelUUID\": \"63734409-f745-4e4d-a38b-131638a0edce\",\n \"vfModuleModelCustomizationUUID\": \"86baddea-c730-4fb8-9410-cd2e17fd7f27\",\n \"min_vf_module_instances\": 1,\n \"vf_module_label\": \"base_template\",\n \"max_vf_module_instances\": 1,\n \"vf_module_type\": \"Base\",\n \"isBase\": true,\n \"initial_count\": 1,\n \"volume_group\": false\n },\n \"Vloadbalancerms..vlb..module-2\": {\n \"vfModuleModelInvariantUUID\": \"a772a1f4-0064-412c-833d-4749b15828dd\",\n \"vfModuleModelVersion\": \"1\",\n \"vfModuleModelName\": \"Vloadbalancerms..vlb..module-2\",\n \"vfModuleModelUUID\": \"0f5c3f6a-650a-4303-abb6-fff3e573a07a\",\n \"vfModuleModelCustomizationUUID\": \"96a78aad-4ffb-4ef0-9c4f-deb03bf1d806\",\n \"min_vf_module_instances\": 0,\n \"vf_module_label\": \"vlb\",\n \"max_vf_module_instances\": 1,\n \"vf_module_type\": \"Expansion\",\n \"isBase\": false,\n \"initial_count\": 0,\n \"volume_group\": false\n }\n }\n}','{\n \"serviceType\": \"\",\n \"serviceRole\": \"\",\n \"description\": \"vLBMS\",\n \"type\": \"Service\",\n \"instantiationType\": \"A-la-carte\",\n \"namingPolicy\": \"\",\n \"serviceEcompNaming\": \"true\",\n \"environmentContext\": \"General_Revenue-Bearing\",\n \"name\": \"vLoadBalancerMS\",\n \"invariantUUID\": \"30ec5b59-4799-48d8-ac5f-1058a6b0e48f\",\n \"ecompGeneratedNaming\": \"true\",\n \"UUID\": \"63cac700-ab9a-4115-a74f-7eac85e3fce0\",\n \"category\": \"Network L4+\"\n}','1.0');
+/*!40000 ALTER TABLE `services` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2021-03-05 16:11:22
diff --git a/runtime/pom.xml b/runtime/pom.xml
new file mode 100644
index 000000000..66d555ac7
--- /dev/null
+++ b/runtime/pom.xml
@@ -0,0 +1,1250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ============LICENSE_START=======================================================
+ ONAP POLICY-CLAMP
+ ================================================================================
+ Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
+ Modifications 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============================================
+ ===================================================================
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.policy.clamp</groupId>
+ <artifactId>policy-clamp</artifactId>
+ <version>6.1.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>policy-clamp-runtime</artifactId>
+ <name>${project.artifactId}</name>
+
+ <description>
+ This is the MAVEN project that builds everything for ONAP POLICY-CLAMP.
+ Docker engine is normally required to perfom all possible tasks (including integration tests)
+
+ It can build:
+ - The ONAP POLICY-CLAMP JAR that contains CLAMP back-end code.
+ - The DOCKER images for:
+ * POLICY-CLAMP backend (Java Spring)
+ * POLICY-CLAMP frontend (Javascript React)
+
+ It can test:
+ - The POLICY-CLAMP backend, JAVA unit testing
+ - The POLICY-CLAMP backend, JAVA integration tests (with Spring + docker mariadb database + docker policy/dcae
+ emulator written in python)
+ - The POLICY-CLAMP frontend, Javascript tests (NodeJS(NPM) + JEST and Enzyme for React)
+
+ The test coverage for dev's can be found after a "clean install" build in:
+ - Clamp backend: target/jacoco-dev.exec (unit tests + integration tests merged)
+ or separately target/coverage-reports/jacoco.exec and target/coverage-reports/jacoco-it.exec
+ - Clamp frontend: target/ui-react/coverage
+
+ Useful mvn commands:
+ - mvn clean install: Build Clamp backend JAR + unit tests + integration tests + NPM tests (+coverage for all)
+ - mvn clean install -DskipITs=true: Build Clamp backend JAR + unit tests + NPM tests (+coverage for all), it
+ does not require a DOCKER engine
+ - mvn clean install -DskipTests -P docker: Build Clamp backend JAR + all docker images
+
+ To start POLICY-CLAMP (Build it before):
+ - Use docker-compose file in ./extra/docker/clamp/docker-compose.yml
+ - Use the script located in ./extra/bin/start-backend.sh + start-frontend.sh
+ - Use your IDE to use the Jar or start NVM/NPM
+
+ </description>
+
+ <properties>
+ <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+ <clamp.project.version>${project.version}</clamp.project.version>
+ <clamp.build.timestamp>${maven.build.timestamp}</clamp.build.timestamp>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+ <eelf.core.version>1.0.0</eelf.core.version>
+ <camel.version>3.7.3</camel.version>
+ <springboot.version>2.4.4</springboot.version>
+
+ <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
+ <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath>
+ <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/jacoco-html-xml-reports/jacoco.xml
+ </sonar.coverage.jacoco.xmlReportPaths>
+ <sonar.projectVersion>${project.version}</sonar.projectVersion>
+ <sonar.log.level>DEBUG</sonar.log.level>
+ <sonar.nodejs.executable>${project.build.directory}/${ui.react.src}/node/node</sonar.nodejs.executable>
+ <sonar.verbose>true</sonar.verbose>
+ <sonar.sources>src/main,${project.build.directory}/${ui.react.src}/src</sonar.sources>
+ <sonar.exclusions>src/main/resources/**</sonar.exclusions>
+ <sonar.scm.exclusions.disabled>true</sonar.scm.exclusions.disabled>
+ <sonar.javascript.lcov.reportPaths>${project.build.directory}/${ui.react.src}/coverage/lcov.info
+ </sonar.javascript.lcov.reportPaths>
+ <sonar.coverage.exclusions>
+ src/main/resources/**,target/ui-react/src/**/*.test.js,target/ui-react/src/setupTests.js
+ </sonar.coverage.exclusions>
+ <docker.push.registry>localhost:5000</docker.push.registry>
+ <docker.pull.registry>nexus3.onap.org:10001</docker.pull.registry>
+ <docker.skip.build>true</docker.skip.build>
+ <docker.skip.push>true</docker.skip.push>
+ <docker.skip.tag>true</docker.skip.tag>
+ <skip.staging.artifacts>false</skip.staging.artifacts>
+ <python.http.proxy.param/>
+ <tomcat.version>9.0.45</tomcat.version>
+ <ui.react.src>ui-react</ui.react.src>
+ <ui.react.lib.src>ui-react-lib</ui.react.lib.src>
+ <npm.publish.url>https://nexus3.onap.org/repository/npm.snapshot/</npm.publish.url>
+ </properties>
+
+ <profiles>
+ <!-- BEGIN: NOT USABLE profiles, those are defined when specific flags are enabled -->
+ <profile>
+ <id>without-test</id>
+ <activation>
+ <property>
+ <name>maven.test.skip</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <properties>
+ <docker.skip.run>true</docker.skip.run>
+ <docker.skip>true</docker.skip>
+ </properties>
+ </profile>
+ <profile>
+ <id>without-IT-only</id>
+ <activation>
+ <property>
+ <name>skipITs</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <properties>
+ <docker.skip.run>true</docker.skip.run>
+ <docker.skip>true</docker.skip>
+ </properties>
+ </profile>
+ <profile>
+ <id>without-IT-only2</id>
+ <activation>
+ <property>
+ <name>skipTests</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <properties>
+ <docker.skip.run>true</docker.skip.run>
+ <docker.skip>true</docker.skip>
+ </properties>
+ </profile>
+ <!-- END: NOT USABLE profiles, those are defined when specific flags are enabled -->
+ <profile>
+ <id>docker</id>
+ <properties>
+ <skip.staging.artifacts>true</skip.staging.artifacts>
+ <docker.skip.build>false</docker.skip.build>
+ <docker.skip.tag>false</docker.skip.tag>
+ <docker.skip.push>false</docker.skip.push>
+ <docker.skip>false</docker.skip>
+ </properties>
+ </profile>
+ </profiles>
+
+ <dependencyManagement>
+ <dependencies>
+ <!-- Spring Boot BOM -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>${springboot.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <!-- Camel BOM -->
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-spring-boot-bom</artifactId>
+ <version>${camel.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.att.eelf</groupId>
+ <artifactId>eelf-core</artifactId>
+ <version>${eelf.core.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.janino</groupId>
+ <artifactId>janino</artifactId>
+ <version>3.0.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-core</artifactId>
+ <version>${tomcat.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-el</artifactId>
+ <version>${tomcat.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-websocket</artifactId>
+ <version>${tomcat.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat-annotations-api</artifactId>
+ <version>${tomcat.version}</version>
+ </dependency>
+ <!-- For CAMEL -->
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-http-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-spring-boot-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-jaxb-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-servlet-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-gson-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-swagger-java-starter</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-ext</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <!-- Spring famework -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-json</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-tomcat</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.glassfish</groupId>
+ <artifactId>jakarta.el</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-autoconfigure</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>com.vaadin.external.google</groupId>
+ <artifactId>android-json</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ </dependency>
+ <!-- Policy dependencies mainly for the models required -->
+ <dependency>
+ <groupId>org.onap.policy.models</groupId>
+ <artifactId>policy-models-pdp</artifactId>
+ <version>${policy.models.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-reflect</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib-common</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Others dependencies -->
+ <!-- Jaxws is required for AAF -->
+ <dependency>
+ <groupId>javax.xml.ws</groupId>
+ <artifactId>jaxws-api</artifactId>
+ <version>2.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.aaf.authz</groupId>
+ <artifactId>aaf-cadi-aaf</artifactId>
+ <version>2.1.15</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.googlecode.json-simple</groupId>
+ <artifactId>json-simple</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-vfs2</artifactId>
+ <version>2.8.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>com.squareup.okhttp</groupId>
+ <artifactId>okhttp</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <!-- Other dependencies to fix nexus IQ reported vulnerabilities -->
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.15</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ <version>3.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.ws.rs</groupId>
+ <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+ <version>1.0.1.Final</version>
+ </dependency>
+
+
+ <!-- Remove the MYSQL connector and replace it by Mariadb -->
+ <dependency>
+ <groupId>org.mariadb.jdbc</groupId>
+ <artifactId>mariadb-java-client</artifactId>
+ <version>2.7.2</version>
+ </dependency>
+ <!-- For SDC Controller -->
+ <dependency>
+ <groupId>org.onap.sdc.sdc-distribution-client</groupId>
+ <artifactId>sdc-distribution-client</artifactId>
+ <version>1.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.sdc.sdc-tosca</groupId>
+ <artifactId>sdc-tosca</artifactId>
+ <version>1.5.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.yaml</groupId>
+ <artifactId>snakeyaml</artifactId>
+ <version>1.28</version>
+ </dependency>
+ <dependency>
+ <groupId>org.dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>2.1.3</version>
+ </dependency>
+
+ <!-- TESTING -->
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ <version>5.7.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.10.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.github.docker-java</groupId>
+ <artifactId>docker-java-core</artifactId>
+ <version>3.2.7</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.github.docker-java</groupId>
+ <artifactId>docker-java</artifactId>
+ <version>3.2.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>utils-test</artifactId>
+ <version>${policy.common.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>policy-clamp-backend</finalName>
+
+ <testResources>
+ <testResource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>clds/aaf/**</exclude>
+ </excludes>
+ </testResource>
+ <testResource>
+ <directory>src/main/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>clds/aaf/**</include>
+ </includes>
+ </testResource>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <excludes>
+ <exclude>**/*.jks</exclude>
+ <exclude>**/*.csar</exclude>
+ </excludes>
+ <filtering>true</filtering>
+ </testResource>
+ <testResource>
+ <directory>src/test/resources/https</directory>
+ <includes>
+ <include>**.jks</include>
+ </includes>
+ <filtering>false</filtering>
+ <targetPath>https</targetPath>
+ </testResource>
+ <testResource>
+ <directory>src/test/resources/example/sdc</directory>
+ <includes>
+ <include>**.csar</include>
+ </includes>
+ <filtering>false</filtering>
+ <targetPath>example/sdc</targetPath>
+ </testResource>
+ </testResources>
+ <resources>
+ <!-- For AAF folder maven should not try to filter Keystores/Truststores ... Otherwise
+ they will be broken and unreadable -->
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>clds/aaf/**</exclude>
+ </excludes>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>clds/aaf/**</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${ui.react.src}</directory>
+ <excludes>
+ <exclude>node_modules</exclude>
+ </excludes>
+ <includes>
+ <include>src/**</include>
+ <include>public/**</include>
+ <include>package.json</include>
+ <include>package-lock.json</include>
+ </includes>
+ <filtering>true</filtering>
+ <targetPath>${project.build.directory}/${ui.react.src}</targetPath>
+ </resource>
+ <resource>
+ <directory>${ui.react.src}</directory>
+ <includes>
+ <include>src/**</include>
+ </includes>
+ <excludes>
+ <exclude>**/__snapshots__/**</exclude>
+ <exclude>**/**.test.js</exclude>
+ </excludes>
+ <filtering>true</filtering>
+ <targetPath>${project.build.directory}/${ui.react.lib.src}</targetPath>
+ </resource>
+ <resource>
+ <directory>${ui.react.lib.src}</directory>
+ <includes>
+ <include>**</include>
+ </includes>
+ <excludes>
+ <exclude>node_modules/**</exclude>
+ <exclude>package-lock.json</exclude>
+ </excludes>
+ <filtering>true</filtering>
+ <targetPath>${project.build.directory}/${ui.react.lib.src}</targetPath>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>de.jpdigital</groupId>
+ <artifactId>hibernate52-ddl-maven-plugin</artifactId>
+ <version>2.2.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.3.0</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>gen-ddl</goal>
+ </goals>
+ <configuration>
+ <packages>
+ <param>org.onap.policy.clamp</param>
+ </packages>
+ <dialects>
+ <param>MARIADB53</param>
+ </dialects>
+ <outputDirectory>${project.basedir}/extra/sql/bulkload/</outputDirectory>
+ <outputFileNameSuffix>create-tables</outputFileNameSuffix>
+ <!-- <createDropStatements>true</createDropStatements> -->
+ <omitDialectFromFileName>true</omitDialectFromFileName>
+ </configuration>
+ </execution>
+ </executions>
+
+ </plugin>
+ <!-- Read the swagger.json file and the definition from SwaggerConfig.java; generate
+ a list of .adoc files containing the APIs info in more structured way -->
+ <plugin>
+ <groupId>io.github.swagger2markup</groupId>
+ <artifactId>swagger2markup-maven-plugin</artifactId>
+ <version>1.3.3</version>
+ <dependencies>
+ <dependency>
+ <groupId>io.github.swagger2markup</groupId>
+ <artifactId>swagger2markup-import-files-ext</artifactId>
+ <version>1.3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>io.github.swagger2markup</groupId>
+ <artifactId>swagger2markup-spring-restdocs-ext</artifactId>
+ <version>1.3.3</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <swaggerInput>${project.basedir}/docs/swagger/swagger.json</swaggerInput>
+ <outputDir>${project.build.directory}/asciidoc/generated</outputDir>
+ <config>
+ <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
+ </config>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>convertSwagger2markup</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Run the generated asciidoc through Asciidoctor to generate other documentation
+ types, such as PDFs or HTML5 -->
+ <plugin>
+ <groupId>org.asciidoctor</groupId>
+ <artifactId>asciidoctor-maven-plugin</artifactId>
+ <version>1.5.7.1</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.asciidoctor</groupId>
+ <artifactId>asciidoctorj-pdf</artifactId>
+ <version>1.5.0-alpha.10.1</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <sourceDirectory>${project.basedir}/src/main/resources/asciidoc</sourceDirectory>
+ <sourceDocumentName>swagger.adoc</sourceDocumentName>
+ <attributes>
+ <doctype>book</doctype>
+ <toc>left</toc>
+ <toclevels>3</toclevels>
+ <numbered/>
+ <hardbreaks/>
+ <sectlinks/>
+ <sectanchors/>
+ <generated>${project.build.directory}/asciidoc/generated</generated>
+ </attributes>
+ </configuration>
+
+ <executions>
+ <execution>
+ <id>output-html</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>process-asciidoc</goal>
+ </goals>
+ <configuration>
+ <backend>html5</backend>
+ <outputDirectory>${project.basedir}/docs/swagger</outputDirectory>
+ <outputDirectory>${project.basedir}/src/main/resources/META-INF/resources/</outputDirectory>
+ </configuration>
+ </execution>
+ <execution>
+ <id>output-pdf</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>process-asciidoc</goal>
+ </goals>
+ <configuration>
+ <backend>pdf</backend>
+ <outputDirectory>${project.basedir}/docs/swagger</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.groovy.maven</groupId>
+ <artifactId>gmaven-plugin</artifactId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <id>docker-tags</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>${project.basedir}/src/main/script/TagVersion.groovy</source>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm-repos-selection</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>${project.basedir}/src/main/script/SelectNpmRepo.groovy</source>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.2.0</version>
+ <executions>
+ <execution>
+ <id>jar-with-only-classes</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <classifier>classes</classifier>
+ <includes>
+ <include>org/**</include>
+ </includes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>3.2.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/policy-clamp-backend-classes.jar</file>
+ <type>jar</type>
+ <classifier>classes</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ <execution>
+ <id>reserve-port-for-tests</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>reserve-network-port</goal>
+ </goals>
+ <configuration>
+ <portNames>
+ <portName>docker.mariadb.port.host</portName>
+ <portName>docker.http-cache.port.host</portName>
+ <portName>clamp.it.tests.http-redirected</portName>
+ <portName>clamp.it.tests.robotframework.http</portName>
+ <portName>clamp.it.tests.https</portName>
+ <portName>clamp.it.tests.http</portName>
+ </portNames>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${springboot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.2</version>
+ <configuration>
+ <forkCount>1C</forkCount>
+ <reuseForks>true</reuseForks>
+ <useSystemClassLoader>false</useSystemClassLoader>
+ <argLine>${surefireArgLine}</argLine>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.22.2</version>
+ <executions>
+ <execution>
+ <id>integration-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <additionalClasspathElements>
+ <additionalClasspathElement>${project.build.directory}/classes
+ </additionalClasspathElement>
+ </additionalClasspathElements>
+ <includes>
+ <include>**/*ItCase.java</include>
+ </includes>
+ <forkCount>1C</forkCount>
+ <reuseForks>true</reuseForks>
+ <useSystemClassLoader>false</useSystemClassLoader>
+ <argLine>${failsafeArgLine}</argLine>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <version>0.35.0</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5.5</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <verbose>true</verbose>
+ <apiVersion>1.35</apiVersion>
+ <images>
+ <image>
+ <name>docker.io/mariadb:10.5.4</name>
+ <alias>mariadb</alias>
+ <run>
+ <env>
+ <MYSQL_ROOT_PASSWORD>strong_pitchou</MYSQL_ROOT_PASSWORD>
+ </env>
+ <hostname>mariadb</hostname>
+ <volumes>
+ <bind>
+ <volume>${project.basedir}/extra/sql/:/docker-entrypoint-initdb.d:rw</volume>
+ <volume>${project.basedir}/extra/docker/mariadb/conf1:/etc/mysql/conf.d</volume>
+ </bind>
+ </volumes>
+ <wait>
+ <log>port: 3306</log>
+ <time>300000</time>
+ <exec>
+ <preStop>/docker-entrypoint-initdb.d/dump/backup-data-only.sh</preStop>
+ </exec>
+ </wait>
+ <ports>
+ <port>${docker.mariadb.port.host}:3306</port>
+ </ports>
+ <network>
+ <mode>bridge</mode>
+ </network>
+ </run>
+ </image>
+ <image>
+ <name>docker.io/python:2-slim</name>
+ <alias>python</alias>
+ <run>
+ <hostname>python</hostname>
+ <volumes>
+ <bind>
+ <volume>
+ ${project.basedir}/src/test/resources/http-cache/:/usr/src/http-cache-app
+ </volume>
+ <volume>
+ ${project.basedir}/src/test/resources/http-cache/example/:/usr/src/http-cache-app/data-cache
+ </volume>
+ </bind>
+ </volumes>
+ <wait>
+ <tcp>
+ <ports>
+ <port>8080</port>
+ </ports>
+ <mode>direct</mode>
+ </tcp>
+ <time>120000</time>
+ </wait>
+ <ports>
+ <port>${docker.http-cache.port.host}:8080</port>
+ </ports>
+ <workingDir>/usr/src/http-cache-app</workingDir>
+ <cmd>
+ <shell>./start_http_cache.sh ${python.http.proxy.param}
+ --python_proxyaddress=localhost:${docker.http-cache.port.host}
+ </shell>
+ </cmd>
+ <network>
+ <mode>bridge</mode>
+ </network>
+ </run>
+ </image>
+ <image>
+ <name>onap/policy-clamp-backend</name>
+ <alias>onap-policy-clamp-backend</alias>
+ <run>
+ <skip>true</skip>
+ </run>
+ <build>
+ <cleanup>true</cleanup>
+ <tags>
+ <tag>latest</tag>
+ <tag>${project.docker.latesttagtimestamp.version}</tag>
+ <tag>${project.docker.latesttag.version}</tag>
+ </tags>
+ <!-- A relative path is looked up in ${project.basedir}/src/main/docker by
+ default -->
+ <dockerFile>backend/Dockerfile</dockerFile>
+ <assembly>
+ <descriptor>backend/backend-files.xml</descriptor>
+ <name>onap-policy-clamp-backend</name>
+ </assembly>
+ </build>
+ </image>
+ <image>
+ <name>onap/policy-clamp-frontend</name>
+ <alias>onap-policy-clamp-frontend</alias>
+ <run>
+ <skip>true</skip>
+ </run>
+ <build>
+ <cleanup>true</cleanup>
+ <tags>
+ <tag>latest</tag>
+ <tag>${project.docker.latesttagtimestamp.version}</tag>
+ <tag>${project.docker.latesttag.version}</tag>
+ </tags>
+ <!-- A relative path is looked up in ${project.basedir}/src/main/docker by
+ default -->
+ <dockerFile>frontend/Dockerfile</dockerFile>
+ <assembly>
+ <descriptor>frontend/frontend-files.xml</descriptor>
+ <name>onap-policy-clamp-frontend</name>
+ </assembly>
+ </build>
+ </image>
+ </images>
+ </configuration>
+
+ <executions>
+ <execution>
+ <id>generate-images</id>
+ <phase>install</phase>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>push-images</id>
+ <phase>deploy</phase>
+ <goals>
+ <goal>push</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>docker-start-for-it</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>start</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>docker-stop-for-it</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.8.5</version>
+ <configuration>
+ <dumpOnExit>true</dumpOnExit>
+ <append>true</append>
+ <includes>
+ <include>org/onap/policy/clamp/**</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <id>pre-unit-test</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ <configuration>
+ <destFile>${project.build.directory}/coverage-reports/jacoco.exec</destFile>
+ <propertyName>surefireArgLine</propertyName>
+ <!-- <append>true</append> -->
+ </configuration>
+ </execution>
+ <execution>
+ <id>pre-integration-test</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ <configuration>
+ <destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
+ <propertyName>failsafeArgLine</propertyName>
+ <!-- <append>true</append> -->
+ <!-- Need to overwrite the policy integration parent flag -->
+ <skip>false</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <goals>
+ <goal>merge</goal>
+ </goals>
+ <phase>post-integration-test</phase>
+ <configuration>
+ <fileSets>
+ <fileSet
+ implementation="org.apache.maven.shared.model.fileset.FileSet">
+ <directory>${project.build.directory}/coverage-reports</directory>
+ <includes>
+ <include>*.exec</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ <destFile>${project.build.directory}/jacoco.exec</destFile>
+ </configuration>
+ </execution>
+ <execution>
+ <id>report-xml</id>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ <configuration>
+ <!-- Setting explicit path, so that we remember where it picks them up from -->
+ <dataFile>${project.build.directory}/jacoco.exec</dataFile>
+ <outputDirectory>${project.build.directory}/jacoco-html-xml-reports</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- This plugin will be useful when we will have multi-modules project -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>versions-maven-plugin</artifactId>
+ <version>1.3.1</version>
+ </plugin>
+
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.11.3</version>
+ <configuration>
+ <installDirectory>${project.build.directory}/${ui.react.src}</installDirectory>
+ <npmDownloadRoot>${repo.npm}</npmDownloadRoot>
+ </configuration>
+ <executions>
+ <execution>
+ <id>install_node_and_npm</id>
+ <goals>
+ <goal>install-node-and-npm</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <nodeVersion>v14.16.1</nodeVersion>
+ <npmVersion>6.14.13</npmVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm_install</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <workingDirectory>${project.build.directory}/${ui.react.src}</workingDirectory>
+ <arguments>install</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm_test</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>test</phase>
+ <configuration>
+ <skip>${maven.test.skip}</skip>
+ <arguments>run-script test:coverage</arguments>
+ <workingDirectory>${project.build.directory}/${ui.react.src}</workingDirectory>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm_install_lib</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>deploy</phase>
+ <configuration>
+ <workingDirectory>${project.build.directory}/${ui.react.lib.src}</workingDirectory>
+ <arguments>install</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm_build_lib</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>deploy</phase>
+ <configuration>
+ <workingDirectory>${project.build.directory}/${ui.react.lib.src}</workingDirectory>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>npm_publish</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <phase>deploy</phase>
+ <configuration>
+ <workingDirectory>${project.build.directory}/${ui.react.lib.src}</workingDirectory>
+ <arguments>publish</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <source>11</source>
+ <target>11</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.sonarsource.scanner.maven</groupId>
+ <artifactId>sonar-maven-plugin</artifactId>
+ <version>3.7.0.1746</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.3.2</version>
+ <executions>
+ <execution>
+ <id>libIndexCheck</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <executable>bash</executable>
+ <arguments>
+ <argument>${project.basedir}/src/main/script/checkLibIndex.sh</argument>
+ </arguments>
+ </configuration>
+ </plugin>
+ <!-- Plugin to generate a X509 Certificate for https tests -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>keytool-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>add-certificate-for-dev</id>
+ <configuration>
+ <keystore>${project.build.directory}/classes/clds/aaf/org.onap.clamp.p12</keystore>
+ <storepass>China in the Spring</storepass>
+ <alias>clamptest</alias>
+ <storetype>PKCS12</storetype>
+ <keyalg>RSA</keyalg>
+ <dname>cn=CN, ou=OU, o=O, c=C</dname>
+ <validity>365</validity>
+ </configuration>
+ <goals>
+ <goal>generateKeyPair</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ </execution>
+ <execution>
+ <id>add-certificate-for-test</id>
+ <configuration>
+ <keystore>${project.build.directory}/test-classes/clds/aaf/org.onap.clamp.p12</keystore>
+ <storepass>China in the Spring</storepass>
+ <alias>clamptest</alias>
+ <storetype>PKCS12</storetype>
+ <keyalg>RSA</keyalg>
+ <dname>cn=CN, ou=OU, o=O, c=C</dname>
+ <validity>365</validity>
+ </configuration>
+ <goals>
+ <goal>generateKeyPair</goal>
+ </goals>
+ <phase>generate-test-resources</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/runtime/runtime/src/main/resources/META-INF/resources/swagger.html b/runtime/runtime/src/main/resources/META-INF/resources/swagger.html
new file mode 100644
index 000000000..b6f49a78f
--- /dev/null
+++ b/runtime/runtime/src/main/resources/META-INF/resources/swagger.html
@@ -0,0 +1,454 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.7.1">
+<title>Untitled</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
+<style>
+/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
+/* Uncomment @import statement below to use as custom stylesheet */
+/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
+audio,canvas,video{display:inline-block}
+audio:not([controls]){display:none;height:0}
+script{display:none!important}
+html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
+a{background:transparent}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+dfn{font-style:italic}
+hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.center{margin-left:auto;margin-right:auto}
+.stretch{width:100%}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:none}
+p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
+ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
+ul.square{list-style-type:square}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
+abbr{text-transform:none}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
+blockquote cite::before{content:"\2014 \0020"}
+blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
+table thead,table tfoot{background:#f7f8f7}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
+.clearfix::after,.float-group::after{clear:both}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
+pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menuref{color:#000}
+.menuseq b:not(.caret),.menuref{font-weight:inherit}
+.menuseq{word-spacing:-.02em}
+.menuseq b.caret{font-size:1.25em;line-height:.8}
+.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
+b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
+b.button::before{content:"[";padding:0 3px 0 2px}
+b.button::after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
+#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
+#content{margin-top:1.25em}
+#content::before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
+#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span::before{content:"\00a0\2013\00a0"}
+#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark::before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber::after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+@media screen and (min-width:768px){#toctitle{font-size:1.375em}
+body.toc2{padding-left:15em;padding-right:0}
+#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
+@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{width:20em}
+#toc.toc2 #toctitle{font-size:1.375em}
+#toc.toc2>ul{font-size:.95em}
+#toc.toc2 ul ul{padding-left:1.25em}
+body.toc2.toc-right{padding-left:0;padding-right:20em}}
+#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+#content #toc>:first-child{margin-top:0}
+#content #toc>:last-child{margin-bottom:0}
+#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
+#content{margin-bottom:.625em}
+.sect1{padding-bottom:.625em}
+@media screen and (min-width:768px){#content{margin-bottom:1.25em}
+.sect1{padding-bottom:1.25em}}
+.sect1:last-child{padding-bottom:0}
+.sect1+.sect1{border-top:1px solid #efefed}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
+.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
+table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
+.exampleblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child{margin-bottom:0}
+.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+.sidebarblock>:first-child{margin-top:0}
+.sidebarblock>:last-child{margin-bottom:0}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
+.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
+.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
+@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
+@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
+.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
+.listingblock:hover code[data-lang]::before{display:block}
+.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
+.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
+table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
+table.pyhltable td.code{padding-left:.75em;padding-right:0}
+pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
+pre.pygments .lineno{display:inline-block;margin-right:.25em}
+table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
+.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
+.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
+.quoteblock .quoteblock blockquote::before{display:none}
+.verseblock{margin:0 1em 1.25em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract{margin:0 1em 1.25em;display:block}
+.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
+.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{word-spacing:0;line-height:1.6}
+.quoteblock.abstract blockquote::before,.quoteblock.abstract p::before{display:none}
+table.tableblock{max-width:100%;border-collapse:separate}
+p.tableblock:last-child{margin-bottom:0}
+td.tableblock>.content{margin-bottom:-1.25em}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
+table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
+table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
+table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
+table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
+table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
+table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
+table.frame-all{border-width:1px}
+table.frame-sides{border-width:0 1px}
+table.frame-topbot,table.frame-ends{border-width:1px 0}
+table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
+table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+td>div.verse{white-space:pre}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
+ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
+ul.unstyled,ol.unstyled{margin-left:0}
+ul.checklist{margin-left:.625em}
+ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
+ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
+ul.inline>li{margin-left:1.25em}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
+.colist td:not([class]):first-child img{max-width:none}
+.colist td:not([class]):last-child{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
+.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
+.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
+.gist .file-data>table td.line-data{width:99%}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background-color:#00fafa}
+.black{color:#000}
+.black-background{background-color:#000}
+.blue{color:#0000bf}
+.blue-background{background-color:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background-color:#fa00fa}
+.gray{color:#606060}
+.gray-background{background-color:#7d7d7d}
+.green{color:#006000}
+.green-background{background-color:#007d00}
+.lime{color:#00bf00}
+.lime-background{background-color:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background-color:#7d0000}
+.navy{color:#000060}
+.navy-background{background-color:#00007d}
+.olive{color:#606000}
+.olive-background{background-color:#7d7d00}
+.purple{color:#600060}
+.purple-background{background-color:#7d007d}
+.red{color:#bf0000}
+.red-background{background-color:#fa0000}
+.silver{color:#909090}
+.silver-background{background-color:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background-color:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background-color:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background-color:#fafa00}
+span.icon>.fa{cursor:default}
+a span.icon>.fa{cursor:inherit}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]::after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
+.print-only{display:none!important}
+@page{margin:1.25cm .75cm}
+@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
+html{font-size:80%}
+a{color:inherit!important;text-decoration:underline!important}
+a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
+a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
+abbr[title]::after{content:" (" attr(title) ")"}
+pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
+thead{display:table-header-group}
+svg{max-width:100%}
+p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
+h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
+#toc,.sidebarblock,.exampleblock>.content{background:none!important}
+#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
+body.book #header{text-align:center}
+body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
+body.book #header .details{border:0!important;display:block;padding:0!important}
+body.book #header .details span:first-child{margin-left:0!important}
+body.book #header .details br{display:block}
+body.book #header .details br+span::before{content:none!important}
+body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
+body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
+.listingblock code[data-lang]::before{display:block}
+#footer{padding:0 .9375em}
+.hide-on-print{display:none!important}
+.print-only{display:block!important}
+.hide-for-print{display:none!important}
+.show-for-print{display:inherit!important}}
+@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
+.sect1{padding:0!important}
+.sect1+.sect1{border:0}
+#footer{background:none}
+#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
+@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
+</style>
+</head>
+<body class="book">
+<div id="header">
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>Unresolved directive in swagger.adoc - include::~\clamp\runtime\target/asciidoc/generated/overview.adoc[]<br>
+Unresolved directive in swagger.adoc - include::~\clamp\runtime\target/asciidoc/generated/paths.adoc[]<br>
+Unresolved directive in swagger.adoc - include::~\clamp\runtime\target/asciidoc/generated/security.adoc[]<br>
+Unresolved directive in swagger.adoc - include::~\clamp\runtime\target/asciidoc/generated/definitions.adoc[]</p>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2021-05-06 17:18:25 BST
+</div>
+</div>
+</body>
+</html>
diff --git a/runtime/src/main/docker/backend/Dockerfile b/runtime/src/main/docker/backend/Dockerfile
new file mode 100644
index 000000000..bb964158e
--- /dev/null
+++ b/runtime/src/main/docker/backend/Dockerfile
@@ -0,0 +1,53 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2018, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+FROM onap/integration-java11:8.0.0
+
+MAINTAINER "The Onap Team"
+LABEL Description="This image contains alpine, openjdk 11 and policy clamp"
+
+ARG http_proxy
+ARG https_proxy
+ENV HTTP_PROXY=$http_proxy
+ENV HTTPS_PROXY=$https_proxy
+ENV http_proxy=$HTTP_PROXY
+ENV https_proxy=$HTTPS_PROXY
+
+USER root
+
+RUN mkdir -p /opt/policy/clamp && \
+ chown -R onap:onap /opt/policy/clamp
+
+VOLUME /opt/policy/clamp/config
+
+COPY --chown=onap:onap onap-policy-clamp-backend/policy-clamp-backend.jar /opt/policy/clamp/policy-clamp-backend.jar
+RUN set -x && \
+ apk add --update libintl && \
+ apk add --virtual build_deps gettext && \
+ cp /usr/bin/envsubst /usr/local/bin/envsubst && \
+ apk del build_deps
+
+USER onap
+WORKDIR /opt/policy/clamp/
+ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-XX:MinRAMPercentage=50.0", "-XX:MaxRAMPercentage=75.0","-jar" ,"./policy-clamp-backend.jar"]
+
diff --git a/runtime/src/main/docker/backend/backend-files.xml b/runtime/src/main/docker/backend/backend-files.xml
new file mode 100644
index 000000000..c73c47f64
--- /dev/null
+++ b/runtime/src/main/docker/backend/backend-files.xml
@@ -0,0 +1,43 @@
+<!--
+ ============LICENSE_START=======================================================
+ ECOMP CLAMP
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property. 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=========================================================
+ -->
+
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+ <id>clamp-files</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <!-- include config files -->
+ <fileSet>
+ <includes>
+ <include>${project.build.finalName}.jar</include>
+ </includes>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/runtime/src/main/docker/frontend/Dockerfile b/runtime/src/main/docker/frontend/Dockerfile
new file mode 100644
index 000000000..1d64d2a2d
--- /dev/null
+++ b/runtime/src/main/docker/frontend/Dockerfile
@@ -0,0 +1,71 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+# build environment
+FROM node:12.10.0-alpine as build
+WORKDIR /app
+#ENV PATH /app/node_modules/.bin:$PATH
+COPY onap-policy-clamp-frontend/ /app/
+RUN npm install --silent && \
+ npm run build
+
+FROM nginx:1.17.0-alpine
+
+MAINTAINER "The Onap Team"
+LABEL Description="This image contains Clamp frontend"
+
+ARG http_proxy
+ARG https_proxy
+ENV HTTP_PROXY=$http_proxy
+ENV HTTPS_PROXY=$https_proxy
+ENV http_proxy=$HTTP_PROXY
+ENV https_proxy=$HTTPS_PROXY
+
+RUN addgroup onap && \
+ adduser -D -G onap clamp && \
+ mkdir /var/log/onap && \
+ chmod a+rwx /var/log/onap
+
+COPY --from=build /app/build /usr/share/nginx/html
+COPY --from=build /app/ssl /etc/ssl
+
+RUN rm /etc/nginx/conf.d/default.conf && \
+ ln -sf /dev/stdout /var/log/nginx/access.log && \
+ ln -sf /dev/stderr /var/log/nginx/error.log
+
+COPY nginx/nginx.conf /etc/nginx/nginx.conf
+COPY nginx/default.conf /etc/nginx/conf.d/default.conf
+
+WORKDIR /app
+
+RUN chown -R clamp:onap /app && chmod -R 755 /app && \
+ chown -R clamp:onap /var/cache/nginx && \
+ chown -R clamp:onap /var/log/nginx && \
+ chown -R clamp:onap /etc/nginx/conf.d && \
+ touch /var/run/nginx.pid && \
+ chown -R clamp:onap /var/run/nginx.pid
+
+USER clamp
+EXPOSE 2443
+CMD ["nginx", "-g", "daemon off;"]
+
diff --git a/runtime/src/main/docker/frontend/frontend-files.xml b/runtime/src/main/docker/frontend/frontend-files.xml
new file mode 100644
index 000000000..aaf32be81
--- /dev/null
+++ b/runtime/src/main/docker/frontend/frontend-files.xml
@@ -0,0 +1,48 @@
+<!--
+ ============LICENSE_START=======================================================
+ ECOMP CLAMP
+ ================================================================================
+ Copyright (C) 2019 AT&T Intellectual Property. 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=========================================================
+ -->
+
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+ <id>clamp-files</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <!-- include config files -->
+ <fileSet>
+ <excludes>
+ <exclude>node_modules</exclude>
+ </excludes>
+ <directory>${project.build.directory}/${ui.react.src}</directory>
+ <outputDirectory></outputDirectory>
+ </fileSet>
+ <!-- include ssl certificates files obtain from aaf p12 -->
+ <fileSet>
+ <directory>${project.basedir}/src/main/resources/clds/aaf/ssl</directory>
+ <outputDirectory>ssl</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+</assembly>
diff --git a/runtime/src/main/docker/frontend/nginx/default.conf b/runtime/src/main/docker/frontend/nginx/default.conf
new file mode 100644
index 000000000..570806034
--- /dev/null
+++ b/runtime/src/main/docker/frontend/nginx/default.conf
@@ -0,0 +1,25 @@
+server {
+
+ listen 2443 default ssl;
+ ssl_protocols TLSv1.2;
+ ssl_certificate /etc/ssl/clamp.pem;
+ ssl_certificate_key /etc/ssl/clamp.key;
+ ssl_verify_client optional_no_ca;
+ location /restservices/clds/ {
+ proxy_pass https://policy-clamp-backend:8443;
+ proxy_set_header X-SSL-Cert $ssl_client_escaped_cert;
+ }
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ try_files $uri $uri/ /index.html;
+ }
+
+ error_page 500 502 503 504 /50x.html;
+
+ location = /50x.html {
+ root /usr/share/nginx/html;
+ }
+
+} \ No newline at end of file
diff --git a/runtime/src/main/docker/frontend/nginx/nginx.conf b/runtime/src/main/docker/frontend/nginx/nginx.conf
new file mode 100644
index 000000000..beeb2b1eb
--- /dev/null
+++ b/runtime/src/main/docker/frontend/nginx/nginx.conf
@@ -0,0 +1,18 @@
+worker_processes 1;
+pid /var/run/nginx.pid;
+error_log /dev/stdout info;
+events {
+}
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+ access_log /var/log/nginx/access.log main;
+ sendfile on;
+ #tcp_nopush on;
+ keepalive_timeout 65;
+ #gzip on;
+ include /etc/nginx/conf.d/*.conf;
+ } \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java
new file mode 100644
index 000000000..89be4fc28
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/AuthorizationController.java
@@ -0,0 +1,182 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.authorization;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.Date;
+import org.apache.camel.Exchange;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.exception.NotAuthorizedException;
+import org.onap.policy.clamp.clds.model.ClampInformation;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+/**
+ * Verify user has right permissions.
+ */
+@Component
+public class AuthorizationController {
+
+ protected static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(AuthorizationController.class);
+ protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ protected static final EELFLogger securityLogger = EELFManager.getInstance().getSecurityLogger();
+
+ // By default we'll set it to a default handler
+ @Autowired
+ private ClampProperties refProp;
+
+ public static final String PERM_PREFIX = "security.permission.type.";
+ private static final String PERM_INSTANCE = "security.permission.instance";
+
+ private static String retrieveUserName(SecurityContext securityContext) {
+ if (securityContext == null || securityContext.getAuthentication() == null) {
+ return null;
+ }
+ if ((securityContext.getAuthentication().getPrincipal()) instanceof String) {
+ // anonymous case
+ return ((String) securityContext.getAuthentication().getPrincipal());
+ } else {
+ return ((UserDetails) securityContext.getAuthentication().getPrincipal()).getUsername();
+ }
+ }
+
+ /**
+ * Get the principal name.
+ *
+ * @return The principal name
+ */
+ public static String getPrincipalName(SecurityContext securityContext) {
+ String principal = AuthorizationController.retrieveUserName(securityContext);
+ return principal != null ? principal : "Not found";
+ }
+
+ /**
+ * Insert authorize the api based on the permission.
+ *
+ * @param camelExchange The Camel Exchange object containing the properties
+ * @param typeVar The type of the permissions
+ * @param instanceVar The instance of the permissions. e.g. dev
+ * @param action The action of the permissions. e.g. read
+ */
+ public void authorize(Exchange camelExchange, String typeVar, String instanceVar,
+ String action) {
+ String type = refProp.getStringValue(PERM_PREFIX + typeVar);
+ String instance = refProp.getStringValue(PERM_INSTANCE);
+
+ if (null == type || type.isEmpty()) {
+ // authorization is turned off, since the permission is not defined
+ return;
+ }
+ if (null != instanceVar && !instanceVar.isEmpty()) {
+ instance = instanceVar;
+ }
+ String principalName = AuthorizationController.getPrincipalName(SecurityContextHolder.getContext());
+ SecureServicePermission perm = SecureServicePermission.create(type, instance, action);
+ Date startTime = new Date();
+ LoggingUtils.setTargetContext("Clamp", "authorize");
+ LoggingUtils.setTimeContext(startTime, new Date());
+ securityLogger.debug("checking if {} has permission: {}", principalName, perm);
+
+ if (!isUserPermitted(perm)) {
+ String msg = principalName + " does not have permission: " + perm;
+ LoggingUtils.setErrorContext("100", "Authorization Error");
+ securityLogger.warn(msg);
+ throw new NotAuthorizedException(msg);
+ }
+ }
+
+ /**
+ * Insert authorize the api based on the permission.
+ *
+ * @param inPermission Security permission in input
+ * @return True if user is permitted
+ */
+ public boolean isUserPermitted(SecureServicePermission inPermission) {
+
+ String principalName = AuthorizationController.getPrincipalName(SecurityContextHolder.getContext());
+ // check if the user has the permission key or the permission key with a
+ // combination of all instance and/or all action.
+ if (hasRole(inPermission.getKey()) || hasRole(inPermission.getKeyAllInstance())) {
+ auditLogger.info("{} authorized because user has permission with * for instance: {}",
+ principalName, inPermission.getKey().replace("|", ":"));
+ return true;
+ // the rest of these don't seem to be required - isUserInRole method
+ // appears to take * as a wildcard
+ } else if (hasRole(inPermission.getKeyAllInstanceAction())) {
+ auditLogger.info(
+ "{} authorized because user has permission with * for instance and * for action: {}",
+ principalName, inPermission.getKey().replace("|", ":"));
+ return true;
+ } else if (hasRole(inPermission.getKeyAllAction())) {
+ auditLogger.info("{} authorized because user has permission with * for action: {}",
+ principalName, inPermission.getKey().replace("|", ":"));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected boolean hasRole(String role) {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return false;
+ }
+ for (GrantedAuthority auth : authentication.getAuthorities()) {
+ if (role.equals(auth.getAuthority())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets clds info. CLDS IFO service will return 3 things 1. User Name 2. CLDS
+ * code version that is currently installed from pom.xml file 3. User
+ * permissions
+ *
+ * @return the clds info
+ */
+ public ClampInformation getClampInformation() {
+ ClampInformation clampInfo = new ClampInformation();
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ return new ClampInformation();
+ }
+ clampInfo.setUserName(AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()));
+ for (GrantedAuthority auth : authentication.getAuthorities()) {
+ clampInfo.getAllPermissions().add(auth.getAuthority());
+ }
+ return clampInfo;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java
new file mode 100644
index 000000000..8f1e2bf67
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/CldsUser.java
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.authorization;
+
+import java.util.Arrays;
+
+/**
+ * The class represents the CldsUser that can be extracted from cldsusers.json.
+ */
+public class CldsUser {
+
+ private String user;
+ private String password;
+ private SecureServicePermission[] permissions;
+
+ /**
+ * Returns the user.
+ *
+ * @return the user
+ */
+ public String getUser() {
+ return user;
+ }
+
+ /**
+ * Sets the user.
+ *
+ * @param user
+ * the user to set
+ */
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ /**
+ * Returns the password.
+ *
+ * @return the password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password.
+ *
+ * @param password
+ * the password to set
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Returns the permissions.
+ *
+ * @return the permissions
+ */
+ public SecureServicePermission[] getPermissions() {
+ return Arrays.copyOf(permissions, permissions.length);
+ }
+
+ public String[] getPermissionsString() {
+ return Arrays.stream(getPermissions()).map(SecureServicePermission::getKey).toArray(String[]::new);
+ }
+
+ /**
+ * Sets the permissions.
+ *
+ * @param permissionsArray
+ * the permissions to set
+ */
+ public void setPermissions(SecureServicePermission[] permissionsArray) {
+ this.permissions = Arrays.copyOf(permissionsArray, permissionsArray.length);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java
new file mode 100644
index 000000000..41887a315
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermission.java
@@ -0,0 +1,203 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.authorization;
+
+/**
+ * Permission class that can be instantiated easily using constructor or factory
+ * methods.
+ */
+public class SecureServicePermission {
+ public static final String ALL = "*";
+
+ private String type;
+ private String instance;
+ private String action;
+
+ /**
+ * Factory method to create permission given type, instance, and action.
+ *
+ * @param type type of the permission
+ * @param instance instance of the permission
+ * @param action action of the permission
+ * @return instance of SecureServicePermission with type, instance and action
+ */
+ public static SecureServicePermission create(String type, String instance, String action) {
+ return new SecureServicePermission(type, instance, action);
+ }
+
+ /**
+ * Factory method to create permission given type and instance. Default
+ * action to ALL/*.
+ *
+ * @param type type of the permission
+ * @param instance instance of the permission
+ * @return instance of SecureServicePermission with type, instance and default action
+ */
+ public static SecureServicePermission create(String type, String instance) {
+ return new SecureServicePermission(type, instance, ALL);
+ }
+
+ /**
+ * Factory method to create permission given type. Default instance and
+ * action to ALL/*.
+ *
+ * @param type type of the permission
+ * @return instance of SecureServicePermission with type and default instance and action
+ */
+ public static SecureServicePermission create(String type) {
+ return new SecureServicePermission(type, ALL, ALL);
+ }
+
+ /**
+ * Instantiate permission given type, instance, and action.
+ *
+ * @param type type of the permission
+ * @param instance instance of the permission
+ * @param action action of the permission
+ */
+ public SecureServicePermission(String type, String instance, String action) {
+ this.type = type;
+ this.instance = instance;
+ this.action = action;
+ }
+
+ /**
+ * Instantiate permission given type from concatenated string.
+ *
+ * @param concatenatedString
+ * the string type|instance|action, less than 3 params can be
+ * provided (e.g. "permission-type-cl", "permission-type-cl|dev",
+ * "permission-type-cl|dev|update" )
+ */
+ public SecureServicePermission(String concatenatedString) {
+ String[] userInfo = concatenatedString.split("[|]");
+ // We should have at least 1 string
+ this.type = userInfo[0];
+ this.instance = (userInfo.length > 1 ? userInfo[1] : ALL);
+ this.action = (userInfo.length > 2 ? userInfo[2] : ALL);
+ }
+
+ /**
+ * Override toString - return permission in key format.
+ */
+ @Override
+ public String toString() {
+ return getKey();
+ }
+
+ /**
+ * Return Permission in Key format = type, instance, and action separate by
+ * pipe character.
+ *
+ * @return permission in key format
+ */
+ public String getKey() {
+ return type + "|" + instance + "|" + action;
+ }
+
+ /**
+ * Return Permission in Key format = type, all instance, and action separate
+ * by pipe character.
+ *
+ * @return permission in key format
+ */
+ public String getKeyAllInstance() {
+ return type + "|" + ALL + "|" + action;
+ }
+
+ /**
+ * Return Permission in Key format = type, all instance, and all action
+ * separate by pipe character.
+ *
+ * @return permission in key format
+ */
+ public String getKeyAllInstanceAction() {
+ return type + "|" + ALL + "|" + ALL;
+ }
+
+ /**
+ * Return Permission in Key format = type, instance, and all action separate
+ * by pipe character.
+ *
+ * @return permission in key format
+ */
+ public String getKeyAllAction() {
+ return type + "|" + instance + "|" + ALL;
+ }
+
+ /**
+ * Returns the permission type.
+ *
+ * @return the type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the type of permission.
+ *
+ * @param type the type to set
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns the instance of permission.
+ *
+ * @return the instance
+ */
+ public String getInstance() {
+ return instance;
+ }
+
+ /**
+ * Sets the instance of permission.
+ *
+ * @param instance the instance to set
+ */
+ public void setInstance(String instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * Returns the action of permission.
+ *
+ * @return the action
+ */
+ public String getAction() {
+ return action;
+ }
+
+ /**
+ * Sets the action of permission.
+ *
+ * @param action the action to set
+ */
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java
new file mode 100644
index 000000000..0b178c256
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/SecureServicePermissionDeserializer.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.authorization;
+
+
+import com.google.gson.Gson;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import java.lang.reflect.Type;
+
+public class SecureServicePermissionDeserializer implements JsonDeserializer<SecureServicePermission> {
+
+ @Override
+ public SecureServicePermission deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ if (json.isJsonPrimitive()) {
+ return new SecureServicePermission(json.getAsString());
+ } else {
+ // if not string try default deserialization
+ return new Gson().fromJson(json, SecureServicePermission.class);
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java b/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java
new file mode 100644
index 000000000..96347f82f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/authorization/UserService.java
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.authorization;
+
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Controller;
+
+/**
+ * User service used for authorization verification at the login page. Do not
+ * remove this class.
+ */
+@Controller
+public class UserService {
+
+ /**
+ * REST service that returns the username.
+ *
+ * @return the user name
+ */
+ public String getUser() {
+ return AuthorizationController.getPrincipalName(SecurityContextHolder.getContext());
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java b/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java
new file mode 100644
index 000000000..ba300ac09
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/Application.java
@@ -0,0 +1,195 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import org.apache.camel.component.servlet.springboot.ServletMappingAutoConfiguration;
+import org.apache.catalina.connector.Connector;
+import org.onap.policy.clamp.clds.util.ClampVersioning;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.util.PassDecoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@ComponentScan(basePackages = {"org.onap.policy.clamp"})
+@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class,
+ ServletMappingAutoConfiguration.class})
+@EnableJpaRepositories(basePackages = {"org.onap.policy.clamp"})
+@EntityScan(basePackages = {"org.onap.policy.clamp"})
+@EnableTransactionManagement
+@EnableConfigurationProperties
+@EnableAsync
+@EnableScheduling
+@EnableJpaAuditing
+public class Application extends SpringBootServletInitializer {
+
+ protected static final EELFLogger eelfLogger = EELFManager.getInstance().getLogger(Application.class);
+ // This settings is an additional one to Spring config,
+ // only if we want to have an additional port automatically redirected to
+ // HTTPS
+ @Value("${server.http-to-https-redirection.port:#{null}}")
+ private String httpRedirectedPort;
+ /**
+ * This 8080 is the default port used by spring if this parameter is not
+ * specified in application.properties.
+ */
+ @Value("${server.port:8080}")
+ private String springServerPort;
+
+ @Value("${server.ssl.key-store:#{null}}")
+ private String keystoreFile;
+
+ @Value("${server.ssl.key-store-password:#{null}}")
+ private String keyStorePass;
+
+ @Value("${server.ssl.key-store-type:JKS}")
+ private String keyStoreType;
+
+
+ @Value("${clamp.config.keyFile:classpath:/clds/aaf/org.onap.clamp.keyfile}")
+ private String keyFile;
+
+ @Autowired
+ private Environment env;
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(Application.class);
+ }
+
+ /**
+ * Main method that starts the Clamp backend.
+ *
+ * @param args app params
+ */
+ public static void main(String[] args) {
+ // Start the Spring application
+ SpringApplication.run(Application.class, args);
+ }
+
+ /**
+ * This method is used to declare the camel servlet.
+ *
+ * @return A servlet bean
+ * @throws IOException IO Exception
+ */
+ @Bean
+ public ServletRegistrationBean camelServletRegistrationBean() throws IOException {
+ eelfLogger.info(ResourceFileUtils.getResourceAsString("boot-message.txt") + "(v"
+ + ClampVersioning.getCldsVersionFromProps() + ")" + System.getProperty("line.separator")
+ + getSslExpirationDate());
+ ServletRegistrationBean registration = new ServletRegistrationBean(new ClampServlet(), "/restservices/clds/*");
+ registration.setName("CamelServlet");
+ return registration;
+ }
+
+ /**
+ * This method is used by Spring to create the servlet container factory.
+ *
+ * @return The TomcatEmbeddedServletContainerFactory just created
+ */
+ @Bean
+ public ServletWebServerFactory getEmbeddedServletContainerFactory() {
+ TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
+ if (httpRedirectedPort != null && keystoreFile != null) {
+ // Automatically redirect to HTTPS
+ tomcat = new TomcatEmbeddedServletContainerFactoryRedirection();
+ Connector newConnector = createRedirectConnector(Integer.parseInt(springServerPort));
+ if (newConnector != null) {
+ tomcat.addAdditionalTomcatConnectors(newConnector);
+ }
+ }
+ return tomcat;
+ }
+
+ private Connector createRedirectConnector(int redirectSecuredPort) {
+ if (redirectSecuredPort <= 0) {
+ eelfLogger.warn("HTTP port redirection to HTTPS is disabled because the HTTPS port is 0 (random port) or -1"
+ + " (Connector disabled)");
+ return null;
+ }
+ Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
+ connector.setScheme("http");
+ connector.setSecure(false);
+ connector.setPort(Integer.parseInt(httpRedirectedPort));
+ connector.setRedirectPort(redirectSecuredPort);
+ return connector;
+ }
+
+ private String getSslExpirationDate() throws IOException {
+ StringBuilder result = new StringBuilder(" :: SSL Certificates :: ");
+ try {
+ if (keystoreFile != null) {
+ KeyStore keystore = KeyStore.getInstance(keyStoreType);
+ keystore.load(ResourceFileUtils.getResourceAsStream(keystoreFile.replace("classpath:", "")),
+ PassDecoder.decode(keyStorePass, keyFile).toCharArray());
+
+ Enumeration<String> aliases = keystore.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ if ("X.509".equals(keystore.getCertificate(alias).getType())) {
+ result.append("* " + alias + " expires "
+ + ((X509Certificate) keystore.getCertificate(alias)).getNotAfter()
+ + System.getProperty("line.separator"));
+ }
+ }
+ } else {
+ result.append("* NONE HAS been configured");
+ }
+ } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) {
+ eelfLogger.warn("SSL certificate access error ", e);
+
+ }
+ return result.toString();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java
new file mode 100644
index 000000000..939cea49c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampInUserAuditorAware.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds;
+
+import java.util.Optional;
+import org.onap.policy.clamp.authorization.AuthorizationController;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ClampInUserAuditorAware implements AuditorAware<String> {
+
+ @Override
+ public Optional<String> getCurrentAuditor() {
+ return Optional.of(AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()));
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java
new file mode 100644
index 000000000..ccde7cf11
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/ClampServlet.java
@@ -0,0 +1,160 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.camel.component.servlet.CamelHttpTransportServlet;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.policy.clamp.authorization.SecureServicePermission;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+public class ClampServlet extends CamelHttpTransportServlet {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = -4198841134910211542L;
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampServlet.class);
+ private static final String PERM_INSTANCE = "clamp.config.security.permission.instance";
+ private static final String PERM_CL = "clamp.config.security.permission.type.cl";
+ private static final String PERM_TEMPLATE = "clamp.config.security.permission.type.template";
+ private static final String PERM_VF = "clamp.config.security.permission.type.filter.vf";
+ private static final String PERM_MANAGE = "clamp.config.security.permission.type.cl.manage";
+ private static final String PERM_TOSCA = "clamp.config.security.permission.type.tosca";
+ private static final String PERM_POLICIES = "clamp.config.security.permission.type.policies";
+ private static final String AUTHENTICATION_CLASS = "clamp.config.security.authentication.class";
+ private static final String READ = "read";
+ private static final String UPDATE = "update";
+
+ private static List<SecureServicePermission> permissionList;
+
+ private synchronized List<String> loadDynamicAuthenticationClasses() {
+ WebApplicationContext webAppContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+ if (webAppContext != null) {
+ String authClassProperty = webAppContext.getEnvironment().getProperty(AUTHENTICATION_CLASS);
+ if (!StringUtils.isBlank(authClassProperty)) {
+ return Arrays.stream(authClassProperty.split(",")).map(String::trim)
+ .collect(Collectors.toList());
+ }
+ logger.warn(
+ "No authentication classes defined in Clamp BE config " + AUTHENTICATION_CLASS
+ + " AAF authentication could be broken due to that");
+ } else {
+ logger.error(
+ "WebApplicationContext is NULL, no authentication classes will be loaded in clamp BE"
+ + ", AAF authentication could be broken");
+ }
+ return Collections.emptyList();
+ }
+
+ private synchronized List<SecureServicePermission> getPermissionList() {
+ if (permissionList == null) {
+ permissionList = new ArrayList<>();
+ ApplicationContext applicationContext = WebApplicationContextUtils
+ .getWebApplicationContext(getServletContext());
+ String cldsPermissionInstance = applicationContext.getEnvironment().getProperty(PERM_INSTANCE);
+ permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL),
+ cldsPermissionInstance, READ));
+ permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL),
+ cldsPermissionInstance, UPDATE));
+ permissionList.add(SecureServicePermission.create(
+ applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, READ));
+ permissionList.add(SecureServicePermission.create(
+ applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, UPDATE));
+ permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_VF),
+ cldsPermissionInstance, "*"));
+ permissionList.add(SecureServicePermission
+ .create(applicationContext.getEnvironment().getProperty(PERM_MANAGE), cldsPermissionInstance, "*"));
+ permissionList.add(SecureServicePermission
+ .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), cldsPermissionInstance, READ));
+ permissionList.add(SecureServicePermission
+ .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), cldsPermissionInstance,
+ UPDATE));
+ permissionList.add(SecureServicePermission
+ .create(applicationContext.getEnvironment().getProperty(PERM_POLICIES), cldsPermissionInstance,
+ READ));
+ permissionList.add(SecureServicePermission
+ .create(applicationContext.getEnvironment().getProperty(PERM_POLICIES), cldsPermissionInstance,
+ UPDATE));
+ }
+ return permissionList;
+ }
+
+ /**
+ * When AAF is enabled, request object will contain a cadi Wrapper, so queries
+ * to isUserInRole will invoke a http call to AAF server.
+ */
+ @Override
+ protected void doService(HttpServletRequest request, HttpServletResponse response) {
+ Principal principal = request.getUserPrincipal();
+ if (principal != null && loadDynamicAuthenticationClasses().stream()
+ .anyMatch(className -> className.equals(principal.getClass().getName()))) {
+ // When AAF is enabled, there is a need to provision the permissions to Spring
+ // system
+ List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ for (SecureServicePermission perm : getPermissionList()) {
+ String permString = perm.toString();
+ if (request.isUserInRole(permString)) {
+ grantedAuths.add(new SimpleGrantedAuthority(permString));
+ }
+ }
+ Authentication auth = new UsernamePasswordAuthenticationToken(new User(principal.getName(), "",
+ grantedAuths), "", grantedAuths);
+ SecurityContextHolder.getContext().setAuthentication(auth);
+ }
+ try {
+ super.doService(request, response);
+ } catch (ServletException | IOException ioe) {
+ logger.error("Exception caught when executing doService in servlet", ioe);
+ try {
+ response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value());
+ } catch (IOException e) {
+ logger.error("Exception caught when executing HTTP sendError in servlet", e);
+ }
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java b/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java
new file mode 100644
index 000000000..f66a09c41
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds;
+
+import org.apache.catalina.Context;
+import org.apache.tomcat.util.descriptor.web.SecurityCollection;
+import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+
+/**
+ * This class is a factory that redirects by default all HTTP to HTTPS
+ * connector. It is used by the Application.java class and defined in a Spring
+ * Bean.
+ * In order to do this, the method postProcessContext has been overridden to
+ * provide another behavior.
+ */
+public class TomcatEmbeddedServletContainerFactoryRedirection extends TomcatServletWebServerFactory {
+
+ /**
+ * This method is there to force the automatic redirection of all calls done
+ * on the tomcat server to a Secure connection.
+ */
+ @Override
+ protected void postProcessContext(Context context) {
+ SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setUserConstraint("CONFIDENTIAL");
+ SecurityCollection collection = new SecurityCollection();
+ collection.addPattern("/*");
+ securityConstraint.addCollection(collection);
+ context.addConstraint(securityConstraint);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java b/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java
new file mode 100644
index 000000000..cb74ad9e4
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/client/CdsServices.java
@@ -0,0 +1,229 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ * ================================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.client;
+
+import static java.lang.Boolean.parseBoolean;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.onap.policy.clamp.clds.exception.cds.CdsParametersException;
+import org.onap.policy.clamp.clds.model.cds.CdsBpWorkFlowListResponse;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class implements the communication with CDS for the service inventory.
+ */
+@Component
+public class CdsServices {
+
+ @Autowired
+ CamelContext camelContext;
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsServices.class);
+
+ private static final String TYPE = "type";
+ private static final String PROPERTIES = "properties";
+ private static final String LIST = "list";
+
+ /**
+ * Query CDS to get blueprint's workflow list.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param blueprintVersion CDS blueprint version
+ * @return CdsBpWorkFlowListResponse CDS blueprint's workflow list
+ */
+ public CdsBpWorkFlowListResponse getBlueprintWorkflowList(String blueprintName, String blueprintVersion) {
+ LoggingUtils.setTargetContext("CDS", "getBlueprintWorkflowList");
+
+ try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) {
+ Exchange exchangeResponse =
+ producerTemplate.send("direct:get-blueprint-workflow-list", ExchangeBuilder.anExchange(camelContext)
+ .withProperty("blueprintName", blueprintName)
+ .withProperty("blueprintVersion", blueprintVersion)
+ .withProperty("raiseHttpExceptionFlag", false).build());
+
+ if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE))
+ .is2xxSuccessful()) {
+ String cdsResponse = (String) exchangeResponse.getIn().getBody();
+ logger.info("getBlueprintWorkflowList, response from CDS:" + cdsResponse);
+ LoggingUtils.setResponseContext("0", "Get Blueprint workflow list", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return JsonUtils.GSON_JPA_MODEL.fromJson(cdsResponse, CdsBpWorkFlowListResponse.class);
+ } else {
+ logger.error("CDS getBlueprintWorkflowList FAILED");
+ }
+ } catch (IOException e) {
+ logger.error("IOException caught when trying to execute get-blueprint-workflow-list flow", e);
+ }
+ return null;
+ }
+
+ /**
+ * Query CDS to get input properties of workflow.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param blueprintVersion CDS blueprint name
+ * @param workflow CDS blueprint's workflow
+ * @return input properties in json format
+ */
+ public JsonObject getWorkflowInputProperties(String blueprintName, String blueprintVersion,
+ String workflow) {
+ LoggingUtils.setTargetContext("CDS", "getWorkflowInputProperties");
+
+ try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) {
+ Exchange exchangeResponse = producerTemplate
+ .send("direct:get-blueprint-workflow-input-properties", ExchangeBuilder.anExchange(camelContext)
+ .withBody(getCdsPayloadForWorkFlow(blueprintName, blueprintVersion, workflow))
+ .withProperty("raiseHttpExceptionFlag", false).build());
+ if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE))
+ .is2xxSuccessful()) {
+ String cdsResponse = (String) exchangeResponse.getIn().getBody();
+ logger.info("getWorkflowInputProperties, response from CDS:" + cdsResponse);
+ LoggingUtils
+ .setResponseContext("0", "Get Blueprint workflow input properties", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return parseCdsResponse(cdsResponse);
+ } else {
+ logger.error("CDS getWorkflowInputProperties FAILED");
+ }
+ } catch (IOException e) {
+ logger.error("IOException caught when trying to execute get-blueprint-workflow-input-properties flow", e);
+ }
+ return null;
+ }
+
+ protected JsonObject parseCdsResponse(String response) {
+ JsonObject root = JsonParser.parseString(response).getAsJsonObject();
+ JsonObject inputs = root.getAsJsonObject("workFlowData").getAsJsonObject("inputs");
+ JsonObject dataTypes = root.getAsJsonObject("dataTypes");
+
+ JsonObject workFlowProperties = new JsonObject();
+ workFlowProperties.add("inputs", getInputProperties(inputs, dataTypes, new JsonObject()));
+ return workFlowProperties;
+ }
+
+ private JsonObject getInputProperties(JsonObject inputs, JsonObject dataTypes, JsonObject inputObject) {
+ if (inputs == null) {
+ return inputObject;
+ }
+
+ for (Map.Entry<String, JsonElement> entry : inputs.entrySet()) {
+ String key = entry.getKey();
+ JsonObject inputProperty = inputs.getAsJsonObject(key);
+ String type = inputProperty.get(TYPE).getAsString();
+ if (isComplexType(type, dataTypes)) {
+ inputObject.add(key, handleComplexType(type, dataTypes));
+ } else if (LIST.equalsIgnoreCase(type)) {
+ handleListType(key, inputProperty, dataTypes, inputObject);
+ } else if (isInputParam(inputProperty)) {
+ inputObject.add(key, entry.getValue());
+ }
+ }
+ return inputObject;
+ }
+
+ private void handleListType(String propertyName,
+ JsonObject inputProperty,
+ JsonObject dataTypes,
+ JsonObject inputObject) {
+ if (inputProperty.get("entry_schema") == null) {
+ throw new CdsParametersException("Entry schema is null for " + propertyName);
+ }
+
+ String type = inputProperty.get("entry_schema").getAsJsonObject().get(
+ TYPE).getAsString();
+ if (dataTypes != null && dataTypes.get(type) != null) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(TYPE, LIST);
+ jsonObject.add(PROPERTIES, getPropertiesObject(type, dataTypes));
+ inputObject.add(propertyName, jsonObject);
+ } else if (isInputParam(inputProperty)) {
+ inputObject.add(propertyName, inputProperty);
+ }
+ }
+
+ private JsonObject handleComplexType(String key, JsonObject dataTypes) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(TYPE, "object");
+ jsonObject.add(PROPERTIES, getPropertiesObject(key, dataTypes));
+ return jsonObject;
+ }
+
+ private JsonObject getPropertiesObject(String key, JsonObject dataTypes) {
+ JsonObject properties = dataTypes.get(key).getAsJsonObject().get(PROPERTIES).getAsJsonObject();
+ JsonObject object = new JsonObject();
+ getInputProperties(properties, dataTypes, object);
+ return object;
+ }
+
+ private boolean isComplexType(String type, JsonObject dataTypes) {
+ if (dataTypes == null) {
+ return false;
+ }
+ return dataTypes.get(type) != null;
+ }
+
+ private boolean isInputParam(JsonObject inputProperty) {
+ JsonElement inputParam = inputProperty.get("input-param");
+ if (inputParam == null) {
+ return false;
+ }
+ return parseBoolean(inputParam.getAsString());
+ }
+
+ /**
+ * Creates payload to query CDS to get workflow input properties.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param version CDS blueprint version
+ * @param workflow CDS blueprint workflow
+ * @return returns payload in json format
+ */
+ public String getCdsPayloadForWorkFlow(String blueprintName, String version, String workflow) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("blueprintName", blueprintName);
+ jsonObject.addProperty("version", version);
+ jsonObject.addProperty("returnContent", "json");
+ jsonObject.addProperty("workflowName", workflow);
+ jsonObject.addProperty("specType", "TOSCA");
+ return jsonObject.toString();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java b/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java
new file mode 100644
index 000000000..843107040
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/client/DcaeInventoryServices.java
@@ -0,0 +1,144 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. 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============================================
+ * Modifications copyright (c) 2018 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.client;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.util.Date;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class implements the communication with DCAE for the service inventory.
+ */
+@Component
+public class DcaeInventoryServices {
+
+ @Autowired
+ CamelContext camelContext;
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeInventoryServices.class);
+ protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+ public static final String DCAE_INVENTORY_URL = "dcae.inventory.url";
+ public static final String DCAE_INVENTORY_RETRY_INTERVAL = "dcae.intentory.retry.interval";
+ public static final String DCAE_INVENTORY_RETRY_LIMIT = "dcae.intentory.retry.limit";
+ private final ClampProperties refProp;
+
+ /**
+ * Constructor.
+ */
+ @Autowired
+ public DcaeInventoryServices(ClampProperties refProp) {
+ this.refProp = refProp;
+ }
+
+ private int getTotalCountFromDcaeInventoryResponse(String responseStr) throws ParseException {
+ JSONParser parser = new JSONParser();
+ Object obj0 = parser.parse(responseStr);
+ JSONObject jsonObj = (JSONObject) obj0;
+ Long totalCount = (Long) jsonObj.get("totalCount");
+ return totalCount.intValue();
+ }
+
+ private DcaeInventoryResponse getItemsFromDcaeInventoryResponse(String responseStr) throws ParseException {
+ JSONParser parser = new JSONParser();
+ Object obj0 = parser.parse(responseStr);
+ JSONObject jsonObj = (JSONObject) obj0;
+ JSONArray itemsArray = (JSONArray) jsonObj.get("items");
+ JSONObject dcaeServiceType0 = (JSONObject) itemsArray.get(0);
+ return JsonUtils.GSON.fromJson(dcaeServiceType0.toString(), DcaeInventoryResponse.class);
+ }
+
+ /**
+ * DO a query to DCAE to get some Information.
+ *
+ * @param artifactName The artifact Name
+ * @param serviceUuid The service UUID
+ * @param resourceUuid The resource UUID
+ * @return The DCAE inventory for the artifact in DcaeInventoryResponse
+ * @throws IOException In case of issues with the stream
+ * @throws ParseException In case of issues with the Json parsing
+ */
+ public DcaeInventoryResponse getDcaeInformation(String artifactName, String serviceUuid, String resourceUuid)
+ throws IOException, ParseException, InterruptedException {
+ LoggingUtils.setTargetContext("DCAE", "getDcaeInformation");
+
+ int retryInterval = 0;
+ int retryLimit = 1;
+ if (refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT) != null) {
+ retryLimit = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT));
+ }
+ if (refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL) != null) {
+ retryInterval = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL));
+ }
+ for (int i = 0; i < retryLimit; i++) {
+ metricsLogger.info("Attempt n°" + i + " to contact DCAE inventory");
+ try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) {
+ Exchange exchangeResponse = producerTemplate
+ .send("direct:get-dcae-blueprint-inventory", ExchangeBuilder.anExchange(camelContext)
+ .withProperty("blueprintResourceId", resourceUuid)
+ .withProperty("blueprintServiceId", serviceUuid)
+ .withProperty("blueprintName", artifactName)
+ .withProperty("raiseHttpExceptionFlag", false).build());
+
+ if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE))
+ .is2xxSuccessful()) {
+ String dcaeResponse = (String) exchangeResponse.getIn().getBody();
+ int totalCount = getTotalCountFromDcaeInventoryResponse(dcaeResponse);
+ metricsLogger.info("getDcaeInformation complete: totalCount returned=" + totalCount);
+ if (totalCount > 0) {
+ logger.info("getDcaeInformation, answer from DCAE inventory:" + dcaeResponse);
+ LoggingUtils.setResponseContext("0", "Get Dcae Information success", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return getItemsFromDcaeInventoryResponse(dcaeResponse);
+ } else {
+ logger.info("Dcae inventory totalCount returned is 0, so waiting " + retryInterval
+ + "ms before retrying ...");
+ // wait for a while and try to connect to DCAE again
+ Thread.sleep(retryInterval);
+ }
+ }
+ }
+ }
+ logger.warn("Dcae inventory totalCount returned is still 0, after " + retryLimit + " attempts, returning NULL");
+ return null;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java
new file mode 100644
index 000000000..9b6338e00
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/AafConfiguration.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import javax.servlet.Filter;
+import org.onap.policy.clamp.clds.filter.ClampCadiFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Profile("clamp-aaf-authentication")
+public class AafConfiguration {
+
+ /**
+ * Method to return clamp cadi filter.
+ *
+ * @return Filter
+ */
+ @Bean(name = "cadiFilter")
+ public Filter cadiFilter() {
+ return new ClampCadiFilter();
+ }
+
+ /**
+ * Method to register cadi filter.
+ *
+ * @return FilterRegistrationBean
+ */
+ @Bean
+ public FilterRegistrationBean cadiFilterRegistration() {
+ FilterRegistrationBean registration = new FilterRegistrationBean();
+ registration.setFilter(cadiFilter());
+ registration.addUrlPatterns("/restservices/clds/v1/user/*");
+ registration.addUrlPatterns("/restservices/clds/v2/dictionary/*");
+ registration.addUrlPatterns("/restservices/clds/v2/templates/*");
+ registration.addUrlPatterns("/restservices/clds/v2/clampInformation/*");
+ registration.addUrlPatterns("/restservices/clds/v2/policyToscaModels/*");
+ registration.addUrlPatterns("/restservices/clds/v2/policies/*");
+ registration.addUrlPatterns("/restservices/clds/v2/loop/*");
+ registration.setName("cadiFilter");
+ registration.setOrder(0);
+ return registration;
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java
new file mode 100644
index 000000000..5f10c0afb
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CamelConfiguration.java
@@ -0,0 +1,166 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Objects;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.http.HttpComponent;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.onap.policy.clamp.clds.util.ClampVersioning;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.util.PassDecoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CamelConfiguration extends RouteBuilder {
+
+ private static final String HTTP = "http";
+ private static final String HTTPS = "https";
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Value("${server.ssl.key-store:#{null}}")
+ private String keyStore;
+
+ @Value("${server.ssl.key-store-type:JKS}")
+ private String keyStoreType;
+
+ @Value("${server.ssl.key-store-password:#{null}}")
+ private String keyStorePass;
+
+ @Value("${server.ssl.trust-store:#{null}}")
+ private String trustStore;
+
+ @Value("${server.ssl.trust-store-password:#{null}}")
+ private String trustStorePass;
+
+ @Value("${server.ssl.trust-store-type:JKS}")
+ private String trustStoreType;
+
+ @Value("${server.ssl.trust-store-algorithm:PKIX}")
+ private String trustStoreAlgorithm;
+
+ @Value("${clamp.config.httpclient.connectTimeout:-1}")
+ private int connectTimeout;
+
+ @Value("${clamp.config.httpclient.connectRequestTimeout:-1}")
+ private int connectRequestTimeout;
+
+ @Value("${clamp.config.httpclient.socketTimeout:-1}")
+ private int socketTimeout;
+
+ @Value("${clamp.config.keyFile:#{null}}")
+ private String keyFile;
+
+
+ @Autowired
+ private ClampProperties clampProperties;
+
+ private void configureDefaultSslProperties() {
+ if (trustStore != null) {
+ System.setProperty("javax.net.ssl.trustStore", Thread.currentThread().getContextClassLoader()
+ .getResource(trustStore.replaceFirst("classpath:", "")).getPath());
+ System.setProperty("javax.net.ssl.trustStorePassword", Objects.requireNonNull(
+ PassDecoder.decode(trustStorePass, keyFile)));
+ System.setProperty("javax.net.ssl.trustStoreType", trustStoreType);
+ System.setProperty("ssl.TrustManagerFactory.algorithm", trustStoreAlgorithm);
+ }
+ if (keyStore != null) {
+ System.setProperty("javax.net.ssl.keyStore", Thread.currentThread().getContextClassLoader()
+ .getResource(keyStore.replaceFirst("classpath:", "")).getPath());
+ System.setProperty("javax.net.ssl.keyStorePassword", Objects.requireNonNull(
+ PassDecoder.decode(keyStorePass, keyFile)));
+ System.setProperty("javax.net.ssl.keyStoreType", keyStoreType);
+ }
+
+ }
+
+ private void configureCamelHttpComponent()
+ throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException,
+ IOException {
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setConnectTimeout(connectTimeout)
+ .setConnectionRequestTimeout(connectRequestTimeout)
+ .setSocketTimeout(socketTimeout).build();
+
+ if (trustStore != null) {
+ KeyStore truststore = KeyStore.getInstance(trustStoreType);
+ truststore.load(
+ ResourceFileUtils.getResourceAsStream(trustStore),
+ Objects.requireNonNull(PassDecoder.decode(trustStorePass, keyFile)).toCharArray());
+ TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
+ trustFactory.init(truststore);
+ SSLContext sslcontext = SSLContext.getInstance("TLS");
+ sslcontext.init(null, trustFactory.getTrustManagers(), null);
+ camelContext.getComponent(HTTPS, HttpComponent.class).setHttpClientConfigurer(builder -> {
+ SSLSocketFactory factory = new SSLSocketFactory(sslcontext,
+ SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ builder.setSSLSocketFactory(factory);
+ builder.setConnectionManager(new BasicHttpClientConnectionManager(
+ RegistryBuilder.<ConnectionSocketFactory>create().register(HTTPS, factory).build()))
+ .setDefaultRequestConfig(requestConfig);
+ });
+ }
+ camelContext.getComponent(HTTP, HttpComponent.class).setHttpClientConfigurer(builder -> {
+ Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+ .register(HTTP, PlainConnectionSocketFactory.getSocketFactory()).build();
+ builder.setConnectionManager(new BasicHttpClientConnectionManager(registry))
+ .setDefaultRequestConfig(requestConfig);
+ });
+ }
+
+ @Override
+ public void configure()
+ throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException,
+ IOException {
+ restConfiguration().component("servlet").bindingMode(RestBindingMode.json).jsonDataFormat("clamp-gson")
+ .dataFormatProperty("prettyPrint", "true")// .enableCORS(true)
+ // turn on swagger api-doc
+ .apiContextPath("api-doc").apiVendorExtension(true).apiProperty("api.title", "Clamp Rest API")
+ .apiProperty("api.version", ClampVersioning.getCldsVersionFromProps())
+ .apiProperty("base.path", "/restservices/clds/");
+
+ // Configure httpClient properties for Camel HTTP/HTTPS calls
+ configureDefaultSslProperties();
+ configureCamelHttpComponent();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java
new file mode 100644
index 000000000..f11e16733
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/ClampProperties.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+/**
+ * Holds Clamp properties and add some functionalities.
+ */
+@Component
+public class ClampProperties {
+
+ @Autowired
+ private ApplicationContext appContext;
+ @Autowired
+ private Environment env;
+ public static final String CONFIG_PREFIX = "clamp.config.";
+
+ /**
+ * get property value.
+ *
+ * @param key The first key
+ * @return The string with the value
+ */
+ public String getStringValue(String key) {
+ return env.getProperty(CONFIG_PREFIX + key);
+ }
+
+ /**
+ * get property value for a combo key (key1 + "." + key2). If not found just use
+ * key1.
+ *
+ * @param key1 The first key
+ * @param key2 The second key after a dot
+ * @return The string with the value
+ */
+ public String getStringValue(String key1, String key2) {
+ String value = getStringValue(key1 + "." + key2);
+ if (value == null || value.length() == 0) {
+ value = getStringValue(key1);
+ }
+ return value;
+ }
+
+ /**
+ * Return the file content. The value obtained from the clds-reference file will
+ * be used as a filename.
+ *
+ * @param key The key that will be used to access the clds-reference file
+ * @return File content in String
+ * @throws IOException In case of issues with the JSON parser
+ */
+ public String getFileContent(String key) throws IOException {
+ String fileReference = getStringValue(key);
+ return (fileReference != null) ? getFileContentFromPath(fileReference) : null;
+ }
+
+ /**
+ * Return the file content. First try with combo key (key1 + "." + key2),
+ * otherwise default to just key1. The value obtained from the clds-reference
+ * file will be used as a filename.
+ *
+ * @param key1 The first key
+ * @param key2 The second key after a dot
+ * @return File content in String
+ * @throws IOException In case of issues with the JSON parser
+ */
+ public String getFileContent(String key1, String key2) throws IOException {
+ String fileReference = getStringValue(key1, key2);
+ return (fileReference != null) ? getFileContentFromPath(fileReference) : null;
+ }
+
+ private String getFileContentFromPath(String filepath) throws IOException {
+ URL url = appContext.getResource(filepath).getURL();
+ return IOUtils.toString(url, StandardCharsets.UTF_8);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java
new file mode 100644
index 000000000..20d7143fb
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoder.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import com.google.gson.JsonParseException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.IOUtils;
+import org.onap.policy.clamp.authorization.CldsUser;
+import org.onap.policy.clamp.clds.exception.CldsUsersException;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+
+public class CldsUserJsonDecoder {
+
+ private CldsUserJsonDecoder() {
+ }
+
+ /**
+ * This method decodes the JSON file provided to a CldsUser Array. The stream is
+ * closed after this call, this is not possible to reuse it.
+ *
+ * @param cldsUsersFile
+ * The inputStream containing the users json file
+ * @return CldsUser[] Array containing a list of the user defined in the JSON
+ * file
+ */
+ public static CldsUser[] decodeJson(InputStream cldsUsersFile) {
+ try {
+ return decodeJson(IOUtils.toString(cldsUsersFile, StandardCharsets.UTF_8.name()));
+ } catch (IOException e) {
+ throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e);
+ }
+ }
+
+ /**
+ * This method decodes the JSON string to a CldsUser Array.
+ *
+ * @param cldsUsersString JSON string
+ * @return CldsUser[] Array containing a list of the user defined in the JSON
+ */
+ public static CldsUser[] decodeJson(String cldsUsersString) {
+ try {
+ // the ObjectMapper readValue method closes the stream no need to do
+ // it
+ return JsonUtils.GSON.fromJson(cldsUsersString, CldsUser[].class);
+ } catch (JsonParseException e) {
+ throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e);
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java
new file mode 100644
index 000000000..27cf0b941
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultDictionaryElements.java
@@ -0,0 +1,167 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import javax.annotation.PostConstruct;
+import org.onap.policy.clamp.tosca.Dictionary;
+import org.onap.policy.clamp.tosca.DictionaryElement;
+import org.onap.policy.clamp.tosca.DictionaryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Profile("default-dictionary-elements")
+public class DefaultDictionaryElements {
+
+ @Autowired
+ private DictionaryService dictionaryService;
+
+ /**
+ * Init method.
+ */
+ @PostConstruct
+ public void init() {
+ preProvisionDefaultActors();
+ preProvisionDefaultOperations();
+ }
+
+ private void preProvisionDefaultActors() {
+ // Set up dictionary elements
+ Dictionary actorDictionary = new Dictionary();
+ actorDictionary.setName("DefaultActors");
+ actorDictionary.setSecondLevelDictionary(0);
+ actorDictionary.setSubDictionaryType("");
+
+ DictionaryElement elementSo = new DictionaryElement();
+ elementSo.setName("SO");
+ elementSo.setShortName("SO");
+ elementSo.setType("string");
+ elementSo.setDescription("SO component");
+ actorDictionary.addDictionaryElements(elementSo);
+
+ DictionaryElement elementSdnc = new DictionaryElement();
+ elementSdnc.setName("SDNC");
+ elementSdnc.setShortName("SDNC");
+ elementSdnc.setType("string");
+ elementSdnc.setDescription("SDNC component");
+ actorDictionary.addDictionaryElements(elementSdnc);
+
+ DictionaryElement elementAppc = new DictionaryElement();
+ elementAppc.setName("APPC");
+ elementAppc.setShortName("APPC");
+ elementAppc.setType("string");
+ elementAppc.setDescription("APPC component");
+ actorDictionary.addDictionaryElements(elementAppc);
+
+ DictionaryElement elementVfc = new DictionaryElement();
+ elementVfc.setName("VFC");
+ elementVfc.setShortName("VFC");
+ elementVfc.setType("string");
+ elementVfc.setDescription("VFC component");
+ actorDictionary.addDictionaryElements(elementVfc);
+
+ DictionaryElement elementSdnr = new DictionaryElement();
+ elementSdnr.setName("SDNR");
+ elementSdnr.setShortName("SDNR");
+ elementSdnr.setType("string");
+ elementSdnr.setDescription("SDNR component");
+ actorDictionary.addDictionaryElements(elementSdnr);
+
+ dictionaryService.saveOrUpdateDictionary(actorDictionary);
+ }
+
+ private void preProvisionDefaultOperations() {
+ // Set up dictionary elements
+ Dictionary operationDictionary = new Dictionary();
+ operationDictionary.setName("DefaultOperations");
+ operationDictionary.setSecondLevelDictionary(0);
+ operationDictionary.setSubDictionaryType("");
+
+ DictionaryElement elementRestart = new DictionaryElement();
+ elementRestart.setName("Restart");
+ elementRestart.setShortName("Restart (APPC operation)");
+ elementRestart.setType("string");
+ elementRestart.setDescription("APPC operation");
+ operationDictionary.addDictionaryElements(elementRestart);
+
+ DictionaryElement elementRebuild = new DictionaryElement();
+ elementRebuild.setName("Rebuild");
+ elementRebuild.setShortName("Rebuild (APPC operation)");
+ elementRebuild.setType("string");
+ elementRebuild.setDescription("APPC operation");
+ operationDictionary.addDictionaryElements(elementRebuild);
+
+ DictionaryElement elementMigrate = new DictionaryElement();
+ elementMigrate.setName("Migrate");
+ elementMigrate.setShortName("Migrate (APPC operation)");
+ elementMigrate.setType("string");
+ elementMigrate.setDescription("APPC operation");
+ operationDictionary.addDictionaryElements(elementMigrate);
+
+ DictionaryElement elementHealthCheck = new DictionaryElement();
+ elementHealthCheck.setName("Health-Check");
+ elementHealthCheck.setShortName("Health-Check (APPC operation)");
+ elementHealthCheck.setType("string");
+ elementHealthCheck.setDescription("APPC operation");
+ operationDictionary.addDictionaryElements(elementHealthCheck);
+
+ DictionaryElement elementModifyConfig = new DictionaryElement();
+ elementModifyConfig.setName("ModifyConfig");
+ elementModifyConfig.setShortName("ModifyConfig (APPC/VFC operation)");
+ elementModifyConfig.setType("string");
+ elementModifyConfig.setDescription("APPC/VFC operation");
+ operationDictionary.addDictionaryElements(elementModifyConfig);
+
+ DictionaryElement elementVfModuleCreate = new DictionaryElement();
+ elementVfModuleCreate.setName("VF Module Create");
+ elementVfModuleCreate.setShortName("VF Module Create (SO operation)");
+ elementVfModuleCreate.setType("string");
+ elementVfModuleCreate.setDescription("SO operation");
+ operationDictionary.addDictionaryElements(elementVfModuleCreate);
+
+ DictionaryElement elementVfModuleDelete = new DictionaryElement();
+ elementVfModuleDelete.setName("VF Module Delete");
+ elementVfModuleDelete.setShortName("VF Module Delete (SO operation)");
+ elementVfModuleDelete.setType("string");
+ elementVfModuleDelete.setDescription("SO operation");
+ operationDictionary.addDictionaryElements(elementVfModuleDelete);
+
+ DictionaryElement elementReroute = new DictionaryElement();
+ elementReroute.setName("Reroute");
+ elementReroute.setShortName("Reroute (SDNC operation)");
+ elementReroute.setType("string");
+ elementReroute.setDescription("SDNC operation");
+ operationDictionary.addDictionaryElements(elementReroute);
+
+ DictionaryElement elementBandwidthOnDemand = new DictionaryElement();
+ elementBandwidthOnDemand.setName("BandwidthOnDemand");
+ elementBandwidthOnDemand.setShortName("BandwidthOnDemand (SDNC operation)");
+ elementBandwidthOnDemand.setType("string");
+ elementBandwidthOnDemand.setDescription("SDNC operation");
+ operationDictionary.addDictionaryElements(elementBandwidthOnDemand);
+
+ dictionaryService.saveOrUpdateDictionary(operationDictionary);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java
new file mode 100644
index 000000000..bb7b76af3
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/DefaultUserConfiguration.java
@@ -0,0 +1,140 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import org.onap.policy.clamp.authorization.CldsUser;
+import org.onap.policy.clamp.clds.exception.CldsConfigException;
+import org.onap.policy.clamp.clds.exception.CldsUsersException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+/**
+ * This class is used to enable the HTTP authentication to login. It requires a
+ * specific JSON file containing the user definition
+ * (classpath:clds/clds-users.json).
+ */
+@Configuration
+@EnableWebSecurity
+@Profile("clamp-default-user")
+public class DefaultUserConfiguration extends WebSecurityConfigurerAdapter {
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DefaultUserConfiguration.class);
+
+ private static final String SETUP_WEB_USERS_EXCEPTION_MSG = "Exception occurred during the "
+ + " setup of the Web users in memory";
+ @Autowired
+ private ClampProperties refProp;
+ @Value("${clamp.config.security.permission.type.cl:permission-type-cl}")
+ private String cldsPersmissionTypeCl;
+ @Value("${CLDS_PERMISSION_INSTANCE:dev}")
+ private String cldsPermissionInstance;
+ @Value("${clamp.config.security.encoder:bcrypt}")
+ private String cldsEncoderMethod;
+ @Value("${clamp.config.security.encoder.bcrypt.strength:10}")
+ private Integer cldsBcryptEncoderStrength;
+
+ /**
+ * This method configures on which URL the authorization will be enabled.
+ */
+ @Override
+ protected void configure(HttpSecurity http) {
+ try {
+ // Do no remove the csrf as recommended by Sonar otherwise Put/post will not work
+ // Moreover this default user class is only used by dev, on prod we use AAF and this code will be disabled
+ http.csrf().disable().httpBasic().and().authorizeRequests().antMatchers("/restservices/clds/v1/user/**")
+ .authenticated().anyRequest().permitAll().and().sessionManagement()
+ .maximumSessions(1);
+
+ } catch (Exception e) {
+ logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e);
+ throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e);
+ }
+ }
+
+ /**
+ * This method is called by the framework and is used to load all the users
+ * defined in cldsUsersFile variable (this file path can be configured in the
+ * application.properties).
+ *
+ * @param auth authentication manager builder
+ */
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) {
+ // configure algorithm used for password hashing
+ final PasswordEncoder passwordEncoder = getPasswordEncoder();
+
+ try {
+ CldsUser[] usersList = loadUsers();
+ // no users defined
+ if (null == usersList) {
+ logger.warn("No users defined. Users should be defined under clds-users.json");
+ return;
+ }
+ for (CldsUser user : usersList) {
+ auth.inMemoryAuthentication().withUser(user.getUser()).password(user.getPassword())
+ .authorities(user.getPermissionsString()).and().passwordEncoder(passwordEncoder);
+ }
+ } catch (Exception e) {
+ logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e);
+ throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e);
+ }
+ }
+
+ /**
+ * This method loads physically the JSON file and convert it to an Array of
+ * CldsUser.
+ *
+ * @return The array of CldsUser
+ * @throws IOException In case of the file is not found
+ */
+ private CldsUser[] loadUsers() throws IOException {
+ logger.info("Load from clds-users.properties");
+ return CldsUserJsonDecoder.decodeJson(refProp.getFileContent("files.cldsUsers"));
+ }
+
+ /**
+ * This methods returns the chosen encoder for password hashing.
+ */
+ private PasswordEncoder getPasswordEncoder() {
+ if ("bcrypt".equals(cldsEncoderMethod)) {
+ return new BCryptPasswordEncoder(cldsBcryptEncoderStrength);
+ } else {
+ throw new CldsConfigException(
+ "Invalid clamp.config.security.encoder value. 'bcrypt' is the only option at this time.");
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java
new file mode 100644
index 000000000..a72cffd09
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SslConfig.java
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.util.PassDecoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.Ssl;
+import org.springframework.boot.web.server.SslStoreProvider;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.ResourceLoader;
+
+@Configuration
+@Profile("clamp-ssl-config")
+public class SslConfig {
+ @Autowired
+ private Environment env;
+
+ @Bean
+ WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer(ServerProperties serverProperties,
+ ResourceLoader resourceLoader) {
+ return (tomcat) -> tomcat.setSslStoreProvider(new SslStoreProvider() {
+ @Override
+ public KeyStore getKeyStore() throws KeyStoreException,
+ NoSuchAlgorithmException, CertificateException, IOException {
+ KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type"));
+ String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"),
+ env.getProperty("clamp.config.keyFile"));
+ keystore.load(ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.key-store")),
+ password.toCharArray());
+ return keystore;
+ }
+
+ @Override
+ public KeyStore getTrustStore() throws KeyStoreException,
+ NoSuchAlgorithmException, CertificateException, IOException {
+ KeyStore truststore = KeyStore.getInstance("JKS");
+ String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"),
+ env.getProperty("clamp.config.keyFile"));
+ truststore.load(
+ ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.trust-store")),
+ password.toCharArray());
+ return truststore;
+ }
+
+ });
+ }
+
+ @Bean
+ WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer(ServerProperties serverProperties,
+ ResourceLoader resourceLoader) {
+ return (tomcat) -> tomcat.setSsl(new Ssl() {
+ @Override
+ public String getKeyPassword() {
+ return PassDecoder.decode(env.getProperty("server.ssl.key-password"),
+ env.getProperty("clamp.config.keyFile"));
+ }
+
+ @Override
+ public String getKeyAlias() {
+ return env.getProperty("server.ssl.key-alias");
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java
new file mode 100644
index 000000000..3e2e62b66
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/SystemPropertiesLoader.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.Properties;
+import javax.annotation.Resource;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SystemPropertiesLoader implements ApplicationListener<ContextRefreshedEvent> {
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(SystemPropertiesLoader.class);
+
+ @Resource(name = "mapper")
+ private Properties myTranslator;
+
+ @Override
+ public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
+ logger.info("Loading additional JVM properties:" + myTranslator.toString());
+ System.getProperties().putAll(myTranslator);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java
new file mode 100644
index 000000000..5d8cbb05e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcControllersConfiguration.java
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config.sdc;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * This class maps the SDC config JSON file. This JSON can have multiple
+ * sdc-controller config. So the json is loaded in a static way and the instance
+ * must specify the controller name that it represents.
+ */
+public class SdcControllersConfiguration {
+
+ private static final String CONTROLLER_SUBTREE_KEY = "sdc-connections";
+ @Autowired
+ protected ApplicationContext appContext;
+
+ @Value("${clamp.config.keyFile:classpath:/clds/aaf/org.onap.clamp.keyfile}")
+ private String keyFile;
+
+ /**
+ * The file name that will be loaded by Spring.
+ */
+ @Value("${clamp.config.files.sdcController:classpath:/clds/sdc-controllers-config.json}")
+ protected String sdcControllerFile;
+ /**
+ * The root of the JSON.
+ */
+ private JsonObject jsonRootNode;
+
+ /**
+ * Loads configuration from SDC controller config file.
+ *
+ * @throws IOException IO Exception
+ */
+ @PostConstruct
+ public void loadConfiguration() throws IOException {
+ try (InputStreamReader controllerFile = new InputStreamReader(
+ appContext.getResource(sdcControllerFile).getInputStream(), StandardCharsets.UTF_8)) {
+ jsonRootNode = JsonUtils.GSON.fromJson(controllerFile, JsonObject.class);
+ }
+ }
+
+ public SdcSingleControllerConfiguration getSdcSingleControllerConfiguration(String controllerName) {
+ return getAllDefinedControllers().get(controllerName);
+ }
+
+ /**
+ * This method reads all Controllers configurations and returns them.
+ *
+ * @return A list of controller Names defined in the config
+ */
+ public Map<String, SdcSingleControllerConfiguration> getAllDefinedControllers() {
+ Map<String, SdcSingleControllerConfiguration> result = new HashMap<>();
+ if (jsonRootNode.get(CONTROLLER_SUBTREE_KEY) != null) {
+ jsonRootNode.get(CONTROLLER_SUBTREE_KEY).getAsJsonObject().entrySet().forEach(
+ entry -> result.put(entry.getKey(),
+ new SdcSingleControllerConfiguration(entry.getValue().getAsJsonObject(), entry.getKey(),
+ keyFile)));
+ } else {
+ throw new SdcParametersException(
+ CONTROLLER_SUBTREE_KEY + " key not found in the file: " + sdcControllerFile);
+ }
+ return result;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java
new file mode 100644
index 000000000..67060d776
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java
@@ -0,0 +1,272 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config.sdc;
+
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException;
+import org.onap.policy.clamp.util.PassDecoder;
+import org.onap.sdc.api.consumer.IConfiguration;
+
+/**
+ * This class maps the SDC config JSON for one controller.
+ */
+public class SdcSingleControllerConfiguration implements IConfiguration {
+
+ private final String keyFile;
+
+ /**
+ * The sdc Controller name corresponding.
+ */
+ private String sdcControllerName;
+ /**
+ * The root of the JSON.
+ */
+ private JsonObject jsonRootNode;
+ // All keys that can be present in the JSON
+ public static final String CONSUMER_GROUP_ATTRIBUTE_NAME = "consumerGroup";
+ public static final String CONSUMER_ID_ATTRIBUTE_NAME = "consumerId";
+ public static final String ENVIRONMENT_NAME_ATTRIBUTE_NAME = "environmentName";
+ public static final String SDC_KEY_ATTRIBUTE_NAME = "password";
+ public static final String POLLING_INTERVAL_ATTRIBUTE_NAME = "pollingInterval";
+ public static final String RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME = "relevantArtifactTypes";
+ public static final String USER_ATTRIBUTE_NAME = "user";
+ public static final String SDC_ADDRESS_ATTRIBUTE_NAME = "sdcAddress";
+ public static final String POLLING_TIMEOUT_ATTRIBUTE_NAME = "pollingTimeout";
+ public static final String ACTIVATE_SERVER_TLS_AUTH = "activateServerTLSAuth";
+ public static final String KEY_STORE_KEY = "keyStorePassword";
+ public static final String KEY_STORE_PATH = "keyStorePath";
+ public static final String MESSAGE_BUS_ADDRESSES = "messageBusAddresses";
+ private String errorMessageKeyNotFound;
+ /**
+ * Supported artifact types.
+ */
+ public static final String HEAT = "HEAT";
+ public static final String HEAT_ARTIFACT = "HEAT_ARTIFACT";
+ public static final String HEAT_ENV = "HEAT_ENV";
+ public static final String HEAT_NESTED = "HEAT_NESTED";
+ public static final String HEAT_NET = "HEAT_NET";
+ public static final String HEAT_VOL = "HEAT_VOL";
+ public static final String OTHER = "OTHER";
+ public static final String TOSCA_CSAR = "TOSCA_CSAR";
+ public static final String VF_MODULES_METADATA = "VF_MODULES_METADATA";
+ private static final String[] SUPPORTED_ARTIFACT_TYPES = {TOSCA_CSAR, VF_MODULES_METADATA};
+ public static final List<String> SUPPORTED_ARTIFACT_TYPES_LIST = List.of(SUPPORTED_ARTIFACT_TYPES);
+
+ /**
+ * This constructor builds a SdcSingleControllerConfiguration from the
+ * corresponding json.
+ *
+ * @param jsonNode The JSON node
+ * @param controllerName The controller name that must appear in the JSON
+ * @param keyFileLocation The location of the file to decode the password using CADI
+ */
+ public SdcSingleControllerConfiguration(JsonObject jsonNode, String controllerName, String keyFileLocation) {
+ jsonRootNode = jsonNode;
+ keyFile = keyFileLocation;
+ setSdcControllerName(controllerName);
+ testAllRequiredParameters();
+ }
+
+ public String getSdcControllerName() {
+ return sdcControllerName;
+ }
+
+ /**
+ * Sets SDC controller name.
+ *
+ * @param controllerName SDC controller name
+ */
+ public void setSdcControllerName(String controllerName) {
+ this.sdcControllerName = controllerName;
+ errorMessageKeyNotFound = " parameter cannot be found in config file for controller name" + sdcControllerName;
+ testAllRequiredParameters();
+ }
+
+ private String getStringConfig(String key) {
+ if (jsonRootNode != null && jsonRootNode.get(key) != null) {
+ String config = jsonRootNode.get(key).getAsString();
+ return config.isEmpty() ? null : config;
+ }
+ return null;
+ }
+
+ private Integer getIntConfig(String key) {
+ if (jsonRootNode != null && jsonRootNode.get(key) != null) {
+ return jsonRootNode.get(key).getAsInt();
+ } else {
+ return 0;
+ }
+ }
+
+ private String getEncryptedStringConfig(String key) {
+ if (jsonRootNode != null && jsonRootNode.get(key) != null) {
+ return jsonRootNode.get(key).getAsString().isEmpty() ? null
+ : PassDecoder.decode(jsonRootNode.get(key).getAsString(), keyFile);
+ }
+ return null;
+ }
+
+ @Override
+ public java.lang.Boolean isUseHttpsWithDmaap() {
+ return false;
+ }
+
+ @Override
+ public String getConsumerGroup() {
+ if (jsonRootNode != null && jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) != null) {
+ String config = jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString();
+ return "NULL".equals(config) || config.isEmpty() ? null : config;
+ }
+ return null;
+ }
+
+ @Override
+ public String getConsumerID() {
+ return getStringConfig(CONSUMER_ID_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public String getEnvironmentName() {
+ return getStringConfig(ENVIRONMENT_NAME_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public String getPassword() {
+ return getEncryptedStringConfig(SDC_KEY_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public int getPollingInterval() {
+ return getIntConfig(POLLING_INTERVAL_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public List<String> getRelevantArtifactTypes() {
+ // DO not return the Static List SUPPORTED_ARTIFACT_TYPES_LIST because
+ // the ASDC Client could try to modify it !!!
+ return Arrays.asList(SUPPORTED_ARTIFACT_TYPES);
+ }
+
+ @Override
+ public String getUser() {
+ return getStringConfig(USER_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public String getAsdcAddress() {
+ return getStringConfig(SDC_ADDRESS_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public int getPollingTimeout() {
+ return getIntConfig(POLLING_TIMEOUT_ATTRIBUTE_NAME);
+ }
+
+ @Override
+ public boolean activateServerTLSAuth() {
+ if (jsonRootNode != null && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH) != null
+ && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).isJsonPrimitive()) {
+ return jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).getAsBoolean();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String getKeyStorePassword() {
+ return getEncryptedStringConfig(KEY_STORE_KEY);
+ }
+
+ @Override
+ public String getKeyStorePath() {
+ return getStringConfig(KEY_STORE_PATH);
+ }
+
+ /**
+ * This method can be used to validate all required parameters are well
+ * there.
+ */
+ public void testAllRequiredParameters() {
+ // Special case for this attribute that can be null from
+ // getConsumerGroup
+ if (jsonRootNode == null) {
+ throw new SdcParametersException("Json is null for controller " + this.getSdcControllerName());
+ }
+ if (this.getConsumerGroup() == null && (jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) == null
+ || !"NULL".equals(jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString()))) {
+ throw new SdcParametersException(CONSUMER_GROUP_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getConsumerID() == null || this.getConsumerID().isEmpty()) {
+ throw new SdcParametersException(CONSUMER_ID_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getEnvironmentName() == null || this.getEnvironmentName().isEmpty()) {
+ throw new SdcParametersException(ENVIRONMENT_NAME_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getAsdcAddress() == null || this.getAsdcAddress().isEmpty()) {
+ throw new SdcParametersException(SDC_ADDRESS_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getMsgBusAddress() == null || this.getMsgBusAddress().isEmpty()) {
+ throw new SdcParametersException(MESSAGE_BUS_ADDRESSES + errorMessageKeyNotFound);
+ }
+ if (this.getPassword() == null || this.getPassword().isEmpty()) {
+ throw new SdcParametersException(SDC_KEY_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getPollingInterval() == 0) {
+ throw new SdcParametersException(POLLING_INTERVAL_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getPollingTimeout() == 0) {
+ throw new SdcParametersException(POLLING_TIMEOUT_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getRelevantArtifactTypes() == null || this.getRelevantArtifactTypes().isEmpty()) {
+ throw new SdcParametersException(RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ if (this.getUser() == null || this.getUser().isEmpty()) {
+ throw new SdcParametersException(USER_ATTRIBUTE_NAME + errorMessageKeyNotFound);
+ }
+ }
+
+ /**
+ * The flag allows the client to receive metadata for all resources of the
+ * service regardless of the artifacts associated to them. Setting the flag
+ * to false will preserve legacy behavior.
+ */
+ @Override
+ public boolean isFilterInEmptyResources() {
+ return false;
+ }
+
+ @Override
+ public List<String> getMsgBusAddress() {
+ List<String> addressesList = new ArrayList<>();
+ if (jsonRootNode != null && jsonRootNode.get(MESSAGE_BUS_ADDRESSES) != null) {
+ jsonRootNode.get(MESSAGE_BUS_ADDRESSES).getAsJsonArray().forEach(k -> addressesList.add(k.getAsString()));
+ return addressesList;
+ } else {
+ return addressesList;
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java
new file mode 100644
index 000000000..72f09ce13
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/CldsConfiguration.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config.spring;
+
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.PropertiesFactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Profile("clamp-default")
+public class CldsConfiguration {
+
+ @Autowired
+ private ApplicationContext appContext;
+ @Autowired
+ private ClampProperties refProp;
+
+
+ /**
+ * This loads the file system.properties.
+ *
+ * @return The PropertiesFactoryBean
+ */
+ @Bean(name = "mapper")
+ public PropertiesFactoryBean mapper() {
+ PropertiesFactoryBean bean = new PropertiesFactoryBean();
+ bean.setLocation(appContext.getResource(refProp.getStringValue("files.systemProperties")));
+ return bean;
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java
new file mode 100644
index 000000000..6005b0d39
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/config/spring/SdcControllerConfiguration.java
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config.spring;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.config.sdc.SdcControllersConfiguration;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcControllerException;
+import org.onap.policy.clamp.clds.sdc.controller.SdcSingleController;
+import org.onap.policy.clamp.clds.sdc.controller.SdcSingleControllerStatus;
+import org.onap.policy.clamp.loop.CsarInstaller;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+@Profile("clamp-sdc-controller")
+public class SdcControllerConfiguration {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcControllerConfiguration.class);
+ private List<SdcSingleController> sdcControllersList = new ArrayList<>();
+ private final ClampProperties clampProp;
+ private final CsarInstaller csarInstaller;
+
+ @Autowired
+ public SdcControllerConfiguration(ClampProperties clampProp,
+ @Qualifier("csarInstaller") CsarInstaller csarInstaller) {
+ this.clampProp = clampProp;
+ this.csarInstaller = csarInstaller;
+ }
+
+ /**
+ * Loads SDC controller configuration.
+ */
+ @PostConstruct
+ public void loadSdcControllers() {
+ SdcControllersConfiguration sdcControllersConfig = getSdcControllersConfiguration();
+ sdcControllersConfig.getAllDefinedControllers().forEach((key, value) -> {
+ logger.info("Creating controller instance:" + key);
+ SdcSingleController sdcController = new SdcSingleController(clampProp, csarInstaller, value, null);
+ sdcControllersList.add(sdcController);
+ });
+ }
+
+ /**
+ * Checks whether all SDC controllers defined are up and running.
+ */
+ @Scheduled(fixedRate = 120000)
+ public void checkAllSdcControllers() {
+ logger.info("Checking that all SDC Controllers defined are up and running");
+ for (SdcSingleController controller : sdcControllersList) {
+ try {
+ if (SdcSingleControllerStatus.STOPPED.equals(controller.getControllerStatus())) {
+ controller.initSdc();
+ }
+ } catch (SdcControllerException e) {
+ logger.error("Exception caught when booting sdc controller", e);
+ }
+ }
+ logger.info("SDC Controllers check completed");
+ }
+
+ /**
+ * Closes all SDC Controller and the SDC Client.
+ */
+ @PreDestroy
+ public void killSdcControllers() {
+ sdcControllersList.forEach(e -> {
+ try {
+ e.closeSdc();
+ } catch (SdcControllerException e1) {
+ logger.error("Exception caught when stopping sdc controller", e1);
+ }
+ });
+ }
+
+ @Bean(name = "sdcControllersConfiguration")
+ public SdcControllersConfiguration getSdcControllersConfiguration() {
+ return new SdcControllersConfiguration();
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java
new file mode 100644
index 000000000..ef1ced0a3
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsConfigException.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception;
+
+/**
+ * New exception to CldsUser errors.
+ *
+ */
+public class CldsConfigException extends RuntimeException {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 5958873136187918505L;
+
+ /**
+ * This constructor can be used to create a new CldsConfigException.
+ *
+ * @param message
+ * A string message detailing the problem
+ * @param ex
+ * The exception sent by the code
+ */
+ public CldsConfigException(String message, Throwable ex) {
+ super(message, ex);
+ }
+
+ /**
+ * This constructor can be used to create a new CldsConfigException. Use
+ * this constructor only if you are creating a new exception stack, not if
+ * an exception was already raised by another code.
+ *
+ * @param message
+ * A string message detailing the problem
+ */
+ public CldsConfigException(String message) {
+ super(message);
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java
new file mode 100644
index 000000000..4d4855b6f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/CldsUsersException.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception;
+
+/**
+ * New exception to CldsUser errors.
+ *
+ */
+public class CldsUsersException extends RuntimeException {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 933535057227505342L;
+
+ /**
+ * This constructor can be used to create a new CldsUsersException.
+ *
+ * @param message
+ * A string message detailing the problem
+ * @param ex
+ * The exception sent by the code
+ */
+ public CldsUsersException(String message, Throwable ex) {
+ super(message, ex);
+ }
+
+ /**
+ * This constructor can be used to create a new CldsUsersException. Use this
+ * constructor only if you are creating a new exception stack, not if an
+ * exception was already raised by another code.
+ *
+ * @param message
+ * A string message detailing the problem
+ */
+ public CldsUsersException(String message) {
+ super(message);
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java
new file mode 100644
index 000000000..73c117932
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/NotAuthorizedException.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception;
+
+/**
+ * New exception to request errors.
+ *
+ */
+public class NotAuthorizedException extends RuntimeException {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = -5738167530541646123L;
+
+ /**
+ * This constructor can be used to create a new CldsConfigException.
+ *
+ * @param message
+ * A string message detailing the problem
+ * @param ex
+ * The exception sent by the code
+ */
+ public NotAuthorizedException(String message, Throwable ex) {
+ super(message, ex);
+ }
+
+ /**
+ * This constructor can be used to create a new CldsConfigException. Use this
+ * constructor only if you are creating a new exception stack, not if an
+ * exception was already raised by another code.
+ *
+ * @param message
+ * A string message detailing the problem
+ */
+ public NotAuthorizedException(String message) {
+ super(message);
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java
new file mode 100644
index 000000000..b4a013eb4
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/cds/CdsParametersException.java
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ * ================================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.cds;
+
+/**
+ * Exception while parsing CDS response.
+ */
+public class CdsParametersException extends RuntimeException {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = 8425657297510362736L;
+
+ /**
+ * This constructor can be used to create a new CdsParametersException.
+ *
+ * @param message The message to dump
+ */
+ public CdsParametersException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new CdsParametersException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public CdsParametersException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java
new file mode 100644
index 000000000..78c2c6331
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/dcae/DcaeDeploymentException.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.dcae;
+
+/**
+ * New exception to capture DCAE communication errors.
+ *
+ */
+public class DcaeDeploymentException extends RuntimeException {
+
+ /**
+ * Generated ID.
+ */
+ private static final long serialVersionUID = 8452294782552680243L;
+
+ /**
+ * This constructor can be used to create a new DcaeDeploymentException.
+ *
+ * @param message
+ * A string message detailing the problem
+ * @param ex
+ * The exception sent by the code
+ */
+ public DcaeDeploymentException(String message, Throwable ex) {
+ super(message, ex);
+ }
+
+ /**
+ * This constructor can be used to create a new DcaeDeploymentException. Use
+ * this constructor only if you are creating a new exception stack, not if
+ * an exception was already raised by another code.
+ *
+ * @param message
+ * A string message detailing the problem
+ */
+ public DcaeDeploymentException(String message) {
+ super(message);
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java
new file mode 100644
index 000000000..6939fdf06
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/BlueprintParserException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception during blueprint parsing.
+ */
+public class BlueprintParserException extends Exception {
+
+ /**
+ * Serial ID.
+ */
+ private static final long serialVersionUID = -3044162346353623199L;
+
+ /**
+ * This constructor can be used to create a new SdcDownloadException.
+ *
+ * @param message The message to dump
+ */
+ public BlueprintParserException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new SdcDownloadException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public BlueprintParserException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java
new file mode 100644
index 000000000..e3f16f908
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/CsarHandlerException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception during Csar operations.
+ */
+public class CsarHandlerException extends Exception {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = -7628640776124409155L;
+
+ /**
+ * This constructor can be used to create a new CsarHandlerException.
+ *
+ * @param message The message to dump
+ */
+ public CsarHandlerException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new CsarHandlerException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public CsarHandlerException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java
new file mode 100644
index 000000000..1202ec199
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception during SDC artifact installation.
+ */
+public class SdcArtifactInstallerException extends Exception {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = 4095937499475915021L;
+
+ /**
+ * This constructor can be used to create a new SdcArtifactInstallerException.
+ *
+ * @param message The message to dump
+ */
+ public SdcArtifactInstallerException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new SdcArtifactInstallerException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public SdcArtifactInstallerException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java
new file mode 100644
index 000000000..e391ee7e8
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcControllerException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception of the SDC controller.
+ */
+public class SdcControllerException extends Exception {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = -4236006447255525130L;
+
+ /**
+ * This constructor can be used to create a new SdcControllerException.
+ *
+ * @param message The message to dump
+ */
+ public SdcControllerException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new SdcControllerException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public SdcControllerException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java
new file mode 100644
index 000000000..3c0240ef3
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcDownloadException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception during download from SDC.
+ */
+public class SdcDownloadException extends Exception {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = -5276848693231134901L;
+
+ /**
+ * This constructor can be used to create a new SdcDownloadException.
+ *
+ * @param message The message to dump
+ */
+ public SdcDownloadException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new SdcDownloadException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public SdcDownloadException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java
new file mode 100644
index 000000000..fe573882f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/exception/sdc/controller/SdcParametersException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.exception.sdc.controller;
+
+/**
+ * Exception of the SDC controller.
+ */
+public class SdcParametersException extends RuntimeException {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = 8425657297510362736L;
+
+ /**
+ * This constructor can be used to create a new SdcParametersException.
+ *
+ * @param message The message to dump
+ */
+ public SdcParametersException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new SdcParametersException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public SdcParametersException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java b/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java
new file mode 100644
index 000000000..6fa8ecb2b
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/filter/ClampCadiFilter.java
@@ -0,0 +1,190 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.filter;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.StandardCopyOption;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.filter.CadiFilter;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+
+public class ClampCadiFilter extends CadiFilter {
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampCadiFilter.class);
+
+ @Autowired
+ private ApplicationContext appContext;
+
+ @Value("${server.ssl.key-store:#{null}}")
+ private String keyStore;
+
+ @Value("${server.ssl.key-store-password:#{null}}")
+ private String keyStorePass;
+
+ @Value("${server.ssl.trust-store:#{null}}")
+ private String trustStore;
+
+ @Value("${server.ssl.trust-store-password:#{null}}")
+ private String trustStorePass;
+
+ @Value("${server.ssl.key-alias:clamp@clamp.onap.org}")
+ private String alias;
+
+ @Value("${clamp.config.keyFile:#{null}}")
+ private String keyFile;
+
+ @Value("${clamp.config.cadi.cadiLoglevel:#{null}}")
+ private String cadiLoglevel;
+
+ @Value("${clamp.config.cadi.cadiLatitude:#{null}}")
+ private String cadiLatitude;
+
+ @Value("${clamp.config.cadi.cadiLongitude:#{null}}")
+ private String cadiLongitude;
+
+ @Value("${clamp.config.cadi.aafLocateUrl:#{null}}")
+ private String aafLocateUrl;
+
+ @Value("${clamp.config.cadi.oauthTokenUrl:#{null}}")
+ private String oauthTokenUrl;
+
+ @Value("${clamp.config.cadi.oauthIntrospectUrl:#{null}}")
+ private String oauthIntrospectUrl;
+
+ @Value("${clamp.config.cadi.aafEnv:#{null}}")
+ private String aafEnv;
+
+ @Value("${clamp.config.cadi.aafUrl:#{null}}")
+ private String aafUrl;
+
+ @Value("${clamp.config.cadi.cadiX509Issuers:#{null}}")
+ private String cadiX509Issuers;
+
+ @Value("${clamp.config.caCerts:#{null}}")
+ private String caCertsPath;
+
+ private void checkIfNullProperty(String key, String value) {
+ /*
+ * When value is null, so not defined in application.properties set nothing in
+ * System properties
+ */
+ if (value != null) {
+ /*
+ * Ensure that any properties already defined in System.prop by JVM params won't
+ * be overwritten by Spring application.properties values
+ */
+ System.setProperty(key, System.getProperty(key, value));
+ }
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // set some properties in System so that Cadi filter will find its config
+ // The JVM values set will always overwrite the Spring ones.
+ checkIfNullProperty(Config.CADI_KEYFILE, convertSpringToPath(keyFile));
+ checkIfNullProperty(Config.CADI_LOGLEVEL, cadiLoglevel);
+ checkIfNullProperty(Config.CADI_LATITUDE, cadiLatitude);
+ checkIfNullProperty(Config.CADI_LONGITUDE, cadiLongitude);
+
+ checkIfNullProperty(Config.AAF_LOCATE_URL, aafLocateUrl);
+ checkIfNullProperty(Config.AAF_OAUTH2_TOKEN_URL, oauthTokenUrl);
+ checkIfNullProperty(Config.AAF_OAUTH2_INTROSPECT_URL, oauthIntrospectUrl);
+
+ checkIfNullProperty(Config.AAF_ENV, aafEnv);
+ checkIfNullProperty(Config.AAF_URL, aafUrl);
+ checkIfNullProperty(Config.CADI_X509_ISSUERS, cadiX509Issuers);
+ checkIfNullProperty(Config.CADI_KEYSTORE, convertSpringToPath(keyStore));
+ checkIfNullProperty(Config.CADI_TRUSTSTORE, convertSpringToPath(trustStore));
+ checkIfNullProperty(Config.CADI_ALIAS, alias);
+ checkIfNullProperty(Config.CADI_KEYSTORE_PASSWORD, keyStorePass);
+ checkIfNullProperty(Config.CADI_TRUSTSTORE_PASSWORD, trustStorePass);
+
+ super.init(filterConfig);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ try {
+ String certHeader = ((HttpServletRequest) request).getHeader("X-SSL-Cert");
+ if (certHeader != null) {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ X509Certificate cert = (X509Certificate) certificateFactory
+ .generateCertificate(new ByteArrayInputStream(
+ URLDecoder.decode(certHeader, StandardCharsets.UTF_8.toString()).getBytes()));
+ X509Certificate caCert = (X509Certificate) certificateFactory
+ .generateCertificate(new ByteArrayInputStream(
+ ResourceFileUtils.getResourceAsString(this.caCertsPath).getBytes()));
+
+ X509Certificate[] certifArray = ((X509Certificate[]) request
+ .getAttribute("javax.servlet.request.X509Certificate"));
+ if (certifArray == null) {
+ certifArray = new X509Certificate[] { cert, caCert };
+ request.setAttribute("javax.servlet.request.X509Certificate", certifArray);
+ } else {
+ certifArray[0] = cert;
+ certifArray[1] = caCert;
+ }
+ }
+
+ } catch (CertificateException e) {
+ logger.error("Unable to inject the X.509 certificate", e);
+ }
+ super.doFilter(request, response, chain);
+ }
+
+ private String convertSpringToPath(String fileName) {
+ try (InputStream ioFile = appContext.getResource(fileName).getInputStream()) {
+ if (!fileName.contains("file:")) {
+ File targetFile = new File(appContext.getResource(fileName).getFilename());
+ java.nio.file.Files.copy(ioFile, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ return targetFile.getPath();
+ } else {
+ return appContext.getResource(fileName).getFile().getPath();
+ }
+ } catch (IOException e) {
+ logger.error("Unable to open and copy the file: " + fileName, e);
+ return null;
+ }
+
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java
new file mode 100644
index 000000000..5708cb6ec
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/ClampInformation.java
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model;
+
+import com.google.gson.annotations.Expose;
+import java.util.ArrayList;
+import java.util.List;
+import org.onap.policy.clamp.clds.util.ClampVersioning;
+
+public class ClampInformation {
+ @Expose
+ private String userName;
+ @Expose
+ private String cldsVersion = ClampVersioning.getCldsVersionFromProps();
+ @Expose
+ List<String> allPermissions = new ArrayList<>();
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getCldsVersion() {
+ return cldsVersion;
+ }
+
+ public void setCldsVersion(String cldsVersion) {
+ this.cldsVersion = cldsVersion;
+ }
+
+ public List<String> getAllPermissions() {
+ return allPermissions;
+ }
+
+ public void setAllPermissions(List<String> allPermissions) {
+ this.allPermissions = allPermissions;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java
new file mode 100644
index 000000000..c814a628d
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/CldsHealthCheck.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model;
+
+import com.google.gson.annotations.Expose;
+
+public class CldsHealthCheck {
+ @Expose
+ private String healthCheckComponent;
+ @Expose
+ private String healthCheckStatus;
+ @Expose
+ private String description;
+
+ public String getHealthCheckComponent() {
+ return healthCheckComponent;
+ }
+
+ public void setHealthCheckComponent(String healthCheckComponent) {
+ this.healthCheckComponent = healthCheckComponent;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getHealthCheckStatus() {
+ return healthCheckStatus;
+ }
+
+ public void setHealthCheckStatus(String healthCheckStatus) {
+ this.healthCheckStatus = healthCheckStatus;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java
new file mode 100644
index 000000000..a3b42524e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ * ================================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.cds;
+
+import com.google.gson.annotations.Expose;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class maps the CDS response to a pojo.
+ */
+public class CdsBpWorkFlowListResponse {
+
+ @Expose
+ private String blueprintName;
+
+ @Expose
+ private String version;
+
+ @Expose
+ private List<String> workflows = new LinkedList<String>();
+
+ public String getBlueprintName() {
+ return blueprintName;
+ }
+
+ public void setBlueprintName(String blueprintName) {
+ this.blueprintName = blueprintName;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public List<String> getWorkflows() {
+ return workflows;
+ }
+
+ public void setWorkflows(List<String> workflows) {
+ this.workflows = workflows;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java
new file mode 100644
index 000000000..a69d1a353
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryCache.java
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class stores the multiple DcaeInventoryResponse coming back from DCAE.
+ * The structure is a map of list indexed by asdcServiceId. The list is sorted
+ * by asdcResourceId. Therefore it's possible to retrieve all the loops defined
+ * in the DCAE inventory and created by DCAE Mod.
+ */
+public class DcaeInventoryCache {
+
+ private static Map<String, Set<DcaeInventoryResponse>> blueprintsMap = new ConcurrentHashMap<>();
+
+ /**
+ * Add Dcae inventory response.
+ *
+ * @param inventoryResponse the Dcae inventory response
+ */
+ public void addDcaeInventoryResponse(DcaeInventoryResponse inventoryResponse) {
+ Set<DcaeInventoryResponse> responsesSet = blueprintsMap.get(inventoryResponse.getAsdcServiceId());
+ if (responsesSet == null) {
+ responsesSet = new TreeSet<>();
+ blueprintsMap.put(inventoryResponse.getAsdcServiceId(), responsesSet);
+ }
+ responsesSet.add(inventoryResponse);
+ }
+
+ public Set<String> getAllLoopIds() {
+ return this.blueprintsMap.keySet();
+ }
+
+ public Set<DcaeInventoryResponse> getAllBlueprintsPerLoopId(String loopId) {
+ return blueprintsMap.getOrDefault(loopId, new TreeSet<>());
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java
new file mode 100644
index 000000000..72ae61359
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponse.java
@@ -0,0 +1,102 @@
+
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import com.google.gson.annotations.Expose;
+
+/**
+ * This class maps the DCAE inventory answer to a nice pojo.
+ */
+public class DcaeInventoryResponse implements Comparable<DcaeInventoryResponse> {
+
+ @Expose
+ private String typeName;
+
+ @Expose
+ private String typeId;
+
+ @Expose
+ private String blueprintTemplate;
+
+ /**
+ * This field will be used to know all blueprints associated a loop.
+ */
+ @Expose
+ private String asdcServiceId;
+
+ /**
+ * This field will be used to know to order of each blueprint microservice in a
+ * loop.
+ */
+ @Expose
+ private String asdcResourceId;
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public String getTypeId() {
+ return typeId;
+ }
+
+ public void setTypeId(String typeId) {
+ this.typeId = typeId;
+ }
+
+ public String getBlueprintTemplate() {
+ return blueprintTemplate;
+ }
+
+ public void setBlueprintTemplate(String blueprintTemplate) {
+ this.blueprintTemplate = blueprintTemplate;
+ }
+
+ public String getAsdcServiceId() {
+ return asdcServiceId;
+ }
+
+ public void setAsdcServiceId(String asdcServiceId) {
+ this.asdcServiceId = asdcServiceId;
+ }
+
+ public String getAsdcResourceId() {
+ return asdcResourceId;
+ }
+
+ public void setAsdcResourceId(String asdcResourceId) {
+ this.asdcResourceId = asdcResourceId;
+ }
+
+ @Override
+ public int compareTo(DcaeInventoryResponse otherResponse) {
+ int thisResourceId = Integer.parseInt(this.asdcResourceId);
+ int otherResourceId = Integer.parseInt(otherResponse.getAsdcResourceId());
+ return (thisResourceId < otherResourceId ? -1 : (thisResourceId > otherResourceId ? 1 : 0));
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java
new file mode 100644
index 000000000..4d6e544da
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeLinks.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import com.google.gson.annotations.Expose;
+
+public class DcaeLinks {
+ @Expose
+ private String self;
+ @Expose
+ private String status;
+ @Expose
+ private String uninstall;
+
+ public String getSelf() {
+ return self;
+ }
+
+ public void setSelf(String self) {
+ this.self = self;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getUninstall() {
+ return uninstall;
+ }
+
+ public void setUninstall(String uninstall) {
+ this.uninstall = uninstall;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java
new file mode 100644
index 000000000..9389a51fc
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/model/dcae/DcaeOperationStatusResponse.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import com.google.gson.annotations.Expose;
+
+/**
+ * This class maps the DCAE deployment handler response to a nice pojo.
+ */
+public class DcaeOperationStatusResponse {
+
+ @Expose
+ private String operationType;
+
+ @Expose
+ private String status;
+
+ @Expose
+ private String requestId;
+
+ @Expose
+ private String error;
+
+ @Expose
+ private DcaeLinks links;
+
+ public String getOperationType() {
+ return operationType;
+ }
+
+ public void setOperationType(String operationType) {
+ this.operationType = operationType;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ public void setRequestId(String requestId) {
+ this.requestId = requestId;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+ public DcaeLinks getLinks() {
+ return links;
+ }
+
+ public void setLinks(DcaeLinks links) {
+ this.links = links;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java
new file mode 100644
index 000000000..ca46c6d31
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/DistributionStatusMessage.java
@@ -0,0 +1,84 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller;
+
+import org.onap.sdc.api.consumer.IDistributionStatusMessage;
+import org.onap.sdc.utils.DistributionStatusEnum;
+
+public class DistributionStatusMessage implements IDistributionStatusMessage {
+
+ private String artifactUrl;
+ private String consumerId;
+ private String distributionId;
+ private DistributionStatusEnum distributionStatus;
+ private long timestamp;
+
+ /**
+ * Distribution status message constructor.
+ *
+ * @param artifactUrl
+ * Url of specific SDC artifact(resource)
+ * @param consumerId
+ * Unique ID of SDC component instance
+ * @param distributionId
+ * Distribution ID published in the distribution notification.
+ * @param distributionStatusEnum
+ * Status to send in the message
+ * @param timestamp
+ * Timestamp of the message
+ */
+ public DistributionStatusMessage(final String artifactUrl, final String consumerId, final String distributionId,
+ final DistributionStatusEnum distributionStatusEnum, final long timestamp) {
+ this.artifactUrl = artifactUrl;
+ this.consumerId = consumerId;
+ this.distributionId = distributionId;
+ this.distributionStatus = distributionStatusEnum;
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public String getArtifactURL() {
+ return artifactUrl;
+ }
+
+ @Override
+ public String getConsumerID() {
+ return consumerId;
+ }
+
+ @Override
+ public String getDistributionID() {
+ return distributionId;
+ }
+
+ @Override
+ public DistributionStatusEnum getStatus() {
+ return distributionStatus;
+ }
+
+ @Override
+ public long getTimestamp() {
+ return timestamp;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java
new file mode 100644
index 000000000..39e64e46b
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleController.java
@@ -0,0 +1,438 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2018-2019, 2021 AT&T Intellectual Property. 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============================================
+ * Modifications copyright (c) 2018 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.security.SecureRandom;
+import java.util.Date;
+import java.util.Map.Entry;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.config.sdc.SdcSingleControllerConfiguration;
+import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcControllerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcDownloadException;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintArtifact;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.onap.policy.clamp.loop.CsarInstaller;
+import org.onap.sdc.api.IDistributionClient;
+import org.onap.sdc.api.consumer.IComponentDoneStatusMessage;
+import org.onap.sdc.api.consumer.IDistributionStatusMessage;
+import org.onap.sdc.api.consumer.INotificationCallback;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.results.IDistributionClientDownloadResult;
+import org.onap.sdc.api.results.IDistributionClientResult;
+import org.onap.sdc.impl.DistributionClientFactory;
+import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
+import org.onap.sdc.utils.DistributionActionResultEnum;
+import org.onap.sdc.utils.DistributionStatusEnum;
+
+/**
+ * This class handles one sdc controller defined in the config.
+ */
+public class SdcSingleController {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcSingleController.class);
+ private boolean isSdcClientAutoManaged = false;
+ private CsarInstaller csarInstaller;
+ private ClampProperties refProp;
+ /**
+ * The constant CONFIG_SDC_FOLDER.
+ */
+ public static final String CONFIG_SDC_FOLDER = "sdc.csarFolder";
+ private int nbOfNotificationsOngoing = 0;
+ private SdcSingleControllerStatus controllerStatus = SdcSingleControllerStatus.STOPPED;
+ private SdcSingleControllerConfiguration sdcConfig;
+ private IDistributionClient distributionClient;
+
+ /**
+ * Inner class for Notification callback.
+ */
+ private final class SdcNotificationCallBack implements INotificationCallback {
+
+ private SdcSingleController sdcController;
+
+ /**
+ * Instantiates a new Sdc notification call back.
+ *
+ * @param controller the controller
+ */
+ SdcNotificationCallBack(SdcSingleController controller) {
+ sdcController = controller;
+ }
+
+ /**
+ * This method can be called multiple times at the same moment. The controller
+ * must be thread safe !
+ */
+ @Override
+ public void activateCallback(INotificationData notificationData) {
+ Date startTime = new Date();
+ logger.info("Receive a callback notification in SDC, nb of resources: "
+ + notificationData.getResources().size());
+ sdcController.treatNotification(notificationData);
+ LoggingUtils.setTimeContext(startTime, new Date());
+ LoggingUtils.setResponseContext("0", "SDC Notification received and processed successfully",
+ this.getClass().getName());
+ }
+ }
+
+ /**
+ * Gets nb of notifications ongoing.
+ *
+ * @return the nb of notifications ongoing
+ */
+ public int getNbOfNotificationsOngoing() {
+ return nbOfNotificationsOngoing;
+ }
+
+ private void changeControllerStatusIdle() {
+ if (this.nbOfNotificationsOngoing > 1) {
+ --this.nbOfNotificationsOngoing;
+ } else {
+ this.nbOfNotificationsOngoing = 0;
+ this.controllerStatus = SdcSingleControllerStatus.IDLE;
+ }
+ }
+
+ /**
+ * Change controller status.
+ *
+ * @param newControllerStatus the new controller status
+ */
+ protected final synchronized void changeControllerStatus(SdcSingleControllerStatus newControllerStatus) {
+ switch (newControllerStatus) {
+ case BUSY:
+ ++this.nbOfNotificationsOngoing;
+ this.controllerStatus = newControllerStatus;
+ break;
+ case IDLE:
+ this.changeControllerStatusIdle();
+ break;
+ default:
+ this.controllerStatus = newControllerStatus;
+ break;
+ }
+ }
+
+ /**
+ * Gets controller status.
+ *
+ * @return the controller status
+ */
+ public final synchronized SdcSingleControllerStatus getControllerStatus() {
+ return this.controllerStatus;
+ }
+
+ /**
+ * Instantiates a new Sdc single controller.
+ *
+ * @param clampProp the clamp prop
+ * @param csarInstaller the csar installer
+ * @param sdcSingleConfig the sdc single config
+ * @param distributionClient the distribution client
+ */
+ public SdcSingleController(ClampProperties clampProp, CsarInstaller csarInstaller,
+ SdcSingleControllerConfiguration sdcSingleConfig,
+ IDistributionClient distributionClient) {
+ this.distributionClient = distributionClient;
+ isSdcClientAutoManaged = (distributionClient == null);
+ this.sdcConfig = sdcSingleConfig;
+ this.refProp = clampProp;
+ this.csarInstaller = csarInstaller;
+ }
+
+ /**
+ * This method initializes the SDC Controller and the SDC Client.
+ *
+ * @throws SdcControllerException It throws an exception if the SDC Client
+ * cannot be instantiated or if an init attempt
+ * is done when already initialized
+ */
+ public void initSdc() throws SdcControllerException {
+ logger.info("Attempt to initialize the SDC Controller: " + sdcConfig.getSdcControllerName());
+ if (this.getControllerStatus() != SdcSingleControllerStatus.STOPPED) {
+ throw new SdcControllerException("The controller is already initialized, call the closeSDC method first");
+ }
+ if (distributionClient == null) {
+ distributionClient = DistributionClientFactory.createDistributionClient();
+ }
+ IDistributionClientResult result = distributionClient.init(sdcConfig, new SdcNotificationCallBack(this));
+ if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
+ logger.error("SDC distribution client init failed with reason:" + result.getDistributionMessageResult());
+ this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);
+ throw new SdcControllerException("Initialization of the SDC Controller failed with reason: "
+ + result.getDistributionMessageResult());
+ }
+ logger.info("SDC Controller successfully initialized: " + sdcConfig.getSdcControllerName());
+ logger.info("Attempt to start the SDC Controller: " + sdcConfig.getSdcControllerName());
+ result = this.distributionClient.start();
+ if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) {
+ logger.error("SDC distribution client start failed with reason:" + result.getDistributionMessageResult());
+ this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);
+ throw new SdcControllerException(
+ "Startup of the SDC Controller failed with reason: " + result.getDistributionMessageResult());
+ }
+ logger.info("SDC Controller successfully started: " + sdcConfig.getSdcControllerName());
+ this.changeControllerStatus(SdcSingleControllerStatus.IDLE);
+ }
+
+ /**
+ * This method closes the SDC Controller and the SDC Client.
+ *
+ * @throws SdcControllerException It throws an exception if the SDC Client
+ * cannot be closed because it's currently BUSY
+ * in processing notifications.
+ */
+ public void closeSdc() throws SdcControllerException {
+ if (this.getControllerStatus() == SdcSingleControllerStatus.BUSY) {
+ throw new SdcControllerException("Cannot close the SDC controller as it's currently in BUSY state");
+ }
+ if (this.distributionClient != null) {
+ this.distributionClient.stop();
+ // If auto managed we can set it to Null, SdcController controls it.
+ // In the other case the client of this class has specified it, so
+ // we can't reset it
+ if (isSdcClientAutoManaged) {
+ // Next init will initialize it with a new SDC Client
+ this.distributionClient = null;
+ }
+ }
+ this.changeControllerStatus(SdcSingleControllerStatus.STOPPED);
+ }
+
+ private void sendAllNotificationForCsarHandler(INotificationData notificationData, CsarHandler csar,
+ NotificationType notificationType,
+ DistributionStatusEnum distributionStatus, String errorMessage) {
+ if (csar != null) {
+ // Notify for the CSAR
+ this.sendSdcNotification(notificationType, csar.getArtifactElement().getArtifactURL(),
+ sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus, errorMessage,
+ System.currentTimeMillis());
+ // Notify for all VF resources found
+ for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {
+ // Normally always 1 artifact in resource for Clamp as we
+ // specified
+ // only VF_METADATA type
+ this.sendSdcNotification(notificationType,
+ blueprint.getValue().getResourceAttached().getArtifacts().get(0).getArtifactURL(),
+ sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus,
+ errorMessage, System.currentTimeMillis());
+ }
+ } else {
+ this.sendSdcNotification(notificationType, null, sdcConfig.getConsumerID(),
+ notificationData.getDistributionID(), distributionStatus, errorMessage, System.currentTimeMillis());
+ }
+ }
+
+ /**
+ * This method processes the notification received from Sdc.
+ *
+ * @param notificationData The INotificationData
+ */
+ public void treatNotification(INotificationData notificationData) {
+ CsarHandler csar = null;
+ try {
+ // wait for a random time, so that 2 running Clamp will not treat
+ // the same Notification at the same time
+ Thread.sleep((new SecureRandom().nextInt(10) + 1) * 1000L);
+ logger.info("Notification received for service UUID:" + notificationData.getServiceUUID());
+ this.changeControllerStatus(SdcSingleControllerStatus.BUSY);
+ csar = new CsarHandler(notificationData, this.sdcConfig.getSdcControllerName(),
+ refProp.getStringValue(CONFIG_SDC_FOLDER));
+ csar.save(downloadTheArtifact(csar.getArtifactElement()));
+ if (csarInstaller.isCsarAlreadyDeployed(csar)) {
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD,
+ DistributionStatusEnum.ALREADY_DOWNLOADED, null);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.ALREADY_DEPLOYED, null);
+ } else {
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD,
+ DistributionStatusEnum.DOWNLOAD_OK, null);
+ csarInstaller.installTheCsar(csar);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.DEPLOY_OK, null);
+ }
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_OK, null);
+ } catch (SdcArtifactInstallerException | SdcToscaParserException e) {
+ logger.error("SdcArtifactInstallerException exception caught during the notification processing", e);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage());
+ } catch (SdcDownloadException | CsarHandlerException e) {
+ logger.error("SdcDownloadException exception caught during the notification processing", e);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD,
+ DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage());
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage());
+ } catch (InterruptedException e) {
+ logger.error("Interrupt exception caught during the notification processing", e);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage());
+ Thread.currentThread().interrupt();
+ } catch (BlueprintParserException e) {
+ logger.error("BlueprintParser exception caught during the notification processing", e);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage());
+ } catch (RuntimeException e) {
+ logger.error("Unexpected exception caught during the notification processing", e);
+ sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY,
+ DistributionStatusEnum.DEPLOY_ERROR, e.getMessage());
+ this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage());
+ } finally {
+ this.changeControllerStatus(SdcSingleControllerStatus.IDLE);
+ }
+ }
+
+ private enum NotificationType {
+ /**
+ * Download notification type.
+ */
+ DOWNLOAD,
+ /**
+ * Deploy notification type.
+ */
+ DEPLOY
+ }
+
+ private IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact) throws SdcDownloadException {
+ logger.info("Trying to download the artifact : " + artifact.getArtifactURL() + " UUID: "
+ + artifact.getArtifactUUID());
+ IDistributionClientDownloadResult downloadResult;
+ try {
+ downloadResult = distributionClient.download(artifact);
+ if (null == downloadResult) {
+ logger.info("downloadResult is Null for: " + artifact.getArtifactUUID());
+ return null;
+ }
+ } catch (RuntimeException e) {
+ throw new SdcDownloadException("Exception caught when downloading the artifact", e);
+ }
+ if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) {
+ logger.info("Successfully downloaded the artifact " + artifact.getArtifactURL() + " UUID "
+ + artifact.getArtifactUUID() + "Size of payload " + downloadResult.getArtifactPayload().length);
+ } else {
+ throw new SdcDownloadException("Artifact " + artifact.getArtifactName()
+ + " could not be downloaded from SDC URL " + artifact.getArtifactURL() + " UUID "
+ + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is "
+ + downloadResult.getDistributionMessageResult() + System.lineSeparator());
+ }
+ return downloadResult;
+ }
+
+ private void sendSdcNotification(NotificationType notificationType, String artifactUrl, String consumerId,
+ String distributionId, DistributionStatusEnum status, String errorReason,
+ long timestamp) {
+ String event = "Sending " + notificationType.name() + "(" + status.name() + ")"
+ + " notification to SDC for artifact:" + artifactUrl;
+ if (errorReason != null) {
+ event = event + "(" + errorReason + ")";
+ }
+ logger.info(event);
+ String action = "";
+ try {
+ IDistributionStatusMessage message = new DistributionStatusMessage(artifactUrl, consumerId, distributionId,
+ status, timestamp);
+ switch (notificationType) {
+ case DOWNLOAD:
+ this.sendDownloadStatus(message, errorReason);
+ action = "sendDownloadStatus";
+ break;
+ case DEPLOY:
+ this.sendDeploymentStatus(message, errorReason);
+ action = "sendDeploymentdStatus";
+ break;
+ default:
+ break;
+ }
+ } catch (RuntimeException e) {
+ logger.warn("Unable to send the SDC Notification (" + action + ") due to an exception", e);
+ }
+ logger.info("SDC Notification sent successfully(" + action + ")");
+ }
+
+ private void sendComponentStatus(INotificationData notificationData, DistributionStatusEnum status,
+ String errorReason) {
+ try {
+ IComponentDoneStatusMessage message = new IComponentDoneStatusMessage() {
+
+ @Override
+ public String getDistributionID() {
+ return notificationData.getDistributionID();
+ }
+
+ @Override
+ public String getConsumerID() {
+ return sdcConfig.getConsumerID();
+ }
+
+ @Override
+ public long getTimestamp() {
+ return System.currentTimeMillis();
+ }
+
+ @Override
+ public DistributionStatusEnum getStatus() {
+ return status;
+ }
+
+ @Override
+ public String getComponentName() {
+ return sdcConfig.getUser();
+ }
+ };
+
+ if (errorReason != null) {
+ this.distributionClient.sendComponentDoneStatus(message, errorReason);
+ } else {
+ this.distributionClient.sendComponentDoneStatus(message);
+ }
+ } catch (RuntimeException e) {
+ logger.warn("Unable to send the SDC Notification (" + status.name() + ") due to an exception", e);
+ }
+ logger.info("SDC Notification sent successfully(" + status.name() + ")");
+ }
+
+ private void sendDownloadStatus(IDistributionStatusMessage message, String errorReason) {
+ if (errorReason != null) {
+ this.distributionClient.sendDownloadStatus(message, errorReason);
+ } else {
+ this.distributionClient.sendDownloadStatus(message);
+ }
+ }
+
+ private void sendDeploymentStatus(IDistributionStatusMessage message, String errorReason) {
+ if (errorReason != null) {
+ this.distributionClient.sendDeploymentStatus(message, errorReason);
+ } else {
+ this.distributionClient.sendDeploymentStatus(message);
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java
new file mode 100644
index 000000000..fe269c486
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/SdcSingleControllerStatus.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller;
+
+public enum SdcSingleControllerStatus {
+ STOPPED, IDLE, BUSY
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java
new file mode 100644
index 000000000..df81cfb0c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintArtifact.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import org.onap.sdc.api.notification.IResourceInstance;
+
+/**
+ * This class is useful to store the information concerning
+ * blueprint artifact extracted from SDC CSAR.
+ */
+public class BlueprintArtifact {
+
+ private String dcaeBlueprint;
+ private String blueprintArtifactName;
+ private String blueprintInvariantServiceUuid;
+ private IResourceInstance resourceAttached;
+
+ public String getDcaeBlueprint() {
+ return dcaeBlueprint;
+ }
+
+ public void setDcaeBlueprint(String dcaeBlueprint) {
+ this.dcaeBlueprint = dcaeBlueprint;
+ }
+
+ public String getBlueprintArtifactName() {
+ return blueprintArtifactName;
+ }
+
+ public void setBlueprintArtifactName(String blueprintArtifactName) {
+ this.blueprintArtifactName = blueprintArtifactName;
+ }
+
+ public String getBlueprintInvariantServiceUuid() {
+ return blueprintInvariantServiceUuid;
+ }
+
+ public void setBlueprintInvariantServiceUuid(String blueprintInvariantServiceUuid) {
+ this.blueprintInvariantServiceUuid = blueprintInvariantServiceUuid;
+ }
+
+ public IResourceInstance getResourceAttached() {
+ return resourceAttached;
+ }
+
+ public void setResourceAttached(IResourceInstance resourceAttached) {
+ this.resourceAttached = resourceAttached;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java
new file mode 100644
index 000000000..519a24f46
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintMicroService.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. 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============================================
+ * Modifications copyright (c) 2019-2020 AT&T
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import java.util.Objects;
+
+public class BlueprintMicroService {
+ private final String name;
+ private final String modelType;
+ private final String inputFrom;
+ private final String modelVersion;
+
+ /**
+ * The Micro service constructor.
+ *
+ * @param name The name in String
+ * @param modelType The model type
+ * @param inputFrom Comes from (single chained)
+ */
+ public BlueprintMicroService(String name, String modelType, String inputFrom, String modelVersion) {
+ this.name = name;
+ this.inputFrom = inputFrom;
+ this.modelType = modelType;
+ this.modelVersion = modelVersion;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getModelType() {
+ return modelType;
+ }
+
+ public String getInputFrom() {
+ return inputFrom;
+ }
+
+ /**
+ * modelVerrsion getter.
+ *
+ * @return the modelVersion
+ */
+ public String getModelVersion() {
+ return modelVersion;
+ }
+
+ @Override
+ public String toString() {
+ return "MicroService {" + "name='" + name + '\'' + ", modelType='" + modelType + '\'' + ", inputFrom='"
+ + inputFrom + '\'' + ", modelVersion='" + modelVersion + '\'' + '}';
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ BlueprintMicroService that = (BlueprintMicroService) obj;
+ return name.equals(that.name) && modelType.equals(that.modelType) && inputFrom.equals(that.inputFrom)
+ && modelVersion.equals(that.modelVersion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, modelType, inputFrom, modelVersion);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java
new file mode 100644
index 000000000..ada47992a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParser.java
@@ -0,0 +1,220 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. 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============================================
+ * Modifications copyright (c) 2019 AT&T
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.json.JSONObject;
+import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException;
+import org.yaml.snakeyaml.Yaml;
+
+public class BlueprintParser {
+
+ static final String TCA = "TCA";
+ private static final String NODE_TEMPLATES = "node_templates";
+ private static final String DCAE_NODES = "dcae.nodes.";
+ private static final String DCAE_NODES_POLICY = ".nodes.policy";
+ private static final String TYPE = "type";
+ private static final String PROPERTIES = "properties";
+ private static final String NAME = "name";
+ private static final String INPUT = "inputs";
+ private static final String GET_INPUT = "get_input";
+ private static final String POLICY_MODEL_ID = "policy_model_id";
+ private static final String POLICY_MODEL_VERSION = "policy_model_version";
+ private static final String RELATIONSHIPS = "relationships";
+ private static final String CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM = "clamp_node.relationships.gets_input_from";
+ private static final String TARGET = "target";
+ public static final String DEFAULT_VERSION = "1.0.0";
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(BlueprintParser.class);
+
+ private BlueprintParser() {
+
+ }
+
+ /**
+ * Get all micro services from blueprint.
+ *
+ * @param blueprintString the blueprint in a String
+ * @return A set of MircoService
+ * @throws BlueprintParserException In case of issues with the parsing
+ */
+ public static Set<BlueprintMicroService> getMicroServices(String blueprintString) throws BlueprintParserException {
+ Set<BlueprintMicroService> microServices = new HashSet<>();
+ JsonObject blueprintJson = BlueprintParser.convertToJson(blueprintString);
+ JsonObject nodeTemplateList = blueprintJson.get(NODE_TEMPLATES).getAsJsonObject();
+ JsonObject inputList = blueprintJson.get(INPUT).getAsJsonObject();
+
+ for (Entry<String, JsonElement> entry : nodeTemplateList.entrySet()) {
+ JsonObject nodeTemplate = entry.getValue().getAsJsonObject();
+ if (!nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES_POLICY)
+ && nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES)) {
+ BlueprintMicroService microService = getNodeRepresentation(entry, nodeTemplateList, inputList);
+ if (!microService.getModelType().isBlank()) {
+ microServices.add(microService);
+ } else {
+ logger.warn("Microservice " + microService.getName()
+ + " will NOT be used by CLAMP as the model type is not defined or has not been found");
+ }
+ }
+ }
+ logger.debug("Those microservices have been found in the blueprint:" + microServices);
+ return microServices;
+ }
+
+ /**
+ * Does a fallback to TCA.
+ *
+ * @return The list of microservices
+ */
+ public static List<BlueprintMicroService> fallbackToOneMicroService() {
+ return Collections.singletonList(
+ new BlueprintMicroService(TCA, "onap.policies.monitoring.cdap.tca.hi.lo.app", "", DEFAULT_VERSION));
+ }
+
+ static String getName(Entry<String, JsonElement> entry) {
+ String microServiceYamlName = entry.getKey();
+ JsonObject ob = entry.getValue().getAsJsonObject();
+ if (ob.has(PROPERTIES)) {
+ JsonObject properties = ob.get(PROPERTIES).getAsJsonObject();
+ if (properties.has(NAME)) {
+ return properties.get(NAME).getAsString();
+ }
+ }
+ return microServiceYamlName;
+ }
+
+ static String getInput(Entry<String, JsonElement> entry) {
+ JsonObject ob = entry.getValue().getAsJsonObject();
+ if (ob.has(RELATIONSHIPS)) {
+ JsonArray relationships = ob.getAsJsonArray(RELATIONSHIPS);
+ for (JsonElement element : relationships) {
+ String target = getTarget(element.getAsJsonObject());
+ if (!target.isEmpty()) {
+ return target;
+ }
+ }
+ }
+ return "";
+ }
+
+ static String findPropertyInRelationshipsArray(String propertyName, JsonArray relationshipsArray,
+ JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException {
+ for (JsonElement elem : relationshipsArray) {
+ if (blueprintNodeTemplateList.get(elem.getAsJsonObject().get(TARGET).getAsString()) == null) {
+ throw new BlueprintParserException(
+ "The Target mentioned in the blueprint is not a known entry in the blueprint: "
+ + elem.getAsJsonObject().get(TARGET).getAsString());
+ } else {
+ String property = getPropertyValue(propertyName,
+ new AbstractMap.SimpleEntry<String, JsonElement>(
+ elem.getAsJsonObject().get(TARGET).getAsString(), blueprintNodeTemplateList
+ .get(elem.getAsJsonObject().get(TARGET).getAsString()).getAsJsonObject()),
+ blueprintNodeTemplateList, blueprintInputList);
+ if (!property.isEmpty()) {
+ return property;
+ }
+ }
+ }
+ return "";
+ }
+
+ static String getDirectOrInputPropertyValue(String propertyName, JsonObject blueprintInputList,
+ JsonObject nodeTemplateContent) {
+ JsonObject properties = nodeTemplateContent.get(PROPERTIES).getAsJsonObject();
+ if (properties.has(propertyName)) {
+ if (properties.get(propertyName).isJsonObject()) {
+ // it's a blueprint parameter
+ return blueprintInputList
+ .get(properties.get(propertyName).getAsJsonObject().get(GET_INPUT).getAsString())
+ .getAsJsonObject().get("default").getAsString();
+ } else {
+ // It's a direct value
+ return properties.get(propertyName).getAsString();
+ }
+ }
+ return "";
+ }
+
+ static String getPropertyValue(String propertyName, Entry<String, JsonElement> nodeTemplateEntry,
+ JsonObject blueprintNodeTemplateList, JsonObject blueprintIputList) throws BlueprintParserException {
+ JsonObject nodeTemplateContent = nodeTemplateEntry.getValue().getAsJsonObject();
+ // Search first in this node template
+ if (nodeTemplateContent.has(PROPERTIES)) {
+ String propValue = getDirectOrInputPropertyValue(propertyName, blueprintIputList, nodeTemplateContent);
+ if (!propValue.isBlank()) {
+ return propValue;
+ }
+ }
+ // Or it's may be defined in a relationship
+ if (nodeTemplateContent.has(RELATIONSHIPS)) {
+ return findPropertyInRelationshipsArray(propertyName,
+ nodeTemplateContent.get(RELATIONSHIPS).getAsJsonArray(), blueprintNodeTemplateList,
+ blueprintIputList);
+ }
+ return "";
+ }
+
+ static BlueprintMicroService getNodeRepresentation(Entry<String, JsonElement> nodeTemplateEntry,
+ JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException {
+ String modelIdFound = getPropertyValue(POLICY_MODEL_ID, nodeTemplateEntry, blueprintNodeTemplateList,
+ blueprintInputList);
+ String versionFound = getPropertyValue(POLICY_MODEL_VERSION, nodeTemplateEntry, blueprintNodeTemplateList,
+ blueprintInputList);
+ if (modelIdFound.isBlank()) {
+ logger.warn("policy_model_id is not defined for the node template:" + nodeTemplateEntry.getKey());
+ }
+ if (versionFound.isBlank()) {
+ logger.warn("policy_model_version is not defined (setting it to a default value) for the node template:"
+ + nodeTemplateEntry.getKey());
+ }
+ return new BlueprintMicroService(getName(nodeTemplateEntry), modelIdFound, getInput(nodeTemplateEntry),
+ !versionFound.isBlank() ? versionFound : DEFAULT_VERSION);
+ }
+
+ private static String getTarget(JsonObject elementObject) {
+ if (elementObject.has(TYPE) && elementObject.has(TARGET)
+ && elementObject.get(TYPE).getAsString().equals(CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM)) {
+ return elementObject.get(TARGET).getAsString();
+ }
+ return "";
+ }
+
+ private static JsonObject convertToJson(String yamlString) {
+ Map<String, Object> map = new Yaml().load(yamlString);
+ return new Gson().fromJson(new JSONObject(map).toString(), JsonObject.class);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java
new file mode 100644
index 000000000..10e7a56a4
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGenerator.java
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ChainGenerator {
+
+ ChainGenerator() {
+ }
+
+ /**
+ * Get list of microservices chain.
+ *
+ * @param input A set of microservices
+ * @return The list of microservice chained
+ */
+ public List<BlueprintMicroService> getChainOfMicroServices(Set<BlueprintMicroService> input) {
+ LinkedList<BlueprintMicroService> returnList = new LinkedList<>();
+ if (preValidate(input)) {
+ LinkedList<BlueprintMicroService> theList = new LinkedList<>();
+ for (BlueprintMicroService ms : input) {
+ insertNodeTemplateIntoChain(ms, theList);
+ }
+ if (postValidate(theList)) {
+ returnList = theList;
+ }
+ }
+ return returnList;
+ }
+
+ private boolean preValidate(Set<BlueprintMicroService> input) {
+ List<BlueprintMicroService> noInputs = input.stream().filter(ms -> "".equals(ms.getInputFrom()))
+ .collect(Collectors.toList());
+ return noInputs.size() == 1;
+ }
+
+ private boolean postValidate(LinkedList<BlueprintMicroService> microServices) {
+ for (int i = 1; i < microServices.size() - 1; i++) {
+ BlueprintMicroService prev = microServices.get(i - 1);
+ BlueprintMicroService current = microServices.get(i);
+ if (!current.getInputFrom().equals(prev.getName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void insertNodeTemplateIntoChain(BlueprintMicroService microServicetoInsert,
+ LinkedList<BlueprintMicroService> chainOfMicroServices) {
+ int insertIndex = 0;
+ for (int i = 0; i < chainOfMicroServices.size(); i++) {
+ BlueprintMicroService current = chainOfMicroServices.get(i);
+ if (microServicetoInsert.getName().equals(current.getInputFrom())) {
+ insertIndex = i;
+ break;
+ } else if (current.getName().equals(microServicetoInsert.getInputFrom())) {
+ insertIndex = i + 1;
+ break;
+ }
+ }
+ chainOfMicroServices.add(insertIndex, microServicetoInsert);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java
new file mode 100644
index 000000000..436e594ce
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandler.java
@@ -0,0 +1,219 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.apache.commons.io.IOUtils;
+import org.codehaus.plexus.util.StringUtils;
+import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.notification.IResourceInstance;
+import org.onap.sdc.api.results.IDistributionClientDownloadResult;
+import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
+import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
+import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory;
+
+/**
+ * CsarDescriptor that will be used to deploy file in CLAMP file system. Some
+ * methods can also be used to get some data from it.
+ */
+public class CsarHandler {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarHandler.class);
+ private IArtifactInfo artifactElement;
+ private String csarFilePath;
+ private String controllerName;
+ private SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance();
+ private ISdcCsarHelper sdcCsarHelper;
+ private Map<String, BlueprintArtifact> mapOfBlueprints = new HashMap<>();
+ public static final String CSAR_TYPE = "TOSCA_CSAR";
+ public static final String BLUEPRINT_TYPE = "DCAE_INVENTORY_BLUEPRINT";
+ private INotificationData sdcNotification;
+ public static final String RESOURCE_INSTANCE_NAME_PREFIX = "/Artifacts/Resources/";
+ public static final String RESOURCE_INSTANCE_NAME_SUFFIX = "/Deployment/";
+ public static final String POLICY_DEFINITION_NAME_SUFFIX = "Definitions/policies.yml";
+ public static final String DATA_DEFINITION_NAME_SUFFIX = "Definitions/data.yml";
+ public static final String DATA_DEFINITION_KEY = "data_types:";
+
+ /**
+ * Constructor for CsarHandler taking sdc notification in input.
+ */
+ public CsarHandler(INotificationData data, String controller, String clampCsarPath) throws CsarHandlerException {
+ this.sdcNotification = data;
+ this.controllerName = controller;
+ this.artifactElement = searchForUniqueCsar(data);
+ this.csarFilePath = buildFilePathForCsar(artifactElement, clampCsarPath);
+ }
+
+ private String buildFilePathForCsar(IArtifactInfo artifactElement, String clampCsarPath) {
+ return clampCsarPath + "/" + controllerName + "/" + artifactElement.getArtifactName();
+ }
+
+ private IArtifactInfo searchForUniqueCsar(INotificationData notificationData) throws CsarHandlerException {
+ List<IArtifactInfo> serviceArtifacts = notificationData.getServiceArtifacts();
+ for (IArtifactInfo artifact : serviceArtifacts) {
+ if (artifact.getArtifactType().equals(CSAR_TYPE)) {
+ return artifact;
+ }
+ }
+ throw new CsarHandlerException("Unable to find a CSAR in the Sdc Notification");
+ }
+
+ /**
+ * This saves the notification to disk and database.
+ *
+ * @param resultArtifact The artifact to install
+ * @throws SdcArtifactInstallerException In case of issues with the installation
+ * @throws SdcToscaParserException In case of issues with the parsing of
+ * the CSAR
+ */
+ public synchronized void save(IDistributionClientDownloadResult resultArtifact)
+ throws SdcArtifactInstallerException, SdcToscaParserException {
+ try {
+ logger.info("Writing CSAR file to: " + csarFilePath + " UUID " + artifactElement.getArtifactUUID() + ")");
+ Path path = Paths.get(csarFilePath);
+ Files.createDirectories(path.getParent());
+ // Create or replace the file
+ try (OutputStream out = Files.newOutputStream(path)) {
+ out.write(resultArtifact.getArtifactPayload(), 0, resultArtifact.getArtifactPayload().length);
+ }
+ sdcCsarHelper = factory.getSdcCsarHelper(csarFilePath);
+ this.loadDcaeBlueprint();
+ } catch (IOException e) {
+ throw new SdcArtifactInstallerException(
+ "Exception caught when trying to write the CSAR on the file system to " + csarFilePath, e);
+ }
+ }
+
+ private IResourceInstance searchForResourceByInstanceName(String blueprintResourceInstanceName)
+ throws SdcArtifactInstallerException {
+ for (IResourceInstance resource : this.sdcNotification.getResources()) {
+ String filteredString = resource.getResourceInstanceName().replaceAll("-", "");
+ filteredString = filteredString.replaceAll(" ", "");
+ if (filteredString.equalsIgnoreCase(blueprintResourceInstanceName)) {
+ return resource;
+ }
+ }
+ throw new SdcArtifactInstallerException("Error when searching for " + blueprintResourceInstanceName
+ + " as ResourceInstanceName in Sdc notification and did not find it");
+ }
+
+ private void loadDcaeBlueprint() throws IOException, SdcArtifactInstallerException {
+ try (ZipFile zipFile = new ZipFile(csarFilePath)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (!entry.isDirectory() && entry.getName().contains(BLUEPRINT_TYPE)) {
+ BlueprintArtifact blueprintArtifact = new BlueprintArtifact();
+ blueprintArtifact.setBlueprintArtifactName(
+ entry.getName().substring(entry.getName().lastIndexOf('/') + 1, entry.getName().length()));
+ blueprintArtifact
+ .setBlueprintInvariantServiceUuid(this.getSdcNotification().getServiceInvariantUUID());
+ try (InputStream stream = zipFile.getInputStream(entry)) {
+ blueprintArtifact.setDcaeBlueprint(IOUtils.toString(stream, StandardCharsets.UTF_8));
+ }
+ blueprintArtifact.setResourceAttached(searchForResourceByInstanceName(entry.getName().substring(
+ entry.getName().indexOf(RESOURCE_INSTANCE_NAME_PREFIX)
+ + RESOURCE_INSTANCE_NAME_PREFIX.length(),
+ entry.getName().indexOf(RESOURCE_INSTANCE_NAME_SUFFIX))));
+ this.mapOfBlueprints.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+ logger.info("Found a blueprint entry in the CSAR " + blueprintArtifact.getBlueprintArtifactName()
+ + " for resource instance Name "
+ + blueprintArtifact.getResourceAttached().getResourceInstanceName());
+ }
+ }
+ logger.info(this.mapOfBlueprints.size() + " blueprint(s) will be converted to closed loop");
+ }
+ }
+
+ public IArtifactInfo getArtifactElement() {
+ return artifactElement;
+ }
+
+ public String getFilePath() {
+ return csarFilePath;
+ }
+
+ public String setFilePath(String newPath) {
+ return csarFilePath = newPath;
+ }
+
+ public synchronized ISdcCsarHelper getSdcCsarHelper() {
+ return sdcCsarHelper;
+ }
+
+ public INotificationData getSdcNotification() {
+ return sdcNotification;
+ }
+
+ public Map<String, BlueprintArtifact> getMapOfBlueprints() {
+ return mapOfBlueprints;
+ }
+
+ /**
+ * Get the whole policy model Yaml. It combines the content of policies.yaml and
+ * data.yaml.
+ *
+ * @return The whole policy model yaml
+ * @throws IOException The IO Exception
+ */
+ public Optional<String> getPolicyModelYaml() throws IOException {
+ String result = null;
+ try (ZipFile zipFile = new ZipFile(csarFilePath)) {
+ ZipEntry entry = zipFile.getEntry(POLICY_DEFINITION_NAME_SUFFIX);
+ if (entry != null) {
+ ZipEntry data = zipFile.getEntry(DATA_DEFINITION_NAME_SUFFIX);
+ if (data != null) {
+ String dataStr = IOUtils.toString(zipFile.getInputStream(data), StandardCharsets.UTF_8);
+ String dataStrWithoutHeader = dataStr.substring(dataStr.indexOf(DATA_DEFINITION_KEY));
+ String policyStr = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8);
+ StringUtils.chomp(policyStr);
+ result = policyStr.concat(dataStrWithoutHeader);
+ } else {
+ result = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8);
+ }
+ } else {
+ logger.info("Policy model not found inside the CSAR file: " + csarFilePath);
+ }
+ return Optional.ofNullable(result);
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java b/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java
new file mode 100644
index 000000000..02481494a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/service/CldsHealthcheckService.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.clds.service;
+
+import java.util.Date;
+import org.onap.policy.clamp.clds.model.CldsHealthCheck;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.onap.policy.clamp.clds.util.OnapLogConstants;
+import org.onap.policy.clamp.loop.LoopController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.Level;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * Service to retrieve the Health Check of the clds application.
+ *
+ */
+@Component
+public class CldsHealthcheckService {
+
+ @Autowired
+ private LoopController loopController;
+
+ protected static final Logger logger = LoggerFactory.getLogger(CldsHealthcheckService.class);
+
+ /**
+ * REST service that retrieves clds healthcheck information.
+ *
+ * @return CldsHealthCheck class containing healthcheck info
+ */
+ public CldsHealthCheck gethealthcheck() {
+ CldsHealthCheck cldsHealthCheck = new CldsHealthCheck();
+ Date startTime = new Date();
+ LoggingUtils util = new LoggingUtils(logger);
+ LoggingUtils.setRequestContext("CldsService: GET healthcheck", "Clamp-Health-Check");
+ LoggingUtils.setTimeContext(startTime, new Date());
+ try {
+ loopController.getLoopNames();
+ cldsHealthCheck.setHealthCheckComponent("CLDS-APP");
+ cldsHealthCheck.setHealthCheckStatus("UP");
+ cldsHealthCheck.setDescription("OK");
+ LoggingUtils.setResponseContext("0", "Get healthcheck success",
+ this.getClass().getName());
+ util.exiting(HttpStatus.OK.value(), "Healthcheck success", Level.INFO,
+ OnapLogConstants.ResponseStatus.COMPLETE);
+ } catch (Exception e) {
+ logger.error("CLAMP application Heath check failed", e);
+ LoggingUtils.setResponseContext("999", "Get healthcheck failed",
+ this.getClass().getName());
+ cldsHealthCheck.setHealthCheckComponent("CLDS-APP");
+ cldsHealthCheck.setHealthCheckStatus("DOWN");
+ cldsHealthCheck.setDescription("NOT-OK");
+ util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Healthcheck failed", Level.INFO,
+ OnapLogConstants.ResponseStatus.ERROR);
+ }
+ return cldsHealthCheck;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java
new file mode 100644
index 000000000..32f328079
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/JsonEditorSchemaConstants.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018-2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca;
+
+public class JsonEditorSchemaConstants {
+
+ //Data types in JSON Schema
+ public static final String TYPE_OBJECT = "object";
+ public static final String TYPE_ARRAY = "array";
+ public static final String TYPE_MAP = "map";
+ public static final String TYPE_STRING = "string";
+ public static final String TYPE_INTEGER = "integer";
+ public static final String TYPE_DATE_TIME = "datetime";
+
+ //Key elements in JSON Schema
+ public static final String TYPE = "type";
+ public static final String TITLE = "title";
+ public static final String REQUIRED = "required";
+ public static final String DEFAULT = "default";
+ public static final String ENUM = "enum";
+ public static final String ENUM_TITLES = "enum_titles";
+ public static final String OPTIONS = "options";
+ public static final String FORMAT = "format";
+ public static final String ITEMS = "items";
+ public static final String PROPERTIES = "properties";
+ public static final String PROPERTY_ORDER = "propertyOrder";
+ public static final String VALUES = "values";
+ public static final String HEADER_TEMPLATE = "headerTemplate";
+ public static final String HEADER_TEMPLATE_VALUE = "{{self.name}}";
+
+ public static final String MINIMUM = "minimum";
+ public static final String MAXIMUM = "maximum";
+ public static final String MIN_LENGTH = "minLength";
+ public static final String MAX_LENGTH = "maxLength";
+ public static final String EXCLUSIVE_MINIMUM = "exclusiveMinimum";
+ public static final String EXCLUSIVE_MAXIMUM = "exclusiveMaximum";
+ public static final String MINITEMS = "minItems";
+ public static final String MAXITEMS = "maxItems";
+
+ public static final String CUSTOM_KEY_FORMAT = "format";
+ public static final String CUSTOM_KEY_FORMAT_TABS_TOP = "tabs-top";
+ public static final String CUSTOM_KEY_FORMAT_TABS = "tabs";
+ public static final String CUSTOM_KEY_FORMAT_INPUT = "input";
+ public static final String FORMAT_SELECT = "select";
+ public static final String UNIQUE_ITEMS = "uniqueItems";
+ public static final String TRUE = "true";
+ public static final String QSSCHEMA = "qschema";
+ public static final String TYPE_QBLDR = "qbldr";
+
+ public static final String ID = "id";
+ public static final String LABEL = "label";
+ public static final String OPERATORS = "operators";
+ public static final String FILTERS = "filters";
+
+ public static final String SCHEMA = "schema";
+ public static final String CURRENT_VALUES = "currentValues";
+
+ public static final String PLUGIN = "plugin";
+ public static final String DATE_TIME_PICKER = "datetimepicker";
+ public static final String VALIDATION = "validation";
+ public static final String DATE_TIME_FORMAT = "YYYY/MM/DD HH:mm:ss";
+ public static final String INPUT_EVENT = "input_event";
+ public static final String DP_CHANGE = "dp.change";
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java
new file mode 100644
index 000000000..c2b5d5963
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/ToscaSchemaConstants.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca;
+
+public class ToscaSchemaConstants {
+
+ // Data types in TOSCA Schema
+ public static final String TYPE_LIST = "list";
+ public static final String TYPE_MAP = "map";
+ public static final String TYPE_STRING = "string";
+ public static final String TYPE_INTEGER = "integer";
+ public static final String TYPE_NUMBER = "number";
+ public static final String TYPE_DATE_TIME = "datetime";
+ public static final String TYPE_FLOAT = "float";
+ public static final String TYPE_BOOLEAN = "boolean";
+ public static final String TYPE_USER_DEFINED = "userDefined";
+
+ // Key elements in Tosca
+ public static final String NODE_TYPES = "policy_types";
+ public static final String DATA_TYPES = "data_types";
+ public static final String TYPE = "type";
+ public static final String DESCRIPTION = "description";
+ public static final String DEFAULT = "default";
+ public static final String PROPERTIES = "properties";
+ public static final String REQUIRED = "required";
+ public static final String ENTRY_SCHEMA = "entry_schema";
+
+ public static final String METADATA = "metadata";
+ public static final String METADATA_POLICY_MODEL_TYPE = "policy_model_type";
+ public static final String METADATA_ACRONYM = "acronym";
+ public static final String METADATA_ELEMENT_NAME = "element_name";
+ public static final String METADATA_HEADER_TEMPLATE = "header_template";
+ public static final String METADATA_CLAMP_POSSIBLE_VALUES = "clamp_possible_values";
+
+ // Constraints
+ public static final String CONSTRAINTS = "constraints";
+ public static final String VALID_VALUES = "valid_values";
+ public static final String EQUAL = "equal";
+ public static final String GREATER_THAN = "greater_than";
+ public static final String GREATER_OR_EQUAL = "greater_or_equal";
+ public static final String LESS_THAN = "less_than";
+ public static final String LESS_OR_EQUAL = "less_or_equal";
+ public static final String IN_RANGE = "in_range";
+ public static final String LENGTH = "length";
+ public static final String MIN_LENGTH = "min_length";
+ public static final String MAX_LENGTH = "max_length";
+ public static final String PATTERN = "pattern";
+
+ // Prefix for policy nodes
+ public static final String POLICY_NODE = "onap.policies.";
+
+ // Prefix for data nodes
+ public static final String POLICY_DATA = "onap.datatypes.";
+
+ // Prefix for dictionary elements
+ public static final String DICTIONARY = "Dictionary:";
+
+ // Custom Elements that must exist in the Tosca models
+ public static final String NAME = "name";
+ public static final String CONTEXT = "context";
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java
new file mode 100644
index 000000000..6702a6200
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser;
+import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParserWithDictionarySupport;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.service.Service;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This is the main class that must be used to convert a tosca to a json schema.
+ * This class adds feature to support the dictionary mechanism that enables json possible values extracted
+ * from the dictionary DB table.
+ *
+ * @see org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport#convertToscaToJsonSchemaObject
+ */
+@Component
+public class ToscaConverterWithDictionarySupport {
+
+ private static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(ToscaConverterWithDictionarySupport.class);
+
+ private ClampProperties clampProperties;
+ private ToscaMetadataParser metadataParser;
+
+ /**
+ * Constructor with Spring support.
+ *
+ * @param clampProperties Clamp Spring properties
+ * @param metadataParser Metadata parser
+ */
+ @Autowired
+ public ToscaConverterWithDictionarySupport(ClampProperties clampProperties,
+ ToscaMetadataParserWithDictionarySupport metadataParser) {
+ this.clampProperties = clampProperties;
+ this.metadataParser = metadataParser;
+ }
+
+ /**
+ * This method converts a tosca file to a json schema.
+ * It uses some parameters specified in the application.properties.
+ *
+ * @param toscaFile The tosca file as String
+ * @param policyTypeToDecode The policy type to decode
+ * @param serviceModel The service model associated so that the clamp enrichment could be done if required by
+ * the tosca model
+ * @return A json object being a json schema
+ */
+ public JsonObject convertToscaToJsonSchemaObject(String toscaFile, String policyTypeToDecode,
+ Service serviceModel) {
+ try {
+ return new JsonTemplateManager(toscaFile,
+ clampProperties.getFileContent("tosca.converter.default.datatypes"),
+ clampProperties.getFileContent("tosca.converter.json.schema.templates"))
+ .getJsonSchemaForPolicyType(policyTypeToDecode, Boolean.parseBoolean(clampProperties.getStringValue(
+ "tosca.converter.dictionary.support.enabled")) ? metadataParser : null, serviceModel);
+ } catch (IOException | UnknownComponentException e) {
+ logger.error("Unable to convert the tosca properly, exception caught during the decoding",
+ e);
+ return new JsonObject();
+ }
+ }
+
+ /**
+ * This method converts a tosca file to a json schema.
+ * It uses some parameters specified in the application.properties.
+ *
+ * @param toscaFile The tosca file as String
+ * @param policyTypeToDecode The policy type to decode
+ * @param serviceModel The service Model so that clamp enrichment could be done if required by tosca model
+ * @return A String containing the json schema
+ */
+ public String convertToscaToJsonSchemaString(String toscaFile, String policyTypeToDecode, Service serviceModel) {
+ return JsonUtils.GSON.toJson(this.convertToscaToJsonSchemaObject(toscaFile, policyTypeToDecode, serviceModel));
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java
new file mode 100644
index 000000000..fb684b57b
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/UnknownComponentException.java
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+public class UnknownComponentException extends Exception {
+ public UnknownComponentException(String nameEntry) {
+ this.getWrongName(nameEntry);
+ }
+
+ public String getWrongName(String nameEntry) {
+ return "Unknown Component: " + nameEntry;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java
new file mode 100644
index 000000000..fb9d66752
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ArrayField.java
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.elements;
+
+import com.google.gson.JsonArray;
+import java.util.ArrayList;
+
+public class ArrayField {
+
+ private ArrayList<Object> complexFields;
+
+ /**
+ * Constructor from arraryList.
+ *
+ * @param arrayProperties the array properties
+ */
+ public ArrayField(ArrayList<Object> arrayProperties) {
+ this.complexFields = arrayProperties;
+ }
+
+ /**
+ * Each LinkedHashMap is parsed to extract the Array and each of its value. They are casted for the JsonObject.
+ *
+ * @return JsonArray
+ */
+ public JsonArray deploy() {
+
+ JsonArray subPropertyValuesArray = new JsonArray();
+ for (Object arrayElement : complexFields) {
+ //Cast for each Primitive Type
+ String typeValue = arrayElement.getClass().getSimpleName();
+ switch (typeValue) {
+ case "String":
+ subPropertyValuesArray.add((String) arrayElement);
+ break;
+ case "Boolean":
+ subPropertyValuesArray.add((Boolean) arrayElement);
+ break;
+ case "Double":
+ subPropertyValuesArray.add((Number) arrayElement);
+ break;
+ case "Integer":
+ subPropertyValuesArray.add((Number) arrayElement);
+ break;
+ default:
+ break;
+ }
+ }
+ return subPropertyValuesArray;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java
new file mode 100644
index 000000000..651456ca6
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/Constraint.java
@@ -0,0 +1,222 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.elements;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+
+public class Constraint {
+
+ private LinkedHashMap<String, Object> constraints;
+ private JsonTemplate jsonTemplate;
+
+ public Constraint(LinkedHashMap<String, Object> constraints, JsonTemplate jsonTemplate) {
+ this.jsonTemplate = jsonTemplate;
+ this.constraints = constraints;
+ }
+
+ /**
+ * Deploy the linkedhashmap which contains the constraints, to extract them one to one.
+ *
+ * @param jsonSchema The json Schema
+ * @param typeProperty The ype property
+ * @return the json object
+ */
+ public JsonObject deployConstraints(JsonObject jsonSchema, String typeProperty) {
+ for (Entry<String, Object> constraint : constraints.entrySet()) {
+ this.parseConstraint(jsonSchema, constraint.getKey(), constraint.getValue(), typeProperty);
+ }
+ return jsonSchema;
+ }
+
+ /**
+ * Each case of Tosca constraints below parse specifically the field in the JsonObject.
+ *
+ * @param jsonSchema Json Schema
+ * @param nameConstraint Name constraint
+ * @param valueConstraint value constraint
+ * @param typeProperty Type Property
+ */
+ @SuppressWarnings("unchecked")
+ public void parseConstraint(JsonObject jsonSchema, String nameConstraint, Object valueConstraint,
+ String typeProperty) {
+ switch (nameConstraint) {
+ case "equal":
+ checkTemplateField("const", jsonSchema, valueConstraint);
+ break;
+ case "greater_than":
+ checkTemplateField("exclusiveMinimum", jsonSchema, valueConstraint);
+ break;
+ case "greater_or_equal":
+ checkTemplateField("minimum", jsonSchema, valueConstraint);
+ break;
+ case "less_than":
+ checkTemplateField("exclusiveMaximum", jsonSchema, valueConstraint);
+ break;
+ case "less_or_equal":
+ checkTemplateField("maximum", jsonSchema, valueConstraint);
+ break;
+ case "in_range":
+ ArrayList<Integer> limitValues = (ArrayList<Integer>) valueConstraint;
+ checkTemplateField("minimum", jsonSchema, limitValues.get(0));
+ checkTemplateField("maximum", jsonSchema, limitValues.get(1));
+ break;
+ case "pattern":
+ jsonSchema.addProperty(nameConstraint, (String) valueConstraint);
+ break;
+ case "length":
+ this.getSpecificLength(jsonSchema, valueConstraint, typeProperty);
+ break;
+ case "min_length":
+ String[] prefixValues = nameConstraint.split("_");
+ this.getLimitValue(jsonSchema, valueConstraint, typeProperty, prefixValues[0]);
+ break;
+ case "max_length":
+ String[] maxtab = nameConstraint.split("_");
+ this.getLimitValue(jsonSchema, valueConstraint, typeProperty, maxtab[0]);
+ break;
+ default://valid_value
+ this.getValueArray(jsonSchema, valueConstraint, typeProperty);
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema json schema
+ * @param fieldValue field value
+ * @param typeProperty For the complex components, get a specific number of items/properties
+ */
+ public void getSpecificLength(JsonObject jsonSchema, Object fieldValue, String typeProperty) {
+ switch (typeProperty.toLowerCase()) {
+ case "string":
+ checkTemplateField("minLength", jsonSchema, fieldValue);
+ checkTemplateField("maxLength", jsonSchema, fieldValue);
+ break;
+ case "array":
+ if (fieldValue.equals(1) && jsonTemplate.hasFields("uniqueItems")) {
+ jsonSchema.addProperty("uniqueItems", true);
+ } else {
+ checkTemplateField("minItems", jsonSchema, fieldValue);
+ checkTemplateField("maxItems", jsonSchema, fieldValue);
+ }
+ break;
+ default:// Map && List
+ checkTemplateField("minProperties", jsonSchema, fieldValue);
+ checkTemplateField("maxProperties", jsonSchema, fieldValue);
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema json schema
+ * @param fieldValue field value
+ * @param typeProperty type property
+ * @param side Get the limits fieldValue for the properties : depend of the type of the component
+ */
+ public void getLimitValue(JsonObject jsonSchema, Object fieldValue, String typeProperty, String side) {
+ switch (typeProperty) {
+ case "string":
+ if (side.equals("min")) {
+ checkTemplateField("minLength", jsonSchema, fieldValue);
+ } else {
+ checkTemplateField("maxLength", jsonSchema, fieldValue);
+ }
+ break;
+ default:// Array
+ if (side.equals("min")) {
+ checkTemplateField("minItems", jsonSchema, fieldValue);
+ } else {
+ checkTemplateField("maxItems", jsonSchema, fieldValue);
+ }
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema Json schema
+ * @param fieldValue field value
+ * @param typeProperty Get as Enum the valid values for the property
+ */
+ public void getValueArray(JsonObject jsonSchema, Object fieldValue, String typeProperty) {
+ if (jsonTemplate.hasFields("enum")) {
+ JsonArray enumeration = new JsonArray();
+ if (typeProperty.equals("string") || typeProperty.equals("String")) {
+ ArrayList<String> arrayValues = (ArrayList<String>) fieldValue;
+ for (String arrayItem : arrayValues) {
+ enumeration.add(arrayItem);
+ }
+ jsonSchema.add("enum", enumeration);
+ } else {
+ ArrayList<Number> arrayValues = (ArrayList<Number>) fieldValue;
+ for (Number arrayItem : arrayValues) {
+ enumeration.add(arrayItem);
+ }
+ jsonSchema.add("enum", enumeration);
+ }
+ }
+ }
+
+ /**
+ * To be done.
+ *
+ * @param field Field
+ * @param jsonSchema Json schema
+ * @param fieldValue Simple way to avoid code duplication
+ */
+ public void checkTemplateField(String field, JsonObject jsonSchema, Object fieldValue) {
+ if (jsonTemplate.hasFields(field)) {
+ String typeField = fieldValue.getClass().getSimpleName();
+ switch (typeField) {
+ case "String":
+ jsonSchema.addProperty(field, (String) fieldValue);
+ break;
+ case "Integer":
+ jsonSchema.addProperty(field, (Integer) fieldValue);
+ break;
+ case "Number":
+ jsonSchema.addProperty(field, (Number) fieldValue);
+ break;
+ case "Boolean":
+ jsonSchema.addProperty(field, (Boolean) fieldValue);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java
new file mode 100644
index 000000000..0c531e9d0
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElement.java
@@ -0,0 +1,121 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.elements;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+public class ToscaElement {
+
+ /**
+ * name parameter is used as "key", in the LinkedHashMap of Components.
+ */
+ private String name;
+ private String derivedFrom;
+ private String version;
+ private String typeVersion;
+ private String description;
+ private LinkedHashMap<String, ToscaElementProperty> properties;
+
+ public ToscaElement() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name name
+ * @param derivedFrom derivedFrom
+ * @param description description
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public ToscaElement(String name, String derivedFrom, String description) {
+ super();
+ this.name = name;
+ this.derivedFrom = derivedFrom;
+ this.description = description;
+ this.properties = new LinkedHashMap();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDerivedFrom() {
+ return derivedFrom;
+ }
+
+ public void setDerivedFrom(String derivedFrom) {
+ this.derivedFrom = derivedFrom;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getTypeVersion() {
+ return typeVersion;
+ }
+
+ public void setTypeVersion(String typeVersion) {
+ this.typeVersion = typeVersion;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public LinkedHashMap<String, ToscaElementProperty> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(LinkedHashMap<String, ToscaElementProperty> properties) {
+ this.properties = properties;
+ }
+
+ public void addProperties(ToscaElementProperty toscaElementProperty) {
+ this.properties.put(toscaElementProperty.getName(), toscaElementProperty);
+ }
+
+ public ArrayList<String> propertiesNames() {
+ return new ArrayList<>(properties.keySet());
+ }
+
+ @Override
+ public String toString() {
+ return name + ": " + description + ", version: " + version + ", nb de properties: " + properties.size()
+ + System.getProperty("line.separator") + propertiesNames();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java
new file mode 100644
index 000000000..4db8b0356
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/elements/ToscaElementProperty.java
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.elements;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+
+public class ToscaElementProperty {
+
+ /**
+ * name parameter is used as "key", in the LinkedHashMap of Components.
+ */
+ private String name;
+ private LinkedHashMap<String, Object> items;
+
+ /**
+ * Constructor.
+ *
+ * @param name the name
+ * @param items the items
+ */
+ public ToscaElementProperty(String name, LinkedHashMap<String, Object> items) {
+ super();
+ this.name = name;
+ this.items = items;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public LinkedHashMap<String, Object> getItems() {
+ return items;
+ }
+
+ public void setItems(LinkedHashMap<String, Object> items) {
+ this.items = items;
+ }
+
+ /**
+ * For each primitive value, requires to get each field Value and cast it and add it in a Json.
+ *
+ * @param fieldsContent field
+ * @param fieldName field
+ * @param value value
+ */
+ public void addFieldToJson(JsonObject fieldsContent, String fieldName, Object value) {
+ if (value != null) {
+ String typeValue = value.getClass().getSimpleName();
+ switch (typeValue) {
+ case "String":
+ fieldsContent.addProperty(fieldName, (String) value);
+ break;
+ case "Boolean":
+ fieldsContent.addProperty(fieldName, (Boolean) value);
+ break;
+ case "Double":
+ fieldsContent.addProperty(fieldName, (Number) value);
+ break;
+ case "Integer":
+ fieldsContent.addProperty(fieldName, (Integer) value);
+ break;
+ default:
+ fieldsContent.add(fieldName, parseArray((ArrayList) value));
+ break;
+ }
+ }
+ }
+
+ /**
+ * If a field value is an Array, create an Instance of ArrayField to insert if in the JsonObject.
+ *
+ * @param arrayProperties array pro
+ * @return a json array
+ */
+ public JsonArray parseArray(ArrayList<Object> arrayProperties) {
+ JsonArray arrayContent = new JsonArray();
+ ArrayList<Object> arrayComponent = new ArrayList<>();
+ for (Object itemArray : arrayProperties) {
+ arrayComponent.add(itemArray);
+ }
+ ArrayField af = new ArrayField(arrayComponent);
+ arrayContent = af.deploy();
+ return arrayContent;
+ }
+
+ /**
+ * Create an instance of Constraint, to extract the values and add it to the Json (according to the type
+ * * of the current property).
+ *
+ * @param json a json
+ * @param constraints constraints
+ * @param jsonTemplate template
+ */
+ @SuppressWarnings("unchecked")
+ public void addConstraintsAsJson(JsonObject json, ArrayList<Object> constraints, JsonTemplate jsonTemplate) {
+ for (Object constraint : constraints) {
+ if (constraint instanceof LinkedHashMap) {
+ LinkedHashMap<String, Object> valueConstraint = (LinkedHashMap<String, Object>) constraint;
+ Constraint constraintParser = new Constraint(valueConstraint, jsonTemplate);
+ constraintParser.deployConstraints(json, (String) getItems().get("type"));
+ }
+ }
+
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java
new file mode 100644
index 000000000..5fac9a213
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.execution;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import org.onap.policy.clamp.clds.tosca.update.execution.cds.ToscaMetadataCdsProcess;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.tosca.DictionaryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class is used to execute a code based on a key found in the metadata section.
+ */
+@Component
+public class ToscaMetadataExecutor {
+
+ private static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(ToscaMetadataExecutor.class);
+
+ @Autowired
+ private DictionaryService dictionaryService;
+
+ private Map<String, ToscaMetadataProcess> mapOfProcesses = new HashMap<>();
+
+ /**
+ * This method executes the required process specified in processInfo.
+ *
+ * @param processInfo A String containing the process to execute, like "cds/param1:value1/param2:value2"
+ * @param childObject The jsonObject
+ * @param serviceModel The service model associated to do clamp enrichment
+ */
+ public void executeTheProcess(String processInfo, JsonObject childObject, Service serviceModel) {
+ String[] processParameters = (processInfo + "/ ").split("/");
+ logger.info("Executing the Tosca clamp process " + processParameters[0] + " with parameters "
+ + processParameters[1].trim());
+ mapOfProcesses.get(processParameters[0].trim())
+ .executeProcess(processParameters[1].trim(), childObject, serviceModel);
+ }
+
+ /**
+ * Init method.
+ */
+ @PostConstruct
+ public void init() {
+ mapOfProcesses.put("CDS", new ToscaMetadataCdsProcess());
+ mapOfProcesses.put("CSAR_RESOURCES", new ToscaMetadataTargetProcess());
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java
new file mode 100644
index 000000000..a1275229d
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.execution;
+
+import com.google.gson.JsonObject;
+import org.onap.policy.clamp.loop.service.Service;
+
+/**
+ * This code is the interface that must be implemented to have a tosca process.
+ */
+public abstract class ToscaMetadataProcess {
+
+ /**
+ * This method add some elements to the JsonObject childObject passed in argument.
+ * The process can take multiple parameters in arguments.
+ *
+ * @param parameters The parameters required by the process
+ * @param childObject The Json Object modified by the current process
+ * @param serviceModel The service model associated to do clamp enrichment
+ */
+ public abstract void executeProcess(String parameters, JsonObject childObject, Service serviceModel);
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java
new file mode 100644
index 000000000..0ffd86f47
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/ToscaMetadataTargetProcess.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.execution;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyRepresentationBuilder;
+
+/**
+ * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model.
+ */
+public class ToscaMetadataTargetProcess extends ToscaMetadataProcess {
+
+
+ private static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(ToscaMetadataTargetProcess.class);
+
+ @Override
+ public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) {
+ if (serviceModel == null) {
+ logger.info("serviceModel is null, therefore the ToscaMetadataTargetProcess is skipped");
+ return;
+ }
+ childObject.add("anyOf", OperationalPolicyRepresentationBuilder.createAnyOfArray(serviceModel, false));
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java
new file mode 100644
index 000000000..c80c91170
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java
@@ -0,0 +1,229 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.execution.cds;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.Map;
+import java.util.Set;
+import org.onap.policy.clamp.clds.tosca.ToscaSchemaConstants;
+import org.onap.policy.clamp.clds.tosca.update.execution.ToscaMetadataProcess;
+import org.onap.policy.clamp.loop.service.Service;
+
+
+/**
+ * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model.
+ */
+public class ToscaMetadataCdsProcess extends ToscaMetadataProcess {
+
+ private static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(ToscaMetadataCdsProcess.class);
+
+ @Override
+ public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) {
+ if (serviceModel == null) {
+ logger.info("serviceModel is null, therefore the ToscaMetadataCdsProcess is skipped");
+ return;
+ }
+ switch (parameters) {
+ case "actor":
+ JsonArray jsonArray = new JsonArray();
+ jsonArray.add("CDS");
+ addToJsonArray(childObject, "enum", jsonArray);
+ break;
+ case "payload":
+ generatePayload(childObject, serviceModel);
+ break;
+ case "operation":
+ generateOperation(childObject, serviceModel);
+ break;
+ default:
+ }
+ }
+
+ private static void generatePayload(JsonObject childObject, Service serviceModel) {
+ JsonArray schemaAnyOf = new JsonArray();
+ schemaAnyOf.addAll(createBlankEntry());
+ schemaAnyOf.addAll(generatePayloadPerResource("VF", serviceModel));
+ schemaAnyOf.addAll(generatePayloadPerResource("PNF", serviceModel));
+ addToJsonArray(childObject, "anyOf", schemaAnyOf);
+ }
+
+ private static void generateOperation(JsonObject childObject, Service serviceModel) {
+ generateOperationPerResource(childObject, "VF", serviceModel);
+ generateOperationPerResource(childObject, "PNF", serviceModel);
+ }
+
+ private static void generateOperationPerResource(JsonObject childObject, String resourceName,
+ Service serviceModel) {
+ JsonArray schemaEnum = new JsonArray();
+ JsonArray schemaTitle = new JsonArray();
+ for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName)
+ .entrySet()) {
+ JsonObject controllerProperties = entry.getValue().getAsJsonObject()
+ .getAsJsonObject("controllerProperties");
+ if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) {
+ for (String workflowsEntry : controllerProperties.getAsJsonObject("workflows").keySet()) {
+ schemaEnum.add(workflowsEntry);
+ schemaTitle.add(workflowsEntry + " (CDS operation)");
+ }
+ }
+ }
+ addToJsonArray(childObject, "enum", schemaEnum);
+ if (childObject.get("options") == null) {
+ JsonObject optionsSection = new JsonObject();
+ childObject.add("options", optionsSection);
+ }
+ addToJsonArray(childObject.getAsJsonObject("options"), "enum_titles", schemaTitle);
+
+ }
+
+ private static JsonArray generatePayloadPerResource(String resourceName,
+ Service serviceModel) {
+ JsonArray schemaAnyOf = new JsonArray();
+
+ for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName)
+ .entrySet()) {
+ JsonObject controllerProperties = entry.getValue().getAsJsonObject()
+ .getAsJsonObject("controllerProperties");
+ if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) {
+ for (Map.Entry<String, JsonElement> workflowsEntry : controllerProperties.getAsJsonObject("workflows")
+ .entrySet()) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty("title", workflowsEntry.getKey());
+ obj.add("properties",
+ createInputPropertiesForPayload(workflowsEntry.getValue().getAsJsonObject(),
+ controllerProperties,
+ workflowsEntry.getKey()));
+ schemaAnyOf.add(obj);
+ }
+ }
+ }
+ return schemaAnyOf;
+ }
+
+ private static JsonArray createBlankEntry() {
+ JsonArray result = new JsonArray();
+ JsonObject blankObject = new JsonObject();
+ blankObject.addProperty("title", "User defined");
+ blankObject.add("properties", new JsonObject());
+ result.add(blankObject);
+ return result;
+ }
+
+ private static JsonObject createAnyOfJsonProperty(String name,
+ String defaultValue,
+ boolean readOnlyFlag) {
+ JsonObject result = new JsonObject();
+ result.addProperty("title", name);
+ result.addProperty("type", "string");
+ result.addProperty("default", defaultValue);
+ result.addProperty("readOnly", readOnlyFlag);
+ return result;
+ }
+
+ private static void addToJsonArray(JsonObject childObject, String section, JsonArray value) {
+ if (childObject.getAsJsonArray(section) != null) {
+ childObject.getAsJsonArray(section).addAll(value);
+ } else {
+ childObject.add(section, value);
+ }
+ }
+
+ /**
+ * Returns the properties of payload based on the cds work flows.
+ *
+ * @param workFlow cds work flows to update payload
+ * @param controllerProperties cds properties to get blueprint name and
+ * version
+ * @param workFlowName work flow name
+ * @return returns the properties of payload
+ */
+ public static JsonObject createInputPropertiesForPayload(JsonObject workFlow,
+ JsonObject controllerProperties,
+ String workFlowName) {
+ String artifactName = controllerProperties.get("sdnc_model_name").getAsString();
+ String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString();
+ JsonObject inputs = workFlow.getAsJsonObject("inputs");
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.add("artifact_name", createAnyOfJsonProperty(
+ "artifact name", artifactName, true));
+ jsonObject.add("artifact_version", createAnyOfJsonProperty(
+ "artifact version", artifactVersion, true));
+ jsonObject.add("mode", createAnyOfJsonProperty(
+ "mode", "async", false));
+ jsonObject.add("data", createDataProperty(inputs, workFlowName));
+ return jsonObject;
+ }
+
+ private static JsonObject createDataProperty(JsonObject inputs, String workFlowName) {
+ JsonObject data = new JsonObject();
+ data.addProperty("title", "data");
+ data.addProperty("type", "string");
+ data.addProperty("format", "textarea");
+ JsonObject defaultValue = new JsonObject();
+ addDefaultValueForData(inputs, defaultValue, workFlowName);
+ data.addProperty("default", defaultValue.toString());
+ return data;
+ }
+
+ private static void addDefaultValueForData(JsonObject inputs,
+ JsonObject defaultValue,
+ String workFlowName) {
+ Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet();
+ for (Map.Entry<String, JsonElement> entry : entrySet) {
+ String key = entry.getKey();
+ JsonObject inputProperty = inputs.getAsJsonObject(key);
+ if (key.equalsIgnoreCase(workFlowName + "-properties")) {
+ addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties")
+ .getAsJsonObject(), defaultValue, workFlowName);
+ } else if ("object".equalsIgnoreCase(inputProperty.get(ToscaSchemaConstants.TYPE).getAsString())) {
+ JsonObject object = new JsonObject();
+ addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties")
+ .getAsJsonObject(), object, workFlowName);
+ defaultValue.add(entry.getKey(), object);
+ } else if (ToscaSchemaConstants.TYPE_LIST.equalsIgnoreCase(inputProperty.get(ToscaSchemaConstants.TYPE)
+ .getAsString())) {
+ defaultValue.add(entry.getKey(), handleListType(entry.getValue().getAsJsonObject(), workFlowName));
+ } else {
+ defaultValue.addProperty(entry.getKey(), "");
+ }
+ }
+ }
+
+ private static JsonArray handleListType(JsonObject inputs,
+ String workFlowName) {
+
+ JsonObject object = new JsonObject();
+ if (inputs.get("properties") != null) {
+ addDefaultValueForData(inputs.get("properties").getAsJsonObject(), object, workFlowName);
+ }
+ JsonArray arr = new JsonArray();
+ arr.add(object);
+ return arr;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java
new file mode 100644
index 000000000..74fd8e5fd
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java
@@ -0,0 +1,353 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.parser;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+import org.onap.policy.clamp.loop.service.Service;
+
+/**
+ * This class can be used to convert a tosca to a json schema.
+ * This class is not supposed to be used directly because it requires the json Schema templates
+ * (template conversion tosca type to json schema entry) but also the supported Tosca main type file.
+ * The class ToscaConverterWithDictionarySupport is more complete for the end user to be used (in the clamp context).
+ *
+ * @see org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport#convertToscaToJsonSchemaObject
+ * @see org.onap.policy.clamp.clds.tosca.update.parser.ToscaConverterToJsonSchema#getJsonSchemaOfToscaElement
+ */
+public class ToscaConverterToJsonSchema {
+ private LinkedHashMap<String, ToscaElement> components;
+ private LinkedHashMap<String, JsonTemplate> templates;
+
+ private ToscaMetadataParser metadataParser;
+
+ private Service serviceModel;
+
+ /**
+ * Constructor.
+ *
+ * @param toscaElementsMap All the tosca elements found (policy type + data types + native tosca datatypes)
+ * @param jsonSchemaTemplates All Json schema templates to use
+ * @param metadataParser The metadata parser to use for metadata section
+ * @param serviceModel The service model for clamp enrichment
+ */
+ public ToscaConverterToJsonSchema(LinkedHashMap<String, ToscaElement> toscaElementsMap,
+ LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates,
+ ToscaMetadataParser metadataParser, Service serviceModel) {
+ this.components = toscaElementsMap;
+ this.templates = jsonSchemaTemplates;
+ this.metadataParser = metadataParser;
+ this.serviceModel = serviceModel;
+ }
+
+ /**
+ * For a given component, launch process to parse it in Json.
+ *
+ * @param toscaElementKey name components
+ * @return return
+ */
+ public JsonObject getJsonSchemaOfToscaElement(String toscaElementKey) {
+ return this.getFieldAsObject(getToscaElement(toscaElementKey));
+ }
+
+ /**
+ * Return the classical/general fields of the component, & launch the properties deployment.
+ *
+ * @param toscaElement the compo
+ * @return a json object
+ */
+ public JsonObject getFieldAsObject(ToscaElement toscaElement) {
+
+ JsonObject globalFields = new JsonObject();
+ if (templates.get("object").hasFields("title")) {
+ globalFields.addProperty("title", toscaElement.getName());
+ }
+ if (templates.get("object").hasFields("type")) {
+ globalFields.addProperty("type", "object");
+ }
+ if (templates.get("object").hasFields("description")) {
+ if (toscaElement.getDescription() != null) {
+ globalFields.addProperty("description", toscaElement.getDescription());
+ }
+ }
+ if (templates.get("object").hasFields("required")) {
+ globalFields.add("required", this.getRequirements(toscaElement.getName()));
+ }
+ if (templates.get("object").hasFields("properties")) {
+ globalFields.add("properties", this.deploy(toscaElement.getName()));
+ }
+ return globalFields;
+ }
+
+ /**
+ * Get the required properties of the Component, including the parents properties requirements.
+ *
+ * @param nameComponent name component
+ * @return a json array
+ */
+ public JsonArray getRequirements(String nameComponent) {
+ JsonArray requirements = new JsonArray();
+ ToscaElement toParse = components.get(nameComponent);
+ //Check for a father component, and launch the same process
+ if (!"tosca.datatypes.Root".equals(toParse.getDerivedFrom())
+ && !"tosca.policies.Root".equals(toParse.getDerivedFrom())) {
+ requirements.addAll(getRequirements(toParse.getDerivedFrom()));
+ }
+ //Each property is checked, and add to the requirement array if it's required
+ Collection<ToscaElementProperty> properties = toParse.getProperties().values();
+ for (ToscaElementProperty toscaElementProperty : properties) {
+ if (toscaElementProperty.getItems().containsKey("required")
+ && toscaElementProperty.getItems().get("required").equals(true)) {
+ requirements.add(toscaElementProperty.getName());
+ }
+ }
+ return requirements;
+ }
+
+ /**
+ * The beginning of the recursive process. Get the parents (or not) to launch the same process, and otherwise
+ * deploy and parse the properties.
+ *
+ * @param nameComponent name component
+ * @return a json object
+ */
+ public JsonObject deploy(String nameComponent) {
+ JsonObject jsonSchema = new JsonObject();
+ ToscaElement toParse = components.get(nameComponent);
+ //Check for a father component, and launch the same process
+ if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root")
+ && !toParse.getDerivedFrom().equals("tosca.policies.Root")) {
+ jsonSchema = this.getParent(toParse.getDerivedFrom());
+ }
+ //For each component property, check if its a complex properties (a component) or not. In that case,
+ //launch the analyse of the property.
+ for (Entry<String, ToscaElementProperty> property : toParse.getProperties().entrySet()) {
+ if (getToscaElement((String) property.getValue().getItems().get("type")) != null) {
+ jsonSchema.add(property.getValue().getName(),
+ this.getJsonSchemaOfToscaElement((String) property.getValue().getItems().get("type")));
+ } else {
+ jsonSchema.add(property.getValue().getName(), this.complexParse(property.getValue()));
+ }
+ }
+ return jsonSchema;
+ }
+
+ /**
+ * If a component has a parent, it is deploy in the same way.
+ *
+ * @param nameComponent name component
+ * @return a json object
+ */
+ public JsonObject getParent(String nameComponent) {
+ return deploy(nameComponent);
+ }
+
+ /**
+ * to be done.
+ *
+ * @param toscaElementProperty property
+ * @return a json object
+ */
+ @SuppressWarnings("unchecked")
+ public JsonObject complexParse(ToscaElementProperty toscaElementProperty) {
+ JsonObject propertiesInJson = new JsonObject();
+ JsonTemplate currentPropertyJsonTemplate;
+ String typeProperty = (String) toscaElementProperty.getItems().get("type");
+ if (typeProperty.toLowerCase().equals("list") || typeProperty.toLowerCase().equals("map")) {
+ currentPropertyJsonTemplate = templates.get("object");
+ } else {
+ String propertyType = (String) toscaElementProperty.getItems().get("type");
+ currentPropertyJsonTemplate = templates.get(propertyType.toLowerCase());
+ }
+ //Each "special" field is analysed, and has a specific treatment
+ for (String propertyField : toscaElementProperty.getItems().keySet()) {
+ switch (propertyField) {
+ case "type":
+ if (currentPropertyJsonTemplate.hasFields(propertyField)) {
+ String fieldtype = (String) toscaElementProperty.getItems().get(propertyField);
+ switch (fieldtype.toLowerCase()) {
+ case "list":
+ propertiesInJson.addProperty("type", "array");
+ break;
+ case "map":
+ propertiesInJson.addProperty("type", "object");
+ break;
+ case "scalar-unit.time":
+ case "scalar-unit.frequency":
+ case "scalar-unit.size":
+ propertiesInJson.addProperty("type", "string");
+ break;
+ case "timestamp":
+ propertiesInJson.addProperty("type", "string");
+ propertiesInJson.addProperty("format", "date-time");
+ break;
+ case "float":
+ propertiesInJson.addProperty("type", "number");
+ break;
+ case "range":
+ propertiesInJson.addProperty("type", "integer");
+ if (!checkConstraintPresence(toscaElementProperty, "greater_than")
+ && currentPropertyJsonTemplate.hasFields("exclusiveMinimum")) {
+ propertiesInJson.addProperty("exclusiveMinimum", false);
+ }
+ if (!checkConstraintPresence(toscaElementProperty, "less_than")
+ && currentPropertyJsonTemplate.hasFields("exclusiveMaximum")) {
+ propertiesInJson.addProperty("exclusiveMaximum", false);
+ }
+ break;
+ default:
+ propertiesInJson.addProperty("type", currentPropertyJsonTemplate.getName());
+ break;
+ }
+ }
+ break;
+ case "metadata":
+ if (metadataParser != null) {
+ metadataParser.processAllMetadataElement(toscaElementProperty, serviceModel).entrySet()
+ .forEach((jsonEntry) -> {
+ propertiesInJson.add(jsonEntry.getKey(),
+ jsonEntry.getValue());
+
+ });
+ }
+ break;
+ case "constraints":
+ toscaElementProperty.addConstraintsAsJson(propertiesInJson,
+ (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ currentPropertyJsonTemplate);
+ break;
+ case "entry_schema":
+ //Here, a way to check if entry is a component (datatype) or a simple string
+ if (getToscaElement(this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema"))
+ != null) {
+ String nameComponent = this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema");
+ ToscaConverterToJsonSchema child = new ToscaConverterToJsonSchema(components, templates,
+ metadataParser, serviceModel);
+ JsonObject propertiesContainer = new JsonObject();
+
+ switch ((String) toscaElementProperty.getItems().get("type")) {
+ case "map": // Get it as an object
+ JsonObject componentAsProperty = child.getJsonSchemaOfToscaElement(nameComponent);
+ propertiesContainer.add(nameComponent, componentAsProperty);
+ if (currentPropertyJsonTemplate.hasFields("properties")) {
+ propertiesInJson.add("properties", propertiesContainer);
+ }
+ break;
+ default://list : get it as an Array
+ JsonObject componentAsItem = child.getJsonSchemaOfToscaElement(nameComponent);
+ if (currentPropertyJsonTemplate.hasFields("properties")) {
+ propertiesInJson.add("items", componentAsItem);
+ propertiesInJson.addProperty("format", "tabs-top");
+ }
+ break;
+ }
+
+ } else if (toscaElementProperty.getItems().get("type").equals("list")) {
+ // Native cases
+ JsonObject itemContainer = new JsonObject();
+ String valueInEntrySchema =
+ this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema");
+ itemContainer.addProperty("type", valueInEntrySchema);
+ propertiesInJson.add("items", itemContainer);
+ propertiesInJson.addProperty("format", "tabs-top");
+ }
+
+ // MAP Case, for now nothing
+
+ break;
+ default:
+ //Each classical field : type, description, default..
+ if (currentPropertyJsonTemplate.hasFields(propertyField) && !propertyField.equals("required")) {
+ toscaElementProperty.addFieldToJson(propertiesInJson, propertyField,
+ toscaElementProperty.getItems().get(propertyField));
+ }
+ break;
+ }
+ }
+ return propertiesInJson;
+ }
+
+ /**
+ * Look for a matching Component for the name parameter, in the components list.
+ *
+ * @param name the tosca element name to search for
+ * @return a tosca element
+ */
+ public ToscaElement getToscaElement(String name) {
+ ToscaElement correspondingToscaElement = null;
+ if (components == null) {
+ return null;
+ }
+ for (ToscaElement toscaElement : components.values()) {
+ if (toscaElement.getName().equals(name)) {
+ correspondingToscaElement = toscaElement;
+ }
+ }
+ return correspondingToscaElement;
+ }
+
+ /**
+ * Simple method to extract quickly a type field from particular property item.
+ *
+ * @param toscaElementProperty the property
+ * @param fieldName the fieldname
+ * @return a string
+ */
+ @SuppressWarnings("unchecked")
+ public String extractSpecificFieldFromMap(ToscaElementProperty toscaElementProperty, String fieldName) {
+ LinkedHashMap<String, String> entrySchemaFields =
+ (LinkedHashMap<String, String>) toscaElementProperty.getItems().get(fieldName);
+ return entrySchemaFields.get("type");
+ }
+
+ /**
+ * Check if a constraint, for a specific property, is there.
+ *
+ * @param toscaElementProperty property
+ * @param nameConstraint name constraint
+ * @return a flag boolean
+ */
+ public boolean checkConstraintPresence(ToscaElementProperty toscaElementProperty, String nameConstraint) {
+ boolean presentConstraint = false;
+ if (toscaElementProperty.getItems().containsKey("constraints")) {
+ ArrayList<Object> constraints = (ArrayList) toscaElementProperty.getItems().get("constraints");
+ for (Object constraint : constraints) {
+ if (constraint instanceof LinkedHashMap) {
+ if (((LinkedHashMap) constraint).containsKey(nameConstraint)) {
+ presentConstraint = true;
+ }
+ }
+ }
+ }
+ return presentConstraint;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java
new file mode 100644
index 000000000..a3dd9c3e1
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/ToscaElementParser.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.parser;
+
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.yaml.snakeyaml.Yaml;
+
+public class ToscaElementParser {
+ /**
+ * Constructor.
+ */
+ private ToscaElementParser() {
+ }
+
+ private static LinkedHashMap<String, Object> searchAllDataTypesAndPolicyTypes(String toscaYaml) {
+ LinkedHashMap<String, LinkedHashMap<String, Object>> file =
+ (LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaYaml);
+ LinkedHashMap<String, Object> allDataTypesFound = file.get("data_types");
+ LinkedHashMap<String, Object> allPolicyTypesFound = file.get("policy_types");
+ LinkedHashMap<String, Object> allItemsFound = new LinkedHashMap<>();
+ // Put the policies and datatypes in the same collection
+ allItemsFound = (allDataTypesFound == null) ? (new LinkedHashMap<>()) : allDataTypesFound;
+ allItemsFound.putAll(allPolicyTypesFound == null ? new LinkedHashMap<>() : allPolicyTypesFound);
+ return allItemsFound;
+ }
+
+ private static LinkedHashMap<String, Object> searchAllNativeToscaDataTypes(String toscaNativeYaml) {
+ return ((LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaNativeYaml))
+ .get("data_types");
+ }
+
+ /**
+ * Yaml Parse gets raw policies and datatypes, in different sections : necessary to extract
+ * all entities and put them at the same level.
+ *
+ * @param toscaYaml the tosca model content
+ * @param nativeToscaYaml the tosca native datatype content
+ * @return a map of Tosca Element containing all tosca elements found (policy types and datatypes)
+ */
+ public static LinkedHashMap<String, ToscaElement> searchAllToscaElements(String toscaYaml,
+ String nativeToscaYaml) {
+ LinkedHashMap<String, Object> allItemsFound = searchAllDataTypesAndPolicyTypes(toscaYaml);
+ allItemsFound.putAll(searchAllNativeToscaDataTypes(nativeToscaYaml));
+ return parseAllItemsFound(allItemsFound);
+ }
+
+ /**
+ * With all the component, get as Map, Components and Components properties are created.
+ *
+ * @param allMaps maps
+ */
+ private static LinkedHashMap<String, ToscaElement> parseAllItemsFound(LinkedHashMap<String, Object> allMaps) {
+ LinkedHashMap<String, ToscaElement> allItemsFound = new LinkedHashMap<String, ToscaElement>();
+ //Component creations, from the file maps
+ for (Entry<String, Object> itemToParse : allMaps.entrySet()) {
+ LinkedHashMap<String, Object> componentBody = (LinkedHashMap<String, Object>) itemToParse.getValue();
+ ToscaElement toscaElement =
+ new ToscaElement(itemToParse.getKey(), (String) componentBody.get("derived_from"),
+ (String) componentBody.get("description"));
+ //If policy, version and type_version :
+ if (componentBody.get("type_version") != null) {
+ toscaElement.setVersion((String) componentBody.get("type_version"));
+ toscaElement.setTypeVersion((String) componentBody.get("type_version"));
+ }
+ //Properties creation, from the map
+ if (componentBody.get("properties") != null) {
+ LinkedHashMap<String, Object> properties =
+ (LinkedHashMap<String, Object>) componentBody.get("properties");
+ for (Entry<String, Object> itemToProperty : properties.entrySet()) {
+ ToscaElementProperty toscaElementProperty = new ToscaElementProperty(itemToProperty.getKey(),
+ (LinkedHashMap<String, Object>) itemToProperty.getValue());
+ toscaElement.addProperties(toscaElementProperty);
+ }
+ }
+ allItemsFound.put(toscaElement.getName(), toscaElement);
+ }
+ return allItemsFound;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java
new file mode 100644
index 000000000..b2568b79f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.parser.metadata;
+
+import com.google.gson.JsonObject;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.loop.service.Service;
+
+public interface ToscaMetadataParser {
+ JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel);
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java
new file mode 100644
index 000000000..4e55263fb
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java
@@ -0,0 +1,211 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.parser.metadata;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Optional;
+import org.onap.policy.clamp.clds.tosca.JsonEditorSchemaConstants;
+import org.onap.policy.clamp.clds.tosca.ToscaSchemaConstants;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.clds.tosca.update.execution.ToscaMetadataExecutor;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.tosca.DictionaryElement;
+import org.onap.policy.clamp.tosca.DictionaryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ToscaMetadataParserWithDictionarySupport implements ToscaMetadataParser {
+
+ @Autowired
+ private ToscaMetadataExecutor toscaMetadataExecutor;
+
+ @Autowired
+ private DictionaryService dictionaryService;
+
+ /**
+ * This method is used to start the processing of the metadata field.
+ *
+ * @param toscaElementProperty The property metadata as Json Object
+ * @return The jsonObject structure that must be added to the json schema
+ */
+ public JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel) {
+ if (dictionaryService != null) {
+ return parseMetadataPossibleValues(toscaElementProperty.getItems(), dictionaryService, serviceModel,
+ toscaMetadataExecutor);
+ } else {
+ return null;
+ }
+ }
+
+ private static JsonObject parseMetadataPossibleValues(LinkedHashMap<String, Object> childNodeMap,
+ DictionaryService dictionaryService, Service serviceModel,
+ ToscaMetadataExecutor toscaMetadataExecutor) {
+ JsonObject childObject = new JsonObject();
+ if (childNodeMap.containsKey(ToscaSchemaConstants.METADATA)
+ && childNodeMap.get(ToscaSchemaConstants.METADATA) != null) {
+ ((LinkedHashMap<String, Object>) childNodeMap.get(ToscaSchemaConstants.METADATA)).forEach((key,
+ value) -> {
+ if (key.equalsIgnoreCase(ToscaSchemaConstants.METADATA_CLAMP_POSSIBLE_VALUES)) {
+ String[] multipleValues = ((String) value).split(",");
+ for (String multipleValue : multipleValues) {
+ if (multipleValue.contains(ToscaSchemaConstants.DICTIONARY)) {
+ processDictionaryElements(multipleValue, childObject, dictionaryService);
+ }
+ if (multipleValue.contains("ClampExecution:")) {
+ executeClampProcess(multipleValue.replaceFirst("ClampExecution:", ""), childObject,
+ serviceModel, toscaMetadataExecutor);
+ }
+ }
+
+ }
+ });
+ }
+ return childObject;
+ }
+
+ private static void executeClampProcess(String processInfo, JsonObject childObject, Service serviceModel,
+ ToscaMetadataExecutor toscaMetadataExecutor) {
+ toscaMetadataExecutor.executeTheProcess(processInfo, childObject, serviceModel);
+ }
+
+ /**
+ * For dictionary with multiple levels (defined by #).
+ *
+ * @param dictionaryKeyArray the array containing the different elements
+ * @param childObject the structure getting the new entries
+ * @param dictionaryService the dictionary service bean
+ */
+ private static void processComplexDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject,
+ DictionaryService dictionaryService) {
+ // We support only one # as of now.
+ List<DictionaryElement> dictionaryElements = null;
+ if (dictionaryKeyArray.length == 2) {
+ dictionaryElements = new ArrayList<>(dictionaryService.getDictionary(dictionaryKeyArray[0])
+ .getDictionaryElements());
+ JsonArray subDictionaryNames = new JsonArray();
+ new ArrayList<DictionaryElement>(dictionaryService.getDictionary(dictionaryKeyArray[1])
+ .getDictionaryElements()).forEach(elem -> subDictionaryNames.add(elem.getShortName()));
+
+ JsonArray jsonArray = new JsonArray();
+
+ Optional.of(dictionaryElements).get().forEach(c -> {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(JsonEditorSchemaConstants.TYPE, getJsonType(c.getType()));
+ if (c.getType() != null
+ && c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) {
+ jsonObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1);
+
+ }
+ jsonObject.addProperty(JsonEditorSchemaConstants.ID, c.getName());
+ jsonObject.addProperty(JsonEditorSchemaConstants.LABEL, c.getShortName());
+ jsonObject.add(JsonEditorSchemaConstants.OPERATORS, subDictionaryNames);
+ jsonArray.add(jsonObject);
+ });
+
+ JsonObject filterObject = new JsonObject();
+ filterObject.add(JsonEditorSchemaConstants.FILTERS, jsonArray);
+
+ childObject.addProperty(JsonEditorSchemaConstants.TYPE,
+ JsonEditorSchemaConstants.TYPE_QBLDR);
+ // TO invoke validation on such parameters
+ childObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1);
+ childObject.add(JsonEditorSchemaConstants.QSSCHEMA, filterObject);
+
+ }
+ }
+
+ /**
+ * For dictionary with single entry.
+ *
+ * @param dictionaryKeyArray the array containing the different elements
+ * @param childObject the structure getting the new entries
+ * @param dictionaryService the dictionary service bean
+ */
+ private static void processSimpleDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject,
+ DictionaryService dictionaryService) {
+ JsonArray dictionaryNames = new JsonArray();
+ JsonArray dictionaryFullNames = new JsonArray();
+ dictionaryService.getDictionary(dictionaryKeyArray[0]).getDictionaryElements().forEach(c -> {
+ // Json type will be translated before Policy creation
+ if (c.getType() != null && !c.getType().equalsIgnoreCase("json")) {
+ dictionaryFullNames.add(c.getName());
+ }
+ dictionaryNames.add(c.getShortName());
+ });
+
+ if (dictionaryFullNames.size() > 0) {
+ if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) {
+ childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryFullNames);
+ } else {
+ childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryFullNames);
+ }
+ // Add Enum titles for generated translated values during JSON instance
+ // generation
+ JsonObject enumTitles = new JsonObject();
+ enumTitles.add(JsonEditorSchemaConstants.ENUM_TITLES, dictionaryNames);
+ if (childObject.get(JsonEditorSchemaConstants.OPTIONS) != null) {
+ childObject.get(JsonEditorSchemaConstants.OPTIONS).getAsJsonArray().add(enumTitles);
+ } else {
+ childObject.add(JsonEditorSchemaConstants.OPTIONS, enumTitles);
+ }
+
+ } else {
+ if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) {
+ childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryNames);
+ } else {
+ childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryNames);
+ }
+ }
+ }
+
+ private static void processDictionaryElements(String dictionaryReference, JsonObject childObject,
+ DictionaryService dictionaryService) {
+ String[] dictionaryKeyArray =
+ dictionaryReference.substring(dictionaryReference.indexOf(ToscaSchemaConstants.DICTIONARY) + 11,
+ dictionaryReference.length()).split("#");
+ if (dictionaryKeyArray.length > 1) {
+ processComplexDictionaryElements(dictionaryKeyArray, childObject, dictionaryService);
+ } else {
+ processSimpleDictionaryElements(dictionaryKeyArray, childObject, dictionaryService);
+ }
+ }
+
+ private static String getJsonType(String toscaType) {
+ String jsonType = null;
+ if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER)) {
+ jsonType = JsonEditorSchemaConstants.TYPE_INTEGER;
+ } else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) {
+ jsonType = JsonEditorSchemaConstants.TYPE_ARRAY;
+ } else {
+ jsonType = JsonEditorSchemaConstants.TYPE_STRING;
+ }
+ return jsonType;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java
new file mode 100644
index 000000000..5c96f2c4a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplate.java
@@ -0,0 +1,223 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.templates;
+
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JsonTemplate {
+
+ /**
+ * name parameter is used as "key", in the LinkedHashMap of Templates.
+ */
+ private String name;
+ private List<JsonTemplateField> jsonTemplateFields;
+
+ public JsonTemplate(String name) {
+ this.name = name;
+ this.jsonTemplateFields = new ArrayList<>();
+ }
+
+ public JsonTemplate(String name, List<JsonTemplateField> jsonTemplateFields) {
+ this.name = name;
+ this.jsonTemplateFields = jsonTemplateFields;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<JsonTemplateField> getJsonTemplateFields() {
+ return jsonTemplateFields;
+ }
+
+ public void setJsonTemplateFields(List<JsonTemplateField> jsonTemplateFields) {
+ this.jsonTemplateFields = jsonTemplateFields;
+ }
+
+ /**
+ * Search in fields if fieldName exists.
+ *
+ * @param fieldName The field name
+ * @return Ture if it exists, false otherwise
+ */
+ public boolean hasFields(String fieldName) {
+ for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) {
+ if (jsonTemplateField.getTitle().equals(fieldName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get a specific Field.
+ *
+ * @param fieldName The field name
+ * @return THe Field found
+ */
+ public JsonTemplateField getSpecificField(String fieldName) {
+ for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) {
+ if (jsonTemplateField.getTitle().equals(fieldName)) {
+ return jsonTemplateField;
+ }
+ }
+ return null;
+ }
+
+ public void addField(JsonTemplateField jsonTemplateField) {
+ jsonTemplateFields.add(jsonTemplateField);
+ }
+
+ public void removeField(JsonTemplateField jsonTemplateField) {
+ jsonTemplateFields.remove(jsonTemplateField);
+ }
+
+ /**
+ * Enable or disable the visibility.
+ *
+ * @param nameField THe field name
+ * @param state True or false
+ */
+ public void setVisibility(String nameField, boolean state) {
+ for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) {
+ if (jsonTemplateField.getTitle().equals(nameField)) {
+ jsonTemplateField.setVisible(state);
+ }
+ }
+ }
+
+ /**
+ * This method defines if a field is static or not.
+ *
+ * @param nameField The name of the field
+ * @param state true or false
+ */
+ public void setStatic(String nameField, boolean state) {
+ for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) {
+ if (jsonTemplateField.getTitle().equals(nameField)) {
+ jsonTemplateField.setStaticValue(state);
+ }
+ }
+ }
+
+ /**
+ * This method updates the value of a specfic field.
+ *
+ * @param nameField The name of the field
+ * @param newValue The new value as Object
+ */
+ public void updateValueField(String nameField, Object newValue) {
+ for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) {
+ if (jsonTemplateField.getTitle().equals(nameField)) {
+ jsonTemplateField.setValue(newValue);
+ }
+ }
+ }
+
+ /**
+ * Compare two templates : size and their contents.
+ *
+ * @param jsonTemplate the template
+ * @return a boolean
+ */
+ public boolean checkFields(JsonTemplate jsonTemplate) {
+ boolean duplicateFields = false;
+ if (jsonTemplate.getJsonTemplateFields().size() == this.getJsonTemplateFields().size()) {
+ int countMatchingFields = 0;
+ //loop each component of first
+ for (JsonTemplateField jsonTemplateFieldToCheck : jsonTemplate.getJsonTemplateFields()) {
+ for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) {
+ if (jsonTemplateFieldToCheck.compareWithField(jsonTemplateField)) {
+ countMatchingFields++;
+ }
+ }
+ }
+
+ if (jsonTemplate.getJsonTemplateFields().size() == countMatchingFields) {
+ duplicateFields = true;
+ }
+ }
+ return duplicateFields;
+ }
+
+ /**
+ * This method gets the specific field status.
+ *
+ * @param field The field name
+ * @return true or false
+ */
+ public boolean fieldStaticStatus(String field) {
+ if (this.hasFields(field) && this.getSpecificField(field).getStaticValue().equals(true)
+ && this.getSpecificField(field).getValue() != null) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isVisible(String field) {
+ return this.getSpecificField(field).getVisible();
+ }
+
+ /**
+ * Set the value of a property of the Field in the json.
+ *
+ * @param jsonSchema The Json schema
+ * @param fieldName The Field name
+ * @param value The value
+ */
+ public void setValue(JsonObject jsonSchema, String fieldName, String value) {
+ if (isVisible(fieldName)) {
+ if (fieldStaticStatus(fieldName)) {
+ String defaultValue = (String) this.getSpecificField(fieldName).getValue();
+ jsonSchema.addProperty(fieldName, defaultValue);
+ } else {
+ jsonSchema.addProperty(fieldName, value);
+ }
+ }
+ }
+
+ /**
+ * Inject a static value in the json.
+ *
+ * @param jsonSchema The json schema object
+ * @param fieldName The field name
+ */
+ public void injectStaticValue(JsonObject jsonSchema, String fieldName) {
+ if (isVisible(fieldName)) {
+ JsonTemplateField toInject = this.getSpecificField(fieldName);
+ jsonSchema.addProperty(fieldName, (String) toInject.getValue());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return " templateFields : " + jsonTemplateFields;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java
new file mode 100644
index 000000000..d9fd11de2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateField.java
@@ -0,0 +1,149 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.templates;
+
+public class JsonTemplateField {
+ private String title;
+ private Object value;
+ private Boolean visible;
+ private Boolean staticValue;
+
+ public JsonTemplateField(String title) {
+ this.title = title;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param title The title
+ * @param value The value
+ * @param visible visible or not
+ * @param staticValue The static value
+ */
+ public JsonTemplateField(String title, Object value, Boolean visible, Boolean staticValue) {
+ this.title = title;
+ this.value = value;
+ this.visible = visible;
+ this.staticValue = staticValue;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public Boolean getVisible() {
+ return visible;
+ }
+
+ public void setVisible(Boolean visible) {
+ this.visible = visible;
+ }
+
+ public Boolean getStaticValue() {
+ return staticValue;
+ }
+
+ public void setStaticValue(Boolean staticValue) {
+ this.staticValue = staticValue;
+ }
+
+ public String toString() {
+ return title + " " + value + " " + visible + " " + staticValue;
+ }
+
+ /**
+ * This method compares two fields.
+ *
+ * @param otherField Compare the current object with the one specified
+ * @return true if they are totally equals, false otherwise
+ */
+ public boolean compareWithField(Object otherField) {
+ if (this == otherField) {
+ return true;
+ }
+ if (otherField == null || getClass() != otherField.getClass()) {
+ return false;
+ }
+
+ JsonTemplateField jsonTemplateField = (JsonTemplateField) otherField;
+
+ if (title != null ? !title.equals(jsonTemplateField.title) : jsonTemplateField.title != null) {
+ return false;
+ }
+ if (value != null ? !value.equals(jsonTemplateField.value) : jsonTemplateField.value != null) {
+ return false;
+ }
+ if (visible != null ? !visible.equals(jsonTemplateField.visible) : jsonTemplateField.visible != null) {
+ return false;
+ }
+ return staticValue != null ? staticValue.equals(jsonTemplateField.staticValue) :
+ jsonTemplateField.staticValue == null;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+
+ JsonTemplateField jsonTemplateField = (JsonTemplateField) object;
+
+ return title != null ? title.equals(jsonTemplateField.title) : jsonTemplateField.title == null;
+ }
+
+ @Override
+ public int hashCode() {
+ return title != null ? title.hashCode() : 0;
+ }
+
+ /**
+ * This method test the entire equality.
+ *
+ * @param jsonTemplateField1 object one
+ * @param jsonTemplateField2 object two
+ * @return true if they are totally equals (all attributes, false otherwise
+ */
+ public static boolean fieldsEquals(JsonTemplateField jsonTemplateField1, JsonTemplateField jsonTemplateField2) {
+ return (jsonTemplateField2.getTitle().equals(jsonTemplateField1.getTitle())
+ && jsonTemplateField2.getValue().equals(jsonTemplateField1.getValue())
+ && jsonTemplateField2.getVisible().equals(jsonTemplateField1.getVisible())
+ && jsonTemplateField2.getStaticValue().equals(jsonTemplateField1.getStaticValue()));
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java
new file mode 100644
index 000000000..1813d0786
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/tosca/update/templates/JsonTemplateManager.java
@@ -0,0 +1,185 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update.templates;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.onap.policy.clamp.clds.tosca.update.UnknownComponentException;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.parser.ToscaConverterToJsonSchema;
+import org.onap.policy.clamp.clds.tosca.update.parser.ToscaElementParser;
+import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.service.Service;
+
+public class JsonTemplateManager {
+ private LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates;
+ private LinkedHashMap<String, ToscaElement> toscaElements;
+
+ /**
+ * Constructor.
+ *
+ * @param toscaYamlContent Policy Tosca Yaml content as string
+ * @param nativeToscaDatatypes The tosca yaml with tosca native datatypes
+ * @param jsonSchemaTemplates template properties as string
+ */
+ public JsonTemplateManager(String toscaYamlContent, String nativeToscaDatatypes, String jsonSchemaTemplates) {
+ if (toscaYamlContent != null && !toscaYamlContent.isEmpty()) {
+ this.toscaElements = ToscaElementParser.searchAllToscaElements(toscaYamlContent, nativeToscaDatatypes);
+ this.jsonSchemaTemplates = initializeTemplates(jsonSchemaTemplates);
+ } else {
+ toscaElements = null;
+ }
+ }
+
+ //GETTERS & SETTERS
+ public LinkedHashMap<String, ToscaElement> getToscaElements() {
+ return toscaElements;
+ }
+
+ public void setToscaElements(LinkedHashMap<String, ToscaElement> toscaElements) {
+ this.toscaElements = toscaElements;
+ }
+
+ public LinkedHashMap<String, JsonTemplate> getJsonSchemaTemplates() {
+ return jsonSchemaTemplates;
+ }
+
+ public void setJsonSchemaTemplates(LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates) {
+ this.jsonSchemaTemplates = jsonSchemaTemplates;
+ }
+
+ /**
+ * Add a template.
+ *
+ * @param name name
+ * @param jsonTemplateFields fields
+ */
+ public void addTemplate(String name, List<JsonTemplateField> jsonTemplateFields) {
+ JsonTemplate jsonTemplate = new JsonTemplate(name, jsonTemplateFields);
+ //If it is true, the operation does not have any interest :
+ // replace OR put two different object with the same body
+ if (!jsonSchemaTemplates.containsKey(jsonTemplate.getName()) || !this.hasTemplate(jsonTemplate)) {
+ this.jsonSchemaTemplates.put(jsonTemplate.getName(), jsonTemplate);
+ }
+ }
+
+ /**
+ * By name, find and remove a given template.
+ *
+ * @param nameTemplate name template
+ */
+ public void removeTemplate(String nameTemplate) {
+ this.jsonSchemaTemplates.remove(nameTemplate);
+ }
+
+ /**
+ * Update Template : adding with true flag, removing with false.
+ *
+ * @param nameTemplate name template
+ * @param jsonTemplateField field name
+ * @param operation operation
+ */
+ public void updateTemplate(String nameTemplate, JsonTemplateField jsonTemplateField, Boolean operation) {
+ // Operation = true && field is not present => add Field
+ if (operation
+ && !this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) {
+ this.jsonSchemaTemplates.get(nameTemplate).addField(jsonTemplateField);
+ } else if (!operation
+ && this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) {
+ // Operation = false && field is present => remove Field
+ this.jsonSchemaTemplates.get(nameTemplate).removeField(jsonTemplateField);
+ }
+ }
+
+ /**
+ * Check if the JSONTemplates have the same bodies.
+ *
+ * @param jsonTemplate template
+ * @return a boolean
+ */
+ public boolean hasTemplate(JsonTemplate jsonTemplate) {
+ boolean duplicateTemplate = false;
+ Collection<String> templatesName = jsonSchemaTemplates.keySet();
+ if (templatesName.contains(jsonTemplate.getName())) {
+ JsonTemplate existingJsonTemplate = jsonSchemaTemplates.get(jsonTemplate.getName());
+ duplicateTemplate = existingJsonTemplate.checkFields(jsonTemplate);
+ }
+ return duplicateTemplate;
+ }
+
+ /**
+ * For a given policy type, get a corresponding JsonObject from the tosca model.
+ *
+ * @param policyType The policy type in the tosca
+ * @param toscaMetadataParser The MetadataParser class that must be used if metadata section are encountered,
+ * if null they will be skipped
+ * @return an json object defining the equivalent json schema from the tosca for a given policy type
+ */
+ public JsonObject getJsonSchemaForPolicyType(String policyType, ToscaMetadataParser toscaMetadataParser,
+ Service serviceModel)
+ throws UnknownComponentException {
+ ToscaConverterToJsonSchema
+ toscaConverterToJsonSchema = new ToscaConverterToJsonSchema(toscaElements, jsonSchemaTemplates,
+ toscaMetadataParser, serviceModel);
+ if (toscaConverterToJsonSchema.getToscaElement(policyType) == null) {
+ throw new UnknownComponentException(policyType);
+ }
+ return toscaConverterToJsonSchema.getJsonSchemaOfToscaElement(policyType);
+ }
+
+ /**
+ * Create and complete several Templates from file.properties.
+ *
+ * @param jsonTemplates The template properties as String
+ * @return a map
+ */
+ @SuppressWarnings("unused")
+ private LinkedHashMap<String, JsonTemplate> initializeTemplates(String jsonTemplates) {
+
+ LinkedHashMap<String, JsonTemplate> generatedTemplates = new LinkedHashMap<>();
+ JsonObject templates = JsonUtils.GSON.fromJson(jsonTemplates, JsonObject.class);
+
+ for (Map.Entry<String, JsonElement> templateAsJson : templates.entrySet()) {
+ JsonTemplate jsonTemplate = new JsonTemplate(templateAsJson.getKey());
+ JsonObject templateBody = (JsonObject) templateAsJson.getValue();
+ for (Map.Entry<String, JsonElement> field : templateBody.entrySet()) {
+ String fieldName = field.getKey();
+ JsonObject bodyFieldAsJson = (JsonObject) field.getValue();
+ Object fieldValue = bodyFieldAsJson.get("defaultValue").getAsString();
+ Boolean fieldVisible = bodyFieldAsJson.get("visible").getAsBoolean();
+ Boolean fieldStatic = bodyFieldAsJson.get("static").getAsBoolean();
+ JsonTemplateField
+ bodyJsonTemplateField = new JsonTemplateField(fieldName, fieldValue, fieldVisible, fieldStatic);
+ jsonTemplate.getJsonTemplateFields().add(bodyJsonTemplateField);
+ }
+ generatedTemplates.put(jsonTemplate.getName(), jsonTemplate);
+ }
+ return generatedTemplates;
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java
new file mode 100644
index 000000000..0890615d9
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ClampVersioning.java
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. 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============================================
+ * Modifications copyright (c) 2018 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * This class give a way to know the Clamp version easily, the version in that
+ * file is set by maven at build time.
+ *
+ */
+public class ClampVersioning {
+ private static final String RESOURCE_NAME = "clds-version.properties";
+ private static final String CLDS_VERSION_PROPERTY = "clds.version";
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ClampVersioning.class);
+
+ private ClampVersioning() {
+ }
+
+ /**
+ * Returns Clds version from properties.
+ *
+ * @return Clds version from properties
+ */
+ public static String getCldsVersionFromProps() {
+ String cldsVersion = "";
+ Properties props = new Properties();
+ try (InputStream resourceStream = ResourceFileUtils.getResourceAsStream(RESOURCE_NAME)) {
+ props.load(resourceStream);
+ cldsVersion = props.getProperty(CLDS_VERSION_PROPERTY);
+ } catch (Exception ex) {
+ LOGGER.error("Exception caught during the " + CLDS_VERSION_PROPERTY + " property reading", ex);
+ }
+ return cldsVersion;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java
new file mode 100644
index 000000000..fd5079c47
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/JsonUtils.java
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018-2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.time.Instant;
+import org.onap.policy.clamp.authorization.SecureServicePermission;
+import org.onap.policy.clamp.authorization.SecureServicePermissionDeserializer;
+import org.onap.policy.clamp.dao.model.gson.converter.InstantDeserializer;
+import org.onap.policy.clamp.dao.model.gson.converter.InstantSerializer;
+
+/**
+ * This class is used to access the GSON with restricted type access.
+ */
+public class JsonUtils {
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(JsonUtils.class);
+
+ public static final Gson GSON = new GsonBuilder().setPrettyPrinting()
+ .registerTypeAdapter(SecureServicePermission.class, new SecureServicePermissionDeserializer()).create();
+
+ public static final Gson GSON_JPA_MODEL = new GsonBuilder().setPrettyPrinting()
+ .registerTypeAdapter(Instant.class, new InstantSerializer())
+ .registerTypeAdapter(Instant.class, new InstantDeserializer()).setPrettyPrinting()
+ .excludeFieldsWithoutExposeAnnotation().create();
+
+ private JsonUtils() {
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java
new file mode 100644
index 000000000..676206e0f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LogMessages.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+import com.att.eelf.i18n.EELFResourceManager;
+
+public enum LogMessages implements EELFResolvableErrorEnum {
+ LOGSERVICE_HELLO_MESSAGE, LOGSERVICE_EMAIL_ERROR, LOGSERVICE_EMAIL_CLASS, LOGSERVICE_EMAIL_CLASS_NULL,
+ PROCESS_INSTANCE_ID;
+
+ static {
+ EELFResourceManager.loadMessageBundle("logmessages");
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java
new file mode 100644
index 000000000..4145844a2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/LoggingUtils.java
@@ -0,0 +1,418 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.UUID;
+import javax.net.ssl.HttpsURLConnection;
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.constraints.NotNull;
+import org.onap.policy.clamp.authorization.AuthorizationController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.event.Level;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * This class handles the special info that appear in the log, like RequestID,
+ * time context, ...
+ */
+public class LoggingUtils {
+
+ protected static final Logger logger = LoggerFactory.getLogger(LoggingUtils.class);
+
+ private static final DateFormat DATE_FORMAT = createDateFormat();
+
+ private static final String DATE_FORMATTER_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+
+ /**
+ * String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc.
+ */
+ private static final String EMPTY_MESSAGE = "";
+
+ /**
+ * Logger delegate.
+ */
+ private final Logger mlogger;
+
+ /**
+ * Automatic UUID, overrideable per adapter or per invocation.
+ */
+ private static final UUID sInstanceUUID = UUID.randomUUID();
+
+ /**
+ * Constructor.
+ */
+ public LoggingUtils(final Logger loggerP) {
+ this.mlogger = checkNotNull(loggerP);
+ }
+
+ /**
+ * Set request related logging variables in thread local data via MDC.
+ *
+ * @param service Service Name of API (ex. "PUT template")
+ * @param partner Partner name (client or user invoking API)
+ */
+ public static void setRequestContext(String service, String partner) {
+ MDC.put("RequestId", UUID.randomUUID().toString());
+ MDC.put("ServiceName", service);
+ MDC.put("PartnerName", partner);
+ // Defaulting to HTTP/1.1 protocol
+ MDC.put("Protocol", "HTTP/1.1");
+ try {
+ MDC.put("ServerFQDN", InetAddress.getLocalHost().getCanonicalHostName());
+ MDC.put("ServerIPAddress", InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ logger.error("Failed to initiate setRequestContext", e);
+ }
+ }
+
+ /**
+ * Set time related logging variables in thread local data via MDC.
+ *
+ * @param beginTimeStamp Start time
+ * @param endTimeStamp End time
+ */
+ public static void setTimeContext(@NotNull Date beginTimeStamp, @NotNull Date endTimeStamp) {
+ MDC.put("EntryTimestamp", generateTimestampStr(beginTimeStamp));
+ MDC.put("EndTimestamp", generateTimestampStr(endTimeStamp));
+ MDC.put("ElapsedTime", String.valueOf(endTimeStamp.getTime() - beginTimeStamp.getTime()));
+ }
+
+ /**
+ * Set response related logging variables in thread local data via MDC.
+ *
+ * @param code Response code ("0" indicates success)
+ * @param description Response description
+ * @param className class name of invoking class
+ */
+ public static void setResponseContext(String code, String description, String className) {
+ MDC.put("ResponseCode", code);
+ MDC.put("StatusCode", "0".equals(code) ? "COMPLETE" : "ERROR");
+ MDC.put("ResponseDescription", description != null ? description : "");
+ MDC.put("ClassName", className != null ? className : "");
+ }
+
+ /**
+ * Set target related logging variables in thread local data via MDC.
+ *
+ * @param targetEntity Target entity (an external/sub component, for ex. "sdc")
+ * @param targetServiceName Target service name (name of API invoked on target)
+ */
+ public static void setTargetContext(String targetEntity, String targetServiceName) {
+ MDC.put("TargetEntity", targetEntity != null ? targetEntity : "");
+ MDC.put("TargetServiceName", targetServiceName != null ? targetServiceName : "");
+ }
+
+ /**
+ * Set error related logging variables in thread local data via MDC.
+ *
+ * @param code Error code
+ * @param description Error description
+ */
+ public static void setErrorContext(String code, String description) {
+ MDC.put("ErrorCode", code);
+ MDC.put("ErrorDescription", description != null ? description : "");
+ }
+
+ private static String generateTimestampStr(Date timeStamp) {
+ return DATE_FORMAT.format(timeStamp);
+ }
+
+ /**
+ * Get a previously stored RequestID for the thread local data via MDC. If
+ * one was not previously stored, generate one, store it, and return that
+ * one.
+ *
+ * @return A string with the request ID
+ */
+ public static String getRequestId() {
+ String requestId = MDC.get(OnapLogConstants.Mdcs.REQUEST_ID);
+ if (requestId == null || requestId.isEmpty()) {
+ requestId = UUID.randomUUID().toString();
+ MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId);
+ }
+ return requestId;
+ }
+
+ private static DateFormat createDateFormat() {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return dateFormat;
+ }
+
+ /* *******************************************************************************************
+ * Method for ONAP Application Logging Specification v1.2
+ * *******************************************************************************************/
+
+ /**
+ * Report <tt>ENTERING</tt> marker.
+ *
+ * @param request non-null incoming request (wrapper)
+ * @param serviceName service name
+ */
+ public void entering(HttpServletRequest request, String serviceName) {
+ // MDC.clear();
+ checkNotNull(request);
+ // Extract MDC values from standard HTTP headers.
+ final String requestId =
+ defaultToUuid(request.getHeader(OnapLogConstants.Headers.REQUEST_ID));
+ final String invocationId =
+ defaultToUuid(request.getHeader(OnapLogConstants.Headers.INVOCATION_ID));
+ final String partnerName =
+ defaultToEmpty(request.getHeader(OnapLogConstants.Headers.PARTNER_NAME));
+
+ // Default the partner name to the user name used to login to clamp
+ if (partnerName.equalsIgnoreCase(EMPTY_MESSAGE)) {
+ MDC.put(OnapLogConstants.Mdcs.PARTNER_NAME,
+ AuthorizationController.getPrincipalName(SecurityContextHolder.getContext()));
+ }
+
+ // Set standard MDCs. Override this entire method if you want to set
+ // others, OR set them BEFORE or AFTER the invocation of #entering,
+ // depending on where you need them to appear, OR extend the
+ // ServiceDescriptor to add them.
+ MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC)
+ .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO)));
+ MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId);
+ MDC.put(OnapLogConstants.Mdcs.INVOCATION_ID, invocationId);
+ MDC.put(OnapLogConstants.Mdcs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getRemoteAddr()));
+ MDC.put(OnapLogConstants.Mdcs.SERVER_FQDN, defaultToEmpty(request.getServerName()));
+ MDC.put(OnapLogConstants.Mdcs.INSTANCE_UUID, defaultToEmpty(sInstanceUUID));
+
+ // Default the service name to the requestURI, in the event that
+ // no value has been provided.
+ if (serviceName == null || serviceName.equalsIgnoreCase(EMPTY_MESSAGE)) {
+ MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, request.getRequestURI());
+ } else {
+ MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, serviceName);
+ }
+
+ // Set the Response Status code to in progress
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE,
+ OnapLogConstants.ResponseStatus.INPROGRESS.toString());
+ setElapsedTime();
+
+ this.mlogger.info(OnapLogConstants.Markers.ENTRY, "Entering");
+ }
+
+ /**
+ * Report <tt>EXITING</tt> marker.
+ *
+ * @param code response code
+ * @param description response description
+ * @param severity response severity
+ * @param status response status code
+ */
+ public void exiting(int code, String description, Level severity,
+ OnapLogConstants.ResponseStatus status) {
+ try {
+
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_CODE, defaultToEmpty(code));
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_DESCRIPTION, defaultToEmpty(description));
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_SEVERITY, defaultToEmpty(severity));
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, defaultToEmpty(status));
+
+ setElapsedTime();
+ this.mlogger.info(OnapLogConstants.Markers.EXIT, "Exiting");
+ } finally {
+ MDC.clear();
+ }
+ }
+
+ private void setElapsedTime() {
+ String entryTimestamp = MDC.get(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP);
+ MDC.put(OnapLogConstants.Mdcs.ELAPSED_TIME, String.valueOf(ChronoUnit.MILLIS
+ .between(ZonedDateTime.parse(entryTimestamp != null ? entryTimestamp : ZonedDateTime.now(ZoneOffset.UTC)
+ .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO)),
+ DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneOffset.UTC)), ZonedDateTime.now(ZoneOffset.UTC))));
+ }
+
+ /**
+ * Get the property value.
+ *
+ * @param name The name of the property
+ * @return The value of the property
+ */
+ public String getProperties(String name) {
+ return MDC.get(name);
+ }
+
+ /**
+ * Report pending invocation with <tt>INVOKE</tt> marker,
+ * setting standard ONAP logging headers automatically.
+ *
+ * @param con The HTTP url connection
+ * @param targetEntity The target entity
+ * @param targetServiceName The target service name
+ * @return The HTTP url connection
+ */
+ public HttpURLConnection invoke(final HttpURLConnection con, String targetEntity,
+ String targetServiceName) {
+ return this.invokeGeneric(con, targetEntity, targetServiceName);
+ }
+
+ /**
+ * Report pending invocation with <tt>INVOKE</tt> marker,
+ * setting standard ONAP logging headers automatically.
+ *
+ * @param targetEntity The target entity
+ * @param targetServiceName The target service name
+ */
+ public void invoke(String targetEntity, String targetServiceName) {
+ final String invocationId = UUID.randomUUID().toString();
+
+ invokeContext(targetEntity, targetServiceName, invocationId);
+
+ // Log INVOKE*, with the invocationID as the message body.
+ // (We didn't really want this kind of behavior in the standard,
+ // but is it worse than new, single-message MDC?)
+ this.mlogger.info(OnapLogConstants.Markers.INVOKE, "INVOKE");
+ this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}");
+ }
+
+ /**
+ * Report pending invocation with <tt>INVOKE</tt> marker,
+ * setting standard ONAP logging headers automatically.
+ *
+ * @param con The HTTPS url connection
+ * @param targetEntity The target entity
+ * @param targetServiceName The target service name
+ * @return The HTTPS url connection
+ */
+ public HttpsURLConnection invokeHttps(final HttpsURLConnection con, String targetEntity,
+ String targetServiceName) {
+ return this.invokeGeneric(con, targetEntity, targetServiceName);
+ }
+
+ /**
+ * Report pending invocation with <tt>INVOKE-RETURN</tt> marker.
+ */
+ public void invokeReturn() {
+ MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE,
+ OnapLogConstants.ResponseStatus.COMPLETE.toString());
+ // Add the Invoke-return marker and clear the needed MDC
+ this.mlogger.info(OnapLogConstants.Markers.INVOKE_RETURN, "INVOKE-RETURN");
+ invokeReturnContext();
+ }
+
+ /**
+ * Dependency-free nullcheck.
+ *
+ * @param in to be checked
+ * @param <T> argument (and return) type
+ * @return input arg
+ */
+ private static <T> T checkNotNull(final T in) {
+ if (in == null) {
+ throw new NullPointerException();
+ }
+ return in;
+ }
+
+ /**
+ * Dependency-free string default.
+ *
+ * @param in to be filtered
+ * @return input string or null
+ */
+ private static String defaultToEmpty(final Object in) {
+ if (in == null) {
+ return "";
+ }
+ return in.toString();
+ }
+
+ /**
+ * Dependency-free string default.
+ *
+ * @param in to be filtered
+ * @return input string or null
+ */
+ private static String defaultToUuid(final String in) {
+ if (in == null) {
+ return UUID.randomUUID().toString();
+ }
+ return in;
+ }
+
+ /**
+ * Set target related logging variables in thread local data via MDC.
+ *
+ * @param targetEntity Target entity (an external/sub component, for ex. "sdc")
+ * @param targetServiceName Target service name (name of API invoked on target)
+ * @param invocationId The invocation ID
+ */
+ private void invokeContext(String targetEntity, String targetServiceName, String invocationId) {
+ MDC.put(OnapLogConstants.Mdcs.TARGET_ENTITY, defaultToEmpty(targetEntity));
+ MDC.put(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME, defaultToEmpty(targetServiceName));
+ MDC.put(OnapLogConstants.Mdcs.INVOCATIONID_OUT, invocationId);
+ MDC.put(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC)
+ .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO)));
+ }
+
+ /**
+ * Clear target related logging variables in thread local data via MDC.
+ */
+ private void invokeReturnContext() {
+ MDC.remove(OnapLogConstants.Mdcs.TARGET_ENTITY);
+ MDC.remove(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME);
+ MDC.remove(OnapLogConstants.Mdcs.INVOCATIONID_OUT);
+ MDC.remove(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP);
+ MDC.remove(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE);
+ }
+
+ private <T extends URLConnection> T invokeGeneric(final T con, String targetEntity,
+ String targetServiceName) {
+ final String invocationId = UUID.randomUUID().toString();
+
+ // Set standard HTTP headers on (southbound request) builder.
+ con.setRequestProperty(OnapLogConstants.Headers.REQUEST_ID,
+ defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.REQUEST_ID)));
+ con.setRequestProperty(OnapLogConstants.Headers.INVOCATION_ID, invocationId);
+ con.setRequestProperty(OnapLogConstants.Headers.PARTNER_NAME,
+ defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.PARTNER_NAME)));
+
+ invokeContext(targetEntity, targetServiceName, invocationId);
+
+ // Log INVOKE*, with the invocationID as the message body.
+ // (We didn't really want this kind of behavior in the standard,
+ // but is it worse than new, single-message MDC?)
+ this.mlogger.info(OnapLogConstants.Markers.INVOKE, "");
+ this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}");
+ return con;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java
new file mode 100644
index 000000000..78b16f1a0
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/OnapLogConstants.java
@@ -0,0 +1,304 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+/**
+ * Constants for standard ONAP headers, MDCs, etc.
+ */
+public final class OnapLogConstants {
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructors.
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Hide and forbid construction.
+ */
+ private OnapLogConstants() {
+ throw new UnsupportedOperationException();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Inner classes.
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Marker constants.
+ */
+ public static final class Markers {
+
+ /** Marker reporting invocation. */
+ public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE");
+
+ /** Marker reporting invocation return. */
+ public static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN");
+
+ /** Marker reporting synchronous invocation. */
+ public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS");
+
+ /** Marker reporting asynchronous invocation. */
+ public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS");
+
+ /** Marker reporting entry into a component. */
+ public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY");
+
+ /** Marker reporting exit from a component. */
+ public static final Marker EXIT = MarkerFactory.getMarker("EXIT");
+
+ /**
+ * Build nested, detached marker.
+ *
+ * @param m1 top token.
+ * @param m2 sub-token.
+ * @return detached Marker.
+ */
+ private static Marker build(final String m1, final String m2) {
+ final Marker marker = MarkerFactory.getDetachedMarker(m1);
+ marker.add(MarkerFactory.getDetachedMarker(m2));
+ return marker;
+ }
+
+ /**
+ * Hide and forbid construction.
+ */
+ private Markers() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * MDC name constants.
+ */
+ public static final class Mdcs {
+
+ // Tracing. ////////////////////////////////////////////////////////////
+
+ /** MDC correlating messages for an invocation. */
+ public static final String INVOCATION_ID = "InvocationID";
+
+ public static final String SERVER_INVOCATION_ID = "ServerInvocationId";
+
+ public static final String CLIENT_INVOCATION_ID = "ClientInvocationId";
+
+ /** MDC correlating messages for a logical transaction. */
+ public static final String REQUEST_ID = "RequestID";
+
+ /** MDC recording calling partner name. */
+ public static final String PARTNER_NAME = "PartnerName";
+
+ /** MDC recording current service. */
+ public static final String SERVICE_NAME = "ServiceName";
+
+ /** MDC recording target service. */
+ public static final String TARGET_SERVICE_NAME = "TargetServiceName";
+
+ /** MDC recording InvocationID Out. */
+ public static final String INVOCATIONID_OUT = "InvocationIDOut";
+
+ /** MDC recording target entity. */
+ public static final String TARGET_ENTITY = "TargetEntity";
+
+ /** MDC recording target element. */
+ public static final String TARGET_ELEMENT = "TargetElement";
+
+ /** MDC recording current service instance id. */
+ public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID";
+
+ /** MDC recording current instance id. */
+ public static final String INSTANCE_UUID = "InstanceID";
+
+ // Network. ////////////////////////////////////////////////////////////
+
+ /** MDC recording caller address. */
+ public static final String CLIENT_IP_ADDRESS = "ClientIPAddress";
+
+ /** MDC recording server IP address. */
+ public static final String SERVER_IP_ADDRESS = "ServerIPAddress";
+
+ /** MDC recording server FQDN. */
+ public static final String SERVER_FQDN = "ServerFQDN";
+
+ /** MDC recording virtual server name. */
+ public static final String VIRTUAL_SERVER_NAME = "VirtualServerName";
+
+ /** MDC recording context name. */
+ public static final String CONTEXT_NAME = "ContextName";
+
+ /**
+ * MDC recording timestamp at the start of the current request,
+ * with the same scope as {@link #REQUEST_ID}.
+ *
+ * <p>
+ * Open issues:
+ * <ul>
+ * <ul>
+ * Easily confused with {@link #INVOKE_TIMESTAMP}.
+ * </ul>
+ * <ul>
+ * No mechanism for propagation between components, e.g. via HTTP headers.
+ * </ul>
+ * <ul>
+ * Whatever mechanism we define, it's going to be costly.
+ * </ul>
+ * </ul>
+ * </p>
+ */
+ public static final String ENTRY_TIMESTAMP = "EntryTimestamp";
+
+ /** MDC recording timestamp at the start of the current invocation. */
+ public static final String INVOKE_TIMESTAMP = "InvokeTimestamp";
+
+ /** MDC recording elapsed time. */
+ public static final String ELAPSED_TIME = "ElapsedTime";
+
+ /** MDC recording log timestamp. */
+ public static final String LOG_TIMESTAMP = "LogTimestamp";
+
+ // Outcomes. ///////////////////////////////////////////////////////////
+
+ /** MDC reporting outcome code. */
+ public static final String RESPONSE_CODE = "ResponseCode";
+
+ /** MDC reporting outcome description. */
+ public static final String RESPONSE_DESCRIPTION = "ResponseDesc";
+
+ /** MDC reporting severity. */
+ public static final String RESPONSE_SEVERITY = "Severity";
+
+ /** MDC reporting response status code. */
+ public static final String RESPONSE_STATUS_CODE = "StatusCode";
+
+ /** MDC recording error code. */
+ public static final String ERROR_CODE = "ErrorCode";
+
+ /** MDC recording error description. */
+ public static final String ERROR_DESC = "ErrorDesc";
+
+ // Unsorted. ///////////////////////////////////////////////////////////
+
+ /**
+ * Hide and forbid construction.
+ */
+ private Mdcs() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Header name constants.
+ */
+ public static final class Headers {
+
+ /** HTTP <tt>X-ONAP-RequestID</tt> header. */
+ public static final String REQUEST_ID = "X-ONAP-RequestID";
+
+ /** HTTP <tt>X-InvocationID</tt> header. */
+ public static final String INVOCATION_ID = "X-ONAP-InvocationID";
+
+ /** HTTP <tt>X-ONAP-PartnerName</tt> header. */
+ public static final String PARTNER_NAME = "X-ONAP-PartnerName";
+
+ /**
+ * Hide and forbid construction.
+ */
+ private Headers() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // Enums.
+ //
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Response success or not, for setting <tt>StatusCode</tt>.
+ */
+ public enum ResponseStatus {
+
+ /** Success. */
+ COMPLETE,
+
+ /** Not. */
+ ERROR,
+
+ /** In Progress. */
+ INPROGRESS
+ }
+
+ /**
+ * Synchronous or asynchronous execution, for setting invocation marker.
+ */
+ public enum InvocationMode {
+
+ /** Synchronous, blocking. */
+ SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS),
+
+ /** Asynchronous, non-blocking. */
+ ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS);
+
+ /** Enum value. */
+ private String enumValue;
+
+ /** Corresponding marker. */
+ private Marker marker;
+
+ /**
+ * Construct enum.
+ *
+ * @param enumValue enum value.
+ * @param marker corresponding Marker.
+ */
+ InvocationMode(final String enumValue, final Marker marker) {
+ this.enumValue = enumValue;
+ this.marker = marker;
+ }
+
+ /**
+ * Get Marker for enum.
+ *
+ * @return Marker.
+ */
+ public Marker getMarker() {
+ return this.marker;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.enumValue;
+ }
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java
new file mode 100644
index 000000000..d6184c656
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/clds/util/ResourceFileUtils.java
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Scanner;
+
+/**
+ * Utility methods supporting resources accesses.
+ */
+public final class ResourceFileUtils {
+
+ /**
+ * getResourceAsStram supports the "file:" prefix as they use URL.
+ * So here we want to eliminate classpath: prefix, so that this class can get
+ * files from jar resource or file system.
+ */
+
+ private static final String CLASSPATH_PREFIX = "classpath:";
+
+ /**
+ * Private constructor to avoid creating instances of util class.
+ */
+ private ResourceFileUtils() {
+ }
+
+ /**
+ * Method to access a file from the jar resource folder or file system.
+ * Give the prefix "classpath:" so that it accesses the jar resource folder (default case)
+ * or the prefix "file:" so that it accesses the file system.
+ *
+ * @param fileName The path of the resource (no prefix it will be a classpath access,
+ * "classpath:/myfilename" or "file:/myfilename")
+ * @return The file as inputStream
+ */
+ public static InputStream getResourceAsStream(String fileName) {
+ InputStream is = Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(fileName.replaceFirst("^" + CLASSPATH_PREFIX, ""));
+ if (is == null) {
+ throw new IllegalArgumentException("Unable to find resource: " + fileName);
+ }
+ return is;
+ }
+
+ /**
+ * Method to access a resource file as a string.
+ * Give the prefix "classpath:" so that it accesses the jar resource folder (default case)
+ * or the prefix "file:" so that it accesses the file system.
+ *
+ * @param fileName The path of the resource (no prefix it will be a classpath access,
+ * "classpath:/myfilename" or "file:/myfilename")
+ * @return The file as String
+ * @throws IOException In case of failure to find the file.
+ */
+ public static String getResourceAsString(String fileName) throws IOException {
+ try (InputStream is = getResourceAsStream(fileName)) {
+ return streamToString(is);
+ }
+ }
+
+ private static String streamToString(InputStream inputStream) {
+ try (Scanner scanner = new Scanner(inputStream)) {
+ Scanner delimitedScanner = scanner.useDelimiter("\\A");
+ return delimitedScanner.hasNext() ? delimitedScanner.next() : "";
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java b/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java
new file mode 100644
index 000000000..6479cf767
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/configuration/ClampGsonDataFormat.java
@@ -0,0 +1,173 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.configuration;
+
+import com.google.gson.Gson;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import org.apache.camel.Exchange;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataFormatName;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.IOHelper;
+import org.apache.commons.io.IOUtils;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+
+public class ClampGsonDataFormat extends ServiceSupport implements DataFormat, DataFormatName {
+ private Gson gson;
+ private Class<?> unmarshalType;
+ private Type unmarshalGenericType;
+ private boolean contentTypeHeader = true;
+
+ public ClampGsonDataFormat() {
+ this(Object.class);
+ }
+
+ /**
+ * Use the default Gson {@link Gson} and with a custom unmarshal type.
+ *
+ * @param unmarshalType the custom unmarshal type
+ */
+ public ClampGsonDataFormat(Class<?> unmarshalType) {
+ this(null, unmarshalType);
+ }
+
+ /**
+ * Use a custom Gson mapper and and unmarshal type.
+ *
+ * @param gson the custom mapper
+ * @param unmarshalType the custom unmarshal type
+ */
+ public ClampGsonDataFormat(Gson gson, Class<?> unmarshalType) {
+ this.gson = gson;
+ this.unmarshalType = unmarshalType;
+ }
+
+ /**
+ * Use the default Gson {@link Gson} and with a custom unmarshal generic type.
+ *
+ * @param unmarshalGenericType the custom unmarshal generic type
+ */
+ public ClampGsonDataFormat(Type unmarshalGenericType) {
+ this(null, unmarshalGenericType);
+ }
+
+ /**
+ * Use a custom Gson mapper and and unmarshal token type.
+ *
+ * @param gson the custom mapper
+ * @param unmarshalGenericType the custom unmarshal generic type
+ */
+ public ClampGsonDataFormat(Gson gson, Type unmarshalGenericType) {
+ this.gson = gson;
+ this.unmarshalGenericType = unmarshalGenericType;
+ }
+
+ @Override
+ public String getDataFormatName() {
+ return "clamp-gson";
+ }
+
+ @Override
+ public void marshal(final Exchange exchange, final Object graph, final OutputStream stream) throws Exception {
+ try (final OutputStreamWriter osw = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
+ final BufferedWriter writer = IOHelper.buffered(osw)) {
+ gson.toJson(graph, writer);
+ }
+
+ if (contentTypeHeader) {
+ if (exchange.hasOut()) {
+ exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json");
+ } else {
+ exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
+ }
+ }
+ }
+
+ @Override
+ public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception {
+ try (final InputStreamReader isr = new InputStreamReader(stream, StandardCharsets.UTF_8);
+ final BufferedReader reader = IOHelper.buffered(isr)) {
+ if (unmarshalType.equals(String.class)) {
+ return IOUtils.toString(reader);
+ } else if (unmarshalGenericType == null) {
+ return gson.fromJson(reader, unmarshalType);
+ } else {
+ return gson.fromJson(reader, unmarshalGenericType);
+ }
+ }
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ if (gson == null) {
+ gson = JsonUtils.GSON_JPA_MODEL;
+ }
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ // noop
+ }
+
+ // Properties
+ // -------------------------------------------------------------------------
+
+ public Class<?> getUnmarshalType() {
+ return this.unmarshalType;
+ }
+
+ public void setUnmarshalType(Class<?> unmarshalType) {
+ this.unmarshalType = unmarshalType;
+ }
+
+ public Type getUnmarshalGenericType() {
+ return this.unmarshalGenericType;
+ }
+
+ public void setUnmarshalGenericType(Type unmarshalGenericType) {
+ this.unmarshalGenericType = unmarshalGenericType;
+ }
+
+ public boolean isContentTypeHeader() {
+ return contentTypeHeader;
+ }
+
+ /**
+ * If enabled then Gson will set the Content-Type header to
+ * <tt>application/json</tt> when marshalling.
+ */
+ public void setContentTypeHeader(boolean contentTypeHeader) {
+ this.contentTypeHeader = contentTypeHeader;
+ }
+
+ public Gson getGson() {
+ return this.gson;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java
new file mode 100644
index 000000000..db024e07a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantDeserializer.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.dao.model.gson.converter;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+import java.util.Locale;
+
+public class InstantDeserializer implements JsonDeserializer<Instant> {
+
+ DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.US)
+ .withZone(ZoneId.systemDefault());
+
+ @Override
+ public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
+ return Instant.parse(json.getAsString());
+
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java
new file mode 100644
index 000000000..7208a472c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/gson/converter/InstantSerializer.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.dao.model.gson.converter;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+
+public class InstantSerializer implements JsonSerializer<Instant> {
+
+ @Override
+ public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(DateTimeFormatter.ISO_INSTANT.format(src));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java
new file mode 100644
index 000000000..d3aaa32a9
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java
@@ -0,0 +1,108 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.dao.model.jsontype;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import org.hibernate.type.descriptor.ValueBinder;
+import org.hibernate.type.descriptor.ValueExtractor;
+import org.hibernate.type.descriptor.WrapperOptions;
+import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
+import org.hibernate.type.descriptor.sql.BasicBinder;
+import org.hibernate.type.descriptor.sql.BasicExtractor;
+import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
+
+public class JsonStringSqlTypeDescriptor implements SqlTypeDescriptor {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 1103168570216921981L;
+
+ public static final JsonStringSqlTypeDescriptor INSTANCE = new JsonStringSqlTypeDescriptor();
+
+ @Override
+ public int getSqlType() {
+ return Types.OTHER;
+ }
+
+ @Override
+ public boolean canBeRemapped() {
+ return true;
+ }
+
+ @Override
+ public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
+ return new BasicBinder<X>(javaTypeDescriptor, this) {
+ @Override
+ protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
+ throws SQLException {
+ st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options));
+ }
+
+ @Override
+ protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
+ throws SQLException {
+ st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options));
+ }
+ };
+ }
+
+ @Override
+ public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
+ return new BasicExtractor<X>(javaTypeDescriptor, this) {
+ @Override
+ protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
+ return javaTypeDescriptor.wrap(extractJson(rs, name), options);
+ }
+
+ @Override
+ protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
+ return javaTypeDescriptor.wrap(extractJson(statement, index), options);
+ }
+
+ @Override
+ protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
+ throws SQLException {
+ return javaTypeDescriptor.wrap(extractJson(statement, name), options);
+ }
+ };
+ }
+
+ protected Object extractJson(ResultSet rs, String name) throws SQLException {
+ return rs.getObject(name);
+ }
+
+ protected Object extractJson(CallableStatement statement, int index) throws SQLException {
+ return statement.getObject(index);
+ }
+
+ protected Object extractJson(CallableStatement statement, String name) throws SQLException {
+ return statement.getObject(name);
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java
new file mode 100644
index 000000000..ed8464b14
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/JsonTypeDescriptor.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.dao.model.jsontype;
+
+import com.google.gson.JsonObject;
+import java.io.Serializable;
+import org.hibernate.type.descriptor.WrapperOptions;
+import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
+import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+
+public class JsonTypeDescriptor extends AbstractTypeDescriptor<JsonObject> {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = -3439698221196089003L;
+
+ public static final JsonTypeDescriptor INSTANCE = new JsonTypeDescriptor();
+
+ /**
+ * Creates an instance of JsonTypeDescriptor.
+ */
+ public JsonTypeDescriptor() {
+ super(JsonObject.class, new ImmutableMutabilityPlan<JsonObject>() {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 1169396106518110214L;
+
+ @Override
+ public Serializable disassemble(JsonObject value) {
+ return JsonUtils.GSON_JPA_MODEL.toJson(value);
+ }
+
+ @Override
+ public JsonObject assemble(Serializable cached) {
+ return JsonUtils.GSON_JPA_MODEL.fromJson((String) cached, JsonObject.class);
+ }
+
+ });
+ }
+
+ @Override
+ public String toString(JsonObject value) {
+ return JsonUtils.GSON_JPA_MODEL.toJson(value);
+ }
+
+ @Override
+ public JsonObject fromString(String string) {
+ return JsonUtils.GSON_JPA_MODEL.fromJson(string, JsonObject.class);
+ }
+
+ @Override
+ public <X> X unwrap(JsonObject value, Class<X> type, WrapperOptions options) {
+ if (value == null) {
+ return null;
+ }
+
+ if (String.class.isAssignableFrom(type)) {
+ return (X) toString(value);
+ }
+
+ if (JsonObject.class.isAssignableFrom(type)) {
+ return (X) JsonUtils.GSON_JPA_MODEL.toJson(toString(value));
+ }
+ throw unknownUnwrap(type);
+ }
+
+ @Override
+ public <X> JsonObject wrap(X value, WrapperOptions options) {
+ if (value == null) {
+ return null;
+ }
+
+ if (String.class.isInstance(value)) {
+ return JsonUtils.GSON_JPA_MODEL.fromJson((String) value, JsonObject.class);
+ }
+
+ throw unknownWrap(value.getClass());
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java
new file mode 100644
index 000000000..4a7b65bb4
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/dao/model/jsontype/StringJsonUserType.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.dao.model.jsontype;
+
+import com.google.gson.JsonObject;
+import org.hibernate.type.AbstractSingleColumnStandardBasicType;
+import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
+import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
+
+public class StringJsonUserType extends AbstractSingleColumnStandardBasicType<JsonObject> {
+
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = -7929809808079327767L;
+
+ public StringJsonUserType() {
+ super(JsonStringSqlTypeDescriptor.INSTANCE, JsonTypeDescriptor.INSTANCE);
+ }
+
+ public StringJsonUserType(SqlTypeDescriptor sqlTypeDescriptor, JavaTypeDescriptor<JsonObject> javaTypeDescriptor) {
+ super(sqlTypeDescriptor, javaTypeDescriptor);
+ }
+
+ @Override
+ public String getName() {
+ return "json";
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java b/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java
new file mode 100644
index 000000000..d54b23b21
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/flow/log/FlowLogOperation.java
@@ -0,0 +1,101 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.flow.log;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.camel.Exchange;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.onap.policy.clamp.clds.util.OnapLogConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.Level;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * The Flow log operations.
+ */
+@Component
+public class FlowLogOperation {
+
+ protected static final Logger logger = LoggerFactory.getLogger(FlowLogOperation.class);
+ private LoggingUtils util = new LoggingUtils(logger);
+
+ @Autowired
+ private HttpServletRequest request;
+
+ /**
+ * Generate the entry log.
+ *
+ * @param serviceDesc
+ * The service description the loop name
+ */
+ public void startLog(Exchange exchange, String serviceDesc) {
+ util.entering(request, serviceDesc);
+ exchange.setProperty(OnapLogConstants.Headers.REQUEST_ID,
+ util.getProperties(OnapLogConstants.Mdcs.REQUEST_ID));
+ exchange.setProperty(OnapLogConstants.Headers.INVOCATION_ID,
+ util.getProperties(OnapLogConstants.Mdcs.INVOCATION_ID));
+ exchange.setProperty(OnapLogConstants.Headers.PARTNER_NAME,
+ util.getProperties(OnapLogConstants.Mdcs.PARTNER_NAME));
+ }
+
+ /**
+ * Generate the exiting log.
+ */
+ public void endLog() {
+ util.exiting(HttpStatus.OK.value(), "Successful", Level.INFO,
+ OnapLogConstants.ResponseStatus.COMPLETE);
+ }
+
+ /**
+ * Generate the error exiting log.
+ */
+ public void errorLog() {
+ util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Failed", Level.INFO,
+ OnapLogConstants.ResponseStatus.ERROR);
+ }
+
+ /**
+ * Generate the error exiting log.
+ */
+ public void httpErrorLog() {
+
+ }
+
+ /**
+ * Generate the invoke log.
+ */
+ public void invokeLog(String targetEntity, String targetServiceName) {
+ util.invoke(targetEntity, targetServiceName);
+ }
+
+ /**
+ * Generate the invoke return marker.
+ */
+ public void invokeReturnLog() {
+ util.invokeReturn();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java
new file mode 100644
index 000000000..f46f4227b
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/CsarInstaller.java
@@ -0,0 +1,209 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import org.json.simple.parser.ParseException;
+import org.onap.policy.clamp.clds.client.DcaeInventoryServices;
+import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintArtifact;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintMicroService;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintParser;
+import org.onap.policy.clamp.clds.sdc.controller.installer.ChainGenerator;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.loop.cds.CdsDataInstaller;
+import org.onap.policy.clamp.loop.service.CsarServiceInstaller;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.LoopTemplatesRepository;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.policy.clamp.policy.PolicyEngineServices;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class will be instantiated by spring config, and used by Sdc Controller.
+ * There is no state kept by the bean. It's used to deploy the csar/notification
+ * received from SDC in DB.
+ */
+@Component
+@Qualifier("csarInstaller")
+public class CsarInstaller {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarInstaller.class);
+
+ @Autowired
+ private PolicyModelsRepository policyModelsRepository;
+
+ @Autowired
+ private LoopTemplatesRepository loopTemplatesRepository;
+
+ @Autowired
+ private ChainGenerator chainGenerator;
+
+ @Autowired
+ private DcaeInventoryServices dcaeInventoryService;
+
+ @Autowired
+ private CsarServiceInstaller csarServiceInstaller;
+
+ @Autowired
+ private CdsDataInstaller cdsDataInstaller;
+
+ @Autowired
+ private PolicyEngineServices policyEngineServices;
+
+ /**
+ * Verify whether Csar is deployed.
+ *
+ * @param csar The Csar Handler
+ * @return The flag indicating whether Csar is deployed
+ * @throws SdcArtifactInstallerException The SdcArtifactInstallerException
+ */
+ public boolean isCsarAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException {
+ boolean alreadyInstalled = csarServiceInstaller.isServiceAlreadyDeployed(csar);
+
+ for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {
+ alreadyInstalled = alreadyInstalled
+ && loopTemplatesRepository.existsById(LoopTemplate.generateLoopTemplateName(
+ csar.getSdcNotification().getServiceName(), csar.getSdcNotification().getServiceVersion(),
+ blueprint.getValue().getResourceAttached().getResourceInstanceName(),
+ blueprint.getValue().getBlueprintArtifactName()));
+ }
+ return alreadyInstalled;
+ }
+
+ /**
+ * Install the service and loop templates from the csar.
+ *
+ * @param csar The Csar Handler
+ * @throws SdcArtifactInstallerException The SdcArtifactInstallerException
+ * @throws InterruptedException The InterruptedException
+ * @throws BlueprintParserException In case of issues with the blueprint
+ * parsing
+ */
+ public void installTheCsar(CsarHandler csar)
+ throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException {
+ logger.info("Installing the CSAR " + csar.getFilePath());
+ Service associatedService = csarServiceInstaller.installTheService(csar);
+ cdsDataInstaller.installCdsServiceProperties(csar, associatedService);
+
+ installTheLoopTemplates(csar, associatedService);
+ logger.info("Successfully installed the CSAR " + csar.getFilePath());
+ }
+
+ /**
+ * Install the loop templates from the csar.
+ *
+ * @param csar The Csar Handler
+ * @param service The service object that is related to the loop
+ * @throws SdcArtifactInstallerException The SdcArtifactInstallerException
+ * @throws InterruptedException The InterruptedException
+ * @throws BlueprintParserException In case of issues with the blueprint
+ * parsing
+ */
+ public void installTheLoopTemplates(CsarHandler csar, Service service)
+ throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException {
+ try {
+ logger.info("Installing the Loops");
+ for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) {
+ logger.info("Processing blueprint " + blueprint.getValue().getBlueprintArtifactName());
+ loopTemplatesRepository.save(createLoopTemplateFromBlueprint(csar, blueprint.getValue(), service));
+ }
+ logger.info("Successfully installed the Loops ");
+ } catch (IOException e) {
+ throw new SdcArtifactInstallerException("Exception caught during the Loop installation in database", e);
+ } catch (ParseException e) {
+ throw new SdcArtifactInstallerException("Exception caught during the Dcae query to get ServiceTypeId", e);
+ }
+ }
+
+ private LoopTemplate createLoopTemplateFromBlueprint(CsarHandler csar, BlueprintArtifact blueprintArtifact,
+ Service service)
+ throws IOException, ParseException, InterruptedException, BlueprintParserException,
+ SdcArtifactInstallerException {
+ LoopTemplate newLoopTemplate = new LoopTemplate();
+ newLoopTemplate.setBlueprint(blueprintArtifact.getDcaeBlueprint());
+ newLoopTemplate.setName(LoopTemplate.generateLoopTemplateName(csar.getSdcNotification().getServiceName(),
+ csar.getSdcNotification().getServiceVersion(),
+ blueprintArtifact.getResourceAttached().getResourceInstanceName(),
+ blueprintArtifact.getBlueprintArtifactName()));
+ List<BlueprintMicroService> microServicesChain = chainGenerator
+ .getChainOfMicroServices(BlueprintParser.getMicroServices(blueprintArtifact.getDcaeBlueprint()));
+ if (microServicesChain.isEmpty()) {
+ microServicesChain = BlueprintParser.fallbackToOneMicroService();
+ }
+ newLoopTemplate.setModelService(service);
+ newLoopTemplate.addLoopElementModels(createMicroServiceModels(blueprintArtifact, microServicesChain));
+ newLoopTemplate.setMaximumInstancesAllowed(0);
+ DcaeInventoryResponse dcaeResponse = queryDcaeToGetServiceTypeId(blueprintArtifact);
+ newLoopTemplate.setDcaeBlueprintId(dcaeResponse.getTypeId());
+ return newLoopTemplate;
+ }
+
+ private HashSet<LoopElementModel> createMicroServiceModels(BlueprintArtifact blueprintArtifact,
+ List<BlueprintMicroService> microServicesChain)
+ throws SdcArtifactInstallerException {
+ HashSet<LoopElementModel> newSet = new HashSet<>();
+ for (BlueprintMicroService microService : microServicesChain) {
+ LoopElementModel loopElementModel =
+ new LoopElementModel(microService.getModelType(), LoopElementModel.MICRO_SERVICE_TYPE,
+ null);
+ newSet.add(loopElementModel);
+ PolicyModel newPolicyModel = policyEngineServices.createPolicyModelFromPolicyEngine(microService);
+ if (newPolicyModel != null) {
+ loopElementModel.addPolicyModel(newPolicyModel);
+ } else {
+ throw new SdcArtifactInstallerException(
+ "Unable to find the policy specified in the blueprint " + blueprintArtifact
+ .getBlueprintArtifactName() + ") on the Policy Engine:"
+ + microService.getModelType() + "/" + microService.getModelVersion());
+ }
+ }
+ return newSet;
+ }
+
+ /**
+ * Get the service blueprint Id in the Dcae inventory using the SDC UUID.
+ *
+ * @return The DcaeInventoryResponse object containing the dcae values
+ */
+ private DcaeInventoryResponse queryDcaeToGetServiceTypeId(BlueprintArtifact blueprintArtifact)
+ throws IOException, ParseException, InterruptedException {
+ return dcaeInventoryService.getDcaeInformation(blueprintArtifact.getBlueprintArtifactName(),
+ blueprintArtifact.getBlueprintInvariantServiceUuid(),
+ blueprintArtifact.getResourceAttached().getResourceInvariantUUID());
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java b/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java
new file mode 100644
index 000000000..99d8d1e69
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/Loop.java
@@ -0,0 +1,389 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.hibernate.annotations.SortNatural;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+import org.onap.policy.clamp.loop.components.external.DcaeComponent;
+import org.onap.policy.clamp.loop.components.external.ExternalComponent;
+import org.onap.policy.clamp.loop.components.external.PolicyComponent;
+import org.onap.policy.clamp.loop.deploy.DcaeDeployParameters;
+import org.onap.policy.clamp.loop.log.LoopLog;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+
+@Entity
+@Table(name = "loops")
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public class Loop extends AuditEntity implements Serializable {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522707701388642L;
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @Expose
+ @Column(name = "dcae_deployment_id")
+ private String dcaeDeploymentId;
+
+ @Expose
+ @Column(name = "dcae_deployment_status_url")
+ private String dcaeDeploymentStatusUrl;
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "global_properties_json")
+ private JsonObject globalPropertiesJson;
+
+ @Expose
+ @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
+ @JoinColumn(name = "service_uuid")
+ private Service modelService;
+
+ @Expose
+ @Column(nullable = false, name = "last_computed_state")
+ @Enumerated(EnumType.STRING)
+ private LoopState lastComputedState;
+
+ @Expose
+ @Transient
+ private final Map<String, ExternalComponent> components = new HashMap<>();
+
+ @Expose
+ @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true)
+ private Set<OperationalPolicy> operationalPolicies = new HashSet<>();
+
+ @Expose
+ @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER)
+ @JoinTable(name = "loops_to_microservicepolicies", joinColumns = @JoinColumn(name = "loop_name"),
+ inverseJoinColumns = @JoinColumn(name = "microservicepolicy_name"))
+ private Set<MicroServicePolicy> microServicePolicies = new HashSet<>();
+
+ @Expose
+ @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true)
+ @SortNatural
+ private SortedSet<LoopLog> loopLogs = new TreeSet<>();
+
+ @Expose
+ @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER)
+ @JoinColumn(name = "loop_template_name", nullable = false)
+ private LoopTemplate loopTemplate;
+
+ private void initializeExternalComponents() {
+ this.addComponent(new PolicyComponent());
+ this.addComponent(new DcaeComponent());
+ }
+
+ /**
+ * Public constructor.
+ */
+ public Loop() {
+ initializeExternalComponents();
+ }
+
+ /**
+ * Constructor.
+ */
+ public Loop(String name) {
+ this.name = name;
+ this.lastComputedState = LoopState.DESIGN;
+ this.globalPropertiesJson = new JsonObject();
+ initializeExternalComponents();
+ }
+
+ /**
+ * This constructor creates a loop from a loop template.
+ *
+ * @param name The loop name
+ * @param loopTemplate The loop template from which a new loop instance must be created
+ */
+ public Loop(String name, LoopTemplate loopTemplate, ToscaConverterWithDictionarySupport toscaConverter) {
+ this(name);
+ this.setLoopTemplate(loopTemplate);
+ this.setModelService(loopTemplate.getModelService());
+ loopTemplate.getLoopElementModelsUsed().forEach(element -> {
+ if (LoopElementModel.MICRO_SERVICE_TYPE.equals(element.getLoopElementModel().getLoopElementType())) {
+ this.addMicroServicePolicy((MicroServicePolicy) element.getLoopElementModel()
+ .createPolicyInstance(this, toscaConverter));
+ } else if (LoopElementModel.OPERATIONAL_POLICY_TYPE
+ .equals(element.getLoopElementModel().getLoopElementType())) {
+ this.addOperationalPolicy((OperationalPolicy) element.getLoopElementModel()
+ .createPolicyInstance(this, toscaConverter));
+ }
+ });
+ this.setGlobalPropertiesJson(DcaeDeployParameters.getDcaeDeploymentParametersInJson(this));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDcaeDeploymentId() {
+ return dcaeDeploymentId;
+ }
+
+ void setDcaeDeploymentId(String dcaeDeploymentId) {
+ this.dcaeDeploymentId = dcaeDeploymentId;
+ }
+
+ public String getDcaeDeploymentStatusUrl() {
+ return dcaeDeploymentStatusUrl;
+ }
+
+ void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) {
+ this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl;
+ }
+
+ public LoopState getLastComputedState() {
+ return lastComputedState;
+ }
+
+ void setLastComputedState(LoopState lastComputedState) {
+ this.lastComputedState = lastComputedState;
+ }
+
+ public Set<OperationalPolicy> getOperationalPolicies() {
+ return operationalPolicies;
+ }
+
+ void setOperationalPolicies(Set<OperationalPolicy> operationalPolicies) {
+ this.operationalPolicies = operationalPolicies;
+ }
+
+ public Set<MicroServicePolicy> getMicroServicePolicies() {
+ return microServicePolicies;
+ }
+
+ void setMicroServicePolicies(Set<MicroServicePolicy> microServicePolicies) {
+ this.microServicePolicies = microServicePolicies;
+ }
+
+ public JsonObject getGlobalPropertiesJson() {
+ return globalPropertiesJson;
+ }
+
+ void setGlobalPropertiesJson(JsonObject globalPropertiesJson) {
+ this.globalPropertiesJson = globalPropertiesJson;
+ }
+
+ public Set<LoopLog> getLoopLogs() {
+ return loopLogs;
+ }
+
+ void setLoopLogs(SortedSet<LoopLog> loopLogs) {
+ this.loopLogs = loopLogs;
+ }
+
+ /**
+ * This method adds an operational policy to the loop.
+ *
+ * @param opPolicy the operationalPolicy to add
+ */
+ public void addOperationalPolicy(OperationalPolicy opPolicy) {
+ operationalPolicies.add(opPolicy);
+ opPolicy.setLoop(this);
+ }
+
+ /**
+ * This method removes an operational policy to the loop.
+ *
+ * @param opPolicy the operationalPolicy to add
+ */
+ public void removeOperationalPolicy(OperationalPolicy opPolicy) {
+ operationalPolicies.remove(opPolicy);
+ }
+
+ /**
+ * This method adds an micro service policy to the loop.
+ *
+ * @param microServicePolicy the micro service to add
+ */
+ public void addMicroServicePolicy(MicroServicePolicy microServicePolicy) {
+ microServicePolicies.add(microServicePolicy);
+ microServicePolicy.getUsedByLoops().add(this);
+ }
+
+ public void addLog(LoopLog log) {
+ log.setLoop(this);
+ this.loopLogs.add(log);
+ }
+
+ public Service getModelService() {
+ return modelService;
+ }
+
+ void setModelService(Service modelService) {
+ this.modelService = modelService;
+ }
+
+ public Map<String, ExternalComponent> getComponents() {
+ refreshDcaeComponents();
+ return components;
+ }
+
+ public ExternalComponent getComponent(String componentName) {
+ refreshDcaeComponents();
+ return this.components.get(componentName);
+ }
+
+ public void addComponent(ExternalComponent component) {
+ this.components.put(component.getComponentName(), component);
+ }
+
+ public LoopTemplate getLoopTemplate() {
+ return loopTemplate;
+ }
+
+ public void setLoopTemplate(LoopTemplate loopTemplate) {
+ this.loopTemplate = loopTemplate;
+ }
+
+ private void refreshDcaeComponents() {
+ if (!this.loopTemplate.getUniqueBlueprint()) {
+ this.components.remove("DCAE");
+ for (MicroServicePolicy policy : this.microServicePolicies) {
+ if (!this.components.containsKey("DCAE_" + policy.getName())) {
+ this.addComponent(new DcaeComponent(policy.getName()));
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the operationalPolicy object with the opPolicyName.
+ *
+ * @param opPolicyName The operationalPolicy name
+ * @return The OperationalPolicy object found in loop object
+ */
+ public OperationalPolicy getOperationalPolicy(String opPolicyName) {
+ for (OperationalPolicy operationalPolicy : this.getOperationalPolicies()) {
+ if (operationalPolicy.getName().equals(opPolicyName)) {
+ return operationalPolicy;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the microServicePolicy object with the msPolicyName.
+ *
+ * @param msPolicyName The microServicePolicy name
+ * @return The MicroServicePolicy object found in loop object
+ */
+ public MicroServicePolicy getMicroServicePolicy(String msPolicyName) {
+ for (MicroServicePolicy microServicePolicy : this.getMicroServicePolicies()) {
+ if (microServicePolicy.getName().equals(msPolicyName)) {
+ return microServicePolicy;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Generate the loop name.
+ *
+ * @param serviceName The service name
+ * @param serviceVersion The service version
+ * @param resourceName The resource name
+ * @param blueprintFileName The blueprint file name
+ * @return The generated loop name
+ */
+ public static String generateLoopName(String serviceName, String serviceVersion, String resourceName,
+ String blueprintFileName) {
+ StringBuilder buffer = new StringBuilder("LOOP_").append(serviceName).append("_v").append(serviceVersion)
+ .append("_").append(resourceName).append("_").append(blueprintFileName.replaceAll(".yaml", ""));
+ return buffer.toString().replace('.', '_').replaceAll(" ", "");
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Loop other = (Loop) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java
new file mode 100644
index 000000000..98459c909
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopController.java
@@ -0,0 +1,204 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.List;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class LoopController {
+
+ private final LoopService loopService;
+
+ private final ToscaConverterWithDictionarySupport toscaConverter;
+
+ private final OperationalPolicyService operationalPolicyService;
+
+ private final MicroServicePolicyService microServicePolicyService;
+
+ private static final Type OPERATIONAL_POLICY_TYPE = new TypeToken<List<OperationalPolicy>>() {
+ }.getType();
+
+ private static final Type MICROSERVICE_POLICY_TYPE = new TypeToken<List<MicroServicePolicy>>() {
+ }.getType();
+
+
+ /**
+ * Constructor.
+ *
+ * @param loopService loopService
+ * @param operationalPolicyService operationalPolicyService
+ * @param microServicePolicyService microServicePolicyService
+ * @param toscaConverter toscaConverter
+ */
+ @Autowired
+ public LoopController(LoopService loopService, OperationalPolicyService operationalPolicyService,
+ MicroServicePolicyService microServicePolicyService,
+ ToscaConverterWithDictionarySupport toscaConverter) {
+ this.loopService = loopService;
+ this.toscaConverter = toscaConverter;
+ this.operationalPolicyService = operationalPolicyService;
+ this.microServicePolicyService = microServicePolicyService;
+ }
+
+ public Loop createLoop(String loopName, String templateName) {
+ return loopService.createLoopFromTemplate(loopName, templateName);
+ }
+
+ public List<String> getLoopNames() {
+ return loopService.getClosedLoopNames();
+ }
+
+ public Loop getLoop(String loopName) {
+ return loopService.getLoop(loopName);
+ }
+
+ /**
+ * Update the Operational Policy properties.
+ *
+ * @param loopName The loop name
+ * @param operationalPoliciesJson The new Operational Policy properties
+ * @return The updated loop
+ */
+ public Loop updateOperationalPolicies(String loopName, JsonArray operationalPoliciesJson) {
+ List<OperationalPolicy> operationalPolicies = JsonUtils.GSON_JPA_MODEL.fromJson(operationalPoliciesJson,
+ OPERATIONAL_POLICY_TYPE);
+ return loopService.updateAndSaveOperationalPolicies(loopName, operationalPolicies);
+ }
+
+ /**
+ * Update the whole array of MicroService policies properties.
+ *
+ * @param loopName The loop name
+ * @param microServicePoliciesJson The array of all MicroService policies
+ * properties
+ * @return The updated loop
+ */
+ public Loop updateMicroservicePolicies(String loopName, JsonArray microServicePoliciesJson) {
+ List<MicroServicePolicy> microservicePolicies = JsonUtils.GSON_JPA_MODEL.fromJson(microServicePoliciesJson,
+ MICROSERVICE_POLICY_TYPE);
+ return loopService.updateAndSaveMicroservicePolicies(loopName, microservicePolicies);
+ }
+
+ /**
+ * Update the global properties.
+ *
+ * @param loopName The loop name
+ * @param globalProperties The updated global properties
+ * @return The updated loop
+ */
+ public Loop updateGlobalPropertiesJson(String loopName, JsonObject globalProperties) {
+ return loopService.updateAndSaveGlobalPropertiesJson(loopName, globalProperties);
+ }
+
+ /**
+ * This method add an operational policy to a loop instance.
+ *
+ * @param loopName The loop name
+ * @param policyType The policy model type
+ * @param policyVersion The policy model version
+ * @return The loop modified
+ */
+ public Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException {
+ return loopService.addOperationalPolicy(loopName, policyType, policyVersion);
+ }
+
+ /**
+ * This method removes an operational policy from a loop instance.
+ *
+ * @param loopName The loop name
+ * @param policyType The policy model type
+ * @param policyVersion The policy model version
+ * @return The loop modified
+ */
+ public Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) {
+ return loopService.removeOperationalPolicy(loopName, policyType, policyVersion);
+ }
+
+ /**
+ * This method deletes the loop.
+ *
+ * @param loopName The loop Name
+ */
+ public void deleteLoop(String loopName) {
+ loopService.deleteLoop(loopName);
+ }
+
+ /**
+ * Update one MicroService policy properties.
+ *
+ * @param loopName The loop name
+ * @param newMicroservicePolicy The new MicroService policy properties
+ * @return The updated MicroService policy
+ */
+ public MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) {
+ return loopService.updateMicroservicePolicy(loopName, newMicroservicePolicy);
+ }
+
+ /**
+ * Refresh the Operational Policy Json representation of the loop.
+ *
+ * @param loop The loop
+ * @param operationalPolicyName The operational policy name that needs a refresh
+ * @return The loop object
+ */
+ public Loop refreshOperationalPolicyJsonRepresentation(Loop loop, String operationalPolicyName) {
+ for (OperationalPolicy operationalPolicy : loop.getOperationalPolicies()) {
+ if (operationalPolicy.getName().equals(operationalPolicyName)) {
+ this.operationalPolicyService
+ .refreshOperationalPolicyJsonRepresentation(operationalPolicy, toscaConverter);
+ }
+ }
+ return loop;
+ }
+
+ /**
+ * Refresh the Config Policy Json representation of the loop.
+ *
+ * @param loop The loop
+ * @param microServicePolicyName The microservice policy name that needs a refresh
+ * @return The loop object
+ */
+ public Loop refreshMicroServicePolicyJsonRepresentation(Loop loop, String microServicePolicyName) {
+ for (MicroServicePolicy microServicePolicy : loop.getMicroServicePolicies()) {
+ if (microServicePolicy.getName().equals(microServicePolicyName)) {
+ this.microServicePolicyService
+ .refreshMicroServicePolicyJsonRepresentation(microServicePolicy, toscaConverter, loop);
+ }
+ }
+ return loop;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java
new file mode 100644
index 000000000..975011669
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopService.java
@@ -0,0 +1,190 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.EntityNotFoundException;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.loop.template.LoopTemplatesService;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LoopService {
+
+ @Autowired
+ private LoopsRepository loopsRepository;
+
+ @Autowired
+ private MicroServicePolicyService microservicePolicyService;
+
+ @Autowired
+ private OperationalPolicyService operationalPolicyService;
+
+ @Autowired
+ private PolicyModelsService policyModelsService;
+
+ @Autowired
+ private LoopTemplatesService loopTemplateService;
+
+ @Autowired
+ private ToscaConverterWithDictionarySupport toscaConverter;
+
+ Loop saveOrUpdateLoop(Loop loop) {
+ return loopsRepository.save(loop);
+ }
+
+ List<String> getClosedLoopNames() {
+ return loopsRepository.getAllLoopNames();
+ }
+
+ public Loop getLoop(String loopName) {
+ return loopsRepository.findById(loopName).orElse(null);
+ }
+
+ public void deleteLoop(String loopName) {
+ loopsRepository.deleteById(loopName);
+ }
+
+ /**
+ * Creates a Loop Instance from Loop Template Name.
+ *
+ * @param loopName Name of the Loop to be created
+ * @param templateName Loop Template to used for Loop
+ * @return Loop Instance
+ */
+ public Loop createLoopFromTemplate(String loopName, String templateName) {
+ return loopsRepository
+ .save(new Loop(loopName, loopTemplateService.getLoopTemplate(templateName), toscaConverter));
+ }
+
+ /**
+ * This method is used to refresh the DCAE deployment status fields.
+ *
+ * @param loop The loop instance to be modified
+ * @param deploymentId The deployment ID as returned by DCAE
+ * @param deploymentUrl The Deployment URL as returned by DCAE
+ */
+ public void updateDcaeDeploymentFields(Loop loop, String deploymentId, String deploymentUrl) {
+ loop.setDcaeDeploymentId(deploymentId);
+ loop.setDcaeDeploymentStatusUrl(deploymentUrl);
+ loopsRepository.saveAndFlush(loop);
+ }
+
+ public void updateLoopState(Loop loop, String newState) {
+ loop.setLastComputedState(LoopState.valueOf(newState));
+ loopsRepository.save(loop);
+ }
+
+ /**
+ * This method add an operational policy to a loop instance.
+ * This creates an operational policy from the policy model info and not the loop element model
+ *
+ * @param loopName The loop name
+ * @param policyType The policy model type
+ * @param policyVersion The policy model version
+ * @return The loop modified
+ */
+ Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException {
+ Loop loop = getLoop(loopName);
+ PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion);
+ Set<OperationalPolicy> opPolicySet = loop.getOperationalPolicies();
+ for (OperationalPolicy opPolicy : opPolicySet) {
+ if (opPolicy.getPolicyModel().equals(policyModel)) {
+ throw new IllegalArgumentException(
+ "This type of Operational Policy is already added to the loop. Please choose another one.");
+ }
+ }
+ if (policyModel == null) {
+ return null;
+ }
+ loop.addOperationalPolicy(
+ new OperationalPolicy(loop, loop.getModelService(), policyModel, toscaConverter));
+ return loopsRepository.saveAndFlush(loop);
+ }
+
+ /**
+ * This method remove an operational policy to a loop instance.
+ *
+ * @param loopName The loop name
+ * @param policyType The policy model type
+ * @param policyVersion The policy model version
+ * @return The loop modified
+ */
+ Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) {
+ Loop loop = getLoop(loopName);
+ PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion);
+ if (policyModel == null) {
+ return null;
+ }
+ for (OperationalPolicy opPolicy : loop.getOperationalPolicies()) {
+ if (opPolicy.getPolicyModel().getPolicyModelType().equals(policyType)
+ && opPolicy.getPolicyModel().getVersion().equals(policyVersion)) {
+ loop.removeOperationalPolicy(opPolicy);
+ break;
+ }
+ }
+ return loopsRepository.saveAndFlush(loop);
+ }
+
+ Loop updateAndSaveOperationalPolicies(String loopName, List<OperationalPolicy> newOperationalPolicies) {
+ Loop loop = findClosedLoopByName(loopName);
+ Set<OperationalPolicy> newPolicies = operationalPolicyService.updatePolicies(loop, newOperationalPolicies);
+ loop.setOperationalPolicies(newPolicies);
+ return loopsRepository.save(loop);
+ }
+
+ Loop updateAndSaveMicroservicePolicies(String loopName, List<MicroServicePolicy> newMicroservicePolicies) {
+ Loop loop = findClosedLoopByName(loopName);
+ Set<MicroServicePolicy> newPolicies = microservicePolicyService.updatePolicies(loop, newMicroservicePolicies);
+ loop.setMicroServicePolicies(newPolicies);
+ return loopsRepository.save(loop);
+ }
+
+ Loop updateAndSaveGlobalPropertiesJson(String loopName, JsonObject newGlobalPropertiesJson) {
+ Loop loop = findClosedLoopByName(loopName);
+ loop.setGlobalPropertiesJson(newGlobalPropertiesJson);
+ return loopsRepository.save(loop);
+ }
+
+ MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) {
+ Loop loop = findClosedLoopByName(loopName);
+ return microservicePolicyService.getAndUpdateMicroServicePolicy(loop, newMicroservicePolicy);
+ }
+
+ private Loop findClosedLoopByName(String loopName) {
+ return loopsRepository.findById(loopName)
+ .orElseThrow(() -> new EntityNotFoundException("Couldn't find closed loop named: " + loopName));
+ }
+}
+
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java
new file mode 100644
index 000000000..48d4487f0
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopState.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+public enum LoopState {
+ DESIGN, SUBMITTED, DEPLOYED, RUNNING, STOPPED, IN_ERROR, WAITING;
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java
new file mode 100644
index 000000000..7b92ed584
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/LoopsRepository.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface LoopsRepository extends JpaRepository<Loop, String> {
+
+ @Query("SELECT loop.name FROM Loop as loop")
+ List<String> getAllLoopNames();
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java
new file mode 100644
index 000000000..68adb3887
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/cds/CdsDataInstaller.java
@@ -0,0 +1,172 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.cds;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import org.onap.policy.clamp.clds.client.CdsServices;
+import org.onap.policy.clamp.clds.model.cds.CdsBpWorkFlowListResponse;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.service.ServicesRepository;
+import org.onap.sdc.tosca.parser.enums.SdcTypes;
+import org.onap.sdc.toscaparser.api.NodeTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class installs the cds data in the service model properties.
+ * This can be refreshed later on by clicking on the button refresh, when recomputing the json schema.
+ */
+@Component
+public class CdsDataInstaller {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsDataInstaller.class);
+
+ @Autowired
+ CdsServices cdsServices;
+
+ @Autowired
+ ServicesRepository serviceRepository;
+
+ public static final String CONTROLLER_PROPERTIES = "controllerProperties";
+ public static final String SDNC_MODEL_NAME = "sdnc_model_name";
+ public static final String SDNC_MODEL_VERSION = "sdnc_model_version";
+
+ /**
+ * This method installs the service model properties for CDS in the service object given in input.
+ *
+ * @param csar The csar from sdc
+ * @param service the service object already provisioned with csar data
+ */
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
+ public Service installCdsServiceProperties(CsarHandler csar, Service service) {
+ // Iterate on all types defined in the tosca lib
+ for (SdcTypes type : SdcTypes.values()) {
+ JsonObject resourcesPropByType = service.getResourceByType(type.getValue());
+ // For each type, get the metadata of each nodetemplate
+ for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) {
+ // get cds artifact information and save in resources Prop
+ if (SdcTypes.PNF == type || SdcTypes.VF == type) {
+ JsonObject controllerProperties = createCdsArtifactProperties(
+ String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_NAME)),
+ String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_VERSION)));
+ if (controllerProperties != null) {
+ resourcesPropByType.getAsJsonObject(nodeTemplate.getName())
+ .add(CONTROLLER_PROPERTIES, controllerProperties);
+ logger.info("Successfully installed the CDS data in Service");
+ } else {
+ logger.warn("Skipping CDS data installation in Service, as sdnc_model_name and "
+ + "sdnc_model_version are not provided in the CSAR");
+ }
+ }
+ }
+ }
+ serviceRepository.save(service);
+
+ return service;
+ }
+
+ /**
+ * This method updates the service model properties for CDS in the service object given in input.
+ *
+ * @param service the service object already provisioned with csar data
+ */
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
+ public Service updateCdsServiceProperties(Service service) {
+ // Iterate on all types defined in the tosca lib
+ for (SdcTypes type : SdcTypes.values()) {
+ JsonObject resourcesPropByType = service.getResourceByType(type.getValue());
+ for (String resourceName : resourcesPropByType.keySet()) {
+ // get cds artifact information and save in resources Prop
+ if ((SdcTypes.PNF == type || SdcTypes.VF == type) && resourcesPropByType.getAsJsonObject(resourceName)
+ .getAsJsonObject(CONTROLLER_PROPERTIES) != null) {
+ JsonObject controllerProperties =
+ createCdsArtifactProperties(resourcesPropByType.getAsJsonObject(resourceName)
+ .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_NAME)
+ .getAsString(),
+ resourcesPropByType.getAsJsonObject(resourceName)
+ .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_VERSION)
+ .getAsString());
+ if (controllerProperties != null) {
+ resourcesPropByType.getAsJsonObject(resourceName)
+ .add(CONTROLLER_PROPERTIES, controllerProperties);
+ }
+ }
+ }
+ }
+ serviceRepository.save(service);
+ logger.info("Successfully updated the CDS data in Service");
+ return service;
+ }
+
+ /**
+ * Retrieve CDS artifacts information from node template and save in resource object.
+ *
+ * @param sdncModelName sdnc model name
+ * @param sdncModelVersion sdnc model version
+ * @return Returns CDS artifacts information
+ */
+ private JsonObject createCdsArtifactProperties(String sdncModelName, String sdncModelVersion) {
+ if (sdncModelName != null && !"null".equals(sdncModelName)
+ && sdncModelVersion != null && !"null".equals(sdncModelVersion)) {
+ JsonObject controllerProperties = new JsonObject();
+ controllerProperties.addProperty(SDNC_MODEL_NAME, sdncModelName);
+ controllerProperties.addProperty(SDNC_MODEL_VERSION, sdncModelVersion);
+
+ CdsBpWorkFlowListResponse response =
+ queryCdsToGetWorkFlowList(sdncModelName, sdncModelVersion);
+ if (response == null) {
+ return controllerProperties;
+ }
+
+ JsonObject workFlowProps = new JsonObject();
+ for (String workFlow : response.getWorkflows()) {
+ logger.info("Found CDS workflow " + workFlow + " for model name " + sdncModelName + " and version "
+ + sdncModelVersion);
+ JsonObject inputs = queryCdsToGetWorkFlowInputProperties(response.getBlueprintName(),
+ response.getVersion(), workFlow);
+ workFlowProps.add(workFlow, inputs);
+ }
+
+ controllerProperties.add("workflows", workFlowProps);
+ return controllerProperties;
+ }
+ return null;
+ }
+
+
+ private CdsBpWorkFlowListResponse queryCdsToGetWorkFlowList(String artifactName, String artifactVersion) {
+ return cdsServices.getBlueprintWorkflowList(artifactName, artifactVersion);
+ }
+
+ private JsonObject queryCdsToGetWorkFlowInputProperties(String artifactName, String artifactVersion,
+ String workFlow) {
+ return cdsServices.getWorkflowInputProperties(artifactName, artifactVersion, workFlow);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java b/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java
new file mode 100644
index 000000000..92c795e90
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/common/AuditEntity.java
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.common;
+
+import com.google.gson.annotations.Expose;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import javax.persistence.Column;
+import javax.persistence.EntityListeners;
+import javax.persistence.MappedSuperclass;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+/**
+ * This class is the parent of the hibernate entities requiring to be audited.
+ */
+@MappedSuperclass
+@EntityListeners(AuditingEntityListener.class)
+public class AuditEntity {
+
+ @Expose
+ @CreatedDate
+ @Column(name = "created_timestamp", nullable = false, updatable = false)
+ private Instant createdDate;
+
+ @Expose
+ @LastModifiedDate
+ @Column(name = "updated_timestamp", nullable = false)
+ private Instant updatedDate;
+
+ @Expose
+ @LastModifiedBy
+ @Column(name = "updated_by")
+ private String updatedBy;
+
+ @Expose
+ @CreatedBy
+ @Column(name = "created_by")
+ private String createdBy;
+
+ public Instant getCreatedDate() {
+ return createdDate;
+ }
+
+ /**
+ * createdDate setter.
+ *
+ * @param createdDate The created Date object
+ */
+ public void setCreatedDate(Instant createdDate) {
+ if (createdDate != null) {
+ this.createdDate = createdDate.truncatedTo(ChronoUnit.SECONDS);
+ } else {
+ this.createdDate = null;
+ }
+ }
+
+ /**
+ * updatedDate getter.
+ *
+ * @return the updatedDate
+ */
+ public Instant getUpdatedDate() {
+ return updatedDate;
+ }
+
+ /**
+ * updatedDate setter.
+ *
+ * @param updatedDate updatedDate to set
+ */
+ public void setUpdatedDate(Instant updatedDate) {
+ if (updatedDate != null) {
+ this.updatedDate = updatedDate.truncatedTo(ChronoUnit.SECONDS);
+ } else {
+ this.updatedDate = null;
+ }
+ }
+
+ /**
+ * updatedBy getter.
+ *
+ * @return the updatedBy
+ */
+ public String getUpdatedBy() {
+ return updatedBy;
+ }
+
+ /**
+ * updatedBy setter.
+ *
+ * @param updatedBy the updatedBy
+ */
+ public void setUpdatedBy(String updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ /**
+ * createdBy getter.
+ *
+ * @return the createdBy
+ */
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ /**
+ * createdBy setter.
+ *
+ * @param createdBy the createdBy to set
+ */
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ /**
+ * Empty constructor.
+ */
+ public AuditEntity() {
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java
new file mode 100644
index 000000000..6a935d011
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/DcaeComponent.java
@@ -0,0 +1,266 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.components.external;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+import javax.persistence.Transient;
+import org.apache.camel.Exchange;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse;
+import org.onap.policy.clamp.clds.model.dcae.DcaeOperationStatusResponse;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+
+public class DcaeComponent extends ExternalComponent {
+
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeComponent.class);
+
+ private static final String DCAE_DEPLOYMENT_PREFIX = "CLAMP_";
+ private static final String DEPLOYMENT_PARAMETER = "dcaeDeployParameters";
+ private static final String DCAE_SERVICETYPE_ID = "serviceTypeId";
+ private static final String DCAE_INPUTS = "inputs";
+ public static final String UNIQUE_BLUEPRINT_PARAMETERS = "uniqueBlueprintParameters";
+
+ private String name;
+
+ public static final ExternalComponentState BLUEPRINT_DEPLOYED = new ExternalComponentState("BLUEPRINT_DEPLOYED",
+ "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop");
+ public static final ExternalComponentState PROCESSING_MICROSERVICE_INSTALLATION = new ExternalComponentState(
+ "PROCESSING_MICROSERVICE_INSTALLATION", "Clamp has requested DCAE to install the microservices "
+ + "defined in the DCAE blueprint and it's currently processing the request");
+ public static final ExternalComponentState MICROSERVICE_INSTALLATION_FAILED = new ExternalComponentState(
+ "MICROSERVICE_INSTALLATION_FAILED",
+ "Clamp has requested DCAE to install the microservices defined in the DCAE blueprint and it failed");
+ public static final ExternalComponentState MICROSERVICE_INSTALLED_SUCCESSFULLY = new ExternalComponentState(
+ "MICROSERVICE_INSTALLED_SUCCESSFULLY",
+ "Clamp has requested DCAE to install the DCAE blueprint and it has been installed successfully");
+ public static final ExternalComponentState PROCESSING_MICROSERVICE_UNINSTALLATION = new ExternalComponentState(
+ "PROCESSING_MICROSERVICE_UNINSTALLATION", "Clamp has requested DCAE to uninstall the microservices "
+ + "defined in the DCAE blueprint and it's currently processing the request");
+ public static final ExternalComponentState MICROSERVICE_UNINSTALLATION_FAILED = new ExternalComponentState(
+ "MICROSERVICE_UNINSTALLATION_FAILED",
+ "Clamp has requested DCAE to uninstall the microservices defined in the DCAE blueprint and it failed");
+ public static final ExternalComponentState MICROSERVICE_UNINSTALLED_SUCCESSFULLY = new ExternalComponentState(
+ "MICROSERVICE_UNINSTALLED_SUCCESSFULLY",
+ "Clamp has requested DCAE to uninstall the DCAE blueprint and it has been uninstalled successfully");
+ public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR",
+ "There was an error during the request done to DCAE, look at the logs or try again");
+
+ public DcaeComponent() {
+ super(BLUEPRINT_DEPLOYED);
+ this.name = "DCAE";
+ }
+
+ public DcaeComponent(String name) {
+ super(BLUEPRINT_DEPLOYED);
+ this.name = "DCAE_" + name;
+ }
+
+ @Override
+ public String getComponentName() {
+ return name;
+ }
+
+
+ /**
+ * Convert the json response to a DcaeOperationStatusResponse.
+ *
+ * @param responseBody The DCAE response Json paylaod
+ * @return The dcae object provisioned
+ */
+ public static DcaeOperationStatusResponse convertDcaeResponse(String responseBody) {
+ if (responseBody != null && !responseBody.isEmpty()) {
+ return JsonUtils.GSON_JPA_MODEL.fromJson(responseBody, DcaeOperationStatusResponse.class);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Generate the deployment id, it's random.
+ *
+ * @return The deployment id
+ */
+ public static String generateDeploymentId() {
+ return DCAE_DEPLOYMENT_PREFIX + UUID.randomUUID();
+ }
+
+ /**
+ * This method prepare the url returned by DCAE to check the status if fine. It
+ * extracts it from the dcaeResponse.
+ *
+ * @param dcaeResponse The dcae response object
+ * @return the Right Url modified if needed
+ */
+ public static String getStatusUrl(DcaeOperationStatusResponse dcaeResponse) {
+ return dcaeResponse.getLinks().getStatus();
+ }
+
+ /**
+ * Return the deploy payload for DCAE.
+ *
+ * @param loop The loop object
+ * @return The payload used to send deploy closed loop request
+ */
+ public static String getDeployPayload(Loop loop) {
+ JsonObject globalProp = loop.getGlobalPropertiesJson();
+ JsonObject deploymentProp = globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject(
+ UNIQUE_BLUEPRINT_PARAMETERS);
+
+ String serviceTypeId = loop.getLoopTemplate().getDcaeBlueprintId();
+
+ JsonObject rootObject = new JsonObject();
+ rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId);
+ if (deploymentProp != null) {
+ rootObject.add(DCAE_INPUTS, deploymentProp);
+ }
+ logger.info("DCAE Deploy payload for unique blueprint: " + rootObject.toString());
+ return rootObject.toString();
+ }
+
+ /**
+ * Return the deploy payload for DCAE.
+ *
+ * @param loop The loop object
+ * @param microServicePolicy The micro service policy
+ * @return The payload used to send deploy closed loop request
+ */
+ public static String getDeployPayload(Loop loop, MicroServicePolicy microServicePolicy) {
+ JsonObject globalProp = loop.getGlobalPropertiesJson();
+ JsonObject deploymentProp =
+ globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject(microServicePolicy.getName());
+
+ String serviceTypeId = microServicePolicy.getDcaeBlueprintId();
+
+ JsonObject rootObject = new JsonObject();
+ rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId);
+ if (deploymentProp != null) {
+ rootObject.add(DCAE_INPUTS, deploymentProp);
+ }
+ logger.info("DCAE Deploy payload for multiple blueprints: " + rootObject.toString());
+ return rootObject.toString();
+ }
+
+ /**
+ * Return the uninstallation payload for DCAE.
+ *
+ * @param loop The loop object
+ * @return The payload in string (json)
+ */
+ public static String getUndeployPayload(Loop loop) {
+ JsonObject rootObject = new JsonObject();
+ rootObject.addProperty(DCAE_SERVICETYPE_ID, loop.getLoopTemplate().getDcaeBlueprintId());
+ logger.info("DCAE Undeploy payload for unique blueprint: " + rootObject.toString());
+ return rootObject.toString();
+ }
+
+ /**
+ * Return the uninstallation payload for DCAE.
+ *
+ * @param policy The microServicePolicy object
+ * @return The payload in string (json)
+ */
+ public static String getUndeployPayload(MicroServicePolicy policy) {
+ JsonObject rootObject = new JsonObject();
+ rootObject.addProperty(DCAE_SERVICETYPE_ID, policy.getDcaeBlueprintId());
+ logger.info("DCAE Undeploy payload for multiple blueprints: " + rootObject.toString());
+ return rootObject.toString();
+ }
+
+ @Override
+ public ExternalComponentState computeState(Exchange camelExchange) {
+
+ DcaeOperationStatusResponse dcaeResponse = (DcaeOperationStatusResponse) camelExchange.getIn().getExchange()
+ .getProperty("dcaeResponse");
+
+ if (dcaeResponse == null) {
+ setState(BLUEPRINT_DEPLOYED);
+ } else {
+ if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus().equals("succeeded")) {
+ setState(MICROSERVICE_INSTALLED_SUCCESSFULLY);
+ } else {
+ if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus()
+ .equals("processing")) {
+ setState(PROCESSING_MICROSERVICE_INSTALLATION);
+ } else {
+ if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus()
+ .equals("failed")) {
+ setState(MICROSERVICE_INSTALLATION_FAILED);
+ } else {
+ if (dcaeResponse.getOperationType().equals("uninstall")
+ && dcaeResponse.getStatus().equals("succeeded")) {
+ setState(MICROSERVICE_UNINSTALLED_SUCCESSFULLY);
+ } else {
+ if (dcaeResponse.getOperationType().equals("uninstall")
+ && dcaeResponse.getStatus().equals("processing")) {
+ setState(PROCESSING_MICROSERVICE_UNINSTALLATION);
+ } else {
+ if (dcaeResponse.getOperationType().equals("uninstall") && dcaeResponse.getStatus()
+ .equals("failed")) {
+ setState(MICROSERVICE_UNINSTALLATION_FAILED);
+ } else {
+ setState(IN_ERROR);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return this.getState();
+ }
+
+ /**
+ * Convert the json response to a DcaeInventoryResponse.
+ *
+ * @param responseBody The DCAE response Json paylaod
+ * @return list of DcaeInventoryResponse
+ * @throws ParseException In case of issues with the Json parsing
+ */
+ public static List<DcaeInventoryResponse> convertToDcaeInventoryResponse(String responseBody)
+ throws ParseException {
+ JSONParser parser = new JSONParser();
+ JSONObject jsonObj = (JSONObject) parser.parse(responseBody);
+ JSONArray itemsArray = (JSONArray) jsonObj.get("items");
+ Iterator it = itemsArray.iterator();
+ List<DcaeInventoryResponse> inventoryResponseList = new LinkedList<>();
+ while (it.hasNext()) {
+ JSONObject item = (JSONObject) it.next();
+ DcaeInventoryResponse response = JsonUtils.GSON.fromJson(item.toString(), DcaeInventoryResponse.class);
+ inventoryResponseList.add(response);
+ }
+ return inventoryResponseList;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java
new file mode 100644
index 000000000..ce7efe494
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponent.java
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.components.external;
+
+import com.google.gson.annotations.Expose;
+import org.apache.camel.Exchange;
+
+/**
+ * Should be abstract but Gson can't instantiate it if it's an abstract.
+ */
+public class ExternalComponent {
+ @Expose
+ private ExternalComponentState componentState;
+
+ public void setState(ExternalComponentState newState) {
+ this.componentState = newState;
+ }
+
+ public ExternalComponentState getState() {
+ return this.componentState;
+ }
+
+ public String getComponentName() {
+ return null;
+ }
+
+ public ExternalComponentState computeState(Exchange camelExchange) {
+ return new ExternalComponentState("INIT", "no desc", 0);
+ }
+
+ public ExternalComponent(ExternalComponentState initialState) {
+ setState(initialState);
+ }
+
+ public ExternalComponent() {
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java
new file mode 100644
index 000000000..a57800025
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/ExternalComponentState.java
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.components.external;
+
+import com.google.gson.annotations.Expose;
+
+/**
+ * This is a transient state reflecting the deployment status of a component. It
+ * can be Policy, DCAE, or whatever... This is object is generic. Clamp is now
+ * stateless, so it triggers the different components at runtime, the status per
+ * component is stored here. The state level is used to re-compute the global
+ * state when multiple sub states are required for that computation (generally
+ * provided sequentially to the method computeState from the camel routes.
+ *
+ */
+public class ExternalComponentState implements Comparable<ExternalComponentState> {
+ @Expose
+ private String stateName;
+ @Expose
+ private String description;
+ private int stateLevel;
+
+ /**
+ * Constructor taking stateName, description and its level.
+ *
+ * @param stateName The stateName in string
+ * @param description The description in string
+ * @param level The level, higher value has higher priority and can't be
+ * down-graded
+ */
+ public ExternalComponentState(String stateName, String description, int level) {
+ this.stateName = stateName;
+ this.description = description;
+ this.stateLevel = level;
+ }
+
+ public ExternalComponentState(String stateName, String description) {
+ this(stateName, description, 0);
+ }
+
+ public ExternalComponentState() {
+ }
+
+ public String getStateName() {
+ return stateName;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String toString() {
+ return stateName;
+ }
+
+ public int getLevel() {
+ return stateLevel;
+ }
+
+ public void setLevel(int priority) {
+ this.stateLevel = priority;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((stateName == null) ? 0 : stateName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ExternalComponentState other = (ExternalComponentState) obj;
+ if (stateName == null) {
+ if (other.stateName != null) {
+ return false;
+ }
+ } else if (!stateName.equals(other.stateName)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * This method compares this object by using the level of them.
+ *
+ * @param stateToCompare The state to compare to the current object
+ * @return If the one given in input has a higher level than the current object
+ * it returns -1, 1 otherwise and 0 if equals.
+ */
+ @Override
+ public int compareTo(ExternalComponentState stateToCompare) {
+ return Integer.compare(this.getLevel(), stateToCompare.getLevel());
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java
new file mode 100644
index 000000000..27e8e1a13
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/components/external/PolicyComponent.java
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.components.external;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import javax.persistence.Transient;
+import org.apache.camel.Exchange;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.policy.pdpgroup.PdpGroupPayload;
+
+/**
+ * This class represents the policy state according to all policies involved in the control loop.
+ * It can compute it with all policy queries result.
+ * It contains also the method to generate the PDP payload used for the policies deployment.
+ */
+public class PolicyComponent extends ExternalComponent {
+
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyComponent.class);
+
+ public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR",
+ "There was an error during the sending to policy, the policy engine may be corrupted or inconsistent", 100);
+ public static final ExternalComponentState NOT_SENT = new ExternalComponentState("NOT_SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ public static final ExternalComponentState SENT = new ExternalComponentState("SENT",
+ "The policies defined have been created but NOT deployed on the policy engine", 50);
+ public static final ExternalComponentState SENT_AND_DEPLOYED = new ExternalComponentState("SENT_AND_DEPLOYED",
+ "The policies defined have been created and deployed on the policy engine", 10);
+ public static final ExternalComponentState UNKNOWN = new ExternalComponentState("UNKNOWN",
+ "The current status is not clear. Need to refresh the status to get the current status.", 0);
+
+ /**
+ * Default constructor.
+ */
+ public PolicyComponent() {
+ /*
+ * We assume it's good by default as we will receive the state for each policy
+ * on by one, each time we increase the level we can't decrease it anymore.
+ * That's why it starts with the lowest one SENT_AND_DEPLOYED.
+ */
+ super(UNKNOWN);
+ }
+
+ @Override
+ public String getComponentName() {
+ return "POLICY";
+ }
+
+ /**
+ * Generates the Json that must be sent to policy to add all policies to Active
+ * PDP group.
+ *
+ * @param loop the loop object
+ * @param action POST (to add policy to group) or DELETE (to delete policy from group)
+ * @return The json, payload to send
+ */
+ public static String createPoliciesPayloadPdpGroup(Loop loop, String action) {
+ PdpGroupPayload pdpGroupPayload = new PdpGroupPayload();
+ loop.getOperationalPolicies().stream().forEach(opPolicy -> pdpGroupPayload
+ .updatePdpGroupMap(opPolicy.getPdpGroup(), opPolicy.getPdpSubgroup(), opPolicy.getName(), "1.0.0",
+ action));
+
+ loop.getMicroServicePolicies().stream().forEach(msPolicy -> pdpGroupPayload
+ .updatePdpGroupMap(msPolicy.getPdpGroup(), msPolicy.getPdpSubgroup(), msPolicy.getName(), "1.0.0",
+ action));
+ return pdpGroupPayload.generatePdpGroupPayload();
+ }
+
+ private static ExternalComponentState findNewState(boolean found, boolean deployed) {
+
+ ExternalComponentState newState = NOT_SENT;
+ if (found && deployed) {
+ newState = SENT_AND_DEPLOYED;
+ } else {
+ if (found) {
+ newState = SENT;
+ } else {
+ if (deployed) {
+ newState = IN_ERROR;
+ }
+ }
+ }
+ return newState;
+ }
+
+ private static ExternalComponentState mergeStates(ExternalComponentState oldState,
+ ExternalComponentState newState) {
+ return (oldState.compareTo(newState) < 0) ? newState : oldState;
+ }
+
+ /**
+ * This is a method that expect the results of the queries getPolicy and
+ * getPolicyDeployed for a unique policy (op, config, etc ...). It
+ * re-computes the global policy state for each policy results given. Therefore
+ * this method is called multiple times from the camel route and must be reset
+ * for a new global policy state retrieval. The state to compute the global
+ * policy state is stored in this class.
+ */
+ @Override
+ public ExternalComponentState computeState(Exchange camelExchange) {
+ this.setState(mergeStates(this.getState(),
+ findNewState((boolean) camelExchange.getIn().getExchange().getProperty("policyFound"),
+ (boolean) camelExchange.getIn().getExchange().getProperty("policyDeployed"))));
+ return this.getState();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java b/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java
new file mode 100644
index 000000000..1a1414611
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.deploy;
+
+import com.google.gson.JsonObject;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.components.external.DcaeComponent;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * To decode the bluprint input parameters.
+ */
+public class DcaeDeployParameters {
+
+ private static LinkedHashMap<String, JsonObject> init(Loop loop) {
+ LinkedHashMap<String, JsonObject> deploymentParamMap = new LinkedHashMap<>();
+ Set<MicroServicePolicy> microServiceList = loop.getMicroServicePolicies();
+
+ for (MicroServicePolicy microService : microServiceList) {
+ deploymentParamMap.put(microService.getName(),
+ generateDcaeDeployParameter(microService));
+ }
+ return deploymentParamMap;
+ }
+
+ private static JsonObject generateDcaeDeployParameter(MicroServicePolicy microService) {
+ return generateDcaeDeployParameter(microService.getLoopElementModel().getBlueprint(),
+ microService.getName());
+ }
+
+ private static JsonObject generateDcaeDeployParameter(String blueprint, String policyId) {
+ JsonObject deployJsonBody = new JsonObject();
+ Yaml yaml = new Yaml();
+ Map<String, Object> inputsNodes = ((Map<String, Object>) ((Map<String, Object>) yaml
+ .load(blueprint)).get("inputs"));
+ inputsNodes.entrySet().stream().filter(e -> !e.getKey().contains("policy_id")).forEach(elem -> {
+ Object defaultValue = ((Map<String, Object>) elem.getValue()).get("default");
+ if (defaultValue != null) {
+ addPropertyToNode(deployJsonBody, elem.getKey(), defaultValue);
+ } else {
+ deployJsonBody.addProperty(elem.getKey(), "");
+ }
+ });
+ deployJsonBody.addProperty("policy_id", policyId);
+ return deployJsonBody;
+ }
+
+ private static void addPropertyToNode(JsonObject node, String key, Object value) {
+ if (value instanceof String) {
+ node.addProperty(key, (String) value);
+ } else if (value instanceof Number) {
+ node.addProperty(key, (Number) value);
+ } else if (value instanceof Boolean) {
+ node.addProperty(key, (Boolean) value);
+ } else if (value instanceof Character) {
+ node.addProperty(key, (Character) value);
+ } else {
+ node.addProperty(key, JsonUtils.GSON.toJson(value));
+ }
+ }
+
+ /**
+ * Convert the object in Json.
+ *
+ * @return The deploymentParameters in Json
+ */
+ public static JsonObject getDcaeDeploymentParametersInJson(Loop loop) {
+ JsonObject globalProperties = new JsonObject();
+ JsonObject deployParamJson = new JsonObject();
+ if (loop.getLoopTemplate().getUniqueBlueprint()) {
+ // Normally the unique blueprint could contain multiple microservices but then we can't guess
+ // the policy id params that will be used, so here we expect only one by default.
+ deployParamJson.add(DcaeComponent.UNIQUE_BLUEPRINT_PARAMETERS,
+ generateDcaeDeployParameter(loop.getLoopTemplate().getBlueprint(),
+ ((MicroServicePolicy) loop.getMicroServicePolicies().toArray()[0]).getName()));
+
+ } else {
+ LinkedHashMap<String, JsonObject> deploymentParamMap = init(loop);
+ for (Map.Entry<String, JsonObject> mapElement : deploymentParamMap.entrySet()) {
+ deployParamJson.add(mapElement.getKey(), mapElement.getValue());
+ }
+ }
+ globalProperties.add("dcaeDeployParameters", deployParamJson);
+ return globalProperties;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java
new file mode 100644
index 000000000..50f6571d6
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LogType.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.log;
+
+public enum LogType {
+ INFO, WARNING, ERROR;
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java
new file mode 100644
index 000000000..00f7e1f41
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLog.java
@@ -0,0 +1,193 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.log;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.onap.policy.clamp.loop.Loop;
+
+/**
+ * This class holds the logs created by the Clamp Backend. The Instant is always
+ * rounded to the nearest second as the nano seconds can't be stored in the
+ * database. The logs can be therefore exposed to the UI or the client doing
+ * some GET Loop on the backend.
+ *
+ */
+@Entity
+@Table(name = "loop_logs")
+public class LoopLog implements Serializable, Comparable<LoopLog> {
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 1988276670074437631L;
+
+ @Expose
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Expose
+ @Column(name = "log_type", nullable = false)
+ @Enumerated(EnumType.STRING)
+ private LogType logType;
+
+ @Expose
+ @Column(name = "log_component", nullable = false)
+ private String logComponent;
+
+ @Expose
+ @Column(name = "message", columnDefinition = "MEDIUMTEXT", nullable = false)
+ private String message;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "loop_id", nullable = false)
+ private Loop loop;
+
+ @Expose
+ @Column(name = "log_instant", nullable = false)
+ private Instant logInstant = Instant.now().truncatedTo(ChronoUnit.SECONDS);
+
+ public LoopLog() {
+ }
+
+ /**
+ * Constructor For LoopLog taking message and logtype, logComponent and loop
+ * reference.
+ *
+ * @param message The message as string
+ * @param logType Type like INFO, WARN, DEBUG
+ * @param logComponent A String with DCAE, POLICY, CLAMP ,etc...
+ * @param loop The loop object that this log is about
+ */
+ public LoopLog(String message, LogType logType, String logComponent, Loop loop) {
+ this.message = message;
+ this.logType = logType;
+ this.loop = loop;
+ this.logComponent = logComponent;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public LogType getLogType() {
+ return logType;
+ }
+
+ public void setLogType(LogType logType) {
+ this.logType = logType;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Loop getLoop() {
+ return loop;
+ }
+
+ public void setLoop(Loop loop) {
+ this.loop = loop;
+ }
+
+ public Instant getLogInstant() {
+ return logInstant;
+ }
+
+ public void setLogInstant(Instant logInstant) {
+ this.logInstant = logInstant.truncatedTo(ChronoUnit.SECONDS);
+ }
+
+ public String getLogComponent() {
+ return logComponent;
+ }
+
+ public void setLogComponent(String logComponent) {
+ this.logComponent = logComponent;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ LoopLog other = (LoopLog) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int compareTo(LoopLog arg0) {
+ // Reverse it, so that by default we have the latest
+ if (getId() == null) {
+ return 1;
+ }
+ if (arg0.getId() == null) {
+ return -1;
+ }
+ return arg0.getId().compareTo(this.getId());
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java
new file mode 100644
index 000000000..df1f3919e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogRepository.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.log;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface LoopLogRepository extends JpaRepository<LoopLog, Long> {
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java
new file mode 100644
index 000000000..a2f133f2f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/log/LoopLogService.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.log;
+
+import org.onap.policy.clamp.loop.Loop;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LoopLogService {
+
+ private final LoopLogRepository repository;
+
+ @Autowired
+ public LoopLogService(LoopLogRepository repository) {
+ this.repository = repository;
+ }
+
+ public void addLog(String message, String logType, Loop loop) {
+ this.addLogForComponent(message, logType, "CLAMP", loop);
+ }
+
+ public void addLogForComponent(String message, String logType, String component, Loop loop) {
+ loop.addLog(repository.save(new LoopLog(message, LogType.valueOf(logType), component, loop)));
+ }
+
+ public boolean isExisting(Long logId) {
+ return repository.existsById(logId);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java
new file mode 100644
index 000000000..1429d73c2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/CsarServiceInstaller.java
@@ -0,0 +1,129 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.service;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import java.util.Map.Entry;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.sdc.tosca.parser.api.IEntityDetails;
+import org.onap.sdc.tosca.parser.elements.queries.EntityQuery;
+import org.onap.sdc.tosca.parser.elements.queries.TopologyTemplateQuery;
+import org.onap.sdc.tosca.parser.enums.EntityTemplateType;
+import org.onap.sdc.tosca.parser.enums.SdcTypes;
+import org.onap.sdc.toscaparser.api.NodeTemplate;
+import org.onap.sdc.toscaparser.api.Property;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Qualifier("csarInstaller")
+public class CsarServiceInstaller {
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarServiceInstaller.class);
+
+ @Autowired
+ ServicesRepository serviceRepository;
+
+ /**
+ * Install the Service from the csar.
+ *
+ * @param csar The Csar Handler
+ * @return The service object
+ */
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
+ public Service installTheService(CsarHandler csar) {
+ logger.info("Start to install the Service from csar");
+ JsonObject serviceDetails = JsonUtils.GSON.fromJson(
+ JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class);
+
+ // Add properties details for each type, VfModule, VF, VFC, ....
+ JsonObject resourcesProp = createServicePropertiesByType(csar);
+ resourcesProp.add("VFModule", createVfModuleProperties(csar));
+
+ Service modelService = new Service(serviceDetails, resourcesProp,
+ csar.getSdcNotification().getServiceVersion());
+
+ serviceRepository.save(modelService);
+ logger.info("Successfully installed the Service");
+ return modelService;
+ }
+
+ private JsonObject createServicePropertiesByType(CsarHandler csar) {
+ JsonObject resourcesProp = new JsonObject();
+ // Iterate on all types defined in the tosca lib
+ for (SdcTypes type : SdcTypes.values()) {
+ JsonObject resourcesPropByType = new JsonObject();
+ // For each type, get the metadata of each nodetemplate
+ for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) {
+ resourcesPropByType.add(nodeTemplate.getName(),
+ JsonUtils.GSON.toJsonTree(nodeTemplate.getMetaData().getAllProperties()));
+ }
+ resourcesProp.add(type.getValue(), resourcesPropByType);
+ }
+ return resourcesProp;
+ }
+
+ private static JsonObject createVfModuleProperties(CsarHandler csar) {
+ JsonObject vfModuleProps = new JsonObject();
+ // Loop on all Groups defined in the service (VFModule entries type:
+ // org.openecomp.groups.VfModule)
+ for (IEntityDetails entity : csar.getSdcCsarHelper().getEntity(
+ EntityQuery.newBuilder(EntityTemplateType.GROUP).build(),
+ TopologyTemplateQuery.newBuilder(SdcTypes.SERVICE).build(), false)) {
+ // Get all metadata info
+ JsonObject allVfProps = (JsonObject) JsonUtils.GSON.toJsonTree(entity.getMetadata().getAllProperties());
+ vfModuleProps.add(entity.getMetadata().getAllProperties().get("vfModuleModelName"), allVfProps);
+ // now append the properties section so that we can also have isBase,
+ // volume_group, etc ... fields under the VFmodule name
+ for (Entry<String, Property> additionalProp : entity.getProperties().entrySet()) {
+ allVfProps.add(additionalProp.getValue().getName(),
+ JsonUtils.GSON.toJsonTree(additionalProp.getValue().getValue()));
+ }
+ }
+ return vfModuleProps;
+ }
+
+ /**
+ * Verify whether Service in Csar is deployed.
+ *
+ * @param csar The Csar Handler
+ * @return The flag indicating whether Service is deployed
+ * @throws SdcArtifactInstallerException The SdcArtifactInstallerException
+ */
+ public boolean isServiceAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException {
+ boolean alreadyInstalled = true;
+ JsonObject serviceDetails = JsonUtils.GSON.fromJson(
+ JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class);
+ alreadyInstalled = serviceRepository.existsById(serviceDetails.get("UUID").getAsString());
+
+ return alreadyInstalled;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java
new file mode 100644
index 000000000..b7442abc5
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/Service.java
@@ -0,0 +1,169 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.service;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+
+@Entity
+@Table(name = "services")
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public class Service implements Serializable {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = 1331119060272760758L;
+
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(Service.class);
+
+ @Id
+ @Column(name = "service_uuid", unique = true)
+ private String serviceUuid;
+
+ @Column(nullable = false, name = "name")
+ private String name;
+
+ @Column(name = "version")
+ private String version;
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "service_details")
+ private JsonObject serviceDetails;
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "resource_details")
+ private JsonObject resourceDetails;
+
+ /**
+ * Default constructor for serialization.
+ */
+ public Service() {
+ }
+
+ /**
+ * Constructor with string.
+ */
+ public Service(String serviceDetails, String resourceDetails) {
+ JsonObject serviceDetailsJson = JsonUtils.GSON.fromJson(serviceDetails, JsonObject.class);
+ this.name = serviceDetailsJson.get("name").getAsString();
+ this.serviceUuid = serviceDetailsJson.get("UUID").getAsString();
+ this.serviceDetails = serviceDetailsJson;
+ this.resourceDetails = JsonUtils.GSON.fromJson(resourceDetails, JsonObject.class);
+ }
+
+ /**
+ * Constructor with Json Object.
+ */
+ public Service(JsonObject serviceDetails, JsonObject resourceDetails, String version) {
+ this.name = serviceDetails.get("name").getAsString();
+ this.serviceUuid = serviceDetails.get("UUID").getAsString();
+ this.serviceDetails = serviceDetails;
+ this.resourceDetails = resourceDetails;
+ this.version = version;
+ }
+
+ public String getServiceUuid() {
+ return serviceUuid;
+ }
+
+ public JsonObject getServiceDetails() {
+ return serviceDetails;
+ }
+
+ public JsonObject getResourceDetails() {
+ return resourceDetails;
+ }
+
+ public JsonObject getResourceByType(String type) {
+ return (JsonObject) resourceDetails.get(type);
+ }
+
+ /**
+ * Name getter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Version getter.
+ *
+ * @return the version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((serviceUuid == null) ? 0 : serviceUuid.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Service other = (Service) obj;
+ if (serviceUuid == null) {
+ if (other.serviceUuid != null) {
+ return false;
+ }
+ } else {
+ if (!serviceUuid.equals(other.serviceUuid)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java
new file mode 100644
index 000000000..62596a08e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/service/ServicesRepository.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.service;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ServicesRepository extends JpaRepository<Service, String> {
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java
new file mode 100644
index 000000000..6eb3c7195
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModel.java
@@ -0,0 +1,295 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.hibernate.annotations.SortNatural;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+import org.onap.policy.clamp.policy.Policy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+
+/**
+ * This class represents a micro service/operational/... model for a loop template.
+ * So it's an element in the flow (a box shown in the loop).
+ */
+
+@Entity
+@Table(name = "loop_element_models")
+public class LoopElementModel extends AuditEntity implements Serializable {
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522707701376645L;
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @Expose
+ @Column(name = "dcae_blueprint_id")
+ private String dcaeBlueprintId;
+
+ /**
+ * Here we store the blueprint coming from DCAE, it can be null if this is not a micro service model.
+ */
+ @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml")
+ private String blueprint;
+
+ public static final String MICRO_SERVICE_TYPE = "MICRO_SERVICE_TYPE";
+ public static final String OPERATIONAL_POLICY_TYPE = "OPERATIONAL_POLICY_TYPE";
+ /**
+ * The type of element.
+ */
+ @Expose
+ @Column(nullable = false, name = "loop_element_type")
+ private String loopElementType;
+
+ /**
+ * This variable is used to display the micro-service name in the SVG.
+ */
+ @Expose
+ @Column(name = "short_name")
+ private String shortName;
+
+ /**
+ * This variable is used to store the type mentioned in the micro-service
+ * blueprint.
+ */
+ @Expose
+ @ManyToMany(
+ fetch = FetchType.EAGER,
+ cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
+ @JoinTable(
+ name = "loopelementmodels_to_policymodels",
+ joinColumns = @JoinColumn(name = "loop_element_name", referencedColumnName = "name"),
+ inverseJoinColumns = {
+ @JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"),
+ @JoinColumn(name = "policy_model_version", referencedColumnName = "version")})
+ @SortNatural
+ private SortedSet<PolicyModel> policyModels = new TreeSet<>();
+
+ @OneToMany(fetch = FetchType.LAZY, mappedBy = "loopElementModel", orphanRemoval = true)
+ private Set<LoopTemplateLoopElementModel> usedByLoopTemplates = new HashSet<>();
+
+ /**
+ * policyModels getter.
+ *
+ * @return the policyModel
+ */
+ public SortedSet<PolicyModel> getPolicyModels() {
+ return policyModels;
+ }
+
+ /**
+ * Method to add a new policyModel to the list.
+ *
+ * @param policyModel The policy model
+ */
+ public void addPolicyModel(PolicyModel policyModel) {
+ policyModels.add(policyModel);
+ policyModel.getUsedByElementModels().add(this);
+ }
+
+ /**
+ * name getter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * blueprint getter.
+ *
+ * @return the blueprint
+ */
+ public String getBlueprint() {
+ return blueprint;
+ }
+
+ /**
+ * blueprint setter.
+ *
+ * @param blueprint the blueprint to set
+ */
+ public void setBlueprint(String blueprint) {
+ this.blueprint = blueprint;
+ }
+
+ /**
+ * dcaeBlueprintId getter.
+ *
+ * @return the dcaeBlueprintId
+ */
+ public String getDcaeBlueprintId() {
+ return dcaeBlueprintId;
+ }
+
+ /**
+ * dcaeBlueprintId setter.
+ *
+ * @param dcaeBlueprintId the dcaeBlueprintId to set
+ */
+ public void setDcaeBlueprintId(String dcaeBlueprintId) {
+ this.dcaeBlueprintId = dcaeBlueprintId;
+ }
+
+ /**
+ * loopElementType getter.
+ *
+ * @return the loopElementType
+ */
+ public String getLoopElementType() {
+ return loopElementType;
+ }
+
+ /**
+ * loopElementType setter.
+ *
+ * @param loopElementType the loopElementType to set
+ */
+ public void setLoopElementType(String loopElementType) {
+ this.loopElementType = loopElementType;
+ }
+
+ /**
+ * shortName getter.
+ *
+ * @return the shortName
+ */
+ public String getShortName() {
+ return shortName;
+ }
+
+ /**
+ * * @param shortName the shortName to set.
+ */
+ public void setShortName(String shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * usedByLoopTemplates getter.
+ *
+ * @return the usedByLoopTemplates
+ */
+ public Set<LoopTemplateLoopElementModel> getUsedByLoopTemplates() {
+ return usedByLoopTemplates;
+ }
+
+ /**
+ * Default constructor for serialization.
+ */
+ public LoopElementModel() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The name id
+ * @param loopElementType The type of loop element
+ * @param blueprint The blueprint defined for dcae that contains the
+ * policy type to use
+ */
+ public LoopElementModel(String name, String loopElementType, String blueprint) {
+ this.name = name;
+ this.loopElementType = loopElementType;
+ this.blueprint = blueprint;
+ }
+
+ /**
+ * Create a policy instance from the current loop element model.
+ *
+ * @return A Policy object.
+ */
+ public Policy createPolicyInstance(Loop loop, ToscaConverterWithDictionarySupport toscaConverter) {
+ if (LoopElementModel.MICRO_SERVICE_TYPE.equals(this.getLoopElementType())) {
+ return new MicroServicePolicy(loop, loop.getModelService(), this, toscaConverter);
+ } else if (LoopElementModel.OPERATIONAL_POLICY_TYPE.equals(this.getLoopElementType())) {
+ return new OperationalPolicy(loop, loop.getModelService(), this, toscaConverter);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ LoopElementModel other = (LoopElementModel) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java
new file mode 100644
index 000000000..d9b879d0f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopElementModelsRepository.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface LoopElementModelsRepository extends JpaRepository<LoopElementModel, String> {
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java
new file mode 100644
index 000000000..ab7367aaf
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplate.java
@@ -0,0 +1,341 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.hibernate.annotations.SortNatural;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+import org.onap.policy.clamp.loop.service.Service;
+
+@Entity
+@Table(name = "loop_templates")
+public class LoopTemplate extends AuditEntity implements Serializable {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522707701388642L;
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @Expose
+ @Column(name = "dcae_blueprint_id")
+ private String dcaeBlueprintId;
+
+ /**
+ * This field is used when we have a blueprint defining all microservices. The
+ * other option would be to have independent blueprint for each microservices.
+ * In that case they are stored in each MicroServiceModel
+ */
+ @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml")
+ private String blueprint;
+
+ @Expose
+ @OneToMany(
+ cascade = CascadeType.ALL,
+ fetch = FetchType.EAGER,
+ mappedBy = "loopTemplate",
+ orphanRemoval = true)
+ @SortNatural
+ private SortedSet<LoopTemplateLoopElementModel> loopElementModelsUsed = new TreeSet<>();
+
+ @Expose
+ @ManyToOne(
+ fetch = FetchType.EAGER,
+ cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
+ @JoinColumn(name = "service_uuid")
+ private Service modelService;
+
+ @Expose
+ @Column(name = "maximum_instances_allowed")
+ private Integer maximumInstancesAllowed;
+
+ @Expose
+ @Column(name = "unique_blueprint", columnDefinition = "boolean default false")
+ private boolean uniqueBlueprint;
+
+ /**
+ * Type of Loop allowed to be created.
+ */
+ @Expose
+ @Column(name = "allowed_loop_type")
+ @Convert(converter = LoopTypeConvertor.class)
+ private LoopType allowedLoopType = LoopType.CLOSED;
+
+ /**
+ * name getter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * blueprint getter.
+ *
+ * @return the blueprint
+ */
+ public String getBlueprint() {
+ return blueprint;
+ }
+
+ /**
+ * dcaeBlueprintId getter.
+ *
+ * @return the dcaeBlueprintId
+ */
+ public String getDcaeBlueprintId() {
+ return dcaeBlueprintId;
+ }
+
+ /**
+ * dcaeBlueprintId setter.
+ *
+ * @param dcaeBlueprintId the dcaeBlueprintId to set
+ */
+ public void setDcaeBlueprintId(String dcaeBlueprintId) {
+ this.dcaeBlueprintId = dcaeBlueprintId;
+ }
+
+ /**
+ * blueprint setter.
+ *
+ * @param blueprint the blueprint to set
+ */
+ public void setBlueprint(String blueprint) {
+ this.blueprint = blueprint;
+ if (blueprint == null) {
+ this.uniqueBlueprint = false;
+ } else {
+ this.uniqueBlueprint = true;
+ }
+ }
+
+ /**
+ * loopElementModelsUsed getter.
+ *
+ * @return the loopElementModelsUsed
+ */
+ public SortedSet<LoopTemplateLoopElementModel> getLoopElementModelsUsed() {
+ return loopElementModelsUsed;
+ }
+
+ /**
+ * maximumInstancesAllowed getter.
+ *
+ * @return the maximumInstancesAllowed
+ */
+ public Integer getMaximumInstancesAllowed() {
+ return maximumInstancesAllowed;
+ }
+
+ /**
+ * maximumInstancesAllowed setter.
+ *
+ * @param maximumInstancesAllowed the maximumInstancesAllowed to set
+ */
+ public void setMaximumInstancesAllowed(Integer maximumInstancesAllowed) {
+ this.maximumInstancesAllowed = maximumInstancesAllowed;
+ }
+
+ /**
+ * allowedLoopType getter.
+ *
+ * @return the allowedLoopType Type of Loop allowed to be created
+ */
+ public LoopType getAllowedLoopType() {
+ return allowedLoopType;
+ }
+
+ /**
+ * allowedLoopType setter.
+ *
+ * @param allowedLoopType the allowedLoopType to set
+ */
+ public void setAllowedLoopType(LoopType allowedLoopType) {
+ this.allowedLoopType = allowedLoopType;
+ }
+
+ /**
+ * Add list of loopElements to the current template, each loopElementModel is
+ * added at the end of the list so the flowOrder is computed automatically.
+ *
+ * @param loopElementModels The loopElementModel set to add
+ */
+ public void addLoopElementModels(Set<LoopElementModel> loopElementModels) {
+ for (LoopElementModel loopElementModel : loopElementModels) {
+ addLoopElementModel(loopElementModel);
+ }
+ }
+
+ /**
+ * Add a loopElement to the current template, the loopElementModel is added at
+ * the end of the list so the flowOrder is computed automatically.
+ *
+ * @param loopElementModel The loopElementModel to add
+ */
+ public void addLoopElementModel(LoopElementModel loopElementModel) {
+ this.addLoopElementModel(loopElementModel, this.loopElementModelsUsed.size());
+ }
+
+ /**
+ * Add a loopElement model to the current template, the flow order must be
+ * specified manually.
+ *
+ * @param loopElementModel The loopElementModel to add
+ * @param listPosition The position in the flow
+ */
+ public void addLoopElementModel(LoopElementModel loopElementModel, Integer listPosition) {
+ LoopTemplateLoopElementModel jointEntry =
+ new LoopTemplateLoopElementModel(this, loopElementModel, listPosition);
+ this.loopElementModelsUsed.add(jointEntry);
+ loopElementModel.getUsedByLoopTemplates().add(jointEntry);
+ }
+
+ /**
+ * modelService getter.
+ *
+ * @return the modelService
+ */
+ public Service getModelService() {
+ return modelService;
+ }
+
+ /**
+ * modelService setter.
+ *
+ * @param modelService the modelService to set
+ */
+ public void setModelService(Service modelService) {
+ this.modelService = modelService;
+ }
+
+ /**
+ * uniqueBlueprint getter.
+ *
+ * @return the uniqueBlueprint
+ */
+ public boolean getUniqueBlueprint() {
+ return uniqueBlueprint;
+ }
+
+ /**
+ * Default constructor for serialization.
+ */
+ public LoopTemplate() {
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The loop template name id
+ * @param blueprint The blueprint containing all microservices (legacy
+ * case)
+ * @param maxInstancesAllowed The maximum number of instances that can be
+ * created from that template
+ * @param service The service associated to that loop template
+ */
+ public LoopTemplate(String name, String blueprint, Integer maxInstancesAllowed, Service service) {
+ this.name = name;
+ this.setBlueprint(blueprint);
+
+ this.maximumInstancesAllowed = maxInstancesAllowed;
+ this.modelService = service;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ LoopTemplate other = (LoopTemplate) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Generate the loop template name.
+ *
+ * @param serviceName The service name
+ * @param serviceVersion The service version
+ * @param resourceName The resource name
+ * @param blueprintFileName The blueprint file name
+ * @return The generated loop template name
+ */
+ public static String generateLoopTemplateName(String serviceName, String serviceVersion,
+ String resourceName, String blueprintFileName) {
+ StringBuilder buffer = new StringBuilder("LOOP_TEMPLATE_").append(serviceName).append("_v")
+ .append(serviceVersion).append("_").append(resourceName).append("_")
+ .append(blueprintFileName.replaceAll(".yaml", ""));
+ return buffer.toString().replace('.', '_').replaceAll(" ", "");
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java
new file mode 100644
index 000000000..c0b0c7d24
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModel.java
@@ -0,0 +1,192 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapsId;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "looptemplates_to_loopelementmodels")
+public class LoopTemplateLoopElementModel implements Serializable, Comparable<LoopTemplateLoopElementModel> {
+
+ /**
+ * Serial ID.
+ */
+ private static final long serialVersionUID = 5924989899078094245L;
+
+ @EmbeddedId
+ private LoopTemplateLoopElementModelId loopTemplateLoopElementModelId;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @MapsId("loopTemplateName")
+ @JoinColumn(name = "loop_template_name")
+ private LoopTemplate loopTemplate;
+
+ @Expose
+ @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
+ @MapsId("loopElementModelName")
+ @JoinColumn(name = "loop_element_model_name")
+ private LoopElementModel loopElementModel;
+
+ @Expose
+ @Column(nullable = false, name = "flow_order")
+ private Integer flowOrder;
+
+ /**
+ * Default constructor for serialization.
+ */
+ public LoopTemplateLoopElementModel() {
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param loopTemplate The loop template object
+ * @param loopElementModel The loopElementModel object
+ * @param flowOrder The position of the micro service in the flow
+ */
+ public LoopTemplateLoopElementModel(LoopTemplate loopTemplate, LoopElementModel loopElementModel,
+ Integer flowOrder) {
+ this.loopTemplate = loopTemplate;
+ this.loopElementModel = loopElementModel;
+ this.flowOrder = flowOrder;
+ this.loopTemplateLoopElementModelId = new LoopTemplateLoopElementModelId(loopTemplate.getName(),
+ loopElementModel.getName());
+ }
+
+ /**
+ * loopTemplate getter.
+ *
+ * @return the loopTemplate
+ */
+ public LoopTemplate getLoopTemplate() {
+ return loopTemplate;
+ }
+
+ /**
+ * loopTemplate setter.
+ *
+ * @param loopTemplate the loopTemplate to set
+ */
+ public void setLoopTemplate(LoopTemplate loopTemplate) {
+ this.loopTemplate = loopTemplate;
+ }
+
+ /**
+ * loopElementModel getter.
+ *
+ * @return the loopElementModel
+ */
+ public LoopElementModel getLoopElementModel() {
+ return loopElementModel;
+ }
+
+ /**
+ * loopElementModel setter.
+ *
+ * @param loopElementModel the loopElementModel to set
+ */
+ public void setLoopElementModel(LoopElementModel loopElementModel) {
+ this.loopElementModel = loopElementModel;
+ }
+
+ /**
+ * flowOrder getter.
+ *
+ * @return the flowOrder
+ */
+ public Integer getFlowOrder() {
+ return flowOrder;
+ }
+
+ /**
+ * flowOrder setter.
+ *
+ * @param flowOrder the flowOrder to set
+ */
+ public void setFlowOrder(Integer flowOrder) {
+ this.flowOrder = flowOrder;
+ }
+
+ @Override
+ public int compareTo(LoopTemplateLoopElementModel arg0) {
+ // Reverse it, so that by default we have the latest
+ if (getFlowOrder() == null) {
+ return 1;
+ }
+ if (arg0.getFlowOrder() == null) {
+ return -1;
+ }
+ return arg0.getFlowOrder().compareTo(this.getFlowOrder());
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((loopTemplate == null) ? 0 : loopTemplate.hashCode());
+ result = prime * result + ((loopElementModel == null) ? 0 : loopElementModel.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ LoopTemplateLoopElementModel other = (LoopTemplateLoopElementModel) obj;
+ if (loopTemplate == null) {
+ if (other.loopTemplate != null) {
+ return false;
+ }
+ } else if (!loopTemplate.equals(other.loopTemplate)) {
+ return false;
+ }
+ if (loopElementModel == null) {
+ if (other.loopElementModel != null) {
+ return false;
+ }
+ } else if (!loopElementModel.equals(other.loopElementModel)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java
new file mode 100644
index 000000000..9da8272bd
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplateLoopElementModelId.java
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class LoopTemplateLoopElementModelId implements Serializable {
+
+ /**
+ * Serial ID.
+ */
+ private static final long serialVersionUID = 4089888115504914773L;
+
+ @Expose
+ @Column(name = "loop_template_name")
+ private String loopTemplateName;
+
+ @Expose
+ @Column(name = "loop_element_model_name")
+ private String loopElementModelName;
+
+ /**
+ * Default constructor for serialization.
+ */
+ public LoopTemplateLoopElementModelId() {
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param loopTemplateName The loop template name id
+ * @param microServiceModelName THe micro Service name id
+ */
+ public LoopTemplateLoopElementModelId(String loopTemplateName, String microServiceModelName) {
+ this.loopTemplateName = loopTemplateName;
+ this.loopElementModelName = microServiceModelName;
+ }
+
+ /**
+ * loopTemplateName getter.
+ *
+ * @return the loopTemplateName
+ */
+ public String getLoopTemplateName() {
+ return loopTemplateName;
+ }
+
+ /**
+ * loopTemplateName setter.
+ *
+ * @param loopTemplateName the loopTemplateName to set
+ */
+ public void setLoopTemplateName(String loopTemplateName) {
+ this.loopTemplateName = loopTemplateName;
+ }
+
+ /**
+ * microServiceModelName getter.
+ *
+ * @return the microServiceModelName
+ */
+ public String getLoopElementModelName() {
+ return loopElementModelName;
+ }
+
+ /**
+ * loopElementModelName setter.
+ *
+ * @param loopElementModelName the loopElementModelName to set
+ */
+ public void setLoopElementModelName(String loopElementModelName) {
+ this.loopElementModelName = loopElementModelName;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java
new file mode 100644
index 000000000..3993dee34
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesRepository.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface LoopTemplatesRepository extends JpaRepository<LoopTemplate, String> {
+
+ @Query("SELECT looptemplate.name FROM LoopTemplate as looptemplate")
+ List<String> getAllLoopTemplateNames();
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java
new file mode 100644
index 000000000..974cf3b5c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTemplatesService.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import java.util.List;
+import org.onap.policy.clamp.clds.sdc.controller.installer.ChainGenerator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LoopTemplatesService {
+
+ private final LoopTemplatesRepository loopTemplatesRepository;
+
+ @Autowired
+ ChainGenerator chainGenerator;
+
+ /**
+ * Constructor.
+ */
+ @Autowired
+ public LoopTemplatesService(LoopTemplatesRepository loopTemplatesRepository) {
+ this.loopTemplatesRepository = loopTemplatesRepository;
+
+ }
+
+ public LoopTemplate saveOrUpdateLoopTemplate(LoopTemplate loopTemplate) {
+ return loopTemplatesRepository.save(loopTemplate);
+ }
+
+ public List<String> getLoopTemplateNames() {
+ return loopTemplatesRepository.getAllLoopTemplateNames();
+ }
+
+ public List<LoopTemplate> getAllLoopTemplates() {
+ return loopTemplatesRepository.findAll();
+ }
+
+ public LoopTemplate getLoopTemplate(String name) {
+ return loopTemplatesRepository.findById(name).orElse(null);
+ }
+
+ public void deleteLoopTemplate(String name) {
+ loopTemplatesRepository.deleteById(name);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java
new file mode 100644
index 000000000..eacfecb5e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopType.java
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+/**
+ * Enums for AllowedLoopType in LoopTemplate enity.
+ *
+ */
+public enum LoopType {
+ OPEN("OPEN"), CLOSED("CLOSED"), HYBRID("HYBRID");
+
+ private String value;
+
+ private LoopType(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java
new file mode 100644
index 000000000..81ca18d57
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/LoopTypeConvertor.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import java.util.stream.Stream;
+import javax.persistence.AttributeConverter;
+
+/**
+ * Attribute Converter to allow using LoopType Enum values in DB and Java classes.
+ *
+ */
+public class LoopTypeConvertor implements AttributeConverter<LoopType, String> {
+
+ @Override
+ public String convertToDatabaseColumn(LoopType loopType) {
+ if (loopType == null) {
+ return null;
+ }
+ return loopType.getValue();
+ }
+
+ @Override
+ public LoopType convertToEntityAttribute(String value) {
+ if (value == null) {
+ return null;
+ }
+
+ return Stream.of(LoopType.values()).filter(c -> c.getValue().equals(value)).findFirst()
+ .orElseThrow(IllegalArgumentException::new);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java
new file mode 100644
index 000000000..2414377d7
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModel.java
@@ -0,0 +1,282 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+import org.onap.policy.clamp.util.SemanticVersioning;
+
+/**
+ * This class represents the policy model tosca revision that we can have to a
+ * specific microservice.
+ */
+@Entity
+@Table(name = "policy_models")
+@IdClass(PolicyModelId.class)
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public class PolicyModel extends AuditEntity implements Serializable, Comparable<PolicyModel> {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522705701376645L;
+
+ /**
+ * This variable is used to store the type mentioned in the micro-service
+ * blueprint.
+ */
+ @Id
+ @Expose
+ @Column(nullable = false, name = "policy_model_type")
+ private String policyModelType;
+
+ /**
+ * Semantic versioning on policy side.
+ */
+ @Id
+ @Expose
+ @Column(name = "version", nullable = false)
+ private String version;
+
+ @Column(columnDefinition = "MEDIUMTEXT", name = "policy_tosca")
+ private String policyModelTosca;
+
+ @Expose
+ @Column(name = "policy_acronym")
+ private String policyAcronym;
+
+ @ManyToMany(mappedBy = "policyModels", fetch = FetchType.EAGER)
+ private Set<LoopElementModel> usedByElementModels = new HashSet<>();
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "policy_pdp_group")
+ private JsonObject policyPdpGroup;
+
+ /**
+ * usedByElementModels getter.
+ *
+ * @return the usedByElementModels
+ */
+ public Set<LoopElementModel> getUsedByElementModels() {
+ return usedByElementModels;
+ }
+
+ /**
+ * policyPdpGroup getter.
+ *
+ * @return the policyPdpGroup
+ */
+ public JsonObject getPolicyPdpGroup() {
+ return policyPdpGroup;
+ }
+
+ /**
+ * policyPdpGroup setter.
+ *
+ * @param policyPdpGroup the policyPdpGroup to set
+ */
+ public void setPolicyPdpGroup(JsonObject policyPdpGroup) {
+ this.policyPdpGroup = policyPdpGroup;
+ }
+
+ /**
+ * policyModelTosca getter.
+ *
+ * @return the policyModelTosca
+ */
+ public String getPolicyModelTosca() {
+ return policyModelTosca;
+ }
+
+ /**
+ * policyModelTosca setter.
+ *
+ * @param policyModelTosca the policyModelTosca to set
+ */
+ public void setPolicyModelTosca(String policyModelTosca) {
+ this.policyModelTosca = policyModelTosca;
+ }
+
+ /**
+ * policyModelType getter.
+ *
+ * @return the modelType
+ */
+ public String getPolicyModelType() {
+ return policyModelType;
+ }
+
+ /**
+ * policyModelType setter.
+ *
+ * @param modelType the modelType to set
+ */
+ public void setPolicyModelType(String modelType) {
+ this.policyModelType = modelType;
+ }
+
+ /**
+ * version getter.
+ *
+ * @return the version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * version setter.
+ *
+ * @param version the version to set
+ */
+ public void setVersion(String version) {
+ // Try to convert it before
+ this.version = version;
+ }
+
+ /**
+ * policyAcronym getter.
+ *
+ * @return the policyAcronym value
+ */
+ public String getPolicyAcronym() {
+ return policyAcronym;
+ }
+
+ /**
+ * policyAcronym setter.
+ *
+ * @param policyAcronym The policyAcronym to set
+ */
+ public void setPolicyAcronym(String policyAcronym) {
+ this.policyAcronym = policyAcronym;
+ }
+
+ /**
+ * Default constructor for serialization.
+ */
+ public PolicyModel() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param policyType The policyType (referenced in the blueprint
+ * @param policyModelTosca The policy tosca model in yaml
+ * @param version the version like 1.0.0
+ * @param policyAcronym Subtype for policy if it exists (could be used by UI)
+ */
+ public PolicyModel(String policyType, String policyModelTosca, String version,
+ String policyAcronym) {
+ this.policyModelType = policyType;
+ this.policyModelTosca = policyModelTosca;
+ this.version = version;
+ this.policyAcronym = policyAcronym;
+ if (this.policyAcronym == null) {
+ this.policyAcronym = createDefaultPolicyAcronym(policyType);
+ }
+ }
+
+ /**
+ * Constructor with acronym generated by default from policyType.
+ *
+ * @param policyType The policyType (referenced in the blueprint
+ * @param policyModelTosca The policy tosca model in yaml
+ * @param version the version like 1.0.0
+ */
+ public PolicyModel(String policyType, String policyModelTosca, String version) {
+ this(policyType, policyModelTosca, version, null);
+ }
+
+ public static String createDefaultPolicyAcronym(String policyType) {
+ String[] policyNameArray = policyType.split("\\.");
+ return policyNameArray[policyNameArray.length - 1];
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((policyModelType == null) ? 0 : policyModelType.hashCode());
+ result = prime * result + ((version == null) ? 0 : version.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PolicyModel other = (PolicyModel) obj;
+ if (policyModelType == null) {
+ if (other.policyModelType != null) {
+ return false;
+ }
+ } else if (!policyModelType.equals(other.policyModelType)) {
+ return false;
+ }
+ if (version == null) {
+ if (other.version != null) {
+ return false;
+ }
+ } else if (!version.equals(other.version)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int compareTo(PolicyModel arg0) {
+
+ if (this.getPolicyModelType().equals(arg0.getPolicyModelType())) {
+ // Reverse it, so that by default we have the latest in they are same model type
+ return SemanticVersioning.compare(arg0.getVersion(), this.version);
+ } else {
+ return this.getPolicyModelType().compareTo(arg0.getPolicyModelType());
+ }
+
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java
new file mode 100644
index 000000000..2591bd174
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelId.java
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+
+public class PolicyModelId implements Serializable {
+
+ /**
+ * Serial Id.
+ */
+ private static final long serialVersionUID = -2846526482064334745L;
+
+ @Expose
+ private String policyModelType;
+
+ @Expose
+ private String version;
+
+ /**
+ * Default constructor for serialization.
+ */
+ public PolicyModelId() {
+
+ }
+
+ /**
+ * Constructor.
+ */
+ public PolicyModelId(String policyModelType, String version) {
+ this.policyModelType = policyModelType;
+ this.version = version;
+ }
+
+ /**
+ * policyModelType getter.
+ *
+ * @return the policyModelType
+ */
+ public String getPolicyModelType() {
+ return policyModelType;
+ }
+
+ /**
+ * policyModelType setter.
+ *
+ * @param policyModelType the policyModelType to set
+ */
+ public void setPolicyModelType(String policyModelType) {
+ this.policyModelType = policyModelType;
+ }
+
+ /**
+ * version getter.
+ *
+ * @return the version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * version setter.
+ *
+ * @param version the version to set
+ */
+ public void setVersion(String version) {
+ this.version = version;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java
new file mode 100644
index 000000000..6ff7e3d0c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsRepository.java
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface PolicyModelsRepository extends JpaRepository<PolicyModel, PolicyModelId> {
+ @Query("SELECT policymodel.policyModelType FROM PolicyModel as policymodel")
+ List<String> getAllPolicyModelType();
+
+ List<PolicyModel> findByPolicyModelType(String policyModelType);
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java
new file mode 100644
index 000000000..2d31b3b10
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/loop/template/PolicyModelsService.java
@@ -0,0 +1,138 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.template;
+
+import com.google.gson.JsonObject;
+import java.util.List;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.policy.pdpgroup.PdpGroupsAnalyzer;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * This class contains the methods to access the policyModel object in db.
+ */
+@Service
+public class PolicyModelsService {
+ private final PolicyModelsRepository policyModelsRepository;
+
+ /**
+ * This is the new tosca converter that must be used in clamp.
+ */
+ @Autowired
+ private ToscaConverterWithDictionarySupport toscaConverterWithDictionarySupport;
+
+ @Autowired
+ public PolicyModelsService(PolicyModelsRepository policyModelrepo) {
+ policyModelsRepository = policyModelrepo;
+ }
+
+ /**
+ * Save or Update Policy Model.
+ *
+ * @param policyModel The policyModel
+ * @return The Policy Model
+ */
+ public PolicyModel saveOrUpdatePolicyModel(PolicyModel policyModel) {
+ return policyModelsRepository.saveAndFlush(policyModel);
+ }
+
+ /**
+ * Verify whether Policy Model exist by ID.
+ *
+ * @param policyModelId The policyModel Id
+ * @return The flag indicates whether Policy Model exist
+ */
+ public boolean existsById(PolicyModelId policyModelId) {
+ return policyModelsRepository.existsById(policyModelId);
+ }
+
+ /**
+ * This method retrieves the tosca model and convert it to a Json schema.
+ * That json schema is normally used by the UI.
+ *
+ * @param policyType The policy model type id
+ * @param policyTypeVersion The policy model type version
+ * @return A JsonObject with the json schema describing the tosca
+ */
+ public JsonObject getPolicyModelJson(String policyType, String policyTypeVersion) {
+ PolicyModel thePolicyModel = getPolicyModel(policyType, policyTypeVersion);
+ // In the following use case we are not in the context of a closed loop, so the enrichment
+ // of the json cannot be done, that's why the serviceModel provided is NULL.
+ return toscaConverterWithDictionarySupport
+ .convertToscaToJsonSchemaObject(thePolicyModel.getPolicyModelTosca(), policyType, null);
+ }
+
+ public List<String> getAllPolicyModelTypes() {
+ return policyModelsRepository.getAllPolicyModelType();
+ }
+
+ public Iterable<PolicyModel> getAllPolicyModels() {
+ return policyModelsRepository.findAll();
+ }
+
+ public PolicyModel getPolicyModel(String type, String version) {
+ return policyModelsRepository.findById(new PolicyModelId(type, version)).orElse(null);
+ }
+
+ public Iterable<PolicyModel> getAllPolicyModelsByType(String type) {
+ return policyModelsRepository.findByPolicyModelType(type);
+ }
+
+ /**
+ * Retrieves the Tosca model Yaml string.
+ *
+ * @param type The Policy Model Type
+ * @param version The policy model version
+ * @return The Tosca model Yaml string
+ */
+ public String getPolicyModelTosca(String type, String version) {
+ return policyModelsRepository.findById(new PolicyModelId(type, version))
+ .orElse(new PolicyModel()).getPolicyModelTosca();
+ }
+
+ /**
+ * This method creates an PolicyModel in Db if it does not exist.
+ *
+ * @param policyModel The policyModel to save
+ */
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
+ public PolicyModel savePolicyModelInNewTransaction(PolicyModel policyModel) {
+ return policyModelsRepository.saveAndFlush(policyModel);
+ }
+
+ /**
+ * Update the Pdp Group info in Policy Model DB.
+ *
+ * @param pdpGroups The list of Pdp Group info received from Policy Engine
+ */
+ public void updatePdpGroupInfo(PdpGroups pdpGroups) {
+ List<PolicyModel> policyModelsList = policyModelsRepository.findAll();
+ PdpGroupsAnalyzer.updatePdpGroupOfPolicyModels(policyModelsList, pdpGroups);
+ this.policyModelsRepository.saveAll(policyModelsList);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java
new file mode 100644
index 000000000..f8bdab6c2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/Policy.java
@@ -0,0 +1,255 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (C) 2021 AT&T
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.ManyToOne;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.json.JSONObject;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.yaml.snakeyaml.Yaml;
+
+@MappedSuperclass
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public abstract class Policy extends AuditEntity {
+
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(Policy.class);
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "json_representation", nullable = false)
+ private JsonObject jsonRepresentation;
+
+ @Expose
+ @Type(type = "json")
+ @Column(columnDefinition = "json", name = "configurations_json")
+ private JsonObject configurationsJson;
+
+ /**
+ * This attribute can be null when the user add a policy on the loop instance, not the template.
+ * When null, It therefore indicates that this policy is not by default in the loop template.
+ */
+ @Expose
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "loop_element_model_id")
+ private LoopElementModel loopElementModel;
+
+ @Expose
+ @Column(name = "pdp_group")
+ private String pdpGroup;
+
+ @Expose
+ @Column(name = "pdp_sub_group")
+ private String pdpSubgroup;
+
+ @Expose
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumns({@JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"),
+ @JoinColumn(name = "policy_model_version", referencedColumnName = "version")})
+ private PolicyModel policyModel;
+
+ /**
+ * This method create the policy payload that must be sent to PEF.
+ *
+ * @return A String containing the payload
+ * @throws UnsupportedEncodingException In case of failure
+ */
+ public String createPolicyPayload() throws UnsupportedEncodingException {
+ return PolicyPayload
+ .createPolicyPayload(this.getPolicyModel().getPolicyModelType(), this.getPolicyModel().getVersion(),
+ this.getName(), this.getPolicyModel().getVersion(), this.getConfigurationsJson(),
+ this.getPolicyModel() != null ? this.getPolicyModel().getPolicyModelTosca() : "");
+ }
+
+ /**
+ * Name getter.
+ *
+ * @return the name
+ */
+ public abstract String getName();
+
+ /**
+ * Name setter.
+ */
+ public abstract void setName(String name);
+
+ /**
+ * jsonRepresentation getter.
+ *
+ * @return the jsonRepresentation
+ */
+ public JsonObject getJsonRepresentation() {
+ return jsonRepresentation;
+ }
+
+ /**
+ * jsonRepresentation setter.
+ *
+ * @param jsonRepresentation The jsonRepresentation to set
+ */
+ public void setJsonRepresentation(JsonObject jsonRepresentation) {
+ this.jsonRepresentation = jsonRepresentation;
+ }
+
+ /**
+ * Regenerate the Policy Json Representation.
+ *
+ * @param toscaConverter The tosca converter required to regenerate the json schema
+ * @param serviceModel The service model associated
+ */
+ public abstract void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter,
+ Service serviceModel);
+
+ /**
+ * policyModel getter.
+ *
+ * @return the policyModel
+ */
+ public PolicyModel getPolicyModel() {
+ return policyModel;
+ }
+
+ /**
+ * policyModel setter.
+ *
+ * @param policyModel The new policyModel
+ */
+ public void setPolicyModel(PolicyModel policyModel) {
+ this.policyModel = policyModel;
+ }
+
+ /**
+ * configurationsJson getter.
+ *
+ * @return The configurationsJson
+ */
+ public JsonObject getConfigurationsJson() {
+ return configurationsJson;
+ }
+
+ /**
+ * configurationsJson setter.
+ *
+ * @param configurationsJson the configurationsJson to set
+ */
+ public void setConfigurationsJson(JsonObject configurationsJson) {
+ this.configurationsJson = configurationsJson;
+ }
+
+ /**
+ * loopElementModel getter.
+ *
+ * @return the loopElementModel
+ */
+ public LoopElementModel getLoopElementModel() {
+ return loopElementModel;
+ }
+
+ /**
+ * loopElementModel setter.
+ *
+ * @param loopElementModel the loopElementModel to set
+ */
+ public void setLoopElementModel(LoopElementModel loopElementModel) {
+ this.loopElementModel = loopElementModel;
+ }
+
+ /**
+ * pdpGroup getter.
+ *
+ * @return the pdpGroup
+ */
+ public String getPdpGroup() {
+ return pdpGroup;
+ }
+
+ /**
+ * pdpGroup setter.
+ *
+ * @param pdpGroup the pdpGroup to set
+ */
+ public void setPdpGroup(String pdpGroup) {
+ this.pdpGroup = pdpGroup;
+ }
+
+ /**
+ * pdpSubgroup getter.
+ *
+ * @return the pdpSubgroup
+ */
+ public String getPdpSubgroup() {
+ return pdpSubgroup;
+ }
+
+ /**
+ * pdpSubgroup setter.
+ *
+ * @param pdpSubgroup the pdpSubgroup to set
+ */
+ public void setPdpSubgroup(String pdpSubgroup) {
+ this.pdpSubgroup = pdpSubgroup;
+ }
+
+ /**
+ * Generate the policy name.
+ *
+ * @param policyType The policy type
+ * @param serviceName The service name
+ * @param serviceVersion The service version
+ * @param resourceName The resource name
+ * @param blueprintFilename The blueprint file name
+ * @return The generated policy name
+ */
+ public static String generatePolicyName(String policyType, String serviceName, String serviceVersion,
+ String resourceName, String blueprintFilename) {
+ StringBuilder buffer = new StringBuilder(policyType).append("_").append(serviceName).append("_v")
+ .append(serviceVersion).append("_").append(resourceName).append("_")
+ .append(blueprintFilename.replaceAll(".yaml", ""));
+ return buffer.toString().replace('.', '_').replaceAll(" ", "");
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java
new file mode 100644
index 000000000..4142841e2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyEngineServices.java
@@ -0,0 +1,223 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintMicroService;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+
+/**
+ * The class implements the communication with the Policy Engine to retrieve
+ * policy models (tosca). It mainly delegates the physical calls to Camel
+ * engine.
+ * It supports a retry mechanism for these calls, configurations can be specified in the
+ * application.properties "policy.retry.interval"(default 0) and "policy.retry.limit"(default 1).
+ */
+@Component
+public class PolicyEngineServices {
+ private final CamelContext camelContext;
+
+ private final PolicyModelsService policyModelsService;
+
+ private static final String RAISE_EXCEPTION_FLAG = "raiseHttpExceptionFlag";
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineServices.class);
+ private int retryInterval = 0;
+ private int retryLimit = 1;
+
+ public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval";
+ public static final String POLICY_RETRY_LIMIT = "policy.retry.limit";
+
+ /**
+ * Default constructor.
+ *
+ * @param camelContext Camel context bean
+ * @param clampProperties ClampProperties bean
+ * @param policyModelsService policyModel service
+ */
+ @Autowired
+ public PolicyEngineServices(CamelContext camelContext, ClampProperties clampProperties,
+ PolicyModelsService policyModelsService) {
+ this.camelContext = camelContext;
+ this.policyModelsService = policyModelsService;
+ if (clampProperties.getStringValue(POLICY_RETRY_LIMIT) != null) {
+ retryLimit = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_LIMIT));
+ }
+ if (clampProperties.getStringValue(POLICY_RETRY_INTERVAL) != null) {
+ retryInterval = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_INTERVAL));
+ }
+ }
+
+ /**
+ * This method query Policy engine and create a PolicyModel object with type and version.
+ * If the policy already exist in the db it returns the existing one.
+ *
+ * @param policyType The policyType id
+ * @param policyVersion The policy version of that type
+ * @return A PolicyModel created from policyEngine data or null if nothing is found on policyEngine
+ */
+ public PolicyModel createPolicyModelFromPolicyEngine(String policyType, String policyVersion) {
+ PolicyModel policyModelFound = policyModelsService.getPolicyModel(policyType, policyVersion);
+ if (policyModelFound == null) {
+ String policyTosca = this.downloadOnePolicyToscaModel(policyType, policyVersion);
+ if (policyTosca != null && !policyTosca.isEmpty()) {
+ return policyModelsService.savePolicyModelInNewTransaction(
+ new PolicyModel(policyType, policyTosca, policyVersion));
+ } else {
+ logger.error("Policy not found in the Policy Engine, returning null: " + policyType
+ + "/" + policyVersion);
+ return null;
+ }
+ } else {
+ logger.info("Skipping policy model download as it exists already in the database " + policyType
+ + "/" + policyVersion);
+ return policyModelFound;
+ }
+ }
+
+ /**
+ * This method query Policy engine and create a PolicyModel object with type and version.
+ *
+ * @param microService microservice object instance
+ * @return A PolicyModel created from policyEngine data
+ */
+ public PolicyModel createPolicyModelFromPolicyEngine(BlueprintMicroService microService) {
+ return createPolicyModelFromPolicyEngine(microService.getModelType(), microService.getModelVersion());
+ }
+
+ /**
+ * This method synchronize the clamp database and the policy engine.
+ * So it creates the required PolicyModel.
+ */
+ public void synchronizeAllPolicies() {
+ LinkedHashMap<String, Object> loadedYaml;
+ loadedYaml = new Yaml().load(downloadAllPolicyModels());
+ if (loadedYaml == null || loadedYaml.isEmpty()) {
+ logger.warn("getAllPolicyType yaml returned by policy engine could not be decoded, as it's null or empty");
+ return;
+ }
+
+ LinkedHashMap<String, Object> policyTypesMap = (LinkedHashMap<String, Object>) loadedYaml.get("policy_types");
+ policyTypesMap.forEach((key, value) ->
+ this.createPolicyModelFromPolicyEngine(key,
+ ((String) ((LinkedHashMap<String, Object>) value).get("version"))));
+ }
+
+ /**
+ * This method can be used to download all policy types + data types defined in
+ * policy engine.
+ *
+ * @return A yaml containing all policy Types and all data types
+ */
+ public String downloadAllPolicyModels() {
+ return callCamelRoute(
+ ExchangeBuilder.anExchange(camelContext).withProperty(RAISE_EXCEPTION_FLAG, true).build(),
+ "direct:get-all-policy-models", "Get all policies models");
+ }
+
+ /**
+ * This method can be used to download a policy tosca model on the engine.
+ *
+ * @param policyType The policy type (id)
+ * @param policyVersion The policy version
+ * @return A string with the whole policy tosca model
+ */
+ public String downloadOnePolicyToscaModel(String policyType, String policyVersion) {
+ logger.info("Downloading the policy tosca model " + policyType + "/" + policyVersion);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
+ options.setIndent(4);
+ options.setPrettyFlow(true);
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ Yaml yamlParser = new Yaml(options);
+ String responseBody = callCamelRoute(
+ ExchangeBuilder.anExchange(camelContext).withProperty("policyModelType", policyType)
+ .withProperty("policyModelVersion", policyVersion).withProperty(RAISE_EXCEPTION_FLAG, false)
+ .build(), "direct:get-policy-tosca-model",
+ "Get one policy");
+
+ if (responseBody == null || responseBody.isEmpty()) {
+ logger.warn("getPolicyToscaModel returned by policy engine could not be decoded, as it's null or empty");
+ return null;
+ }
+
+ return yamlParser.dump(yamlParser.load(responseBody));
+ }
+
+ /**
+ * This method can be used to download all Pdp Groups data from policy engine.
+ */
+ public void downloadPdpGroups() {
+ String responseBody =
+ callCamelRoute(
+ ExchangeBuilder.anExchange(camelContext).withProperty(RAISE_EXCEPTION_FLAG, false).build(),
+ "direct:get-all-pdp-groups", "Get Pdp Groups");
+
+ if (responseBody == null || responseBody.isEmpty()) {
+ logger.warn("getPdpGroups returned by policy engine could not be decoded, as it's null or empty");
+ return;
+ }
+
+ policyModelsService.updatePdpGroupInfo(JsonUtils.GSON.fromJson(responseBody, PdpGroups.class));
+ }
+
+ private String callCamelRoute(Exchange exchange, String camelFlow, String logMsg) {
+ for (int i = 0; i < retryLimit; i++) {
+ try (ProducerTemplate producerTemplate = camelContext.createProducerTemplate()) {
+ Exchange exchangeResponse = producerTemplate.send(camelFlow, exchange);
+ if (HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE))
+ .is2xxSuccessful()) {
+ return (String) exchangeResponse.getIn().getBody();
+ } else {
+ logger.info(logMsg + " query " + retryInterval + "ms before retrying ...");
+ // wait for a while and try to connect to DCAE again
+ Thread.sleep(retryInterval);
+
+ }
+ } catch (IOException e) {
+ logger.error("IOException caught when trying to call Camel flow:" + camelFlow, e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return "";
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java
new file mode 100644
index 000000000..d2c860150
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyPayload.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * This class is a utility class to create the policy payload.
+ */
+public class PolicyPayload {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyPayload.class);
+
+ private static JsonObject createJsonFromPolicyTosca(String toscaContent) {
+ Map<String, Object> map =
+ new Yaml().load(!StringUtils.isEmpty(toscaContent) ? toscaContent : "");
+ return JsonUtils.GSON.fromJson(new JSONObject(map).toString(), JsonObject.class);
+ }
+
+ /**
+ * This method create the policy payload that must be sent to PEF.
+ *
+ * @return A String containing the payload
+ * @throws UnsupportedEncodingException In case of failure
+ */
+ public static String createPolicyPayload(String policyModelType, String policyModelVersion, String policyName,
+ String policyVersion, JsonObject policyProperties, String toscaContent)
+ throws UnsupportedEncodingException {
+ JsonObject policyPayloadResult = new JsonObject();
+
+ policyPayloadResult.add("tosca_definitions_version",
+ createJsonFromPolicyTosca(toscaContent).get("tosca_definitions_version"));
+
+ JsonObject topologyTemplateNode = new JsonObject();
+ policyPayloadResult.add("topology_template", topologyTemplateNode);
+
+ JsonArray policiesArray = new JsonArray();
+ topologyTemplateNode.add("policies", policiesArray);
+
+ JsonObject thisPolicy = new JsonObject();
+ policiesArray.add(thisPolicy);
+
+ JsonObject policyDetails = new JsonObject();
+ thisPolicy.add(policyName, policyDetails);
+ policyDetails.addProperty("type", policyModelType);
+ policyDetails.addProperty("type_version", policyModelVersion);
+ policyDetails.addProperty("version", policyVersion);
+ policyDetails.addProperty("name", policyName);
+
+ JsonObject policyMetadata = new JsonObject();
+ policyDetails.add("metadata", policyMetadata);
+ policyMetadata.addProperty("policy-id", policyName);
+ policyMetadata.addProperty("policy-version", policyVersion);
+
+ policyDetails.add("properties", policyProperties);
+
+ String policyPayload = JsonUtils.GSON.toJson(policyPayloadResult);
+ logger.info("Policy payload: " + policyPayload);
+ return policyPayload;
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java
new file mode 100644
index 000000000..35ffa2443
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/PolicyService.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy;
+
+import java.util.List;
+import java.util.Set;
+import org.onap.policy.clamp.loop.Loop;
+
+public interface PolicyService<T extends Policy> {
+
+ Set<T> updatePolicies(Loop loop, List<T> newPolicies);
+
+ boolean isExisting(String policyName);
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java b/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java
new file mode 100644
index 000000000..81775e5da
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/downloader/PolicyEngineController.java
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.downloader;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.time.Instant;
+import org.json.simple.parser.ParseException;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.policy.clamp.policy.PolicyEngineServices;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.scheduling.annotation.Scheduled;
+
+/**
+ * This class implements a periodic job that is done in the background to
+ * synchronize policy models available on the policy engine and the clamp
+ * database table PolicyModel.
+ */
+@Configuration
+@Profile("clamp-policy-controller")
+public class PolicyEngineController {
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineController.class);
+ protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+ public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval";
+ public static final String POLICY_RETRY_LIMIT = "policy.retry.limit";
+
+ private final PolicyEngineServices policyEngineServices;
+
+ private Instant lastInstantExecuted;
+
+ @Autowired
+ public PolicyEngineController(PolicyEngineServices policyEngineService,
+ PolicyModelsRepository policyModelsRepository) {
+ this.policyEngineServices = policyEngineService;
+ }
+
+ @Scheduled(fixedRate = 300000)
+ public synchronized void synchronizeAllPolicies() {
+ policyEngineServices.synchronizeAllPolicies();
+ lastInstantExecuted = Instant.now();
+ }
+
+ public Instant getLastInstantExecuted() {
+ return lastInstantExecuted;
+ }
+
+ @Scheduled(fixedRate = 300000)
+ public synchronized void downloadPdpGroups() throws ParseException {
+ policyEngineServices.downloadPdpGroups();
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java
new file mode 100644
index 000000000..be5e7917c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicy.java
@@ -0,0 +1,276 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.microservice;
+
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.security.SecureRandom;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.policy.Policy;
+
+@Entity
+@Table(name = "micro_service_policies")
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public class MicroServicePolicy extends Policy implements Serializable {
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 6271238288583332616L;
+
+ @Expose
+ @Id
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @Expose
+ @Column(name = "context")
+ private String context;
+
+ @Expose
+ @Column(name = "device_type_scope")
+ private String deviceTypeScope;
+
+ @Expose
+ @Column(name = "shared", nullable = false)
+ private Boolean shared;
+
+ @ManyToMany(mappedBy = "microServicePolicies", fetch = FetchType.EAGER)
+ private Set<Loop> usedByLoops = new HashSet<>();
+
+ @Expose
+ @Column(name = "dcae_deployment_id")
+ private String dcaeDeploymentId;
+
+ @Expose
+ @Column(name = "dcae_deployment_status_url")
+ private String dcaeDeploymentStatusUrl;
+
+ @Expose
+ @Column(name = "dcae_blueprint_id")
+ private String dcaeBlueprintId;
+
+ /**
+ * Constructor for serialization.
+ */
+ public MicroServicePolicy() {
+ }
+
+ /**
+ * The constructor that does not make use of ToscaYamlToJsonConvertor but take
+ * the jsonRepresentation instead.
+ *
+ * @param name The name of the MicroService
+ * @param policyModel The policy model type of the MicroService
+ * @param shared The flag indicate whether the MicroService is
+ * shared
+ * @param jsonRepresentation The UI representation in json format
+ * @param loopElementModel The loop element model from which this instance should be created
+ * @param pdpGroup The Pdp Group info
+ * @param pdpSubgroup The Pdp Subgroup info
+ */
+ public MicroServicePolicy(String name, PolicyModel policyModel, Boolean shared,
+ JsonObject jsonRepresentation, LoopElementModel loopElementModel, String pdpGroup,
+ String pdpSubgroup) {
+ this.name = name;
+ this.setPolicyModel(policyModel);
+ this.shared = shared;
+ this.setJsonRepresentation(jsonRepresentation);
+ this.setLoopElementModel(loopElementModel);
+ this.setPdpGroup(pdpGroup);
+ this.setPdpSubgroup(pdpSubgroup);
+ }
+
+ /**
+ * Constructor with tosca converter.
+ *
+ * @param loop The loop instance
+ * @param service The service model object
+ * @param loopElementModel The loop element model from which this microservice instance is created
+ * @param toscaConverter The tosca converter that will used to convert the tosca policy model
+ */
+ public MicroServicePolicy(Loop loop, Service service, LoopElementModel loopElementModel,
+ ToscaConverterWithDictionarySupport toscaConverter) {
+ this(Policy.generatePolicyName("MICROSERVICE", service.getName(), service.getVersion(),
+ loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_'
+ + loopElementModel.getPolicyModels().first().getVersion(),
+ RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())),
+ loopElementModel.getPolicyModels().first(), false, new JsonObject(), loopElementModel, null, null);
+ this.updateJsonRepresentation(toscaConverter, service);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ @Override
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) {
+ this.setJsonRepresentation(
+ toscaConverter.convertToscaToJsonSchemaObject(this.getPolicyModel().getPolicyModelTosca(),
+ this.getPolicyModel().getPolicyModelType(), serviceModel));
+ }
+
+ public Boolean getShared() {
+ return shared;
+ }
+
+ void setShared(Boolean shared) {
+ this.shared = shared;
+ }
+
+ public Set<Loop> getUsedByLoops() {
+ return usedByLoops;
+ }
+
+ void setUsedByLoops(Set<Loop> usedBy) {
+ this.usedByLoops = usedBy;
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ public void setContext(String context) {
+ this.context = context;
+ }
+
+ public String getDeviceTypeScope() {
+ return deviceTypeScope;
+ }
+
+ public void setDeviceTypeScope(String deviceTypeScope) {
+ this.deviceTypeScope = deviceTypeScope;
+ }
+
+ /**
+ * dcaeDeploymentId getter.
+ *
+ * @return the dcaeDeploymentId
+ */
+ public String getDcaeDeploymentId() {
+ return dcaeDeploymentId;
+ }
+
+ /**
+ * dcaeDeploymentId setter.
+ *
+ * @param dcaeDeploymentId the dcaeDeploymentId to set
+ */
+ public void setDcaeDeploymentId(String dcaeDeploymentId) {
+ this.dcaeDeploymentId = dcaeDeploymentId;
+ }
+
+ /**
+ * dcaeDeploymentStatusUrl getter.
+ *
+ * @return the dcaeDeploymentStatusUrl
+ */
+ public String getDcaeDeploymentStatusUrl() {
+ return dcaeDeploymentStatusUrl;
+ }
+
+ /**
+ * dcaeDeploymentStatusUrl setter.
+ *
+ * @param dcaeDeploymentStatusUrl the dcaeDeploymentStatusUrl to set
+ */
+ public void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) {
+ this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl;
+ }
+
+ /**
+ * dcaeBlueprintId getter.
+ *
+ * @return the dcaeBlueprintId
+ */
+ public String getDcaeBlueprintId() {
+ return dcaeBlueprintId;
+ }
+
+ /**
+ * dcaeBlueprintId setter.
+ *
+ * @param dcaeBlueprintId the dcaeBlueprintId to set
+ */
+ void setDcaeBlueprintId(String dcaeBlueprintId) {
+ this.dcaeBlueprintId = dcaeBlueprintId;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ MicroServicePolicy other = (MicroServicePolicy) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java
new file mode 100644
index 000000000..2ce2c4f17
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyRepository.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.microservice;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface MicroServicePolicyRepository extends JpaRepository<MicroServicePolicy, String> {
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java
new file mode 100644
index 000000000..b9871049e
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/microservice/MicroServicePolicyService.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.microservice;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.policy.PolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MicroServicePolicyService implements PolicyService<MicroServicePolicy> {
+
+ private final MicroServicePolicyRepository microServiceRepository;
+
+ @Autowired
+ public MicroServicePolicyService(MicroServicePolicyRepository microServiceRepository) {
+ this.microServiceRepository = microServiceRepository;
+ }
+
+ @Override
+ public Set<MicroServicePolicy> updatePolicies(Loop loop, List<MicroServicePolicy> newMicroservicePolicies) {
+ return newMicroservicePolicies.stream().map(policy -> getAndUpdateMicroServicePolicy(loop, policy))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean isExisting(String policyName) {
+ return microServiceRepository.existsById(policyName);
+ }
+
+ /**
+ * Get and update the MicroService policy properties.
+ *
+ * @param loop The loop
+ * @param policy The new MicroService policy
+ * @return The updated MicroService policy
+ */
+ public MicroServicePolicy getAndUpdateMicroServicePolicy(Loop loop, MicroServicePolicy policy) {
+ return microServiceRepository.save(
+ microServiceRepository
+ .findById(policy.getName()).map(p -> updateMicroservicePolicyProperties(p, policy, loop))
+ .orElse(new MicroServicePolicy(policy.getName(), policy.getPolicyModel(),
+ policy.getShared(), policy.getJsonRepresentation(), null, policy.getPdpGroup(),
+ policy.getPdpSubgroup())));
+ }
+
+ private MicroServicePolicy updateMicroservicePolicyProperties(MicroServicePolicy oldPolicy,
+ MicroServicePolicy newPolicy, Loop loop) {
+ oldPolicy.setConfigurationsJson(newPolicy.getConfigurationsJson());
+ if (!oldPolicy.getUsedByLoops().contains(loop)) {
+ oldPolicy.getUsedByLoops().add(loop);
+ }
+ oldPolicy.setPdpGroup(newPolicy.getPdpGroup());
+ oldPolicy.setPdpSubgroup(newPolicy.getPdpSubgroup());
+ return oldPolicy;
+ }
+
+ /**
+ * Update the MicroService policy deployment related parameters.
+ *
+ * @param microServicePolicy The micro service policy
+ * @param deploymentId The deployment ID as returned by DCAE
+ * @param deploymentUrl The Deployment URL as returned by DCAE
+ */
+ public void updateDcaeDeploymentFields(MicroServicePolicy microServicePolicy, String deploymentId,
+ String deploymentUrl) {
+ microServicePolicy.setDcaeDeploymentId(deploymentId);
+ microServicePolicy.setDcaeDeploymentStatusUrl(deploymentUrl);
+ microServiceRepository.saveAndFlush(microServicePolicy);
+ }
+
+
+ /**
+ * Api to refresh the MicroService Policy UI window.
+ *
+ * @param microServicePolicy The micro Service policy object
+ * @param toscaConverter The tosca converter required to convert the tosca model to json schema
+ * @param loop As a microservice object can belong to multiple loops, we need it here
+ */
+ public void refreshMicroServicePolicyJsonRepresentation(MicroServicePolicy microServicePolicy,
+ ToscaConverterWithDictionarySupport toscaConverter,
+ Loop loop) {
+ microServicePolicy.updateJsonRepresentation(toscaConverter, loop.getModelService());
+ this.microServiceRepository.saveAndFlush(microServicePolicy);
+
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java
new file mode 100644
index 000000000..1646a7cc7
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicy.java
@@ -0,0 +1,219 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.operational;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.dao.model.jsontype.StringJsonUserType;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.policy.Policy;
+
+@Entity
+@Table(name = "operational_policies")
+@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)})
+public class OperationalPolicy extends Policy implements Serializable {
+ /**
+ * The serial version ID.
+ */
+ private static final long serialVersionUID = 6117076450841538255L;
+
+ @Transient
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicy.class);
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "loop_id", nullable = false)
+ private Loop loop;
+
+ /**
+ * Constructor for serialization.
+ */
+ public OperationalPolicy() {
+ }
+
+ /**
+ * The constructor.
+ *
+ * @param name The name of the operational policy
+ * @param configurationsJson The operational policy property in the format of
+ * json
+ * @param jsonRepresentation The jsonObject defining the json schema
+ * @param policyModel The policy model associated if any, can be null
+ * @param loopElementModel The loop element from which this instance is supposed to be created
+ * @param pdpGroup The Pdp Group info
+ * @param pdpSubgroup The Pdp Subgroup info
+ */
+ public OperationalPolicy(String name, JsonObject configurationsJson,
+ JsonObject jsonRepresentation, PolicyModel policyModel,
+ LoopElementModel loopElementModel, String pdpGroup, String pdpSubgroup) {
+ this.name = name;
+ this.setPolicyModel(policyModel);
+ this.setConfigurationsJson(configurationsJson);
+ this.setPdpGroup(pdpGroup);
+ this.setPdpSubgroup(pdpSubgroup);
+ this.setLoopElementModel(loopElementModel);
+ this.setJsonRepresentation(jsonRepresentation);
+
+ }
+
+ /**
+ * Create an operational policy from a loop element model.
+ *
+ * @param loop The parent loop
+ * @param service The loop service
+ * @param loopElementModel The loop element model
+ * @param toscaConverter The tosca converter that must be used to create the Json representation
+ */
+ public OperationalPolicy(Loop loop, Service service, LoopElementModel loopElementModel,
+ ToscaConverterWithDictionarySupport toscaConverter) {
+ this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(),
+ loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_'
+ + loopElementModel.getPolicyModels().first().getVersion(),
+ RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())), new JsonObject(),
+ new JsonObject(), loopElementModel.getPolicyModels().first(), loopElementModel, null, null);
+ this.setLoop(loop);
+ this.updateJsonRepresentation(toscaConverter, service);
+ }
+
+ /**
+ * Create an operational policy from a policy model.
+ *
+ * @param loop The parent loop
+ * @param service The loop service
+ * @param policyModel The policy model
+ * @param toscaConverter The tosca converter that must be used to create the Json representation
+ */
+ public OperationalPolicy(Loop loop, Service service, PolicyModel policyModel,
+ ToscaConverterWithDictionarySupport toscaConverter) {
+ this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(),
+ policyModel.getPolicyAcronym() + '_' + policyModel.getVersion(),
+ RandomStringUtils.random(3, 0, 0, true, true, null, new SecureRandom())),
+ new JsonObject(),
+ new JsonObject(), policyModel, null, null, null);
+ this.setLoop(loop);
+ this.updateJsonRepresentation(toscaConverter, service);
+ }
+
+ public void setLoop(Loop loopName) {
+ this.loop = loopName;
+ }
+
+ public Loop getLoop() {
+ return loop;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ @Override
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) {
+ {
+ this.setJsonRepresentation(new JsonObject());
+ if (this.getPolicyModel() == null) {
+ return;
+ }
+
+ // Generic Case
+ this.setJsonRepresentation(toscaConverter.convertToscaToJsonSchemaObject(
+ this.getPolicyModel().getPolicyModelTosca(),
+ this.getPolicyModel().getPolicyModelType(), serviceModel));
+
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ OperationalPolicy other = (OperationalPolicy) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else {
+ if (!name.equals(other.name)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String createPolicyPayload() throws UnsupportedEncodingException {
+ return super.createPolicyPayload();
+
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java
new file mode 100644
index 000000000..b0a33669a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepository.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.operational;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface OperationalPolicyRepository extends JpaRepository<OperationalPolicy, String> {
+ void deleteByName(String policyName);
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java
new file mode 100644
index 000000000..6718475ca
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java
@@ -0,0 +1,348 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.operational;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.service.Service;
+
+public class OperationalPolicyRepresentationBuilder {
+
+ private static final EELFLogger logger =
+ EELFManager.getInstance().getLogger(OperationalPolicyRepresentationBuilder.class);
+
+ public static final String PROPERTIES = "properties";
+ public static final String ITEMS = "items";
+ public static final String ANY_OF = "anyOf";
+ public static final String TITLE = "title";
+ public static final String RECIPE = "recipe";
+ public static final String DEFAULT = "default";
+ public static final String STRING = "string";
+ public static final String TYPE = "type";
+ public static final String TYPE_LIST = "list";
+ public static final String TYPE_OBJECT = "object";
+ public static final String TYPE_ARRAY = "array";
+
+ private OperationalPolicyRepresentationBuilder() {
+ throw new IllegalStateException("This is Utility class, not supposed to be initiated.");
+ }
+
+ /**
+ * This method generates the operational policy json representation that will be
+ * used by ui for rendering. It uses the model (VF and VFModule) defined in the
+ * loop object to do so, so it's dynamic. It also uses the operational policy
+ * schema template defined in the resource folder.
+ *
+ * @param modelJson The loop model json
+ * @return The json representation
+ */
+ public static JsonObject generateOperationalPolicySchema(Service modelJson) {
+
+ JsonObject jsonSchema = null;
+ try {
+ jsonSchema = JsonUtils.GSON.fromJson(
+ ResourceFileUtils
+ .getResourceAsString("clds/json-schema/operational_policies/operational_policy.json"),
+ JsonObject.class);
+ jsonSchema.get(PROPERTIES).getAsJsonObject()
+ .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies")
+ .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("target")
+ .getAsJsonObject().get(ANY_OF).getAsJsonArray().addAll(createAnyOfArray(modelJson, true));
+
+ // update CDS recipe and payload information to schema
+ for (JsonElement actor : jsonSchema.get(PROPERTIES).getAsJsonObject()
+ .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies")
+ .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("actor")
+ .getAsJsonObject().get(ANY_OF).getAsJsonArray()) {
+ if ("CDS".equalsIgnoreCase(actor.getAsJsonObject().get(TITLE).getAsString())) {
+ actor.getAsJsonObject().get(PROPERTIES).getAsJsonObject().get(RECIPE).getAsJsonObject()
+ .get(ANY_OF).getAsJsonArray()
+ .addAll(createAnyOfArrayForCdsRecipe(modelJson));
+ }
+ }
+ return jsonSchema;
+ } catch (IOException e) {
+ logger.error("Unable to generate the json schema because of an exception", e);
+ return new JsonObject();
+ }
+ }
+
+ private static JsonObject createSchemaProperty(String title, String type, String defaultValue, String readOnlyFlag,
+ String[] enumArray) {
+ JsonObject property = new JsonObject();
+ property.addProperty(TITLE, title);
+ property.addProperty(TYPE, type);
+ property.addProperty(DEFAULT, defaultValue);
+ property.addProperty("readOnly", readOnlyFlag);
+
+ if (enumArray != null) {
+ JsonArray jsonArray = new JsonArray();
+ property.add("enum", jsonArray);
+ for (String val : enumArray) {
+ jsonArray.add(val);
+ }
+ }
+ return property;
+ }
+
+ private static JsonArray createVnfSchema(Service modelService, boolean generateType) {
+ JsonArray vnfSchemaArray = new JsonArray();
+ JsonObject modelVnfs = modelService.getResourceByType("VF");
+
+ for (Entry<String, JsonElement> entry : modelVnfs.entrySet()) {
+ JsonObject vnfOneOfSchema = new JsonObject();
+ vnfOneOfSchema.addProperty(TITLE, "VNF" + "-" + entry.getKey());
+ JsonObject properties = new JsonObject();
+ if (generateType) {
+ properties.add(TYPE, createSchemaProperty("Type", STRING, "VNF", "True", null));
+ }
+ properties.add("resourceID", createSchemaProperty("Resource ID", STRING,
+ modelVnfs.get(entry.getKey()).getAsJsonObject().get("invariantUUID").getAsString(), "True", null));
+
+ vnfOneOfSchema.add(PROPERTIES, properties);
+ vnfSchemaArray.add(vnfOneOfSchema);
+ }
+ return vnfSchemaArray;
+ }
+
+ private static JsonArray createBlankEntry() {
+ JsonArray result = new JsonArray();
+ JsonObject blankObject = new JsonObject();
+ blankObject.addProperty(TITLE, "User defined");
+ blankObject.add(PROPERTIES, new JsonObject());
+ result.add(blankObject);
+ return result;
+ }
+
+ private static JsonArray createVfModuleSchema(Service modelService, boolean generateType) {
+ JsonArray vfModuleOneOfSchemaArray = new JsonArray();
+ JsonObject modelVfModules = modelService.getResourceByType("VFModule");
+
+ for (Entry<String, JsonElement> entry : modelVfModules.entrySet()) {
+ JsonObject vfModuleOneOfSchema = new JsonObject();
+ vfModuleOneOfSchema.addProperty(TITLE, "VFMODULE" + "-" + entry.getKey());
+ JsonObject properties = new JsonObject();
+ if (generateType) {
+ properties.add(TYPE, createSchemaProperty("Type", STRING, "VFMODULE", "True", null));
+ }
+ properties.add("resourceID",
+ createSchemaProperty("Resource ID", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(),
+ "True", null));
+ properties.add("modelInvariantId",
+ createSchemaProperty("Model Invariant Id (ModelInvariantUUID)", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelInvariantUUID")
+ .getAsString(),
+ "True", null));
+ properties.add("modelVersionId",
+ createSchemaProperty("Model Version Id (ModelUUID)", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelUUID").getAsString(),
+ "True", null));
+ properties.add("modelName",
+ createSchemaProperty("Model Name", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(),
+ "True", null));
+ properties.add("modelVersion", createSchemaProperty("Model Version", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelVersion").getAsString(),
+ "True", null));
+ properties
+ .add("modelCustomizationId",
+ createSchemaProperty("Customization ID", STRING,
+ modelVfModules.get(entry.getKey()).getAsJsonObject()
+ .get("vfModuleModelCustomizationUUID").getAsString(), "True",
+ null));
+
+ vfModuleOneOfSchema.add(PROPERTIES, properties);
+ vfModuleOneOfSchemaArray.add(vfModuleOneOfSchema);
+ }
+ return vfModuleOneOfSchemaArray;
+ }
+
+ /**
+ * Create an anyOf array of possible structure we may have for Target.
+ *
+ * @param modelJson The service object
+ * @return A JsonArray with everything inside
+ */
+ public static JsonArray createAnyOfArray(Service modelJson, boolean generateType) {
+ JsonArray targetOneOfStructure = new JsonArray();
+ // First entry must be user defined
+ targetOneOfStructure.addAll(createBlankEntry());
+ targetOneOfStructure.addAll(createVnfSchema(modelJson, generateType));
+ targetOneOfStructure.addAll(createVfModuleSchema(modelJson, generateType));
+ return targetOneOfStructure;
+ }
+
+ private static JsonArray createAnyOfArrayForCdsRecipe(Service modelJson) {
+ JsonArray anyOfStructure = new JsonArray();
+ anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("VF")));
+ anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("PNF")));
+ return anyOfStructure;
+ }
+
+ private static JsonArray createAnyOfCdsRecipe(JsonObject jsonObject) {
+ JsonArray schemaArray = new JsonArray();
+ for (Entry<String, JsonElement> entry : jsonObject.entrySet()) {
+ JsonObject controllerProperties = entry.getValue().getAsJsonObject()
+ .getAsJsonObject("controllerProperties");
+
+ if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) {
+ JsonObject workflows = controllerProperties.getAsJsonObject("workflows");
+ for (Entry<String, JsonElement> workflowsEntry : workflows.entrySet()) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty(TITLE, workflowsEntry.getKey());
+ obj.addProperty(TYPE, TYPE_OBJECT);
+ obj.add(PROPERTIES, createPayloadProperty(workflowsEntry.getValue().getAsJsonObject(),
+ controllerProperties, workflowsEntry.getKey()));
+ schemaArray.add(obj);
+ }
+
+ }
+ }
+ return schemaArray;
+ }
+
+ private static JsonObject createPayloadProperty(JsonObject workFlow,
+ JsonObject controllerProperties, String workFlowName) {
+ JsonObject payload = new JsonObject();
+ payload.addProperty(TITLE, "Payload");
+ payload.addProperty(TYPE, TYPE_OBJECT);
+ payload.add(PROPERTIES, createInputPropertiesForPayload(workFlow, controllerProperties,
+ workFlowName));
+ JsonObject properties = new JsonObject();
+ properties.add(RECIPE, createRecipeForCdsWorkflow(workFlowName));
+ properties.add("payload", payload);
+ return properties;
+ }
+
+ private static JsonObject createRecipeForCdsWorkflow(String workflow) {
+ JsonObject recipe = new JsonObject();
+ recipe.addProperty(TITLE, RECIPE);
+ recipe.addProperty(TYPE, STRING);
+ recipe.addProperty(DEFAULT, workflow);
+ JsonObject options = new JsonObject();
+ options.addProperty("hidden", true);
+ recipe.add("options", options);
+ return recipe;
+ }
+
+ /**
+ * Returns the properties of payload based on the cds work flows.
+ *
+ * @param workFlow cds work flows to update payload
+ * @param controllerProperties cds properties to get blueprint name and
+ * version
+ * @param workFlowName work flow name
+ * @return returns the properties of payload
+ */
+ public static JsonObject createInputPropertiesForPayload(JsonObject workFlow,
+ JsonObject controllerProperties,
+ String workFlowName) {
+ String artifactName = controllerProperties.get("sdnc_model_name").getAsString();
+ String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString();
+ JsonObject inputs = workFlow.getAsJsonObject("inputs");
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.add("artifact_name", createSchemaProperty(
+ "artifact name", STRING, artifactName, "True", null));
+ jsonObject.add("artifact_version", createSchemaProperty(
+ "artifact version", STRING, artifactVersion, "True", null));
+ jsonObject.add("mode", createCdsInputProperty(
+ "mode", STRING, "async", null));
+ jsonObject.add("data", createDataProperty(inputs, workFlowName));
+ return jsonObject;
+ }
+
+ private static JsonObject createDataProperty(JsonObject inputs, String workflowName) {
+ JsonObject data = new JsonObject();
+ data.addProperty(TITLE, "data");
+ JsonObject dataObj = new JsonObject();
+ addDataFields(inputs, dataObj, workflowName);
+ data.add(PROPERTIES, dataObj);
+ return data;
+ }
+
+ private static void addDataFields(JsonObject inputs,
+ JsonObject dataObj,
+ String workFlowName) {
+ Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet();
+ for (Map.Entry<String, JsonElement> entry : entrySet) {
+ String key = entry.getKey();
+ JsonObject inputProperty = inputs.getAsJsonObject(key);
+ if (key.equalsIgnoreCase(workFlowName + "-properties")) {
+ addDataFields(entry.getValue().getAsJsonObject().get(PROPERTIES).getAsJsonObject(),
+ dataObj, workFlowName);
+ } else {
+ dataObj.add(entry.getKey(),
+ createCdsInputProperty(key, inputProperty.get(TYPE).getAsString(), null,
+ entry.getValue().getAsJsonObject()));
+ }
+ }
+ }
+
+ private static JsonObject createCdsInputProperty(String title,
+ String type,
+ String defaultValue,
+ JsonObject cdsProperty) {
+ JsonObject property = new JsonObject();
+ property.addProperty(TITLE, title);
+
+ if (TYPE_LIST.equalsIgnoreCase(type)) {
+ property.addProperty(TYPE, TYPE_ARRAY);
+ if (cdsProperty != null && cdsProperty.get(PROPERTIES) != null) {
+ JsonObject listProperties = new JsonObject();
+ listProperties.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject()));
+ property.add(ITEMS, listProperties);
+ }
+ } else if (cdsProperty != null && TYPE_OBJECT.equalsIgnoreCase(type)) {
+ property.addProperty(TYPE, TYPE_OBJECT);
+ property.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject()));
+ } else {
+ property.addProperty(TYPE, type);
+ }
+
+ if (defaultValue != null) {
+ property.addProperty(DEFAULT, defaultValue);
+ }
+ return property;
+ }
+
+ private static JsonObject getProperties(JsonObject inputProperties) {
+ if (inputProperties == null) {
+ return null;
+ }
+ JsonObject dataObject = new JsonObject();
+ addDataFields(inputProperties, dataObject, null);
+ return dataObject;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java
new file mode 100644
index 000000000..3f3f39b45
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/operational/OperationalPolicyService.java
@@ -0,0 +1,94 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.operational;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.onap.policy.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.policy.clamp.policy.PolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class OperationalPolicyService implements PolicyService<OperationalPolicy> {
+
+ private final OperationalPolicyRepository operationalPolicyRepository;
+
+ private final PolicyModelsRepository policyModelsRepository;
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicyService.class);
+
+ @Autowired
+ public OperationalPolicyService(OperationalPolicyRepository repository,
+ PolicyModelsRepository policyModelsRepository) {
+ this.operationalPolicyRepository = repository;
+ this.policyModelsRepository = policyModelsRepository;
+ }
+
+ @Override
+ public Set<OperationalPolicy> updatePolicies(Loop loop, List<OperationalPolicy> operationalPolicies) {
+ return operationalPolicies
+ .parallelStream()
+ .map(policy ->
+ operationalPolicyRepository
+ .findById(policy.getName())
+ .map(p -> setConfiguration(p, policy))
+ .orElse(initializeMissingFields(loop, policy)))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean isExisting(String policyName) {
+ return operationalPolicyRepository.existsById(policyName);
+ }
+
+ private OperationalPolicy initializeMissingFields(Loop loop, OperationalPolicy policy) {
+ policy.setLoop(loop);
+ return policy;
+ }
+
+ private OperationalPolicy setConfiguration(OperationalPolicy policy, OperationalPolicy newPolicy) {
+ policy.setConfigurationsJson(newPolicy.getConfigurationsJson());
+ policy.setPdpGroup(newPolicy.getPdpGroup());
+ policy.setPdpSubgroup(newPolicy.getPdpSubgroup());
+ return policy;
+ }
+
+ /**
+ * Api to refresh the Operational Policy UI window.
+ *
+ * @param operationalPolicy The operational policy object
+ * @param toscaConverter the tosca converter required to convert the tosca model to json schema
+ */
+ public void refreshOperationalPolicyJsonRepresentation(OperationalPolicy operationalPolicy,
+ ToscaConverterWithDictionarySupport toscaConverter) {
+ operationalPolicy.updateJsonRepresentation(toscaConverter, operationalPolicy.getLoop().getModelService());
+ this.operationalPolicyRepository.saveAndFlush(operationalPolicy);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java
new file mode 100644
index 000000000..c6b44076f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayload.java
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonElement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.models.pdp.concepts.DeploymentGroup;
+import org.onap.policy.models.pdp.concepts.DeploymentGroups;
+import org.onap.policy.models.pdp.concepts.DeploymentSubGroup;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * This is an utility class that build the PDP group policy payload.
+ * This is used when policies have to be deployed to PDP group/subgroups on the Policy Engine.
+ * Currently it does not group the queries per pdpgroup/subgroups/action.
+ * This is currently NOT thread safe, do not use parallel streams to update the structure.
+ */
+public class PdpGroupPayload {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(PdpGroupPayload.class);
+
+ /**
+ * The default node that will contain the actions array.
+ */
+ public static final String PDP_ACTIONS = "PdpActions";
+
+ private final DeploymentGroups deploymentGroups = new DeploymentGroups();
+
+ /**
+ * Default constructor.
+ */
+ public PdpGroupPayload() {
+ deploymentGroups.setGroups(new ArrayList<>());
+ }
+
+ /**
+ * Constructor that takes a list of actions in input.
+ *
+ * @param listOfPdpActions The list of actions that needs to be done.
+ * e.g: {"Pdpactions":["DELETE/PdpGroup1/PdpSubGroup1/PolicyName1/1.0.0",....]}
+ * @throws PdpGroupPayloadException in case of issues to read the listOfActions
+ */
+ public PdpGroupPayload(final JsonElement listOfPdpActions) throws PdpGroupPayloadException {
+ this();
+ this.readListOfActions(listOfPdpActions);
+ }
+
+ /**
+ * This method converts the list of actions directly to the pdp payload query as String.
+ *
+ * @param listOfPdpActions The list of actions that needs to be done.
+ * e.g: {"Pdpactions":["DELETE/PdpGroup1/PdpSubGroup1/PolicyName1/1.0.0",....]}
+ * @return The string containing the PDP payload that can be sent directly
+ * @throws PdpGroupPayloadException in case of issues to read the listOfActions
+ */
+ public static String generatePdpGroupPayloadFromList(final JsonElement listOfPdpActions)
+ throws PdpGroupPayloadException {
+ return new PdpGroupPayload(listOfPdpActions).generatePdpGroupPayload();
+ }
+
+
+ private void readListOfActions(final JsonElement listOfPdpActions) throws PdpGroupPayloadException {
+ for (JsonElement action : listOfPdpActions.getAsJsonObject().getAsJsonArray(PDP_ACTIONS)) {
+ String[] opParams = action.getAsString().split("/");
+ if (opParams.length == 5) {
+ this.updatePdpGroupMap(opParams[1], opParams[2], opParams[3], opParams[4], opParams[0]);
+ } else {
+ logger.error("One PDP push command does not contain the right number of arguments: " + action);
+ throw new PdpGroupPayloadException(
+ "One PDP push command does not contain the right number of arguments: " + action);
+ }
+ }
+ }
+
+ /**
+ * This method updates the pdpGroupMap structure for a specific policy/version/pdpdGroup/PdpSubGroup.
+ *
+ * @param pdpGroup The pdp Group in String
+ * @param pdpSubGroup The pdp Sub Group in String
+ * @param policyName The policy name
+ * @param policyVersion The policy Version
+ * @param action DELETE or POST
+ */
+ public void updatePdpGroupMap(String pdpGroup,
+ String pdpSubGroup,
+ String policyName,
+ String policyVersion, String action) {
+ // create subgroup
+ DeploymentSubGroup newSubGroup = new DeploymentSubGroup();
+ newSubGroup.setPdpType(pdpSubGroup);
+ newSubGroup.setAction(DeploymentSubGroup.Action.valueOf(action));
+ newSubGroup.setPolicies(Arrays.asList(new ToscaConceptIdentifier(policyName, policyVersion)));
+ // Add to deployment Groups structure
+ this.deploymentGroups.getGroups().stream().filter(group ->
+ group.getName().equals(pdpGroup)).findFirst()
+ .ifPresentOrElse(group -> group.getDeploymentSubgroups().add(newSubGroup),
+ () -> {
+ DeploymentGroup newGroup = new DeploymentGroup();
+ newGroup.setName(pdpGroup);
+ newGroup.setDeploymentSubgroups(new ArrayList<>(Arrays.asList(newSubGroup)));
+ this.deploymentGroups.getGroups().add(newGroup);
+ });
+ }
+
+ /**
+ * This method generates the Payload in Json from the pdp Group structure containing the policies/versions
+ * that must be sent to the policy framework.
+ *
+ * @return The Json that can be sent to policy framework as String
+ */
+ public String generatePdpGroupPayload() {
+ String payload = JsonUtils.GSON.toJson(this.deploymentGroups);
+ logger.info("PdpGroup policy payload: " + payload);
+ return payload;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java
new file mode 100644
index 000000000..4ce0721b2
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadException.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+/**
+ * Exception during Pdp Group payload construction.
+ */
+public class PdpGroupPayloadException extends Exception {
+
+ /**
+ * serialization id.
+ */
+ private static final long serialVersionUID = -5676848693241134101L;
+
+ /**
+ * This constructor can be used to create a new PdpGroupPayloadException.
+ *
+ * @param message The message to dump
+ */
+ public PdpGroupPayloadException(final String message) {
+ super(message);
+ }
+
+ /**
+ * This constructor can be used to create a new PdpGroupPayloadException.
+ *
+ * @param message The message to dump
+ * @param cause The Throwable cause object
+ */
+ public PdpGroupPayloadException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java
new file mode 100644
index 000000000..6098d0f63
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupsAnalyzer.java
@@ -0,0 +1,180 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.commons.collections4.CollectionUtils;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.enums.PdpState;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * This is an utility class to do searching in pdp groups and create json object describing the result.
+ */
+public class PdpGroupsAnalyzer {
+
+ public static final String ASSIGNED_PDP_GROUPS_INFO = "pdpGroupInfo";
+ public static final String SUPPORTED_PDP_GROUPS_INFO = "supportedPdpGroups";
+
+ /**
+ * This structure holds the map of PdpGroups per policies, policies are identifed by ToscaConceptIdentifier.
+ */
+ private final Map<ToscaConceptIdentifier, Map<String, PdpGroup>> pdpGroupsDeploymentPerPolicy =
+ new ConcurrentHashMap<>();
+
+ /**
+ * Constructor taking he PDPGroups info from the PEF.
+ * It then caches the groups per policies and per types.
+ *
+ * @param pdpGroups The pdpgroup info from the PEF
+ */
+ public PdpGroupsAnalyzer(PdpGroups pdpGroups) {
+ this.analyzePdpGroups(pdpGroups);
+ }
+
+ /**
+ * Getter of the GroupDeploymentPerPolicy structure.
+ *
+ * @return The map of policies.
+ */
+ public Map<ToscaConceptIdentifier, Map<String, PdpGroup>> getPdpGroupsDeploymentPerPolicy() {
+ return pdpGroupsDeploymentPerPolicy;
+ }
+
+ private static void addInfoToPdpGroupsStructure(ToscaConceptIdentifier toscaId,
+ Map<ToscaConceptIdentifier,
+ Map<String,
+ PdpGroup>> pdpGroupsDeploymentPerToscaIdentifier,
+ PdpGroup pdpGroupSource,
+ PdpSubGroup pdpSubGroupSource) {
+ // Copy the subgroup but empty the policies & types
+ pdpGroupsDeploymentPerToscaIdentifier.computeIfAbsent(toscaId, toscaKey -> new ConcurrentHashMap<>())
+ .computeIfAbsent(pdpGroupSource.getName(), pdpGroupName -> {
+ PdpGroup pdpGroupCopy = new PdpGroup(pdpGroupSource);
+ pdpGroupCopy.setPdpSubgroups(new ArrayList<>());
+ return pdpGroupCopy;
+ }).getPdpSubgroups().add(new PdpSubGroup(pdpSubGroupSource));
+ }
+
+ private void analyzePdpGroups(PdpGroups pdpGroups) {
+ CollectionUtils.emptyIfNull(pdpGroups.getGroups()).stream()
+ .forEach(group -> CollectionUtils.emptyIfNull(group.getPdpSubgroups()).stream().forEach(subGroup ->
+ CollectionUtils.emptyIfNull(subGroup.getPolicies()).parallelStream().forEach(policy ->
+ PdpGroupsAnalyzer.addInfoToPdpGroupsStructure(policy, this.pdpGroupsDeploymentPerPolicy,
+ group, subGroup))));
+ }
+
+ /**
+ * This method retrieves all pdpGroups and subgroups where a specific policy name/version is deployed.
+ *
+ * @param policyName The policy name that must be used for searching
+ * @param version THe policy version that must be used for searching
+ * @return It returns a JsonObject containing each pdpGroup and subgroups associated
+ */
+ public JsonObject getPdpGroupsForPolicy(String policyName, String version) {
+ Map<String, PdpGroup> mapOfGroups =
+ this.pdpGroupsDeploymentPerPolicy.get(new ToscaConceptIdentifier(policyName, version));
+ if (mapOfGroups != null) {
+ JsonObject policyPdpGroups = new JsonObject();
+ JsonArray pdpGroupsArray = new JsonArray();
+ policyPdpGroups.add(ASSIGNED_PDP_GROUPS_INFO, pdpGroupsArray);
+ pdpGroupsArray.add(JsonUtils.GSON
+ .toJsonTree(mapOfGroups));
+ return policyPdpGroups;
+ }
+ return null;
+ }
+
+ /**
+ * Get supported subGroups based on the defined policy type and version for specific PDPGroup.
+ * It returns null if the Group is TERMINATED or if the policytype/version has not been found in the PDPSubgroups.
+ *
+ * @param pdpGroup The pdpGroup that must be analyzed
+ * @param policyType The policy type
+ * @param version The version
+ * @return The supported subGroups list in Json format
+ * @see org.onap.policy.models.pdp.concepts.PdpGroup
+ * @see org.onap.policy.models.pdp.enums.PdpState
+ */
+ private static JsonObject getSupportedPdpSubgroupsForModelType(PdpGroup pdpGroup, String policyType,
+ String version) {
+ if (PdpState.TERMINATED.equals(pdpGroup.getPdpGroupState())) {
+ return null;
+ }
+ JsonObject supportedPdpGroup = new JsonObject();
+ JsonArray supportedSubgroups = new JsonArray();
+ supportedPdpGroup.add(pdpGroup.getName(), supportedSubgroups);
+ pdpGroup.getPdpSubgroups().stream().forEach(pdpSubGroup -> {
+ if (pdpSubGroup.getSupportedPolicyTypes().stream().anyMatch(policyTypeIdentifier ->
+ policyType.matches(policyTypeIdentifier.getName().replace(".", "\\.").replace("*", ".*"))
+ && version.equals(policyTypeIdentifier.getVersion()))) {
+ supportedSubgroups.add(pdpSubGroup.getPdpType());
+ }
+ });
+ return supportedSubgroups.size() == 0 ? null : supportedPdpGroup;
+ }
+
+ /**
+ * This method retrieves all supported pdpGroups and subgroups for a specific policy type/version.
+ *
+ * @param pdpGroups The PdpGroups object containing all PEF pdp groups info
+ * @param policyType The policy type that must be used for searching
+ * @param version THe policy type version that must be used for searching
+ * @return It returns a JsonObject containing each pdpGroup and subgroups associated
+ */
+ public static JsonObject getSupportedPdpGroupsForModelType(PdpGroups pdpGroups, String policyType, String version) {
+ JsonObject supportedPdpGroups = new JsonObject();
+ JsonArray pdpGroupsArray = new JsonArray();
+ supportedPdpGroups.add(SUPPORTED_PDP_GROUPS_INFO, pdpGroupsArray);
+
+ pdpGroups.getGroups().stream().map(pdpGroup -> PdpGroupsAnalyzer.getSupportedPdpSubgroupsForModelType(pdpGroup,
+ policyType, version)).filter(Objects::nonNull)
+ .forEach(pdpGroupsArray::add);
+
+ return pdpGroupsArray.size() != 0 ? supportedPdpGroups : null;
+ }
+
+ /**
+ * This method updates each element in the policyModelsList given in argument based on the pdpGroups given.
+ *
+ * @param policyModelsList The list of Policy Models where each PolicyModel will be updated
+ * @param pdpGroups The PdpGroups containing all PDP group definition
+ */
+ public static void updatePdpGroupOfPolicyModels(List<PolicyModel> policyModelsList, PdpGroups pdpGroups) {
+ policyModelsList.parallelStream().forEach(policyModel -> policyModel
+ .setPolicyPdpGroup(getSupportedPdpGroupsForModelType(pdpGroups, policyModel.getPolicyModelType(),
+ policyModel.getVersion())));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java
new file mode 100644
index 000000000..6775eb0c6
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.stream.StreamSupport;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+
+/**
+ * This is an utility class that contains methods to work on the different results provided by the PEF.
+ * Mainly used to aggregate the results.
+ */
+public class PoliciesPdpMerger {
+
+ private PoliciesPdpMerger() {}
+
+ /**
+ * This method extract the content of a policy without knowing the key (policy Id).
+ * This JsonElement normally contains only the policy ID then the content,
+ * there is only one member in the Json element.
+ * As this is not really practical to use this method remove that
+ * nested Json.
+ *
+ * @param policyJsonElement The policy as JsonElement
+ * @return It return the content as JsonObject
+ */
+ public static JsonObject getPolicyContentOutOfJsonElement(JsonElement policyJsonElement) {
+ mergeJsonElement(policyJsonElement.getAsJsonObject(), policyJsonElement.getAsJsonObject()
+ .remove(((String) policyJsonElement.getAsJsonObject().keySet().toArray()[0])).getAsJsonObject());
+ return policyJsonElement.getAsJsonObject();
+ }
+
+ /**
+ * This method merges 2 JsonElement together. If the jsonToMerge is null nothing is changed.
+ *
+ * @param json The initial json that will received the data
+ * @param jsonToMerge The json that will be added to the first json object
+ */
+ public static void mergeJsonElement(JsonObject json, JsonObject jsonToMerge) {
+ if (jsonToMerge != null) {
+ jsonToMerge.entrySet().stream().forEach(entry -> json.add(entry.getKey(), entry.getValue()));
+ }
+ }
+
+ /**
+ * This method merges the result of the policy listing and the associated Pdp Group info.
+ * It can be seen as an enrichment of the policy listing.
+ *
+ * @param jsonPoliciesList The Json containing the policies from the PEF
+ * @param pdpGroupsJson The json containing the PDP groups info from the PEF
+ * @return It returns a JsonObject containing the policies list enriched with PdpGroup info
+ */
+ public static JsonObject mergePoliciesAndPdpGroupStates(String jsonPoliciesList, String pdpGroupsJson) {
+ PdpGroups pdpGroups = JsonUtils.GSON.fromJson(pdpGroupsJson, PdpGroups.class);
+ JsonObject policiesListJson =
+ JsonUtils.GSON.fromJson(jsonPoliciesList, JsonObject.class).get("topology_template")
+ .getAsJsonObject();
+ StreamSupport.stream(policiesListJson.get("policies").getAsJsonArray().spliterator(), true)
+ .forEach(policyJson -> enrichOnePolicy(pdpGroups, getPolicyContentOutOfJsonElement(policyJson)));
+ return policiesListJson;
+ }
+
+ /**
+ * Enrich one policy json node object with pdpGroup info.
+ *
+ * @param pdpGroups The pdpGroups from PEF to search the policy
+ * @param policyJsonNode The policy json node that must be enriched
+ */
+ private static void enrichOnePolicy(PdpGroups pdpGroups, JsonObject policyJsonNode) {
+ PdpGroupsAnalyzer pdpGroupAnalyzer = new PdpGroupsAnalyzer(pdpGroups);
+ JsonObject deploymentPdpJson = pdpGroupAnalyzer
+ .getPdpGroupsForPolicy(policyJsonNode.get("name").getAsString(),
+ policyJsonNode.get("version").getAsString());
+ mergeJsonElement(policyJsonNode, deploymentPdpJson);
+
+ JsonObject supportedPdpGroupsJson = PdpGroupsAnalyzer
+ .getSupportedPdpGroupsForModelType(pdpGroups, policyJsonNode.get("type").getAsString(),
+ policyJsonNode.get("type_version").getAsString());
+ mergeJsonElement(policyJsonNode, supportedPdpGroupsJson);
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java
new file mode 100644
index 000000000..4b01d6902
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/Dictionary.java
@@ -0,0 +1,219 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+
+/**
+ * Represents Dictionary.
+ */
+
+@Entity
+@Table(name = "dictionary")
+public class Dictionary extends AuditEntity implements Serializable {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522707701388645L;
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "name", unique = true)
+ private String name;
+
+ @Expose
+ @Column(name = "dictionary_second_level")
+ private int secondLevelDictionary = 0;
+
+ @Expose
+ @Column(name = "dictionary_type")
+ private String subDictionaryType;
+
+ @Expose
+ @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
+ @JoinTable(
+ name = "dictionary_to_dictionaryelements",
+ joinColumns = @JoinColumn(name = "dictionary_name", referencedColumnName = "name"),
+ inverseJoinColumns = {@JoinColumn(
+ name = "dictionary_element_short_name",
+ referencedColumnName = "short_name")})
+ private Set<DictionaryElement> dictionaryElements = new HashSet<>();
+
+ /**
+ * name getter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * secondLevelDictionary getter.
+ *
+ * @return the secondLevelDictionary
+ */
+ public int getSecondLevelDictionary() {
+ return secondLevelDictionary;
+ }
+
+ /**
+ * secondLevelDictionary setter.
+ *
+ * @param secondLevelDictionary the secondLevelDictionary to set
+ */
+ public void setSecondLevelDictionary(int secondLevelDictionary) {
+ this.secondLevelDictionary = secondLevelDictionary;
+ }
+
+ /**
+ * subDictionaryType getter.
+ *
+ * @return the subDictionaryType
+ */
+ public String getSubDictionaryType() {
+ return subDictionaryType;
+ }
+
+ /**
+ * subDictionaryType setter.
+ *
+ * @param subDictionaryType the subDictionaryType to set
+ */
+ public void setSubDictionaryType(String subDictionaryType) {
+ this.subDictionaryType = subDictionaryType;
+ }
+
+ /**
+ * dictionaryElements getter.
+ *
+ * @return the dictionaryElements List of dictionary element
+ */
+ public Set<DictionaryElement> getDictionaryElements() {
+ return dictionaryElements;
+ }
+
+ /**
+ * Method to add a new dictionaryElement to the list.
+ *
+ * @param dictionaryElement The dictionary element
+ */
+ public void addDictionaryElements(DictionaryElement dictionaryElement) {
+ dictionaryElements.add(dictionaryElement);
+ dictionaryElement.getUsedByDictionaries().add(this);
+ }
+
+ /**
+ * Method to set dictionaryElements.
+ *
+ * @param dictionaryElements The dictionary elements set
+ */
+ public void setDictionaryElements(Set<DictionaryElement> dictionaryElements) {
+ this.dictionaryElements = dictionaryElements;
+ }
+
+ /**
+ * Method to delete a dictionaryElement from the list.
+ *
+ * @param dictionaryElement The dictionary element
+ */
+ public void removeDictionaryElement(DictionaryElement dictionaryElement) {
+ dictionaryElements.remove(dictionaryElement);
+ dictionaryElement.getUsedByDictionaries().remove(this);
+ }
+
+ /**
+ * Default Constructor.
+ */
+ public Dictionary() {
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The Dictionary name
+ * @param secondLevelDictionary defines if dictionary is a secondary level
+ * @param subDictionaryType defines the type of secondary level dictionary
+ */
+ public Dictionary(String name, int secondLevelDictionary, String subDictionaryType) {
+ this.name = name;
+ this.secondLevelDictionary = secondLevelDictionary;
+ this.subDictionaryType = subDictionaryType;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Dictionary other = (Dictionary) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java
new file mode 100644
index 000000000..ecf4b876c
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElement.java
@@ -0,0 +1,254 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import com.google.gson.annotations.Expose;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import org.onap.policy.clamp.loop.common.AuditEntity;
+
+/**
+ * Represents a Dictionary Item.
+ */
+@Entity
+@Table(name = "dictionary_elements")
+public class DictionaryElement extends AuditEntity implements Serializable {
+
+ /**
+ * The serial version id.
+ */
+ private static final long serialVersionUID = -286522707701388644L;
+
+ @Id
+ @Expose
+ @Column(nullable = false, name = "short_name")
+ private String shortName;
+
+ @Expose
+ @Column(nullable = false, name = "name")
+ private String name;
+
+ @Expose
+ @Column(nullable = false, name = "description")
+ private String description;
+
+ @Expose
+ @Column(nullable = false, name = "type")
+ private String type;
+
+ @Expose
+ @Column(nullable = true, name = "subdictionary_name")
+ private String subDictionary;
+
+ @ManyToMany(mappedBy = "dictionaryElements", fetch = FetchType.EAGER)
+ private Set<Dictionary> usedByDictionaries = new HashSet<>();
+
+ /**
+ * name getter.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * name setter.
+ *
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * shortName getter.
+ *
+ * @return the shortName
+ */
+ public String getShortName() {
+ return shortName;
+ }
+
+ /**
+ * shortName setter.
+ *
+ * @param shortName the shortName to set
+ */
+ public void setShortName(String shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * description getter.
+ *
+ * @return the description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * description setter.
+ *
+ * @param description the description to set
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * type getter.
+ *
+ * @return the type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * type setter.
+ *
+ * @param type the type to set
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * subDictionary getter.
+ *
+ * @return the subDictionary
+ */
+ public String getSubDictionary() {
+ return subDictionary;
+ }
+
+ /**
+ * subDictionary setter.
+ *
+ * @param subDictionary the subDictionary to set
+ */
+ public void setSubDictionary(String subDictionary) {
+ this.subDictionary = subDictionary;
+ }
+
+ /**
+ * usedByDictionaries getter.
+ *
+ * @return the usedByDictionaries
+ */
+ public Set<Dictionary> getUsedByDictionaries() {
+ return usedByDictionaries;
+ }
+
+ /**
+ * usedByDictionaries setter.
+ *
+ * @param usedByDictionaries the usedByDictionaries to set
+ */
+ public void setUsedByDictionaries(Set<Dictionary> usedByDictionaries) {
+ this.usedByDictionaries = usedByDictionaries;
+ }
+
+ /**
+ * Default Constructor.
+ */
+ public DictionaryElement() {
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The Dictionary element name
+ * @param shortName The short name
+ * @param description The description
+ * @param type The type of element
+ * @param subDictionary The sub type
+ */
+ public DictionaryElement(String name, String shortName, String description, String type,
+ String subDictionary) {
+ this.name = name;
+ this.shortName = shortName;
+ this.description = description;
+ this.type = type;
+ this.subDictionary = subDictionary;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The Dictionary element name
+ * @param shortName The short name
+ * @param description The description
+ * @param type The type of element
+ * @param subDictionary The sub type
+ */
+ public DictionaryElement(String name, String shortName, String description, String type,
+ String subDictionary, Set<Dictionary> usedByDictionaries) {
+ this.name = name;
+ this.shortName = shortName;
+ this.description = description;
+ this.type = type;
+ this.subDictionary = subDictionary;
+ this.usedByDictionaries = usedByDictionaries;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((shortName == null) ? 0 : shortName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ DictionaryElement other = (DictionaryElement) obj;
+ if (shortName == null) {
+ if (other.shortName != null) {
+ return false;
+ }
+ } else if (!shortName.equals(other.shortName)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java
new file mode 100644
index 000000000..0bc50fe1a
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryElementsRepository.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface DictionaryElementsRepository extends JpaRepository<DictionaryElement, String> {
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java
new file mode 100644
index 000000000..a2f417d17
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryRepository.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface DictionaryRepository extends JpaRepository<Dictionary, String> {
+
+ @Query("SELECT dict.name FROM Dictionary as dict")
+ List<String> getAllDictionaryNames();
+
+ @Query("SELECT dict.name FROM Dictionary as dict where dict.secondLevelDictionary = 1")
+ List<String> getAllSecondaryLevelDictionaryNames();
+
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java
new file mode 100644
index 000000000..849d4baae
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/tosca/DictionaryService.java
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import com.google.common.collect.Sets;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.persistence.EntityNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DictionaryService {
+
+ private final DictionaryRepository dictionaryRepository;
+ private final DictionaryElementsRepository dictionaryElementsRepository;
+
+ /**
+ * Constructor.
+ */
+ @Autowired
+ public DictionaryService(DictionaryRepository dictionaryRepository,
+ DictionaryElementsRepository dictionaryElementsRepository) {
+ this.dictionaryRepository = dictionaryRepository;
+ this.dictionaryElementsRepository = dictionaryElementsRepository;
+
+ }
+
+ public Dictionary saveOrUpdateDictionary(Dictionary dictionary) {
+ return dictionaryRepository.saveAndFlush(dictionary);
+ }
+
+ /**
+ * Creates or Updates Dictionary Element.
+ *
+ * @param dictionaryName The Dictionary name
+ * @param dictionary The Dictionary object with dictionary elements
+ * @return updated Dictionary object with all dictionary elements
+ */
+ public Dictionary saveOrUpdateDictionaryElement(String dictionaryName, Dictionary dictionary) {
+ Dictionary dict = getDictionary(dictionaryName);
+
+ Set<DictionaryElement> newDictionaryElements = dictionary.getDictionaryElements();
+
+ if (newDictionaryElements != null && !newDictionaryElements.isEmpty()) {
+ Set<DictionaryElement> updatedDictionaryElements = newDictionaryElements.stream()
+ .map(dictionaryElement -> getAndUpdateDictionaryElement(dict, dictionaryElement))
+ .collect(Collectors.toSet());
+
+ dict.getDictionaryElements().forEach(dictElement -> {
+ if (!updatedDictionaryElements.contains(dictElement)) {
+ updatedDictionaryElements.add(dictElement);
+ }
+ });
+ dict.setDictionaryElements(updatedDictionaryElements);
+ }
+ return dictionaryRepository.saveAndFlush(dict);
+
+ }
+
+ private DictionaryElement getAndUpdateDictionaryElement(Dictionary dictionary,
+ DictionaryElement element) {
+ return dictionaryElementsRepository
+ .save(dictionaryElementsRepository.findById(element.getShortName())
+ .map(p -> updateDictionaryElement(p, element, dictionary))
+ .orElse(new DictionaryElement(element.getName(), element.getShortName(),
+ element.getDescription(), element.getType(), element.getSubDictionary(),
+ Sets.newHashSet(dictionary))));
+ }
+
+ public void deleteDictionary(Dictionary dictionary) {
+ dictionaryRepository.delete(dictionary);
+ }
+
+ public void deleteDictionary(String dictionaryName) {
+ dictionaryRepository.deleteById(dictionaryName);
+ }
+
+ public List<Dictionary> getAllDictionaries() {
+ return dictionaryRepository.findAll();
+ }
+
+ public List<String> getAllSecondaryLevelDictionaryNames() {
+ return dictionaryRepository.getAllSecondaryLevelDictionaryNames();
+ }
+
+ public Dictionary getDictionary(String dictionaryName) {
+ return dictionaryRepository.findById(dictionaryName).orElseThrow(
+ () -> new EntityNotFoundException("Couldn't find Dictionary named: " + dictionaryName));
+ }
+
+ /**
+ * Deletes a dictionary element from Dictionary by shortName.
+ *
+ * @param dictionaryName The dictionary name
+ * @param dictionaryElementShortName the dictionary Element Short name
+ */
+ public void deleteDictionaryElement(String dictionaryName, String dictionaryElementShortName) {
+ if (dictionaryRepository.existsById(dictionaryName)) {
+ DictionaryElement element =
+ dictionaryElementsRepository.findById(dictionaryElementShortName).orElse(null);
+ if (element != null) {
+ Dictionary dict = getDictionary(dictionaryName);
+ dict.removeDictionaryElement(element);
+ dictionaryRepository.saveAndFlush(dict);
+ }
+ }
+ }
+
+ private DictionaryElement updateDictionaryElement(DictionaryElement oldDictionaryElement,
+ DictionaryElement newDictionaryElement, Dictionary dictionary) {
+ oldDictionaryElement.setName(newDictionaryElement.getName());
+ oldDictionaryElement.setDescription(newDictionaryElement.getDescription());
+ oldDictionaryElement.setType(newDictionaryElement.getType());
+ oldDictionaryElement.setSubDictionary(newDictionaryElement.getSubDictionary());
+ oldDictionaryElement.getUsedByDictionaries().add(dictionary);
+ return oldDictionaryElement;
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java b/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java
new file mode 100644
index 000000000..b8e90e3d0
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/util/PassDecoder.java
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.IOException;
+import org.onap.aaf.cadi.Symm;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+/**
+ * PassDecoder for decrypting the truststore and keystore password.
+ */
+public class PassDecoder {
+
+ private PassDecoder() {
+ }
+
+ /**
+ * Used to log PassDecoder class.
+ */
+ private static final EELFLogger logger = EELFManager.getInstance().getLogger(PassDecoder.class);
+
+ /**
+ * Decode the password.
+ *
+ * @param encryptedPass The encrypted password
+ * @param keyFileName The key file name in String
+ */
+ public static String decode(String encryptedPass, String keyFileName) {
+ if (null == keyFileName) {
+ logger.debug("Key file is not defined, thus password will not be decrypted");
+ return encryptedPass;
+ }
+ if (null == encryptedPass) {
+ logger.error("Encrypted password is not defined");
+ return null;
+ }
+ try {
+ return Symm.obtain(ResourceFileUtils.getResourceAsStream(keyFileName)).depass(encryptedPass);
+ } catch (IOException e) {
+ logger.error("Exception occurred during the key decryption", e);
+ return null;
+ }
+ }
+}
diff --git a/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java b/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java
new file mode 100644
index 000000000..58367193f
--- /dev/null
+++ b/runtime/src/main/java/org/onap/policy/clamp/util/SemanticVersioning.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.util;
+
+/**
+ * This class is the base class for object that requires semantic versioning.
+ * ... This class supports also a.b.c.d... etc ... as a version.
+ */
+public class SemanticVersioning {
+ public static final int BEFORE = -1;
+ public static final int EQUAL = 0;
+ public static final int AFTER = 1;
+ public static final String DEFAULT_VERSION = "1.0.0";
+
+ /**
+ * The compare method that compare arg0 to arg1.
+ *
+ * @param arg0 A version in string for semantic versioning (a.b.c.d...)
+ * @param arg1 A version in string for semantic versioning (a.b.c.d...)
+ * @return objects (arg0, arg1) given as parameters. It returns the value: 0: if
+ * (arg0==arg1) -1: if (arg0 < arg1) 1: if (arg0 > arg1)
+ */
+ public static int compare(String arg0, String arg1) {
+
+ if (arg0 == null && arg1 == null) {
+ return EQUAL;
+ }
+ if (arg0 == null) {
+ return BEFORE;
+ }
+ if (arg1 == null) {
+ return AFTER;
+ }
+ String[] arg0Array = arg0.split("\\.");
+ String[] arg1Array = arg1.split("\\.");
+
+ int smalestStringLength = Math.min(arg0Array.length, arg1Array.length);
+
+ for (int currentVersionIndex =
+ 0; currentVersionIndex < smalestStringLength; ++currentVersionIndex) {
+ if (Integer.parseInt(arg0Array[currentVersionIndex]) < Integer
+ .parseInt(arg1Array[currentVersionIndex])) {
+ return BEFORE;
+ } else if (Integer.parseInt(arg0Array[currentVersionIndex]) > Integer
+ .parseInt(arg1Array[currentVersionIndex])) {
+ return AFTER;
+ }
+ // equals, so do not return anything, continue
+ }
+ if (arg0Array.length == arg1Array.length) {
+ return EQUAL;
+ } else {
+ return Integer.compare(arg0Array.length, arg1Array.length);
+ }
+ }
+
+ /**
+ * Method to increment a version from its current version.
+ *
+ * @param currentVersion The current Version
+ * @return the increment version string
+ */
+ public static String incrementMajorVersion(String currentVersion) {
+ if (currentVersion == null || currentVersion.isEmpty()) {
+ return DEFAULT_VERSION;
+ }
+ String[] versionArray = currentVersion.split("\\.");
+ return String.valueOf(Integer.parseInt(versionArray[0]) + 1) + ".0.0";
+ }
+}
diff --git a/runtime/src/main/resources/META-INF/resources/swagger.html b/runtime/src/main/resources/META-INF/resources/swagger.html
new file mode 100644
index 000000000..f7fbeb039
--- /dev/null
+++ b/runtime/src/main/resources/META-INF/resources/swagger.html
@@ -0,0 +1,4508 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.7.1">
+<title>Clamp Rest API</title>
+<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
+<style>
+/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
+/* Uncomment @import statement below to use as custom stylesheet */
+/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
+article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
+audio,canvas,video{display:inline-block}
+audio:not([controls]){display:none;height:0}
+script{display:none!important}
+html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
+a{background:transparent}
+a:focus{outline:thin dotted}
+a:active,a:hover{outline:0}
+h1{font-size:2em;margin:.67em 0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+dfn{font-style:italic}
+hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
+mark{background:#ff0;color:#000}
+code,kbd,pre,samp{font-family:monospace;font-size:1em}
+pre{white-space:pre-wrap}
+q{quotes:"\201C" "\201D" "\2018" "\2019"}
+small{font-size:80%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+img{border:0}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0}
+button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
+button,input{line-height:normal}
+button,select{text-transform:none}
+button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
+button[disabled],html input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
+html,body{font-size:100%}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
+a:hover{cursor:pointer}
+img,object,embed{max-width:100%;height:auto}
+object,embed{height:100%}
+img{-ms-interpolation-mode:bicubic}
+.left{float:left!important}
+.right{float:right!important}
+.text-left{text-align:left!important}
+.text-right{text-align:right!important}
+.text-center{text-align:center!important}
+.text-justify{text-align:justify!important}
+.hide{display:none}
+img,object,svg{display:inline-block;vertical-align:middle}
+textarea{height:auto;min-height:50px}
+select{width:100%}
+.center{margin-left:auto;margin-right:auto}
+.stretch{width:100%}
+.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
+a{color:#2156a5;text-decoration:underline;line-height:inherit}
+a:hover,a:focus{color:#1d4b8f}
+a img{border:none}
+p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
+p aside{font-size:.875em;line-height:1.35;font-style:italic}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
+h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
+h1{font-size:2.125em}
+h2{font-size:1.6875em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
+h4,h5{font-size:1.125em}
+h6{font-size:1em}
+hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
+em,i{font-style:italic;line-height:inherit}
+strong,b{font-weight:bold;line-height:inherit}
+small{font-size:60%;line-height:inherit}
+code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
+ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
+ul,ol{margin-left:1.5em}
+ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
+ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
+ul.square{list-style-type:square}
+ul.circle{list-style-type:circle}
+ul.disc{list-style-type:disc}
+ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
+dl dt{margin-bottom:.3125em;font-weight:bold}
+dl dd{margin-bottom:1.25em}
+abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
+abbr{text-transform:none}
+blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
+blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
+blockquote cite::before{content:"\2014 \0020"}
+blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
+blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
+@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
+h1{font-size:2.75em}
+h2{font-size:2.3125em}
+h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
+h4{font-size:1.4375em}}
+table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
+table thead,table tfoot{background:#f7f8f7}
+table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
+table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
+table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
+table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
+h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
+h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
+.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
+.clearfix::after,.float-group::after{clear:both}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
+pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
+.keyseq{color:rgba(51,51,51,.8)}
+kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
+.keyseq kbd:first-child{margin-left:0}
+.keyseq kbd:last-child{margin-right:0}
+.menuseq,.menuref{color:#000}
+.menuseq b:not(.caret),.menuref{font-weight:inherit}
+.menuseq{word-spacing:-.02em}
+.menuseq b.caret{font-size:1.25em;line-height:.8}
+.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
+b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
+b.button::before{content:"[";padding:0 3px 0 2px}
+b.button::after{content:"]";padding:0 2px 0 3px}
+p a>code:hover{color:rgba(0,0,0,.9)}
+#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
+#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
+#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
+#content{margin-top:1.25em}
+#content::before{content:none}
+#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
+#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
+#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
+#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
+#header .details span:first-child{margin-left:-.125em}
+#header .details span.email a{color:rgba(0,0,0,.85)}
+#header .details br{display:none}
+#header .details br+span::before{content:"\00a0\2013\00a0"}
+#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
+#header .details br+span#revremark::before{content:"\00a0|\00a0"}
+#header #revnumber{text-transform:capitalize}
+#header #revnumber::after{content:"\00a0"}
+#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
+#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
+#toc>ul{margin-left:.125em}
+#toc ul.sectlevel0>li>a{font-style:italic}
+#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
+#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
+#toc li{line-height:1.3334;margin-top:.3334em}
+#toc a{text-decoration:none}
+#toc a:active{text-decoration:underline}
+#toctitle{color:#7a2518;font-size:1.2em}
+@media screen and (min-width:768px){#toctitle{font-size:1.375em}
+body.toc2{padding-left:15em;padding-right:0}
+#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
+#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
+#toc.toc2>ul{font-size:.9em;margin-bottom:0}
+#toc.toc2 ul ul{margin-left:0;padding-left:1em}
+#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
+body.toc2.toc-right{padding-left:0;padding-right:15em}
+body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
+@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
+#toc.toc2{width:20em}
+#toc.toc2 #toctitle{font-size:1.375em}
+#toc.toc2>ul{font-size:.95em}
+#toc.toc2 ul ul{padding-left:1.25em}
+body.toc2.toc-right{padding-left:0;padding-right:20em}}
+#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+#content #toc>:first-child{margin-top:0}
+#content #toc>:last-child{margin-bottom:0}
+#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
+#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
+#content{margin-bottom:.625em}
+.sect1{padding-bottom:.625em}
+@media screen and (min-width:768px){#content{margin-bottom:1.25em}
+.sect1{padding-bottom:1.25em}}
+.sect1:last-child{padding-bottom:0}
+.sect1+.sect1{border-top:1px solid #efefed}
+#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
+#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
+#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
+#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
+#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
+.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
+.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
+table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
+.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
+table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
+.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
+.admonitionblock>table td.icon{text-align:center;width:80px}
+.admonitionblock>table td.icon img{max-width:none}
+.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
+.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
+.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
+.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
+.exampleblock>.content>:first-child{margin-top:0}
+.exampleblock>.content>:last-child{margin-bottom:0}
+.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
+.sidebarblock>:first-child{margin-top:0}
+.sidebarblock>:last-child{margin-bottom:0}
+.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
+.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
+.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
+.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
+.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
+.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
+@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
+@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
+.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
+.listingblock pre.highlightjs{padding:0}
+.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
+.listingblock pre.prettyprint{border-width:0}
+.listingblock>.content{position:relative}
+.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
+.listingblock:hover code[data-lang]::before{display:block}
+.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
+.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
+table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
+table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
+table.pyhltable td.code{padding-left:.75em;padding-right:0}
+pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
+pre.pygments .lineno{display:inline-block;margin-right:.25em}
+table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
+.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
+.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
+.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
+.quoteblock blockquote{margin:0;padding:0;border:0}
+.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
+.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
+.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
+.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
+.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
+.quoteblock .quoteblock blockquote::before{display:none}
+.verseblock{margin:0 1em 1.25em}
+.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
+.verseblock pre strong{font-weight:400}
+.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
+.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
+.quoteblock .attribution br,.verseblock .attribution br{display:none}
+.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
+.quoteblock.abstract{margin:0 1em 1.25em;display:block}
+.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
+.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{word-spacing:0;line-height:1.6}
+.quoteblock.abstract blockquote::before,.quoteblock.abstract p::before{display:none}
+table.tableblock{max-width:100%;border-collapse:separate}
+p.tableblock:last-child{margin-bottom:0}
+td.tableblock>.content{margin-bottom:-1.25em}
+table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
+table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
+table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
+table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
+table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
+table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
+table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
+table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
+table.frame-all{border-width:1px}
+table.frame-sides{border-width:0 1px}
+table.frame-topbot,table.frame-ends{border-width:1px 0}
+table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
+table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
+th.halign-left,td.halign-left{text-align:left}
+th.halign-right,td.halign-right{text-align:right}
+th.halign-center,td.halign-center{text-align:center}
+th.valign-top,td.valign-top{vertical-align:top}
+th.valign-bottom,td.valign-bottom{vertical-align:bottom}
+th.valign-middle,td.valign-middle{vertical-align:middle}
+table thead th,table tfoot th{font-weight:bold}
+tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
+tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
+p.tableblock>code:only-child{background:none;padding:0}
+p.tableblock{font-size:1em}
+td>div.verse{white-space:pre}
+ol{margin-left:1.75em}
+ul li ol{margin-left:1.5em}
+dl dd{margin-left:1.125em}
+dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
+ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
+ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
+ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
+ul.unstyled,ol.unstyled{margin-left:0}
+ul.checklist{margin-left:.625em}
+ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
+ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
+ul.inline>li{margin-left:1.25em}
+.unstyled dl dt{font-weight:400;font-style:normal}
+ol.arabic{list-style-type:decimal}
+ol.decimal{list-style-type:decimal-leading-zero}
+ol.loweralpha{list-style-type:lower-alpha}
+ol.upperalpha{list-style-type:upper-alpha}
+ol.lowerroman{list-style-type:lower-roman}
+ol.upperroman{list-style-type:upper-roman}
+ol.lowergreek{list-style-type:lower-greek}
+.hdlist>table,.colist>table{border:0;background:none}
+.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
+td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
+td.hdlist1{font-weight:bold;padding-bottom:1.25em}
+.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
+.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
+.colist td:not([class]):first-child img{max-width:none}
+.colist td:not([class]):last-child{padding:.25em 0}
+.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
+.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
+.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
+.imageblock>.title{margin-bottom:0}
+.imageblock.thumb,.imageblock.th{border-width:6px}
+.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
+.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
+.image.left{margin-right:.625em}
+.image.right{margin-left:.625em}
+a.image{text-decoration:none;display:inline-block}
+a.image object{pointer-events:none}
+sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
+sup.footnote a,sup.footnoteref a{text-decoration:none}
+sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
+#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
+#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
+#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
+#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
+#footnotes .footnote:last-of-type{margin-bottom:0}
+#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
+.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
+.gist .file-data>table td.line-data{width:99%}
+div.unbreakable{page-break-inside:avoid}
+.big{font-size:larger}
+.small{font-size:smaller}
+.underline{text-decoration:underline}
+.overline{text-decoration:overline}
+.line-through{text-decoration:line-through}
+.aqua{color:#00bfbf}
+.aqua-background{background-color:#00fafa}
+.black{color:#000}
+.black-background{background-color:#000}
+.blue{color:#0000bf}
+.blue-background{background-color:#0000fa}
+.fuchsia{color:#bf00bf}
+.fuchsia-background{background-color:#fa00fa}
+.gray{color:#606060}
+.gray-background{background-color:#7d7d7d}
+.green{color:#006000}
+.green-background{background-color:#007d00}
+.lime{color:#00bf00}
+.lime-background{background-color:#00fa00}
+.maroon{color:#600000}
+.maroon-background{background-color:#7d0000}
+.navy{color:#000060}
+.navy-background{background-color:#00007d}
+.olive{color:#606000}
+.olive-background{background-color:#7d7d00}
+.purple{color:#600060}
+.purple-background{background-color:#7d007d}
+.red{color:#bf0000}
+.red-background{background-color:#fa0000}
+.silver{color:#909090}
+.silver-background{background-color:#bcbcbc}
+.teal{color:#006060}
+.teal-background{background-color:#007d7d}
+.white{color:#bfbfbf}
+.white-background{background-color:#fafafa}
+.yellow{color:#bfbf00}
+.yellow-background{background-color:#fafa00}
+span.icon>.fa{cursor:default}
+a span.icon>.fa{cursor:inherit}
+.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
+.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
+.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
+.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
+.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
+.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
+.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
+.conum[data-value] *{color:#fff!important}
+.conum[data-value]+b{display:none}
+.conum[data-value]::after{content:attr(data-value)}
+pre .conum[data-value]{position:relative;top:-.125em}
+b.conum *{color:inherit!important}
+.conum:not([data-value]):empty{display:none}
+dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
+h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
+p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
+p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
+p{margin-bottom:1.25rem}
+.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
+.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
+.print-only{display:none!important}
+@page{margin:1.25cm .75cm}
+@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
+html{font-size:80%}
+a{color:inherit!important;text-decoration:underline!important}
+a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
+a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
+abbr[title]::after{content:" (" attr(title) ")"}
+pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
+thead{display:table-header-group}
+svg{max-width:100%}
+p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
+h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
+#toc,.sidebarblock,.exampleblock>.content{background:none!important}
+#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
+body.book #header{text-align:center}
+body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
+body.book #header .details{border:0!important;display:block;padding:0!important}
+body.book #header .details span:first-child{margin-left:0!important}
+body.book #header .details br{display:block}
+body.book #header .details br+span::before{content:none!important}
+body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
+body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
+.listingblock code[data-lang]::before{display:block}
+#footer{padding:0 .9375em}
+.hide-on-print{display:none!important}
+.print-only{display:block!important}
+.hide-for-print{display:none!important}
+.show-for-print{display:inherit!important}}
+@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
+.sect1{padding:0!important}
+.sect1+.sect1{border:0}
+#footer{background:none}
+#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
+@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
+</style>
+</head>
+<body class="book toc2 toc-left">
+<div id="header">
+<h1>Clamp Rest API</h1>
+<div id="toc" class="toc2">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_overview">1. Overview</a>
+<ul class="sectlevel2">
+<li><a href="#_version_information">1.1. Version information</a></li>
+<li><a href="#_uri_scheme">1.2. URI scheme</a></li>
+</ul>
+</li>
+<li><a href="#_paths">2. Paths</a>
+<ul class="sectlevel2">
+<li><a href="#_verb189">2.1. GET /v1/healthcheck</a>
+<ul class="sectlevel3">
+<li><a href="#_responses">2.1.1. Responses</a></li>
+<li><a href="#_produces">2.1.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb190">2.2. GET /v1/user/getUser</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_2">2.2.1. Responses</a></li>
+<li><a href="#_produces_2">2.2.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb188">2.3. GET /v2/clampInformation</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_3">2.3.1. Responses</a></li>
+<li><a href="#_produces_3">2.3.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb173">2.4. GET /v2/dictionary</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_4">2.4.1. Responses</a></li>
+<li><a href="#_produces_4">2.4.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb176">2.5. PUT /v2/dictionary</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters">2.5.1. Parameters</a></li>
+<li><a href="#_responses_5">2.5.2. Responses</a></li>
+<li><a href="#_consumes">2.5.3. Consumes</a></li>
+<li><a href="#_produces_5">2.5.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb174">2.6. GET /v2/dictionary/secondary/names</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_6">2.6.1. Responses</a></li>
+<li><a href="#_produces_6">2.6.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb175">2.7. GET /v2/dictionary/{dictionaryName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_2">2.7.1. Parameters</a></li>
+<li><a href="#_responses_7">2.7.2. Responses</a></li>
+<li><a href="#_produces_7">2.7.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb177">2.8. PUT /v2/dictionary/{name}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_3">2.8.1. Parameters</a></li>
+<li><a href="#_responses_8">2.8.2. Responses</a></li>
+<li><a href="#_consumes_2">2.8.3. Consumes</a></li>
+<li><a href="#_produces_8">2.8.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb178">2.9. DELETE /v2/dictionary/{name}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_4">2.9.1. Parameters</a></li>
+<li><a href="#_responses_9">2.9.2. Responses</a></li>
+<li><a href="#_produces_9">2.9.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb179">2.10. DELETE /v2/dictionary/{name}/elements/{shortName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_5">2.10.1. Parameters</a></li>
+<li><a href="#_responses_10">2.10.2. Responses</a></li>
+<li><a href="#_produces_10">2.10.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb167">2.11. PUT /v2/loop/addOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_6">2.11.1. Parameters</a></li>
+<li><a href="#_responses_11">2.11.2. Responses</a></li>
+<li><a href="#_produces_11">2.11.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb169">2.12. POST /v2/loop/create/{loopName}?templateName={templateName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_7">2.12.1. Parameters</a></li>
+<li><a href="#_responses_12">2.12.2. Responses</a></li>
+<li><a href="#_consumes_3">2.12.3. Consumes</a></li>
+<li><a href="#_produces_12">2.12.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb165">2.13. PUT /v2/loop/delete/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_8">2.13.1. Parameters</a></li>
+<li><a href="#_responses_13">2.13.2. Responses</a></li>
+</ul>
+</li>
+<li><a href="#_verb158">2.14. PUT /v2/loop/deploy/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_9">2.14.1. Parameters</a></li>
+<li><a href="#_responses_14">2.14.2. Responses</a></li>
+<li><a href="#_produces_13">2.14.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb153">2.15. GET /v2/loop/getAllNames</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_15">2.15.1. Responses</a></li>
+<li><a href="#_produces_14">2.15.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb166">2.16. GET /v2/loop/getstatus/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_10">2.16.1. Parameters</a></li>
+<li><a href="#_responses_16">2.16.2. Responses</a></li>
+<li><a href="#_produces_15">2.16.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb159">2.17. PUT /v2/loop/refreshMicroServicePolicyJsonSchema/{loopName}/{microServicePolicyName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_11">2.17.1. Parameters</a></li>
+<li><a href="#_responses_17">2.17.2. Responses</a></li>
+<li><a href="#_produces_16">2.17.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb160">2.18. PUT /v2/loop/refreshOperationalPolicyJsonSchema/{loopName}/{operationalPolicyName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_12">2.18.1. Parameters</a></li>
+<li><a href="#_responses_18">2.18.2. Responses</a></li>
+<li><a href="#_produces_17">2.18.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb168">2.19. PUT /v2/loop/removeOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}/{policyName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_13">2.19.1. Parameters</a></li>
+<li><a href="#_responses_19">2.19.2. Responses</a></li>
+<li><a href="#_produces_18">2.19.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb163">2.20. PUT /v2/loop/restart/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_14">2.20.1. Parameters</a></li>
+<li><a href="#_responses_20">2.20.2. Responses</a></li>
+<li><a href="#_produces_19">2.20.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb162">2.21. PUT /v2/loop/stop/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_15">2.21.1. Parameters</a></li>
+<li><a href="#_responses_21">2.21.2. Responses</a></li>
+<li><a href="#_produces_20">2.21.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb164">2.22. PUT /v2/loop/submit/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_16">2.22.1. Parameters</a></li>
+<li><a href="#_responses_22">2.22.2. Responses</a></li>
+<li><a href="#_produces_21">2.22.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb161">2.23. PUT /v2/loop/undeploy/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_17">2.23.1. Parameters</a></li>
+<li><a href="#_responses_23">2.23.2. Responses</a></li>
+<li><a href="#_produces_22">2.23.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb155">2.24. POST /v2/loop/updateGlobalProperties/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_18">2.24.1. Parameters</a></li>
+<li><a href="#_responses_24">2.24.2. Responses</a></li>
+<li><a href="#_consumes_4">2.24.3. Consumes</a></li>
+<li><a href="#_produces_23">2.24.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb157">2.25. POST /v2/loop/updateMicroservicePolicy/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_19">2.25.1. Parameters</a></li>
+<li><a href="#_responses_25">2.25.2. Responses</a></li>
+<li><a href="#_consumes_5">2.25.3. Consumes</a></li>
+<li><a href="#_produces_24">2.25.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb156">2.26. POST /v2/loop/updateOperationalPolicies/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_20">2.26.1. Parameters</a></li>
+<li><a href="#_responses_26">2.26.2. Responses</a></li>
+<li><a href="#_consumes_6">2.26.3. Consumes</a></li>
+<li><a href="#_produces_25">2.26.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb154">2.27. GET /v2/loop/{loopName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_21">2.27.1. Parameters</a></li>
+<li><a href="#_responses_27">2.27.2. Responses</a></li>
+<li><a href="#_produces_26">2.27.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb183">2.28. GET /v2/policies</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_28">2.28.1. Responses</a></li>
+<li><a href="#_produces_27">2.28.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb186">2.29. PUT /v2/policies/pdpDeployment</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_22">2.29.1. Parameters</a></li>
+<li><a href="#_responses_29">2.29.2. Responses</a></li>
+<li><a href="#_consumes_7">2.29.3. Consumes</a></li>
+</ul>
+</li>
+<li><a href="#_verb187">2.30. POST /v2/policies/policytype</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_23">2.30.1. Parameters</a></li>
+<li><a href="#_responses_30">2.30.2. Responses</a></li>
+<li><a href="#_consumes_8">2.30.3. Consumes</a></li>
+</ul>
+</li>
+<li><a href="#_verb184">2.31. POST /v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_24">2.31.1. Parameters</a></li>
+<li><a href="#_responses_31">2.31.2. Responses</a></li>
+<li><a href="#_consumes_9">2.31.3. Consumes</a></li>
+<li><a href="#_produces_28">2.31.4. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb185">2.32. DELETE /v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_25">2.32.1. Parameters</a></li>
+<li><a href="#_responses_32">2.32.2. Responses</a></li>
+</ul>
+</li>
+<li><a href="#_verb180">2.33. GET /v2/policyToscaModels</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_33">2.33.1. Responses</a></li>
+<li><a href="#_produces_29">2.33.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb182">2.34. GET /v2/policyToscaModels/yaml/{policyModelType}/{policyModelVersion}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_26">2.34.1. Parameters</a></li>
+<li><a href="#_responses_34">2.34.2. Responses</a></li>
+<li><a href="#_produces_30">2.34.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb181">2.35. GET /v2/policyToscaModels/{policyModelType}/{policyModelVersion}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_27">2.35.1. Parameters</a></li>
+<li><a href="#_responses_35">2.35.2. Responses</a></li>
+<li><a href="#_produces_31">2.35.3. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb170">2.36. GET /v2/templates</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_36">2.36.1. Responses</a></li>
+<li><a href="#_produces_32">2.36.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb172">2.37. GET /v2/templates/names</a>
+<ul class="sectlevel3">
+<li><a href="#_responses_37">2.37.1. Responses</a></li>
+<li><a href="#_produces_33">2.37.2. Produces</a></li>
+</ul>
+</li>
+<li><a href="#_verb171">2.38. GET /v2/templates/{templateName}</a>
+<ul class="sectlevel3">
+<li><a href="#_parameters_28">2.38.1. Parameters</a></li>
+<li><a href="#_responses_38">2.38.2. Responses</a></li>
+<li><a href="#_produces_34">2.38.3. Produces</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="#_definitions">3. Definitions</a>
+<ul class="sectlevel2">
+<li><a href="#_clampinformation">3.1. ClampInformation</a></li>
+<li><a href="#_cldshealthcheck">3.2. CldsHealthCheck</a></li>
+<li><a href="#_dictionary">3.3. Dictionary</a></li>
+<li><a href="#_dictionaryelement">3.4. DictionaryElement</a></li>
+<li><a href="#_externalcomponent">3.5. ExternalComponent</a></li>
+<li><a href="#_externalcomponentstate">3.6. ExternalComponentState</a></li>
+<li><a href="#_jsonarray">3.7. JsonArray</a></li>
+<li><a href="#_jsonelement">3.8. JsonElement</a></li>
+<li><a href="#_jsonnull">3.9. JsonNull</a></li>
+<li><a href="#_jsonobject">3.10. JsonObject</a></li>
+<li><a href="#_jsonprimitive">3.11. JsonPrimitive</a></li>
+<li><a href="#_loop">3.12. Loop</a></li>
+<li><a href="#_loopelementmodel">3.13. LoopElementModel</a></li>
+<li><a href="#_looplog">3.14. LoopLog</a></li>
+<li><a href="#_looptemplate">3.15. LoopTemplate</a></li>
+<li><a href="#_looptemplateloopelementmodel">3.16. LoopTemplateLoopElementModel</a></li>
+<li><a href="#_microservicepolicy">3.17. MicroServicePolicy</a></li>
+<li><a href="#_number">3.18. Number</a></li>
+<li><a href="#_operationalpolicy">3.19. OperationalPolicy</a></li>
+<li><a href="#_policymodel">3.20. PolicyModel</a></li>
+<li><a href="#_service">3.21. Service</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_overview"><a class="anchor" href="#_overview"></a><a class="link" href="#_overview">1. Overview</a></h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_version_information"><a class="anchor" href="#_version_information"></a><a class="link" href="#_version_information">1.1. Version information</a></h3>
+<div class="paragraph">
+<p><em>Version</em> : 6.1.2-SNAPSHOT</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_uri_scheme"><a class="anchor" href="#_uri_scheme"></a><a class="link" href="#_uri_scheme">1.2. URI scheme</a></h3>
+<div class="paragraph">
+<p><em>Host</em> : localhost:37747<br>
+<em>BasePath</em> : /restservices/clds/<br>
+<em>Schemes</em> : HTTP</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_paths"><a class="anchor" href="#_paths"></a><a class="link" href="#_paths">2. Paths</a></h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_verb189"><a class="anchor" href="#_verb189"></a><a class="link" href="#_verb189">2.1. GET /v1/healthcheck</a></h3>
+<div class="sect3">
+<h4 id="_responses"><a class="anchor" href="#_responses"></a><a class="link" href="#_responses">2.1.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_cldshealthcheck">CldsHealthCheck</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces"><a class="anchor" href="#_produces"></a><a class="link" href="#_produces">2.1.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb190"><a class="anchor" href="#_verb190"></a><a class="link" href="#_verb190">2.2. GET /v1/user/getUser</a></h3>
+<div class="sect3">
+<h4 id="_responses_2"><a class="anchor" href="#_responses_2"></a><a class="link" href="#_responses_2">2.2.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_2"><a class="anchor" href="#_produces_2"></a><a class="link" href="#_produces_2">2.2.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>text/plain</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb188"><a class="anchor" href="#_verb188"></a><a class="link" href="#_verb188">2.3. GET /v2/clampInformation</a></h3>
+<div class="sect3">
+<h4 id="_responses_3"><a class="anchor" href="#_responses_3"></a><a class="link" href="#_responses_3">2.3.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_clampinformation">ClampInformation</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_3"><a class="anchor" href="#_produces_3"></a><a class="link" href="#_produces_3">2.3.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb173"><a class="anchor" href="#_verb173"></a><a class="link" href="#_verb173">2.4. GET /v2/dictionary</a></h3>
+<div class="sect3">
+<h4 id="_responses_4"><a class="anchor" href="#_responses_4"></a><a class="link" href="#_responses_4">2.4.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_4"><a class="anchor" href="#_produces_4"></a><a class="link" href="#_produces_4">2.4.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb176"><a class="anchor" href="#_verb176"></a><a class="link" href="#_verb176">2.5. PUT /v2/dictionary</a></h3>
+<div class="sect3">
+<h4 id="_parameters"><a class="anchor" href="#_parameters"></a><a class="link" href="#_parameters">2.5.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_5"><a class="anchor" href="#_responses_5"></a><a class="link" href="#_responses_5">2.5.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes"><a class="anchor" href="#_consumes"></a><a class="link" href="#_consumes">2.5.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_5"><a class="anchor" href="#_produces_5"></a><a class="link" href="#_produces_5">2.5.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb174"><a class="anchor" href="#_verb174"></a><a class="link" href="#_verb174">2.6. GET /v2/dictionary/secondary/names</a></h3>
+<div class="sect3">
+<h4 id="_responses_6"><a class="anchor" href="#_responses_6"></a><a class="link" href="#_responses_6">2.6.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; string &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_6"><a class="anchor" href="#_produces_6"></a><a class="link" href="#_produces_6">2.6.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb175"><a class="anchor" href="#_verb175"></a><a class="link" href="#_verb175">2.7. GET /v2/dictionary/{dictionaryName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_2"><a class="anchor" href="#_parameters_2"></a><a class="link" href="#_parameters_2">2.7.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dictionaryName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_7"><a class="anchor" href="#_responses_7"></a><a class="link" href="#_responses_7">2.7.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_7"><a class="anchor" href="#_produces_7"></a><a class="link" href="#_produces_7">2.7.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb177"><a class="anchor" href="#_verb177"></a><a class="link" href="#_verb177">2.8. PUT /v2/dictionary/{name}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_3"><a class="anchor" href="#_parameters_3"></a><a class="link" href="#_parameters_3">2.8.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_8"><a class="anchor" href="#_responses_8"></a><a class="link" href="#_responses_8">2.8.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_dictionary">Dictionary</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_2"><a class="anchor" href="#_consumes_2"></a><a class="link" href="#_consumes_2">2.8.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_8"><a class="anchor" href="#_produces_8"></a><a class="link" href="#_produces_8">2.8.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb178"><a class="anchor" href="#_verb178"></a><a class="link" href="#_verb178">2.9. DELETE /v2/dictionary/{name}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_4"><a class="anchor" href="#_parameters_4"></a><a class="link" href="#_parameters_4">2.9.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_9"><a class="anchor" href="#_responses_9"></a><a class="link" href="#_responses_9">2.9.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_9"><a class="anchor" href="#_produces_9"></a><a class="link" href="#_produces_9">2.9.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb179"><a class="anchor" href="#_verb179"></a><a class="link" href="#_verb179">2.10. DELETE /v2/dictionary/{name}/elements/{shortName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_5"><a class="anchor" href="#_parameters_5"></a><a class="link" href="#_parameters_5">2.10.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>shortName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_10"><a class="anchor" href="#_responses_10"></a><a class="link" href="#_responses_10">2.10.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_10"><a class="anchor" href="#_produces_10"></a><a class="link" href="#_produces_10">2.10.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb167"><a class="anchor" href="#_verb167"></a><a class="link" href="#_verb167">2.11. PUT /v2/loop/addOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_6"><a class="anchor" href="#_parameters_6"></a><a class="link" href="#_parameters_6">2.11.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_11"><a class="anchor" href="#_responses_11"></a><a class="link" href="#_responses_11">2.11.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_11"><a class="anchor" href="#_produces_11"></a><a class="link" href="#_produces_11">2.11.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb169"><a class="anchor" href="#_verb169"></a><a class="link" href="#_verb169">2.12. POST /v2/loop/create/{loopName}?templateName={templateName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_7"><a class="anchor" href="#_parameters_7"></a><a class="link" href="#_parameters_7">2.12.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>templateName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_12"><a class="anchor" href="#_responses_12"></a><a class="link" href="#_responses_12">2.12.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_3"><a class="anchor" href="#_consumes_3"></a><a class="link" href="#_consumes_3">2.12.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_12"><a class="anchor" href="#_produces_12"></a><a class="link" href="#_produces_12">2.12.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb165"><a class="anchor" href="#_verb165"></a><a class="link" href="#_verb165">2.13. PUT /v2/loop/delete/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_8"><a class="anchor" href="#_parameters_8"></a><a class="link" href="#_parameters_8">2.13.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_13"><a class="anchor" href="#_responses_13"></a><a class="link" href="#_responses_13">2.13.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb158"><a class="anchor" href="#_verb158"></a><a class="link" href="#_verb158">2.14. PUT /v2/loop/deploy/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_9"><a class="anchor" href="#_parameters_9"></a><a class="link" href="#_parameters_9">2.14.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_14"><a class="anchor" href="#_responses_14"></a><a class="link" href="#_responses_14">2.14.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_13"><a class="anchor" href="#_produces_13"></a><a class="link" href="#_produces_13">2.14.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb153"><a class="anchor" href="#_verb153"></a><a class="link" href="#_verb153">2.15. GET /v2/loop/getAllNames</a></h3>
+<div class="sect3">
+<h4 id="_responses_15"><a class="anchor" href="#_responses_15"></a><a class="link" href="#_responses_15">2.15.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; string &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_14"><a class="anchor" href="#_produces_14"></a><a class="link" href="#_produces_14">2.15.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb166"><a class="anchor" href="#_verb166"></a><a class="link" href="#_verb166">2.16. GET /v2/loop/getstatus/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_10"><a class="anchor" href="#_parameters_10"></a><a class="link" href="#_parameters_10">2.16.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_16"><a class="anchor" href="#_responses_16"></a><a class="link" href="#_responses_16">2.16.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_15"><a class="anchor" href="#_produces_15"></a><a class="link" href="#_produces_15">2.16.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb159"><a class="anchor" href="#_verb159"></a><a class="link" href="#_verb159">2.17. PUT /v2/loop/refreshMicroServicePolicyJsonSchema/{loopName}/{microServicePolicyName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_11"><a class="anchor" href="#_parameters_11"></a><a class="link" href="#_parameters_11">2.17.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>microServicePolicyName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_17"><a class="anchor" href="#_responses_17"></a><a class="link" href="#_responses_17">2.17.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_16"><a class="anchor" href="#_produces_16"></a><a class="link" href="#_produces_16">2.17.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb160"><a class="anchor" href="#_verb160"></a><a class="link" href="#_verb160">2.18. PUT /v2/loop/refreshOperationalPolicyJsonSchema/{loopName}/{operationalPolicyName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_12"><a class="anchor" href="#_parameters_12"></a><a class="link" href="#_parameters_12">2.18.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>operationalPolicyName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_18"><a class="anchor" href="#_responses_18"></a><a class="link" href="#_responses_18">2.18.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_17"><a class="anchor" href="#_produces_17"></a><a class="link" href="#_produces_17">2.18.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb168"><a class="anchor" href="#_verb168"></a><a class="link" href="#_verb168">2.19. PUT /v2/loop/removeOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}/{policyName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_13"><a class="anchor" href="#_parameters_13"></a><a class="link" href="#_parameters_13">2.19.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_19"><a class="anchor" href="#_responses_19"></a><a class="link" href="#_responses_19">2.19.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_18"><a class="anchor" href="#_produces_18"></a><a class="link" href="#_produces_18">2.19.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb163"><a class="anchor" href="#_verb163"></a><a class="link" href="#_verb163">2.20. PUT /v2/loop/restart/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_14"><a class="anchor" href="#_parameters_14"></a><a class="link" href="#_parameters_14">2.20.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_20"><a class="anchor" href="#_responses_20"></a><a class="link" href="#_responses_20">2.20.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_19"><a class="anchor" href="#_produces_19"></a><a class="link" href="#_produces_19">2.20.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb162"><a class="anchor" href="#_verb162"></a><a class="link" href="#_verb162">2.21. PUT /v2/loop/stop/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_15"><a class="anchor" href="#_parameters_15"></a><a class="link" href="#_parameters_15">2.21.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_21"><a class="anchor" href="#_responses_21"></a><a class="link" href="#_responses_21">2.21.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_20"><a class="anchor" href="#_produces_20"></a><a class="link" href="#_produces_20">2.21.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb164"><a class="anchor" href="#_verb164"></a><a class="link" href="#_verb164">2.22. PUT /v2/loop/submit/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_16"><a class="anchor" href="#_parameters_16"></a><a class="link" href="#_parameters_16">2.22.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_22"><a class="anchor" href="#_responses_22"></a><a class="link" href="#_responses_22">2.22.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_21"><a class="anchor" href="#_produces_21"></a><a class="link" href="#_produces_21">2.22.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb161"><a class="anchor" href="#_verb161"></a><a class="link" href="#_verb161">2.23. PUT /v2/loop/undeploy/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_17"><a class="anchor" href="#_parameters_17"></a><a class="link" href="#_parameters_17">2.23.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_23"><a class="anchor" href="#_responses_23"></a><a class="link" href="#_responses_23">2.23.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_22"><a class="anchor" href="#_produces_22"></a><a class="link" href="#_produces_22">2.23.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb155"><a class="anchor" href="#_verb155"></a><a class="link" href="#_verb155">2.24. POST /v2/loop/updateGlobalProperties/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_18"><a class="anchor" href="#_parameters_18"></a><a class="link" href="#_parameters_18">2.24.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_24"><a class="anchor" href="#_responses_24"></a><a class="link" href="#_responses_24">2.24.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_4"><a class="anchor" href="#_consumes_4"></a><a class="link" href="#_consumes_4">2.24.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_23"><a class="anchor" href="#_produces_23"></a><a class="link" href="#_produces_23">2.24.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb157"><a class="anchor" href="#_verb157"></a><a class="link" href="#_verb157">2.25. POST /v2/loop/updateMicroservicePolicy/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_19"><a class="anchor" href="#_parameters_19"></a><a class="link" href="#_parameters_19">2.25.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_microservicepolicy">MicroServicePolicy</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_25"><a class="anchor" href="#_responses_25"></a><a class="link" href="#_responses_25">2.25.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_microservicepolicy">MicroServicePolicy</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_5"><a class="anchor" href="#_consumes_5"></a><a class="link" href="#_consumes_5">2.25.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_24"><a class="anchor" href="#_produces_24"></a><a class="link" href="#_produces_24">2.25.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb156"><a class="anchor" href="#_verb156"></a><a class="link" href="#_verb156">2.26. POST /v2/loop/updateOperationalPolicies/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_20"><a class="anchor" href="#_parameters_20"></a><a class="link" href="#_parameters_20">2.26.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_26"><a class="anchor" href="#_responses_26"></a><a class="link" href="#_responses_26">2.26.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_6"><a class="anchor" href="#_consumes_6"></a><a class="link" href="#_consumes_6">2.26.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_25"><a class="anchor" href="#_produces_25"></a><a class="link" href="#_produces_25">2.26.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb154"><a class="anchor" href="#_verb154"></a><a class="link" href="#_verb154">2.27. GET /v2/loop/{loopName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_21"><a class="anchor" href="#_parameters_21"></a><a class="link" href="#_parameters_21">2.27.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_27"><a class="anchor" href="#_responses_27"></a><a class="link" href="#_responses_27">2.27.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_26"><a class="anchor" href="#_produces_26"></a><a class="link" href="#_produces_26">2.27.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb183"><a class="anchor" href="#_verb183"></a><a class="link" href="#_verb183">2.28. GET /v2/policies</a></h3>
+<div class="sect3">
+<h4 id="_responses_28"><a class="anchor" href="#_responses_28"></a><a class="link" href="#_responses_28">2.28.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_27"><a class="anchor" href="#_produces_27"></a><a class="link" href="#_produces_27">2.28.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb186"><a class="anchor" href="#_verb186"></a><a class="link" href="#_verb186">2.29. PUT /v2/policies/pdpDeployment</a></h3>
+<div class="sect3">
+<h4 id="_parameters_22"><a class="anchor" href="#_parameters_22"></a><a class="link" href="#_parameters_22">2.29.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonelement">JsonElement</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_29"><a class="anchor" href="#_responses_29"></a><a class="link" href="#_responses_29">2.29.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_7"><a class="anchor" href="#_consumes_7"></a><a class="link" href="#_consumes_7">2.29.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb187"><a class="anchor" href="#_verb187"></a><a class="link" href="#_verb187">2.30. POST /v2/policies/policytype</a></h3>
+<div class="sect3">
+<h4 id="_parameters_23"><a class="anchor" href="#_parameters_23"></a><a class="link" href="#_parameters_23">2.30.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_30"><a class="anchor" href="#_responses_30"></a><a class="link" href="#_responses_30">2.30.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_8"><a class="anchor" href="#_consumes_8"></a><a class="link" href="#_consumes_8">2.30.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>plain/text</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb184"><a class="anchor" href="#_verb184"></a><a class="link" href="#_verb184">2.31. POST /v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_24"><a class="anchor" href="#_parameters_24"></a><a class="link" href="#_parameters_24">2.31.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Body</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>body</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonelement">JsonElement</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_31"><a class="anchor" href="#_responses_31"></a><a class="link" href="#_responses_31">2.31.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_consumes_9"><a class="anchor" href="#_consumes_9"></a><a class="link" href="#_consumes_9">2.31.3. Consumes</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_produces_28"><a class="anchor" href="#_produces_28"></a><a class="link" href="#_produces_28">2.31.4. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb185"><a class="anchor" href="#_verb185"></a><a class="link" href="#_verb185">2.32. DELETE /v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_25"><a class="anchor" href="#_parameters_25"></a><a class="link" href="#_parameters_25">2.32.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_32"><a class="anchor" href="#_responses_32"></a><a class="link" href="#_responses_32">2.32.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 33.3333%;">
+<col style="width: 66.6667%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">No Content</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb180"><a class="anchor" href="#_verb180"></a><a class="link" href="#_verb180">2.33. GET /v2/policyToscaModels</a></h3>
+<div class="sect3">
+<h4 id="_responses_33"><a class="anchor" href="#_responses_33"></a><a class="link" href="#_responses_33">2.33.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_policymodel">PolicyModel</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_29"><a class="anchor" href="#_produces_29"></a><a class="link" href="#_produces_29">2.33.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb182"><a class="anchor" href="#_verb182"></a><a class="link" href="#_verb182">2.34. GET /v2/policyToscaModels/yaml/{policyModelType}/{policyModelVersion}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_26"><a class="anchor" href="#_parameters_26"></a><a class="link" href="#_parameters_26">2.34.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_34"><a class="anchor" href="#_responses_34"></a><a class="link" href="#_responses_34">2.34.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_30"><a class="anchor" href="#_produces_30"></a><a class="link" href="#_produces_30">2.34.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb181"><a class="anchor" href="#_verb181"></a><a class="link" href="#_verb181">2.35. GET /v2/policyToscaModels/{policyModelType}/{policyModelVersion}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_27"><a class="anchor" href="#_parameters_27"></a><a class="link" href="#_parameters_27">2.35.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelType</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelVersion</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_35"><a class="anchor" href="#_responses_35"></a><a class="link" href="#_responses_35">2.35.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_31"><a class="anchor" href="#_produces_31"></a><a class="link" href="#_produces_31">2.35.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb170"><a class="anchor" href="#_verb170"></a><a class="link" href="#_verb170">2.36. GET /v2/templates</a></h3>
+<div class="sect3">
+<h4 id="_responses_36"><a class="anchor" href="#_responses_36"></a><a class="link" href="#_responses_36">2.36.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_looptemplate">LoopTemplate</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_32"><a class="anchor" href="#_produces_32"></a><a class="link" href="#_produces_32">2.36.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb172"><a class="anchor" href="#_verb172"></a><a class="link" href="#_verb172">2.37. GET /v2/templates/names</a></h3>
+<div class="sect3">
+<h4 id="_responses_37"><a class="anchor" href="#_responses_37"></a><a class="link" href="#_responses_37">2.37.1. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; string &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_33"><a class="anchor" href="#_produces_33"></a><a class="link" href="#_produces_33">2.37.2. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_verb171"><a class="anchor" href="#_verb171"></a><a class="link" href="#_verb171">2.38. GET /v2/templates/{templateName}</a></h3>
+<div class="sect3">
+<h4 id="_parameters_28"><a class="anchor" href="#_parameters_28"></a><a class="link" href="#_parameters_28">2.38.1. Parameters</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 22.2222%;">
+<col style="width: 33.3333%;">
+<col style="width: 44.4445%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Type</th>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>Path</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>templateName</strong><br>
+<em>required</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_responses_38"><a class="anchor" href="#_responses_38"></a><a class="link" href="#_responses_38">2.38.2. Responses</a></h4>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 10%;">
+<col style="width: 70%;">
+<col style="width: 20%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">HTTP Code</th>
+<th class="tableblock halign-left valign-middle">Description</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>200</strong></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">Output type</p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_looptemplate">LoopTemplate</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect3">
+<h4 id="_produces_34"><a class="anchor" href="#_produces_34"></a><a class="link" href="#_produces_34">2.38.3. Produces</a></h4>
+<div class="ulist">
+<ul>
+<li>
+<p><code>application/json</code></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_definitions"><a class="anchor" href="#_definitions"></a><a class="link" href="#_definitions">3. Definitions</a></h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_clampinformation"><a class="anchor" href="#_clampinformation"></a><a class="link" href="#_clampinformation">3.1. ClampInformation</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>allPermissions</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; string &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>cldsVersion</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>userName</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_cldshealthcheck"><a class="anchor" href="#_cldshealthcheck"></a><a class="link" href="#_cldshealthcheck">3.2. CldsHealthCheck</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>description</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>healthCheckComponent</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>healthCheckStatus</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_dictionary"><a class="anchor" href="#_dictionary"></a><a class="link" href="#_dictionary">3.3. Dictionary</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dictionaryElements</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_dictionaryelement">DictionaryElement</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>secondLevelDictionary</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>subDictionaryType</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_dictionaryelement"><a class="anchor" href="#_dictionaryelement"></a><a class="link" href="#_dictionaryelement">3.4. DictionaryElement</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>description</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>shortName</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>subDictionary</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>type</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>usedByDictionaries</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_dictionary">Dictionary</a> &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_externalcomponent"><a class="anchor" href="#_externalcomponent"></a><a class="link" href="#_externalcomponent">3.5. ExternalComponent</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>componentName</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>state</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_externalcomponentstate">ExternalComponentState</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_externalcomponentstate"><a class="anchor" href="#_externalcomponentstate"></a><a class="link" href="#_externalcomponentstate">3.6. ExternalComponentState</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>description</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>level</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>stateName</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_jsonarray"><a class="anchor" href="#_jsonarray"></a><a class="link" href="#_jsonarray">3.7. JsonArray</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigDecimal</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigInteger</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBoolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asByte</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string (byte)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asCharacter</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asDouble</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (double)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asFloat</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (float)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asInt</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonnull">JsonNull</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonprimitive">JsonPrimitive</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asLong</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asNumber</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_number">Number</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asShort</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asString</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_jsonelement"><a class="anchor" href="#_jsonelement"></a><a class="link" href="#_jsonelement">3.8. JsonElement</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigDecimal</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigInteger</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBoolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asByte</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string (byte)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asCharacter</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asDouble</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (double)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asFloat</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (float)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asInt</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonnull">JsonNull</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonprimitive">JsonPrimitive</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asLong</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asNumber</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_number">Number</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asShort</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asString</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_jsonnull"><a class="anchor" href="#_jsonnull"></a><a class="link" href="#_jsonnull">3.9. JsonNull</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigDecimal</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigInteger</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBoolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asByte</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string (byte)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asCharacter</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asDouble</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (double)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asFloat</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (float)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asInt</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonnull">JsonNull</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonprimitive">JsonPrimitive</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asLong</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asNumber</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_number">Number</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asShort</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asString</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_jsonobject"><a class="anchor" href="#_jsonobject"></a><a class="link" href="#_jsonobject">3.10. JsonObject</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigDecimal</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigInteger</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBoolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asByte</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string (byte)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asCharacter</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asDouble</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (double)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asFloat</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (float)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asInt</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonnull">JsonNull</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonprimitive">JsonPrimitive</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asLong</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asNumber</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_number">Number</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asShort</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asString</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_jsonprimitive"><a class="anchor" href="#_jsonprimitive"></a><a class="link" href="#_jsonprimitive">3.11. JsonPrimitive</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigDecimal</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBigInteger</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asBoolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asByte</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string (byte)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asCharacter</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asDouble</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (double)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asFloat</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">number (float)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asInt</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonarray">JsonArray</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonnull">JsonNull</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asJsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonprimitive">JsonPrimitive</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asLong</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asNumber</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_number">Number</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asShort</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>asString</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>boolean</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonArray</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonNull</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonObject</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonPrimitive</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>number</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>string</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_loop"><a class="anchor" href="#_loop"></a><a class="link" href="#_loop">3.12. Loop</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>components</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; string, <a href="#_externalcomponent">ExternalComponent</a> &gt; map</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeDeploymentId</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeDeploymentStatusUrl</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>globalPropertiesJson</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>lastComputedState</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">enum (DESIGN, SUBMITTED, DEPLOYED, RUNNING, STOPPED, IN_ERROR, WAITING)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopLogs</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_looplog">LoopLog</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopTemplate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_looptemplate">LoopTemplate</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>microServicePolicies</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_microservicepolicy">MicroServicePolicy</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>modelService</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_service">Service</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>operationalPolicies</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_operationalpolicy">OperationalPolicy</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_loopelementmodel"><a class="anchor" href="#_loopelementmodel"></a><a class="link" href="#_loopelementmodel">3.13. LoopElementModel</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>blueprint</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeBlueprintId</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopElementType</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModels</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_policymodel">PolicyModel</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>shortName</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>usedByLoopTemplates</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_looptemplateloopelementmodel">LoopTemplateLoopElementModel</a> &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_looplog"><a class="anchor" href="#_looplog"></a><a class="link" href="#_looplog">3.14. LoopLog</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>id</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>logComponent</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>logInstant</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>logType</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">enum (INFO, WARNING, ERROR)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loop</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>message</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_looptemplate"><a class="anchor" href="#_looptemplate"></a><a class="link" href="#_looptemplate">3.15. LoopTemplate</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>allowedLoopType</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">enum (OPEN, CLOSED, HYBRID)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>blueprint</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeBlueprintId</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopElementModelsUsed</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_looptemplateloopelementmodel">LoopTemplateLoopElementModel</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>maximumInstancesAllowed</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>modelService</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_service">Service</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>uniqueBlueprint</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_looptemplateloopelementmodel"><a class="anchor" href="#_looptemplateloopelementmodel"></a><a class="link" href="#_looptemplateloopelementmodel">3.16. LoopTemplateLoopElementModel</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>flowOrder</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int32)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopElementModel</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loopelementmodel">LoopElementModel</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopTemplate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_looptemplate">LoopTemplate</a></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_microservicepolicy"><a class="anchor" href="#_microservicepolicy"></a><a class="link" href="#_microservicepolicy">3.17. MicroServicePolicy</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>configurationsJson</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>context</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeBlueprintId</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeDeploymentId</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>dcaeDeploymentStatusUrl</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>deviceTypeScope</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonRepresentation</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopElementModel</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loopelementmodel">LoopElementModel</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>pdpGroup</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>pdpSubgroup</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModel</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_policymodel">PolicyModel</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>shared</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>usedByLoops</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_loop">Loop</a> &gt; array</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_number"><a class="anchor" href="#_number"></a><a class="link" href="#_number">3.18. Number</a></h3>
+<div class="paragraph">
+<p><em>Type</em> : object</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_operationalpolicy"><a class="anchor" href="#_operationalpolicy"></a><a class="link" href="#_operationalpolicy">3.19. OperationalPolicy</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>configurationsJson</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>jsonRepresentation</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loop</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loop">Loop</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>loopElementModel</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_loopelementmodel">LoopElementModel</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>pdpGroup</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>pdpSubgroup</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModel</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_policymodel">PolicyModel</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_policymodel"><a class="anchor" href="#_policymodel"></a><a class="link" href="#_policymodel">3.20. PolicyModel</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>createdDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyAcronym</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelTosca</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyModelType</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>policyPdpGroup</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedBy</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>updatedDate</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">integer (int64)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>usedByElementModels</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">&lt; <a href="#_loopelementmodel">LoopElementModel</a> &gt; array</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>version</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_service"><a class="anchor" href="#_service"></a><a class="link" href="#_service">3.21. Service</a></h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 42.8571%;">
+<col style="width: 57.1429%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-middle">Name</th>
+<th class="tableblock halign-left valign-middle">Schema</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>name</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>resourceDetails</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>serviceDetails</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="#_jsonobject">JsonObject</a></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>serviceUuid</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><strong>version</strong><br>
+<em>optional</em></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock">string</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2021-05-10 12:05:55 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/runtime/src/main/resources/META-INF/services/org/apache/camel/dataformat/clamp-gson b/runtime/src/main/resources/META-INF/services/org/apache/camel/dataformat/clamp-gson
new file mode 100644
index 000000000..04caffa99
--- /dev/null
+++ b/runtime/src/main/resources/META-INF/services/org/apache/camel/dataformat/clamp-gson
@@ -0,0 +1,23 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ */
+
+class=org.onap.policy.clamp.configuration.ClampGsonDataFormat \ No newline at end of file
diff --git a/runtime/src/main/resources/application-noaaf.properties b/runtime/src/main/resources/application-noaaf.properties
new file mode 100644
index 000000000..1145b393d
--- /dev/null
+++ b/runtime/src/main/resources/application-noaaf.properties
@@ -0,0 +1,190 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP POLICY-CLAMP
+# ================================================================================
+# Copyright (C) 2017-2019, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+### Set the port for HTTP or HTTPS protocol (Controlled by Spring framework, only one at a time).
+### (See below for the parameter 'server.http.port' if you want to have both enabled)
+### To have only HTTP, keep the lines server.ssl.* commented
+### To have only HTTPS enabled, uncomment the server.ssl.* lines and specify a right keystore location
+### server.port=8080
+### Settings for HTTPS (this automatically enables the HTTPS on the port 'server.port')
+#server.ssl.key-store=file:/tmp/mykey.jks
+#server.ssl.key-store-password=pass
+#server.ssl.key-password=pass
+
+### In order to be user friendly when HTTPS is enabled,
+### you can add another HTTP port that will be automatically redirected to HTTPS
+### by enabling this parameter (server.http.port) and set it to another port (80 or 8080, 8090, etc ...)
+#server.http-to-https-redirection.port=8090
+
+### HTTP Example:
+###--------------
+### server.port=8080
+
+### HTTPS Example:
+### --------------
+### server.port=8443
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+server.port=8443
+## Config part for Server certificates
+# Can be a classpath parameter instead of file:/
+server.ssl.key-store=classpath:/clds/aaf/org.onap.clamp.p12
+server.ssl.key-store-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-store-type=PKCS12
+server.ssl.key-alias=clamptest
+
+## Config part for Client certificates
+server.ssl.client-auth=want
+server.ssl.trust-store=classpath:/clds/aaf/truststoreONAPall.jks
+server.ssl.trust-store-password=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
+
+# The key file used to decode the key store and trust store password
+# If not defined, the key store and trust store password will not be decrypted
+clamp.config.keyFile=classpath:/clds/aaf/org.onap.clamp.keyfile
+
+#server.http-to-https-redirection.port=8080
+
+server.servlet.context-path=/
+#Modified engine-rest applicationpath
+spring.profiles.active=clamp-default,clamp-default-user,clamp-sdc-controller,clamp-ssl-config,clamp-policy-controller,default-dictionary-elements
+spring.http.converters.preferred-json-mapper=gson
+
+#The max number of active threads in this pool
+server.tomcat.max-threads=200
+#The minimum number of threads always kept alive
+server.tomcat.min-Spare-Threads=25
+#The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads
+server.tomcat.max-idle-time=60000
+
+#Servlet context parameters
+server.context_parameters.p-name=value #context parameter with p-name as key and value as value.
+
+camel.springboot.tracing=true
+camel.springboot.consumer-template-cache-size=1000
+camel.springboot.producer-template-cache-size=1000
+camel.springboot.jmx-enabled=true
+camel.defaultthreadpool.poolsize=10
+camel.defaultthreadpool.maxpoolsize=20
+camel.defaultthreadpool.maxqueuesize=1000
+camel.defaultthreadpool.keepaliveTime=60
+camel.defaultthreadpool.rejectpolicy=CallerRuns
+camel.springboot.xml-routes=classpath:/clds/camel/routes/*.xml
+camel.springboot.xml-rests=classpath:/clds/camel/rest/*.xml
+camel.springboot.backlog-tracing=true
+camel.springboot.tracing=true
+
+#clds datasource connection details
+spring.datasource.driverClassName=org.mariadb.jdbc.Driver
+spring.datasource.url=jdbc:mariadb:sequential://localhost:3306/cldsdb4?autoReconnect=true&connectTimeout=10000&socketTimeout=10000&retriesAllDown=3
+spring.datasource.username=clds
+spring.datasource.password=sidnnd83K
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.validationQueryTimeout=20000
+spring.datasource.validationInterval=30000
+spring.datasource.testWhileIdle = true
+spring.datasource.minIdle = 0
+spring.datasource.initialSize=0
+# Automatically test whether a connection provided is good or not
+spring.datasource.testOnBorrow=true
+spring.datasource.ignoreExceptionOnPreLoad=true
+# control the sql db initialization (from schema.sql and data.sql)
+spring.datasource..initialize=false
+
+spring.jpa.properties.javax.persistence.schema-generation.database.action=none
+s#pring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+# disable Hibernate DDL generation because the schema will be generated from a sql script
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+spring.jpa.properties.hibernate.ddl-auto=validate
+spring.jpa.properties.hibernate.hbm2ddl.delimiter=;
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
+
+# Whether to enable logging of SQL statements.
+#spring.jpa.show-sql=true
+
+#Async Executor default Parameters
+async.core.pool.size=10
+async.max.pool.size=20
+async.queue.capacity=500
+
+#For EELF logback file
+#clamp.config.logback.path=
+clamp.config.logback.filename=logback-default.xml
+#The log folder that will be used in logback.xml file
+clamp.config.log.path=/var/log/onap/clamp
+clamp.config.files.systemProperties=classpath:/system.properties
+clamp.config.files.cldsUsers=classpath:/clds/clds-users.json
+clamp.config.files.globalProperties=classpath:/clds/templates/globalProperties.json
+clamp.config.files.sdcController=classpath:/clds/sdc-controllers-config.json
+
+clamp.config.httpclient.socketTimeout=60000
+clamp.config.httpclient.connectTimeout=10000
+
+#
+# Configuration Settings for Policy Engine Components
+clamp.config.policy.api.url=http://localhost:8085
+clamp.config.policy.api.userName=healthcheck
+clamp.config.policy.api.password=zb!XztG34
+clamp.config.policy.pap.url=http://localhost:8085
+clamp.config.policy.pap.userName=healthcheck
+clamp.config.policy.pap.password=zb!XztG34
+
+#
+# Sdc service properties
+clamp.config.sdc.csarFolder = /tmp/sdc-controllers
+
+#DCAE Inventory Url Properties
+clamp.config.dcae.inventory.url=http://localhost:8085
+clamp.config.dcae.intentory.retry.interval=10000
+clamp.config.dcae.intentory.retry.limit=5
+
+#DCAE Deployment Url Properties
+clamp.config.dcae.deployment.url=http://localhost:8085
+clamp.config.dcae.deployment.userName=test
+clamp.config.dcae.deployment.password=test
+
+#Define user permission related parameters, the permission type can be changed but MUST be redefined in clds-users.properties in that case !
+clamp.config.security.permission.type.cl=org.onap.clamp.clds.cl
+clamp.config.security.permission.type.cl.manage=org.onap.clamp.clds.cl.manage
+clamp.config.security.permission.type.cl.event=org.onap.clamp.clds.cl.event
+clamp.config.security.permission.type.filter.vf=org.onap.clamp.clds.filter.vf
+clamp.config.security.permission.type.template=org.onap.clamp.clds.template
+clamp.config.security.permission.type.tosca=org.onap.clamp.clds.tosca
+clamp.config.security.permission.type.policies=org.onap.clamp.clds.policies
+#This one indicates the type of instances (dev|prod|perf...), this must be set accordingly in clds-users.properties
+clamp.config.security.permission.instance=dev
+clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal, org.onap.aaf.cadi.principal.CachedBasicPrincipal
+
+## Tosca converter
+clamp.config.tosca.converter.json.schema.templates=classpath:/clds/tosca-converter/templates.json
+clamp.config.tosca.converter.default.datatypes=classpath:/clds/tosca-converter/default-tosca-types.yaml
+clamp.config.tosca.converter.dictionary.support.enabled=true
+
+# Configuration settings for CDS
+clamp.config.cds.url=http://cds-blueprints-processor-http:8080
+clamp.config.cds.userName=ccsdkapps
+clamp.config.cds.password=ccsdkapps \ No newline at end of file
diff --git a/runtime/src/main/resources/application.properties b/runtime/src/main/resources/application.properties
new file mode 100644
index 000000000..3cbb7e8af
--- /dev/null
+++ b/runtime/src/main/resources/application.properties
@@ -0,0 +1,203 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP POLICY-CLAMP
+# ================================================================================
+# Copyright (C) 2017-2019, 2021 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Modifications copyright (c) 2019 Nokia
+# ================================================================================\
+# 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============================================
+# ===================================================================
+#
+###
+
+### Set the port for HTTP or HTTPS protocol (Controlled by Spring framework, only one at a time).
+### (See below for the parameter 'server.http.port' if you want to have both enabled)
+### To have only HTTP, keep the lines server.ssl.* commented
+### To have only HTTPS enabled, uncomment the server.ssl.* lines and specify a right keystore location
+### server.port=8080
+### Settings for HTTPS (this automatically enables the HTTPS on the port 'server.port')
+#server.ssl.key-store=file:/tmp/mykey.jks
+#server.ssl.key-store-password=pass
+#server.ssl.key-password=pass
+
+### In order to be user friendly when HTTPS is enabled,
+### you can add another HTTP port that will be automatically redirected to HTTPS
+### by enabling this parameter (server.http.port) and set it to another port (80 or 8080, 8090, etc ...)
+#server.http-to-https-redirection.port=8090
+
+### HTTP Example:
+###--------------
+### server.port=8080
+
+### HTTPS Example:
+### --------------
+### server.port=8443
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+
+### HTTP (Redirected to HTTPS) and HTTPS Example:
+### --------------------------------------------
+server.port=8443
+## Config part for Server certificates
+# Can be a classpath parameter instead of file:/
+server.ssl.key-store=classpath:/clds/aaf/org.onap.clamp.p12
+server.ssl.key-store-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-store-type=PKCS12
+server.ssl.key-alias=clamptest
+
+# The key file used to decode the key store and trust store password
+# If not defined, the key store and trust store password will not be decrypted
+clamp.config.keyFile=classpath:/clds/aaf/org.onap.clamp.keyfile
+clamp.config.caCerts=classpath:/clds/aaf/ssl/ca-certs.pem
+
+## Config part for Client certificates
+server.ssl.client-auth=want
+server.ssl.trust-store=classpath:/clds/aaf/truststoreONAPall.jks
+server.ssl.trust-store-password=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
+
+#server.http-to-https-redirection.port=8080
+
+server.servlet.context-path=/
+#Modified engine-rest applicationpath
+spring.profiles.active=clamp-default,clamp-aaf-authentication,clamp-sdc-controller,clamp-ssl-config,clamp-policy-controller,default-dictionary-elements
+spring.http.converters.preferred-json-mapper=gson
+
+#The max number of active threads in this pool
+server.tomcat.max-threads=200
+#The minimum number of threads always kept alive
+server.tomcat.min-Spare-Threads=25
+#The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads
+server.tomcat.max-idle-time=60000
+
+#Servlet context parameters
+server.context_parameters.p-name=value #context parameter with p-name as key and value as value.
+camel.springboot.tracing=true
+camel.springboot.consumer-template-cache-size=1000
+camel.springboot.producer-template-cache-size=1000
+camel.springboot.jmx-enabled=true
+camel.defaultthreadpool.poolsize=10
+camel.defaultthreadpool.maxpoolsize=20
+camel.defaultthreadpool.maxqueuesize=1000
+camel.defaultthreadpool.keepaliveTime=60
+camel.defaultthreadpool.rejectpolicy=CallerRuns
+camel.springboot.xml-routes=classpath:/clds/camel/routes/*.xml
+camel.springboot.xml-rests=classpath:/clds/camel/rest/*.xml
+camel.springboot.backlog-tracing=true
+camel.springboot.tracing=true
+
+#clds datasource connection details
+spring.datasource.driverClassName=org.mariadb.jdbc.Driver
+spring.datasource.url=jdbc:mariadb:sequential://localhost:3306/cldsdb4?autoReconnect=true&connectTimeout=10000&socketTimeout=10000&retriesAllDown=3
+spring.datasource.username=clds
+spring.datasource.password=sidnnd83K
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.validationQueryTimeout=20000
+spring.datasource.validationInterval=30000
+spring.datasource.testWhileIdle = true
+spring.datasource.minIdle = 0
+spring.datasource.initialSize=0
+# Automatically test whether a connection provided is good or not
+spring.datasource.testOnBorrow=true
+spring.datasource.ignoreExceptionOnPreLoad=true
+
+spring.jpa.properties.javax.persistence.schema-generation.database.action=none
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+# disable Hibernate DDL generation because the schema will be generated from a sql script
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+spring.jpa.properties.hibernate.ddl-auto=validate
+spring.jpa.properties.hibernate.hbm2ddl.delimiter=;
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
+
+# Whether to enable logging of SQL statements.
+#spring.jpa.show-sql=true
+
+#Async Executor default Parameters
+async.core.pool.size=10
+async.max.pool.size=20
+async.queue.capacity=500
+
+#For EELF logback file
+#clamp.config.logback.path=
+clamp.config.logback.filename=logback-default.xml
+#The log folder that will be used in logback.xml file
+clamp.config.log.path=/var/log/onap/clamp
+clamp.config.files.systemProperties=classpath:/system.properties
+clamp.config.files.cldsUsers=classpath:/clds/clds-users.json
+clamp.config.files.globalProperties=classpath:/clds/templates/globalProperties.json
+clamp.config.files.sdcController=classpath:/clds/sdc-controllers-config.json
+
+clamp.config.httpclient.socketTimeout=60000
+clamp.config.httpclient.connectTimeout=10000
+#
+# Configuration Settings for Policy Engine Components
+clamp.config.policy.api.url=http://policy.api.simpledemo.onap.org:6969
+clamp.config.policy.api.userName=healthcheck
+clamp.config.policy.api.password=zb!XztG34
+clamp.config.policy.pap.url=http://policy.api.simpledemo.onap.org:6969
+clamp.config.policy.pap.userName=healthcheck
+clamp.config.policy.pap.password=zb!XztG34
+
+#
+# Sdc service properties
+clamp.config.sdc.csarFolder=/tmp/sdc-controllers
+
+#DCAE Inventory Url Properties
+clamp.config.dcae.inventory.url=http://dcae.api.simpledemo.onap.org:8080
+clamp.config.dcae.intentory.retry.interval=10000
+clamp.config.dcae.intentory.retry.limit=5
+
+#DCAE Deployment Url Properties
+clamp.config.dcae.deployment.url=http://dcae.api.simpledemo.onap.org:8188
+clamp.config.dcae.deployment.userName=test
+clamp.config.dcae.deployment.password=test
+
+#Define user permission related parameters, the permission type can be changed but MUST be redefined in clds-users.properties in that case !
+clamp.config.security.permission.type.cl=org.onap.clamp.clds.cl
+clamp.config.security.permission.type.cl.manage=org.onap.clamp.clds.cl.manage
+clamp.config.security.permission.type.cl.event=org.onap.clamp.clds.cl.event
+clamp.config.security.permission.type.filter.vf=org.onap.clamp.clds.filter.vf
+clamp.config.security.permission.type.template=org.onap.clamp.clds.template
+clamp.config.security.permission.type.tosca=org.onap.clamp.clds.tosca
+clamp.config.security.permission.type.policies=org.onap.clamp.clds.policies
+#This one indicates the type of instances (dev|prod|perf...), this must be set accordingly in clds-users.properties
+clamp.config.security.permission.instance=dev
+clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal, org.onap.aaf.cadi.principal.CachedBasicPrincipal
+
+#AAF related parameters
+clamp.config.cadi.cadiLoglevel=DEBUG
+clamp.config.cadi.cadiLatitude=10
+clamp.config.cadi.cadiLongitude=10
+clamp.config.cadi.aafLocateUrl=https://aaf-locate:30251
+clamp.config.cadi.oauthTokenUrl= https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.token:2.1/token
+clamp.config.cadi.oauthIntrospectUrll=https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.introspect:2.1/introspect
+clamp.config.cadi.aafEnv=DEV
+clamp.config.cadi.aafUrl=https://AAF_LOCATE_URL/onap.org.osaaf.aaf.service:2.1
+clamp.config.cadi.cadiX509Issuers=CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US
+
+## Tosca converter
+clamp.config.tosca.converter.json.schema.templates=classpath:/clds/tosca-converter/templates.json
+clamp.config.tosca.converter.default.datatypes=classpath:/clds/tosca-converter/default-tosca-types.yaml
+clamp.config.tosca.converter.dictionary.support.enabled=true
+
+# Configuration settings for CDS
+clamp.config.cds.url=http://cds-blueprints-processor-http:8080
+clamp.config.cds.userName=ccsdkapps
+clamp.config.cds.password=ccsdkapps \ No newline at end of file
diff --git a/runtime/src/main/resources/asciidoc/swagger.adoc b/runtime/src/main/resources/asciidoc/swagger.adoc
new file mode 100644
index 000000000..6896747fd
--- /dev/null
+++ b/runtime/src/main/resources/asciidoc/swagger.adoc
@@ -0,0 +1,4 @@
+include::{generated}/overview.adoc[]
+include::{generated}/paths.adoc[]
+include::{generated}/security.adoc[]
+include::{generated}/definitions.adoc[] \ No newline at end of file
diff --git a/runtime/src/main/resources/boot-message.txt b/runtime/src/main/resources/boot-message.txt
new file mode 100644
index 000000000..5a6cf1824
--- /dev/null
+++ b/runtime/src/main/resources/boot-message.txt
@@ -0,0 +1,16 @@
+
+ ___ _ _ _ ____ ___ _ _ _
+ / _ \| \ | | / \ | _ \ |_ _|___| |_ __ _ _ __ | |__ _ _| |
+ | | | | \| | / _ \ | |_) | | |/ __| __/ _` | '_ \| '_ \| | | | |
+ | |_| | |\ |/ ___ \| __/ | |\__ \ || (_| | | | | |_) | |_| | |
+ \___/|_| \_/_/ \_\_| |___|___/\__\__,_|_| |_|_.__/ \__,_|_|
+ ____ ___ _ ___ ______ __ ____ _ _ __ __ ____
+ | _ \ / _ \| | |_ _/ ___\ \ / / / ___| | / \ | \/ | _ \
+ | |_) | | | | | | | | \ V /____| | | | / _ \ | |\/| | |_) |
+ | __/| |_| | |___ | | |___ | |_____| |___| |___ / ___ \| | | | __/
+ |_| \___/|_____|___\____| |_| \____|_____/_/ \_\_| |_|_|
+
+
+
+
+ :: Starting :: \ No newline at end of file
diff --git a/runtime/src/main/resources/clds-version.properties b/runtime/src/main/resources/clds-version.properties
new file mode 100644
index 000000000..a0dbcdead
--- /dev/null
+++ b/runtime/src/main/resources/clds-version.properties
@@ -0,0 +1,24 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+clds.version=${project.version} \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/aaf/org.onap.clamp.keyfile b/runtime/src/main/resources/clds/aaf/org.onap.clamp.keyfile
new file mode 100644
index 000000000..c2521fc81
--- /dev/null
+++ b/runtime/src/main/resources/clds/aaf/org.onap.clamp.keyfile
@@ -0,0 +1,27 @@
+kzJMxgphAoBxJz1_vYjxx-V87fahDQdYUqBIyWhZp8ojXdNpmB-96T9CvgJScJynbLcqw2Cj2CYx
+wd97vFOYhlyz5zK3tSyIuydOkVGJsJ1S4PviTtjhiJvNourJNDHgtas1Y1y2fQ5_8aVxj-s4W72N
+MNYhkeTinaQx_d_5hkBPABJlgCxKLnmxHo2jAJktnZYa5t5h48m7KiUx_RVEkQVtEvux-7vgXaC4
+ymTXj6zI9XoMTVxM0OAl4y7kBiUoOUaxS4tVKV34RJYNNqBjiUTQa_ag-KeUacRABk1ozfwzpvE5
+Sjz8WCy0L-LtCQnapkhKLt04ndCZtw8LDJ-Zz0ZgR2PVIPpTgs9VnVuOi5jf4LzTrtUatvOWkKB9
+drXKzp6cNXnZ0jkD3vV1BzqzhynKnZR2o_ilZv5CTTdpGUt906N_DwZuX6LfcV_7yvjX42bTfeIR
+ycPtodFPXlqqn9VUyh5nOauJlnOHAQmSDzjMEgjy17nQX3Ad7s4BfvujzUl-d0MqB_HCKbaW32UT
+xcY-0JfI1Y-2IdYfIkUdhVmxop6sSg0jAobWzgCRoRQkP3a2iIlKdfMyskshoWKIDVtlr-3fkDEb
+x_b_o1rRoUfzUzxEdphaUAq80Sc0i77ZLT3KF9vJOhyU_pBnApYFxVk7Hkk3VRxJKS7jyL4H7k1x
+2m5-2G8fB9XbYZT82xmAquNx4oBdpwj3_ncGF9YRF94K6NZgqemT5iWhpXMoelSU1blASgT3qlTm
+B6YgbD5owExNHwRVd8KeRsYrOnBWUiktsIhXFhNZmDUNWMFGQ2KxEcOt1tJwsQDehJFgY_l1JQ0d
+643wJ7rTJkGkYX309cydRQUX4Z0ckSQS9LhMd9stxF5XOHlvHdbW0pXNS7SaLbzKCVldUgncvI6z
+KWkwrWbftrZK2RT1UZKNngQDMGOk9OhbHAs7YzhFNFARZoRNobIv5tZVDomy-YgJb9-mD1UTkRBL
+WXOyoryDlgKrgFsgHclGDI1UFO5N-JfebPKxbP505f4924hxF2r8bspvVW8ZtHQo_SJmhauOX8n_
+eN_LK43LB9k53WAHZ_utvs0s6wGf7I73oj_N7DIFaHTDSm_MhDsFDLVG_wUzCpZ5FP2uL3nnqMkF
+Ob-l1fywfmfOmrz1BY6g4sRPPeWXuclYTnRnDRu5VQyc7_aBEVkyt3zw0JEex0vJNFUJl3pYjS55
+GplAB6p7VbS9ceZEtc5Z3qFIVHEzKWZxT190E23t_LlMuEoQ1zaqdHynNaMs61-q_A2aHRiTqlRm
+7FahVB3RX4AVLl23mu4u3A9ZDXc40nzjs9mwOVsuKlPvQ2rteDUG1njr2R1_V_MyQuoJjdfbIkPG
+4eF0QzlSMdbkeprdQxSfV5YT-yPpkBxSsCMMM43sKm4Hy7_CUdvp4Iayrp3vtK3oYMuCGi6qTadz
+KzxfTf8meKan3eMZW4RLByyniH5nQnX_KGfBly05AmFyVH_j0fyOg-48kDhtEKeqmDnP4C01jOID
+Ip_AKaB6e0GwsHzVTLZOklHwu_qzsaTzchBOG_dJJju7bxY7qv78Pa92wZIP311gSCVbc-gxxbsR
+qI555twmYEoasFm4xz10OYDOkvM1E1Rtxu3ymRLZpe6AoyFBVzEW7Dncdw7O98dKcgrp8ZlQ_8Wg
+5zZH0Cic7xnIZ0bNZyQXw56CSUiXVWuwVY3e0djXP3F-FO5gP8VTxbpW4C0t6McXAOlvSEfFKxN7
+u6OBeOKwjrtHaJk2ghF8MUcpDXanhbAgHez9larGlscCkgvoRLNaRH9GIdSVgY3HtNhJRaJIq01S
+OGeBjC5J4o-nTrqRFkwyDAYcPL373eYX1dBFFVHR-4q50H9m_zMxZHXETafxzV4DT3Qi8Sxh3uaS
+ZX7mRaNaOE0uC1n87_IZ9WhrwIQaZng2lnd9yZ-4rx8fB8WA8KQzifzvHAcMb_HV10JWGaz5A2Rm
+EXDsfexQC6CqYg5rdzzlNWDPNlHy5ubyz7fRXZ99uIwBY9aJcvCXCiEXJkC6utj3NcXQrJmk \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/aaf/ssl/ca-certs.pem b/runtime/src/main/resources/clds/aaf/ssl/ca-certs.pem
new file mode 100644
index 000000000..70bb844b7
--- /dev/null
+++ b/runtime/src/main/resources/clds/aaf/ssl/ca-certs.pem
@@ -0,0 +1,32 @@
+Bag Attributes
+ friendlyName: CN=intermediateCA_9,OU=OSAAF,O=ONAP,C=US
+subject=C = US, O = ONAP, OU = OSAAF, CN = intermediateCA_9
+
+issuer=OU = OSAAF, O = ONAP, C = US
+
+-----BEGIN CERTIFICATE-----
+MIIEdTCCAl2gAwIBAgIBBzANBgkqhkiG9w0BAQsFADAsMQ4wDAYDVQQLDAVPU0FB
+RjENMAsGA1UECgwET05BUDELMAkGA1UEBhMCVVMwHhcNMTgwODE3MTg1MTM3WhcN
+MjMwODE3MTg1MTM3WjBHMQswCQYDVQQGEwJVUzENMAsGA1UECgwET05BUDEOMAwG
+A1UECwwFT1NBQUYxGTAXBgNVBAMMEGludGVybWVkaWF0ZUNBXzkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv0HHUkba3uNtNI3jPKimUcd6RNwmhSCJL
+neMWpnjqp5/A+HCKyNsEaT4y177hNLmCm/aMm1u2JIfikc+8wEqLCSBBPz+P0h+d
+o+sZ7U+4oeQizdYYpEdzHJ2SieHHa8vtu80rU3nO2NEIkuYC20HcKSEtl8fFKsk3
+nqlhY+tGfYJPTXcDOQAO40BTcgat3C3uIJHkWJJ4RivunE4LEuRv9QyKgAw7rkJV
+v+f7guqpZlXy6dzAkuU7XULWcgo55MkZlssoiErMvEZJad5aWKvRY3g7qUjaQ6wO
+15wOAUoRBW96eeZZbytgn8kybcBy++Ue49gPtgm1MF/KlAsp0MD5AgMBAAGjgYYw
+gYMwHQYDVR0OBBYEFIH3mVsQuciM3vNSXupOaaBDPqzdMB8GA1UdIwQYMBaAFFNV
+M/JL69BRscF4msEoMXvv6u1JMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B
+AQsFAAOCAgEADxNymiCNr2e37iLReoaxKmZvwox0cTiNAaj7iafRzmwIoY3VXO8Q
+ix5IYcp4FaQ7fV1jyp/AmaSnyHf6Osl0sx8PxsQkO7ALttxKUrjfbvNSVUA2C/vl
+u5m7UVJLIUtFDZBWanzUSmkTsYLHpiANFQKd2c/cU1qXcyzgJVFEFVyyHNkF7Is+
++pjG9M1hwQHOoTnEuU013P7X1mHek+RXEfhJWwe7UsZnBKZaZKbQZu7hEtqKWYp/
+QsHgnjoLYXsh0WD5rz/mBxdTdDLGpFqWDzDqb8rsYnqBzoowvsasV8X8OSkov0Ht
+8Yka0ckFH9yf8j1Cwmbl6ttuonOhky3N/gwLEozuhy7TPcZGVyzevF70kXy7g1CX
+kpFGJyEHXoprlNi8FR4I+NFzbDe6a2cFow1JN19AJ9Z5Rk5m7M0mQPaQ4RcikjB3
+aoLsASCJTm1OpOFHfxEKiBW4Lsp3Uc5/Rb9ZNbfLrwqWZRM7buW1e3ekLqntgbky
+uKKISHqVJuw/vXHl1jNibEo9+JuQ88VNuAcm7WpGUogeCa2iAlPTckPZei+MwZ8w
+tpvxTyYlZEC8DWzY1VC29+W2N5cvh01e2E3Ql08W1zL63dqrgdEZ3VWjzooYi4ep
+BmMXTvouW+Flyvcw/0oTcfN0biDIt0mCkZ5CQVjfGL9DTOYteR5hw+k=
+-----END CERTIFICATE-----
diff --git a/runtime/src/main/resources/clds/aaf/ssl/clamp.key b/runtime/src/main/resources/clds/aaf/ssl/clamp.key
new file mode 100644
index 000000000..bcbb9f17e
--- /dev/null
+++ b/runtime/src/main/resources/clds/aaf/ssl/clamp.key
@@ -0,0 +1,32 @@
+Bag Attributes
+ friendlyName: clamp@clamp.onap.org
+ localKeyID: 54 69 6D 65 20 31 35 38 30 38 32 39 30 36 35 34 37 39
+Key Attributes: <No Attributes>
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCTB30nMh0hczIk
+vWJo7Omg7cAHhz50NBhLB7u+60oXRGCya4SqssqqxNnNqNQQP9MmflW2q/bZepWn
+8Rk23X6CLmoIUlrj8BMPkUCRqzgvlaWPSNAK5QcOp6GUvXTuX4EsaWxJhbs9Ujz2
++qi137iNOqfAx1sUygah1kjALrqHkXDqJGvIfxU5ES0akBi/lB7A3WpE52KTioSF
+JS5Kbnpj1ogffGNKyAiNqU61LcF1FjWmINat2z3ZMk/3Xm+HCDg/GLPnbh4E1KoE
+10O22AMys6YGEyPvgRfrTF13DsDX52PmmUHbkSB6kwS/CeV5Uu++8b6T2IWpPyZ2
++5ptmL+tAgMBAAECggEBAIUplzRUswWEq7mSvPqC9+YE7pLi7rGYLRhnXKdBuszv
+5RQzROjFHcEkoI8fhVFiPP70FPVpMh0uZTTBrDCA0v9cwjPfQuqGmPzUdUJ5bF3M
+jzICpEn5vDaNpE5ueOUcIoXyxVyhfj+/p++YfgybHy7qHN0AsYFWqEMTLLjCmbYF
+pZozbAcGQoAR8PSfwuvgusuEezrhYertHsdFwlfZhDtJvnm/4YKRUVEBzuaaA7B9
+sUhnQFS8ScqiUbkAGdjfY9wOYRHnQgjtqiP8poIzLkqCNSoVctgh5Pdv4jp4HO90
+J5QC+f7m7rOoWUw8EYbRo/4C4Mckh0GQQ+oP4xzrtZECgYEA3DYALFgOEY+0RR1K
+61HAKqdNy1YbeuidpCBEJEwmIbzdgO1DcJdNznbfdRlmS7VB9orwRfNbf7Hxm2w/
+/xn9USENXWx7fvDoISqSDegvEsBSq5hSEMVl3f7CfQZrYl1f6gxfe7L/jtmbn0eQ
+avsr9RaUCWP794DEXKuA9pC8hVsCgYEAquy5I4hO4jNBQ6v5+omjsEgk4513/RNs
+f47Md8bsDHKJMbCMKCdqM1D3J1xbgV3DgSv0yNlKdU2wenWdgQAyBtz18NBgno85
+YNanFhp1CymgLFHdLJHSOqAkzutSuCNnGTT6AKspOQvy+cuj7XsnbsxtYK3Cgw5h
+Mom3RnUy9ZcCgYAnForHVEYDBgAYuI9g39z9dT8Q1dMA6SN6S6Ps0Xt/R5gF15e9
+941/FYiqr3yB+cWgrp7hu8XFD9/0F63waTuW2AgYSjZNnROHN5g/UbRxXqQOA3al
+tXRUiHEbYjVTe4GX+ORF/8rvH19JUZmn87ekxII4fH/wOfIhBOxaV+yuuwKBgHtz
+5Tizz/3y9TWSdkgtt6uwP+yipLKGn/v1wNrWM1G+PDdGg8TQyxTrasfkHjdu6LFY
+dUHIJ85X4ZphbvRolrl8SKq5Zr+/RLsb7qy5SUZZt1Wrfysc25H6bvuA3ksfTuzW
+5acr+Oc6KTGgkvMI229cebe1aONNtIhTDav3JGpbAoGAX5DQvNreqnP8qSAvUN2I
+TAHXIzawR3f6vgGgVIdkHkiS2eKzs/fgP3VAK80TbrGSR8HvBcPEcR/icOn1u/e6
+tDp0j6mGt5aPKK9VQkBn94bW35T12FUbdB+L8FWWTUrfiVWJtEW8tEsKil5ac8U4
+Bn3vC5WUeKhW6v6kD4AigqE=
+-----END PRIVATE KEY-----
diff --git a/runtime/src/main/resources/clds/aaf/ssl/clamp.pem b/runtime/src/main/resources/clds/aaf/ssl/clamp.pem
new file mode 100644
index 000000000..a01b587a5
--- /dev/null
+++ b/runtime/src/main/resources/clds/aaf/ssl/clamp.pem
@@ -0,0 +1,33 @@
+Bag Attributes
+ friendlyName: clamp@clamp.onap.org
+ localKeyID: 54 69 6D 65 20 31 35 38 30 38 32 39 30 36 35 34 37 39
+subject=CN = clamp, emailAddress = mark.d.manager@people.osaaf.com, OU = clamp@clamp.onap.org:DEV, OU = OSAAF, O = ONAP, C = US
+
+issuer=C = US, O = ONAP, OU = OSAAF, CN = intermediateCA_9
+
+-----BEGIN CERTIFICATE-----
+MIIEWDCCA0CgAwIBAgIILw1zyDGqB5IwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UE
+BhMCVVMxDTALBgNVBAoMBE9OQVAxDjAMBgNVBAsMBU9TQUFGMRkwFwYDVQQDDBBp
+bnRlcm1lZGlhdGVDQV85MB4XDTIwMDIwNDEyMjM1MloXDTIxMDIwNDEyMjM1Mlow
+gY8xDjAMBgNVBAMMBWNsYW1wMS4wLAYJKoZIhvcNAQkBFh9tYXJrLmQubWFuYWdl
+ckBwZW9wbGUub3NhYWYuY29tMSEwHwYDVQQLDBhjbGFtcEBjbGFtcC5vbmFwLm9y
+ZzpERVYxDjAMBgNVBAsMBU9TQUFGMQ0wCwYDVQQKDARPTkFQMQswCQYDVQQGEwJV
+UzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJMHfScyHSFzMiS9Ymjs
+6aDtwAeHPnQ0GEsHu77rShdEYLJrhKqyyqrE2c2o1BA/0yZ+Vbar9tl6lafxGTbd
+foIuaghSWuPwEw+RQJGrOC+VpY9I0ArlBw6noZS9dO5fgSxpbEmFuz1SPPb6qLXf
+uI06p8DHWxTKBqHWSMAuuoeRcOoka8h/FTkRLRqQGL+UHsDdakTnYpOKhIUlLkpu
+emPWiB98Y0rICI2pTrUtwXUWNaYg1q3bPdkyT/deb4cIOD8Ys+duHgTUqgTXQ7bY
+AzKzpgYTI++BF+tMXXcOwNfnY+aZQduRIHqTBL8J5XlS777xvpPYhak/Jnb7mm2Y
+v60CAwEAAaOB/jCB+zAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIF4DAgBgNVHSUB
+Af8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVAYDVR0jBE0wS4AUgfeZWxC5yIze
+81Je6k5poEM+rN2hMKQuMCwxDjAMBgNVBAsMBU9TQUFGMQ0wCwYDVQQKDARPTkFQ
+MQswCQYDVQQGEwJVU4IBBzAdBgNVHQ4EFgQUzfIed+18wgFs7E6q0b6BbMICtfsw
+RwYDVR0RBEAwPoIFY2xhbXCCCmNsYW1wLW9uYXCCHWNsYW1wLmFwaS5zaW1wbGVk
+ZW1vLm9uYXAub3JnggpjbGFtcC5vbmFwMA0GCSqGSIb3DQEBCwUAA4IBAQBizhsW
+XrJ9wQy3PrBxgh90sOF15tayXPRZSFYPoQb5LhRh3IY/PvXLaSHlkgPHlCLLx36S
+0/DiVf86/83ABvyaq9gJIyg/m4ntNae23OKH1AkA1aN+JCKA8yhsAzDBcRF6Aj7E
+VJ+vQlSzz5oh+efP1e/8DUMd1/WwbTXvRd0Iqv/fyZunbjb82qNMrsK1mQ2q+87A
+0jx9u1EdeMihP6vWiuKzlwy4mKoNT573SPpvaOkjX3yDlmf2CTQZ9vdAvjmFmVsH
+1wyrNZOIgW4VjluiZfAk3mOEskrZiP/7aUXnxmNnYTpgZMbhiouLbRrTc4lLEyhx
+G7A61/KGTsLZlvxb
+-----END CERTIFICATE-----
diff --git a/runtime/src/main/resources/clds/aaf/truststoreONAPall.jks b/runtime/src/main/resources/clds/aaf/truststoreONAPall.jks
new file mode 100644
index 000000000..ff844b109
--- /dev/null
+++ b/runtime/src/main/resources/clds/aaf/truststoreONAPall.jks
Binary files differ
diff --git a/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml b/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml
new file mode 100644
index 000000000..4659a90bf
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml
@@ -0,0 +1,1472 @@
+<rests xmlns="http://camel.apache.org/schema/spring">
+ <rest>
+ <get uri="/v2/loop/getAllNames" outType="java.lang.String[]"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Loop')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=getLoopNames()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET All Loop names FAILED: ${exception.stacktrace}"/>
+
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET All Loop names FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/loop/{loopName}" outType="org.onap.policy.clamp.loop.Loop"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Loop')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=getLoop(${header.loopName})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Loop request failed for loop: ${header.loopName}, ${exception.stacktrace}"/>
+
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Loop FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+
+ <post uri="/v2/loop/updateGlobalProperties/{loopName}"
+ type="com.google.gson.JsonObject" consumes="application/json"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Update the global properties')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <setHeader name="GlobalPropertiesJson">
+ <simple>${body}</simple>
+ </setHeader>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=updateGlobalPropertiesJson(${header.loopName},${header.GlobalPropertiesJson})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('Global Properties UPDATED','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="UPDATE Global properties FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>UPDATE Global properties FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+ <post uri="/v2/loop/updateOperationalPolicies/{loopName}"
+ type="com.google.gson.JsonArray" consumes="application/json"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Update operational policies')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <setHeader name="OperationalPoliciesArray">
+ <simple>${body}</simple>
+ </setHeader>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=updateOperationalPolicies(${header.loopName},${header.OperationalPoliciesArray})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('Operational policies UPDATED','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="UPDATE Operational policies FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('UPDATE Operational policies request FAILED, Error reported: ${exception.message}','ERROR',${exchangeProperty[loopObject]})"/>
+
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>UPDATE Operational policies FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+ <post uri="/v2/loop/updateMicroservicePolicy/{loopName}"
+ type="org.onap.policy.clamp.policy.microservice.MicroServicePolicy"
+ consumes="application/json"
+ outType="org.onap.policy.clamp.policy.microservice.MicroServicePolicy"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Update Microservice policies')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <setProperty name="MicroServicePolicyObject">
+ <simple>${body}</simple>
+ </setProperty>
+
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=updateMicroservicePolicy(${header.loopName},${exchangeProperty[MicroServicePolicyObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('Micro Service policies UPDATED','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="UPDATE MicroService policy FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('UPDATE MicroService policy request FAILED, Error reported: ${exception.message}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>UPDATE MicroService policy FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+ <put uri="/v2/loop/deploy/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="DCAE DEPLOY request for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'DCAE DEPLOY request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DCAE DEPLOY request','INFO',${exchangeProperty[loopObject]})"/>
+ <to uri="direct:deploy-loop"/>
+
+ <log loggingLevel="INFO"
+ message="DEPLOY request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DEPLOY request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="DEPLOY request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DEPLOY request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>DEPLOY request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/refreshMicroServicePolicyJsonSchema/{loopName}/{microServicePolicyName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName|microServicePolicyName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Refresh Micro Service Policy UI for loop: ${header.loopName} and ${header.microServicePolicyName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'REFRESH Micro Service Policy UI request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.cds.CdsDataInstaller?method=updateCdsServiceProperties(${exchangeProperty[loopObject].getModelService()})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=refreshMicroServicePolicyJsonRepresentation(${exchangeProperty[loopObject]},${header.microServicePolicyName})"/>
+ <log loggingLevel="INFO"
+ message="REFRESH Micro Service policy request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REFRESH Micro Service policy request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="REFRESH json schema request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REFRESH Json schema request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>REFRESH json schema request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/refreshOperationalPolicyJsonSchema/{loopName}/{operationalPolicyName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName|operationalPolicyName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Refresh Operational Policy UI for loop: ${header.loopName} and ${header.operationalPolicyName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'REFRESH Operational Policy UI request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.cds.CdsDataInstaller?method=updateCdsServiceProperties(${exchangeProperty[loopObject].getModelService()})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=refreshOperationalPolicyJsonRepresentation(${exchangeProperty[loopObject]},${header.operationalPolicyName})"/>
+ <log loggingLevel="INFO"
+ message="REFRESH operational policy request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REFRESH operational policy request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="REFRESH json schema request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REFRESH Json schema request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>REFRESH json schema request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/undeploy/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="DCAE UNDEPLOY request for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'DCAE UNDEPLOY request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DCAE UNDEPLOY request','INFO',${exchangeProperty[loopObject]})"/>
+ <to uri="direct:undeploy-loop"/>
+
+ <log loggingLevel="INFO"
+ message="UNDEPLOY request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('UNDEPLOY request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="UNDEPLOY request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('UNDEPLOY request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>UNDEPLOY request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/stop/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="STOP request for loop: ${header.loopName}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*,'STOP request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('STOP request','INFO',${exchangeProperty[loopObject]})"/>
+
+ <to uri="direct:remove-all-policy-from-active-pdp-group"/>
+ <log loggingLevel="INFO"
+ message="STOP request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('STOP request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="STOP request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('STOP request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>STOP request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/restart/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="RESTART request for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*,'RESTART request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('RESTART request','INFO',${exchangeProperty[loopObject]})"/>
+
+ <to uri="direct:add-policies-from-loop-to-pdp-group"/>
+ <log loggingLevel="INFO"
+ message="RESTART request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('RESTART request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="RESTART request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('RESTART request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>RESTART request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/submit/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="POLICY SUBMIT request for loop: ${header.loopName}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'POLICY SUBMIT request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('POLICY SUBMIT request','INFO',${exchangeProperty[loopObject]})"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:remove-all-policy-from-active-pdp-group"/>
+ <log loggingLevel="INFO"
+ message="Processing all MICRO-SERVICES policies defined in loop ${exchangeProperty[loopObject].getName()}"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="policy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Processing Micro Service Policy: ${exchangeProperty[policy].getName()}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:delete-policy-from-loop-object"/>
+ <to uri="direct:create-policy-from-loop-object"/>
+ </split>
+ <log loggingLevel="INFO"
+ message="Processing all OPERATIONAL policies defined in loop ${exchangeProperty[loopObject].getName()}"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getOperationalPolicies()}
+ </simple>
+ <setProperty name="policy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Processing Operational Policy: ${exchangeProperty[policy].getName()}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+
+ <to uri="direct:delete-policy-from-loop-object"/>
+ <to uri="direct:create-policy-from-loop-object"/>
+ </split>
+
+ <delay>
+ <constant>3000</constant>
+ </delay>
+
+ <to uri="direct:add-policies-from-loop-to-pdp-group"/>
+
+ <log loggingLevel="INFO"
+ message="SUBMIT request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('SUBMIT request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="SUBMIT request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('SUBMIT request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>SUBMIT request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/delete/{loopName}">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="DELETE request for loop: ${header.loopName}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*,'DELETE request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DELETE request','INFO',${exchangeProperty[loopObject]})"/>
+ <to uri="direct:undeploy-loop"/>
+ <to uri="direct:remove-all-policy-from-active-pdp-group"/>
+ <log loggingLevel="INFO"
+ message="Deleting all MICRO-SERVICES policies defined in loop ${exchangeProperty[loopObject].getName()}"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="policy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Deleting Micro Service Policy: ${exchangeProperty[policy].getName()}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:delete-policy-from-loop-object"/>
+ </split>
+ <log loggingLevel="INFO"
+ message="Deleting all OPERATIONAL policies defined in loop ${exchangeProperty[loopObject].getName()}"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getOperationalPolicies()}
+ </simple>
+ <setProperty name="policy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Deleting Operational Policy: ${exchangeProperty[policy].getName()}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:delete-policy-from-loop-object"/>
+ </split>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=deleteLoop(${header.loopName})"/>
+ <log loggingLevel="INFO"
+ message="DELETE request successfully executed for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="DELETE request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('DELETE request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>DELETE request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <get uri="/v2/loop/getstatus/{loopName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="GET STATUS request for loop: ${header.loopName}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET STATUS request')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','read')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET STATUS request','INFO',${exchangeProperty[loopObject]})"/>
+ <to uri="direct:update-policy-status-for-loop"/>
+ <to uri="direct:update-dcae-status-for-loop"/>
+ <to uri="direct:update-loop-state"/>
+
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET STATUS request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET STATUS request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET STATUS request failed, Error reported: ${exception} - Body: ${exception.responseBody}','ERROR',${exchangeProperty[loopObject]})"/>
+ </doCatch>
+ <doFinally>
+ <setBody>
+ <simple>${exchangeProperty[loopObject]}</simple>
+ </setBody>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>200</constant>
+ </setHeader>
+ </doFinally>
+ </doTry>
+ </route>
+ </get>
+
+ <put uri="/v2/loop/addOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName|policyType|policyVersion"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Add operational Policy')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=addOperationalPolicy(${header.loopName},${header.policyType},${header.policyVersion})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('ADD OperationalPolicy request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="ADD operational policy request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('ADD OperationalPolicy request failed','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>ADD Operational policy request FAILED for loop: ${header.loopName},
+ ${exception.message}"
+ </simple>
+ </setBody>
+
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <put uri="/v2/loop/removeOperationaPolicy/{loopName}/policyModel/{policyType}/{policyVersion}/{policyName}"
+ outType="org.onap.policy.clamp.loop.Loop" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="loopName|policyType|policyVersion|policyName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'REMOVE operational Policy')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to uri="direct:load-loop"/>
+ <setProperty name="policyName">
+ <simple>${header.policyName}</simple>
+ </setProperty>
+ <setProperty name="policy">
+ <simple>${exchangeProperty[loopObject].getOperationalPolicy(header.policyName)}</simple>
+ </setProperty>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:remove-one-policy-from-active-pdp-group"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:delete-policy-from-loop-object"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=removeOperationalPolicy(${header.loopName},${header.policyType},${header.policyVersion})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REMOVE OperationalPolicy request successfully executed','INFO',${exchangeProperty[loopObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="REMOVE operational policy request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('REMOVE OperationalPolicy request failed','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>REMOVE Operational policy request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+ <post
+ uri="/v2/loop/create/{loopName}?templateName={templateName}"
+ outType="org.onap.policy.clamp.loop.Loop" consumes="application/json"
+ produces="application/json">
+ <route>
+ <removeHeaders
+ pattern="*"
+ excludePattern="loopName|templateName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Create Loop')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopController?method=createLoop(${header.loopName}, ${header.templateName})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="CREATE Loop from Template request failed for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('CREATE Loop from template request failed','ERROR',${exchangeProperty[loopObject]})"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>CREATE Loop from template FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+ <get uri="/v2/templates"
+ outType="org.onap.policy.clamp.loop.template.LoopTemplate"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Templates')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getAllLoopTemplates()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET ALL templates request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET ALL templates FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/templates/{templateName}"
+ outType="org.onap.policy.clamp.loop.template.LoopTemplate"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="templateName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET a Template by NAME')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplate(${header.templateName})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Template request failed for template: ${header.templateName}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Template FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/templates/names" outType="java.lang.String[]"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Loop Template Names')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplateNames()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET All Template names request failed for template: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET All Template names FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+
+ <!-- NON LOOP related endpoints -->
+ <get uri="/v2/dictionary"
+ outType="org.onap.policy.clamp.tosca.Dictionary" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Dictionaries')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=getAllDictionaries()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Dictionary request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+
+ <get uri="/v2/dictionary/secondary/names"
+ outType="java.lang.String[]" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Secondary Dictionary Level Names')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=getAllSecondaryLevelDictionaryNames()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Dictionary request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/dictionary/{dictionaryName}"
+ outType="org.onap.policy.clamp.tosca.Dictionary" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="dictionaryName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Dictionary Elements for a Dictionary Name')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=getDictionary(${header.dictionaryName})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Dictionary request failed for: ${header.dictionaryName}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <put uri="/v2/dictionary" type="org.onap.policy.clamp.tosca.Dictionary"
+ outType="org.onap.policy.clamp.tosca.Dictionary" consumes="application/json"
+ produces="application/json">
+ <route>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Add New or Update Dictionary')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','update')"/>
+ <setProperty name="DictionaryObject">
+ <simple>${body}</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=saveOrUpdateDictionary(${exchangeProperty[DictionaryObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="PUT Dictionary request failed for: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>PUT Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+
+ <put uri="/v2/dictionary/{name}"
+ type="org.onap.policy.clamp.tosca.Dictionary"
+ outType="org.onap.policy.clamp.tosca.Dictionary" consumes="application/json"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="name"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Add New or Update Dictionary Element')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','update')"/>
+ <setProperty name="DictionaryObject">
+ <simple>${body}</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=saveOrUpdateDictionaryElement(${header.name}, ${exchangeProperty[DictionaryObject]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="PUT Dictionary request failed for: ${header.name}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>PUT Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+
+ <delete uri="/v2/dictionary/{name}" produces="application/json">
+ <route>
+ <removeHeaders pattern="*" excludePattern="name"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Delete Dictionary')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','update')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=deleteDictionary(${header.name})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="DELETE Dictionary request failed for: ${header.name}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>DELETE Dictionary FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </delete>
+
+ <delete uri="/v2/dictionary/{name}/elements/{shortName}"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="name|shortName"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Delete Dictionary Element')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','update')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.tosca.DictionaryService?method=deleteDictionaryElement(${header.name}, ${header.shortName})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="DELETE Dictionary element request failed for: ${header.name}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>DELETE Dictionary element FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </delete>
+
+ <get uri="/v2/policyToscaModels"
+ outType="org.onap.policy.clamp.loop.template.PolicyModel"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Tosca Policy Models')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.PolicyModelsService?method=getAllPolicyModels()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Policy Models request failed for: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Policy models FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/policyToscaModels/{policyModelType}/{policyModelVersion}"
+ outType="com.google.gson.JsonObject" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="policyModelType|policyModelVersion"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Tosca Policy Model by Name/Version')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.PolicyModelsService?method=getPolicyModelJson(${header.policyModelType},${header.policyModelVersion})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Policy Model request failed for type: ${header.policyModelType}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Policy model FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+ <get uri="/v2/policyToscaModels/yaml/{policyModelType}/{policyModelVersion}"
+ outType="java.lang.String" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="policyModelType|policyModelVersion"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Tosca Policy Model Yaml String by Name/Version')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'tosca','','read')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.PolicyModelsService?method=getPolicyModelTosca(${header.policyModelType},${header.policyModelVersion})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Policy Model YAML request failed for type: ${header.policyModelType}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Policy model YAML FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+
+ <!-- Policy Related endpoints, not related to LOOP -->
+ <get uri="/v2/policies" outType="com.google.gson.JsonObject" produces="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Policies List ')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'policies','','read')"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:get-all-policies"/>
+ <setProperty name="policiesListResponse">
+ <simple>${body}</simple>
+ </setProperty>
+ <to uri="direct:get-all-pdp-groups"/>
+ <setProperty name="pdpGroupInfoResponse">
+ <simple>${body}</simple>
+ </setProperty>
+ <setBody>
+ <method ref="org.onap.policy.clamp.policy.pdpgroup.PoliciesPdpMerger"
+ method="mergePoliciesAndPdpGroupStates(${exchangeProperty[policiesListResponse]},${exchangeProperty[pdpGroupInfoResponse]})"/>
+ </setBody>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="GET Policies list JSON request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>GET Policies list JSON FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </get>
+
+ <!-- Create a new policy -->
+ <post uri="/v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}"
+ type="com.google.gson.JsonElement"
+ consumes="application/json"
+ outType="com.google.gson.JsonObject"
+ produces="application/json">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="policyModelType|policyModelVersion|policyName|policyVersion"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'CREATE a new Policy ')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'policies','','update')"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <setProperty name="policyModelType">
+ <simple>${header.policyModelType}</simple>
+ </setProperty>
+ <setProperty name="policyModelVersion">
+ <simple>${header.policyModelVersion}</simple>
+ </setProperty>
+ <setProperty name="policyProperties">
+ <simple>${body}</simple>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.template.PolicyModelsService?method=getPolicyModelTosca(${header.policyModelType},${header.policyModelVersion})"/>
+ <setBody>
+ <method ref="org.onap.policy.clamp.policy.PolicyPayload"
+ method="createPolicyPayload(${header.policyModelType}, ${header.policyModelVersion},
+ ${header.policyName}, ${header.policyVersion}, ${exchangeProperty[policyProperties]}, ${body})"/>
+ </setBody>
+ <to uri="direct:create-policy"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="CREATE Policy request failed for type: ${header.policyModelType}/${header.policyModelVersion}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>CREATE Policy FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+
+ <delete uri="/v2/policies/{policyModelType}/{policyModelVersion}/{policyName}/{policyVersion}">
+ <route>
+ <removeHeaders pattern="*"
+ excludePattern="policyModelType|policyModelVersion|policyName|policyVersion"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'DELETE a Policy ')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'policies','','update')"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <setProperty name="policyModelType">
+ <simple>${header.policyModelType}</simple>
+ </setProperty>
+ <setProperty name="policyModelVersion">
+ <simple>${header.policyModelVersion}</simple>
+ </setProperty>
+ <setProperty name="policyName">
+ <simple>${header.policyName}</simple>
+ </setProperty>
+ <setProperty name="policyVersion">
+ <simple>${header.policyVersion}</simple>
+ </setProperty>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:undeploy-one-policy-from-pap"/>
+ <to uri="direct:delete-policy"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="DELETE Policy request failed for policy: ${header.policyName}/${header.policyVersion}, ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>DELETE Policy FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </delete>
+
+ <put uri="/v2/policies/pdpDeployment" type="com.google.gson.JsonElement" consumes="application/json">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Pdp group deployment update')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'policies','','update')"/>
+ <setBody>
+ <method ref="org.onap.policy.clamp.policy.pdpgroup.PdpGroupPayload"
+ method="generatePdpGroupPayloadFromList(${body})"/>
+ </setBody>
+ <log loggingLevel="INFO"
+ message="PDP Group DEPLOY request payload: ${body}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:add-multiple-policies-to-pdp-group"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="PDP Group deployment request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>PDP Group deployment request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </put>
+
+ <post uri="/v2/policies/policytype" type="java.lang.String" consumes="plain/text">
+ <route>
+ <removeHeaders pattern="*"/>
+ <doTry>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Create policy type')"/>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'policies','','update')"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:create-policy-type"/>
+ <to
+ uri="bean:org.onap.policy.clamp.policy.downloader.PolicyEngineController?method=synchronizeAllPolicies()"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+ <log loggingLevel="ERROR"
+ message="Create policy type request failed: ${exception.stacktrace}"/>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>500</constant>
+ </setHeader>
+ <setBody>
+ <simple>Create policy type request FAILED</simple>
+ </setBody>
+ </doCatch>
+ </doTry>
+ </route>
+ </post>
+
+ <get uri="/v2/clampInformation" outType="org.onap.policy.clamp.clds.model.ClampInformation"
+ produces="application/json">
+ <route>
+ <to
+ uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=getClampInformation()"/>
+ </route>
+ </get>
+ </rest>
+</rests>
diff --git a/runtime/src/main/resources/clds/camel/rest/clds-services.xml b/runtime/src/main/resources/clds/camel/rest/clds-services.xml
new file mode 100644
index 000000000..aa4c3cbee
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/rest/clds-services.xml
@@ -0,0 +1,24 @@
+<rests xmlns="http://camel.apache.org/schema/spring">
+ <rest>
+ <get uri="/v1/healthcheck" produces="application/json"
+ outType="org.onap.policy.clamp.clds.model.CldsHealthCheck">
+ <route>
+ <setBody>
+ <method ref="org.onap.policy.clamp.clds.service.CldsHealthcheckService"
+ method="gethealthcheck()" />
+ </setBody>
+ <when>
+ <simple> ${body} == 'NOT-OK'</simple>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>404</constant>
+ </setHeader>
+ <log loggingLevel="ERROR" message="HealthCheck failed" />
+ </when>
+ </route>
+ </get>
+
+ <get uri="/v1/user/getUser" produces="text/plain">
+ <to uri="bean:org.onap.policy.clamp.authorization.UserService?method=getUser()" />
+ </get>
+ </rest>
+</rests>
diff --git a/runtime/src/main/resources/clds/camel/routes/cds-flows.xml b/runtime/src/main/resources/clds/camel/routes/cds-flows.xml
new file mode 100644
index 000000000..10fcb091e
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/routes/cds-flows.xml
@@ -0,0 +1,64 @@
+<routes xmlns="http://camel.apache.org/schema/spring">
+ <route id="get-blueprint-workflow-list">
+ <from uri="direct:get-blueprint-workflow-list"/>
+ <log loggingLevel="INFO"
+ message="Getting blueprint workflow list from CDS"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('CDS', 'Getting workflow list from CDS')"/>
+ <doTry>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to query workflows from CDS : {{clamp.config.cds.url}}/api/v1/blueprint-model/workflows/blueprint-name/${exchangeProperty[blueprintName]}/version/${exchangeProperty[blueprintVersion]}"></log>
+ <toD uri="{{clamp.config.cds.url}}/api/v1/blueprint-model/workflows/blueprint-name/${exchangeProperty[blueprintName]}/version/${exchangeProperty[blueprintVersion]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.cds.userName}}&amp;authPassword={{clamp.config.cds.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+
+ <log loggingLevel="ERROR"
+ message="GET CDS request FAILED: ${exception.stacktrace}" />
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="get-blueprint-workflow-input-properties">
+ <from uri="direct:get-blueprint-workflow-input-properties"/>
+ <log loggingLevel="INFO"
+ message="Getting blueprint input properties for workflow"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('CDS', 'Getting input properties for workflow')"/>
+ <doTry>
+ <setHeader name="CamelHttpMethod">
+ <constant>POST</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to query input properties for workflow from CDS : {{clamp.config.cds.url}}/api/v1/blueprint-model/workflow-spec"></log>
+ <toD uri="{{clamp.config.cds.url}}/api/v1/blueprint-model/workflow-spec?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.cds.userName}}&amp;authPassword={{clamp.config.cds.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+
+ <log loggingLevel="ERROR"
+ message="GET CDS workflow input request FAILED: ${exception.stacktrace}" />
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+</routes> \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/camel/routes/dcae-flows.xml b/runtime/src/main/resources/clds/camel/routes/dcae-flows.xml
new file mode 100644
index 000000000..d74bd91bf
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/routes/dcae-flows.xml
@@ -0,0 +1,501 @@
+<routes xmlns="http://camel.apache.org/schema/spring">
+ <route id="deploy-loop">
+ <from uri="direct:deploy-loop"/>
+ <choice>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == true
+ </simple>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:deploy-loop-single-blueprint"/>
+ </when>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == false
+ </simple>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:deploy-loop-multi-blueprint"/>
+ </when>
+ </choice>
+ </route>
+ <route id="deploy-loop-multi-blueprint">
+ <from uri="direct:deploy-loop-multi-blueprint"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Deploying the blueprints for loop: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Deploying the loop with multiple blueprints')"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="microServicePolicy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log
+ loggingLevel="INFO"
+ message="Processing Micro Service Policy: ${exchangeProperty[microServicePolicy].getName()}"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <setBody>
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getDeployPayload(${exchangeProperty[loopObject]},${exchangeProperty[microServicePolicy]})"/>
+ </setBody>
+ <setProperty name="dcaeDeploymentId">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="generateDeploymentId()"/>
+ </setProperty>
+ <setHeader name="CamelHttpMethod">
+ <constant>PUT</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to deploy loop: {{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[dcaeDeploymentId]}"></log>
+ <toD
+ uri="{{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[dcaeDeploymentId]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})"/>
+ </setProperty>
+ <setProperty name="dcaeStatusUrl">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getStatusUrl(${exchangeProperty[dcaeResponse]})"/>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.policy.microservice.MicroServicePolicyService?method=updateDcaeDeploymentFields(${exchangeProperty[microServicePolicy]},${exchangeProperty[dcaeDeploymentId]},${exchangeProperty[dcaeStatusUrl]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('Deploy for the micro service: ${exchangeProperty[microServicePolicy].getName()} - ${header.CamelHttpResponseCode} : ${header.CamelHttpResponseText}','INFO','DCAE',${exchangeProperty[loopObject]})"/>
+ </split>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>false</constant>
+ </handled>
+ <setProperty name="logMessage">
+ <simple>DEPLOY micro service failed
+ (MicroService name:${exchangeProperty[microServicePolicy].getName()}),
+ Dep-id:${exchangeProperty[dcaeDeploymentId]},
+ StatusUrl:${exchangeProperty[dcaeStatusUrl]})
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>DCAE</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="deploy-loop-single-blueprint">
+ <from uri="direct:deploy-loop-single-blueprint"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Deploying the loop: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Deploying the loop')"/>
+ <setBody>
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getDeployPayload(${exchangeProperty[loopObject]})"/>
+ </setBody>
+ <setProperty name="dcaeDeploymentId">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="generateDeploymentId()"/>
+ </setProperty>
+ <setHeader name="CamelHttpMethod">
+ <constant>PUT</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to deploy loop: {{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[dcaeDeploymentId]}"></log>
+ <toD
+ uri="{{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[dcaeDeploymentId]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})"/>
+ </setProperty>
+
+
+ <setProperty name="dcaeStatusUrl">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getStatusUrl(${exchangeProperty[dcaeResponse]})"/>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateDcaeDeploymentFields(${exchangeProperty[loopObject]},${exchangeProperty[dcaeDeploymentId]},${exchangeProperty[dcaeStatusUrl]})"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>DEPLOY loop status
+ (Dep-id:${exchangeProperty[dcaeDeploymentId]},
+ StatusUrl:${exchangeProperty[dcaeStatusUrl]})
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>DCAE</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="undeploy-loop">
+ <from uri="direct:undeploy-loop"/>
+ <choice>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == true
+ </simple>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:undeploy-loop-single-blueprint"/>
+ </when>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == false
+ </simple>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:undeploy-loop-multi-blueprint"/>
+ </when>
+ </choice>
+ </route>
+ <route id="undeploy-loop-multi-blueprint">
+ <from uri="direct:undeploy-loop-multi-blueprint"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Undeploying the blueprints for loop: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Undeploying the loop with multiple blueprints')"/>
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="microServicePolicy">
+ <simple>${body}</simple>
+ </setProperty>
+ <log
+ loggingLevel="INFO"
+ message="Processing Micro Service Policy: ${exchangeProperty[microServicePolicy].getName()}"/>
+ <choice>
+ <when>
+ <simple>${exchangeProperty[microServicePolicy].getDcaeDeploymentId()} != null
+ </simple>
+ <setBody>
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getUndeployPayload(${exchangeProperty[microServicePolicy]})"/>
+ </setBody>
+ <setHeader name="CamelHttpMethod">
+ <constant>DELETE</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to undeploy loop: {{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[microServicePolicy].getDcaeDeploymentId()}"></log>
+ <toD
+ uri="{{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[microServicePolicy].getDcaeDeploymentId()}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})"/>
+ </setProperty>
+ <setProperty name="dcaeStatusUrl">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getStatusUrl(${exchangeProperty[dcaeResponse]})"/>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.policy.microservice.MicroServicePolicyService?method=updateDcaeDeploymentFields(${exchangeProperty[microServicePolicy]},null,${exchangeProperty[dcaeStatusUrl]})"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('Undeploy for the micro service: ${exchangeProperty[microServicePolicy].getName()} - ${header.CamelHttpResponseCode} : ${header.CamelHttpResponseText}','INFO','DCAE',${exchangeProperty[loopObject]})"/>
+ </when>
+ <otherwise>
+ <log loggingLevel="WARN"
+ message="Cannot Undeploy for the micro service: ${exchangeProperty[microServicePolicy].getName()}, the Deployment ID does not exist !"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('Cannot Undeploy for the micro service: ${exchangeProperty[microServicePolicy].getName()}, the Deployment ID does not exist !','WARNING','DCAE',${exchangeProperty[loopObject]})"/>
+ </otherwise>
+ </choice>
+ </split>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>false</constant>
+ </handled>
+ <setProperty name="logMessage">
+ <simple>UNDEPLOY micro service failed
+ (MicroService name:${exchangeProperty[microServicePolicy].getName()})
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>DCAE</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="undeploy-loop-single-blueprint">
+ <from uri="direct:undeploy-loop-single-blueprint"/>
+ <log loggingLevel="INFO"
+ message="Undeploying the loop: ${exchangeProperty[loopObject].getName()} : ${exchangeProperty[loopObject].getDcaeDeploymentId()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Undeploying the loop')"/>
+ <choice>
+ <when>
+ <simple>${exchangeProperty[loopObject].getDcaeDeploymentId()} != null</simple>
+ <doTry>
+ <setBody>
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getUndeployPayload(${exchangeProperty[loopObject]})"/>
+ </setBody>
+ <setHeader name="CamelHttpMethod">
+ <constant>DELETE</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to undeploy loop: {{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[loopObject].getDcaeDeploymentId()}"></log>
+ <toD
+ uri="{{clamp.config.dcae.deployment.url}}/dcae-deployments/${exchangeProperty[loopObject].getDcaeDeploymentId()}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})"/>
+ </setProperty>
+ <setProperty name="dcaeStatusUrl">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="getStatusUrl(${exchangeProperty[dcaeResponse]})"/>
+ </setProperty>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateDcaeDeploymentFields(${exchangeProperty[loopObject]},null,${exchangeProperty[dcaeStatusUrl]})"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>UNDEPLOY loop status</simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>DCAE</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </when>
+ <otherwise>
+ <log loggingLevel="WARN"
+ message="Cannot Undeploy for the loop: ${exchangeProperty[loopObject].getName()}, the Deployment ID does not exist !"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('Cannot Undeploy for the loop: ${exchangeProperty[loopObject].getName()}, the Deployment ID does not exist !','WARNING',${exchangeProperty[loopObject]})"/>
+ </otherwise>
+ </choice>
+ </route>
+ <route id="get-dcae-deployment-status">
+ <from uri="direct:get-dcae-deployment-status"/>
+ <log loggingLevel="INFO"
+ message="Getting DCAE deployment status for loop: ${exchangeProperty[loopObject].getName()} - ${exchangeProperty[dcaeComponent].getComponentName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Getting Deployment status')"/>
+ <doTry>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to query microservice deployment status: ${exchangeProperty[getStatusUrlModified]}"></log>
+ <choice>
+ <when>
+ <simple>${exchangeProperty[getStatusUrl].contains("?")} == true
+ </simple>
+ <setProperty name="uriSeparator">
+ <simple>&amp;</simple>
+ </setProperty>
+ </when>
+ <otherwise>
+ <setProperty name="uriSeparator">
+ <simple>?</simple>
+ </setProperty>
+ </otherwise>
+ </choice>
+ <toD
+ uri="${exchangeProperty[getStatusUrl]}${exchangeProperty[uriSeparator]}bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+
+ <log loggingLevel="ERROR"
+ message="GET DCAE deployment request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET DCAE deployment request failed, Error reported: ${exception.message}','ERROR',${exchangeProperty[loopObject]})"/>
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>DCAE deployment status</simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>DCAE</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="get-dcae-blueprint-inventory">
+ <from uri="direct:get-dcae-blueprint-inventory"/>
+ <log loggingLevel="INFO"
+ message="Getting DCAE blueprint id in inventory"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Getting blueprint id in inventory')"/>
+ <doTry>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to query Dcae inventory Loop status: {{clamp.config.dcae.inventory.url}}/dcae-service-types?${header[CamelHttpQuery]}"></log>
+ <toD
+ uri="{{clamp.config.dcae.inventory.url}}/dcae-service-types?asdcResourceId=${exchangeProperty[blueprintResourceId]}&amp;asdcServiceId=${exchangeProperty[blueprintServiceId]}&amp;typeName=${exchangeProperty[blueprintName]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+
+ </route>
+ <route id="get-all-dcae-blueprint-inventory">
+ <from uri="direct:get-all-dcae-blueprint-inventory"/>
+ <log loggingLevel="INFO"
+ message="Getting all DCAE blueprint from inventory"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('DCAE', 'Getting all blueprint from inventory')"/>
+ <doTry>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to query Blueprints from DCAE inventory: {{clamp.config.dcae.inventory.url}}/dcae-service-types?${header[CamelHttpQuery]}"></log>
+ <toD uri="{{clamp.config.dcae.inventory.url}}/dcae-service-types;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.dcae.deployment.userName}}&amp;authPassword={{clamp.config.dcae.deployment.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <setProperty name="dcaeResponseList">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertToDcaeInventoryResponse(${body})"/>
+ </setProperty>
+ <split>
+ <simple>${exchangeProperty[dcaeResponseList]}</simple>
+ <convertBodyTo type="org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse"/>
+ <setProperty name="dcaeResponse">
+ <simple>${body}</simple>
+ </setProperty>
+ <to uri="bean:org.onap.policy.clamp.clds.model.dcae.DcaeInventoryCache?method=addDcaeInventoryResponse(${exchangeProperty[dcaeResponse]})"/>
+ </split>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+</routes> \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/camel/routes/loop-flows.xml b/runtime/src/main/resources/clds/camel/routes/loop-flows.xml
new file mode 100644
index 000000000..4a3cc84b2
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/routes/loop-flows.xml
@@ -0,0 +1,256 @@
+<routes xmlns="http://camel.apache.org/schema/spring">
+ <route id="load-loop">
+ <from uri="direct:load-loop" />
+ <setBody>
+ <simple>${header.loopName}</simple>
+ </setBody>
+ <setProperty name="loopObject">
+ <method ref="org.onap.policy.clamp.loop.LoopService" method="getLoop" />
+ </setProperty>
+
+ <when>
+ <simple>${exchangeProperty[loopObject]} == null</simple>
+ <setHeader name="CamelHttpResponseCode">
+ <constant>404</constant>
+ </setHeader>
+ <log loggingLevel="WARN" message="Loop not found in database: ${body}" />
+ <stop />
+ </when>
+ </route>
+ <route id="update-policy-status-for-loop">
+ <from uri="direct:update-policy-status-for-loop" />
+ <setProperty name="policyComponent">
+ <simple>${exchangeProperty[loopObject].getComponent('POLICY')}
+ </simple>
+ </setProperty>
+ <setProperty name="policyFound">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <setProperty name="policyDeployed">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Processing all MICRO-SERVICES policies defined in loop ${exchangeProperty[loopObject].getName()}" />
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="policyName">
+ <simple>${body.getName()}</simple>
+ </setProperty>
+ <setProperty name="policyType">
+ <simple>${body.getPolicyModel().getPolicyModelType()}</simple>
+ </setProperty>
+ <setProperty name="policyTypeVersion">
+ <simple>${body.getPolicyModel().getVersion()}</simple>
+ </setProperty>
+ <setProperty name="policyPdpGroup">
+ <simple>${body.getPdpGroup()}</simple>
+ </setProperty>
+ <setProperty name="policyVersion">
+ <simple>1.0.0</simple>
+ </setProperty>
+ <setBody>
+ <constant>null</constant>
+ </setBody>
+ <log loggingLevel="INFO"
+ message="Processing Micro Service Policy: ${exchangeProperty[policyName]} of type ${exchangeProperty[policyType]}" />
+ <to uri="direct:verify-one-policy" />
+ </split>
+ <log loggingLevel="INFO"
+ message="Processing all OPERATIONAL policies defined in loop ${exchangeProperty[loopObject].getName()}" />
+ <split>
+ <simple>${exchangeProperty[loopObject].getOperationalPolicies()}
+ </simple>
+ <setProperty name="policyName">
+ <simple>${body.getName()}</simple>
+ </setProperty>
+ <setProperty name="policyType">
+ <simple>${body.getPolicyModel().getPolicyModelType()}</simple>
+ </setProperty>
+ <setProperty name="policyTypeVersion">
+ <simple>${body.getPolicyModel().getVersion()}</simple>
+ </setProperty>
+ <setProperty name="policyVersion">
+ <simple>1.0.0</simple>
+ </setProperty>
+ <setProperty name="policyPdpGroup">
+ <simple>${body.getPdpGroup()}</simple>
+ </setProperty>
+ <setBody>
+ <constant>null</constant>
+ </setBody>
+ <log loggingLevel="INFO"
+ message="Processing Operational Policy: ${exchangeProperty[policyName]} of type ${exchangeProperty[policyType]}" />
+ <to uri="direct:verify-one-policy" />
+ </split>
+ <setProperty name="policyState">
+ <simple> ${exchangeProperty[policyComponent].getState()}
+ </simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="Policy state set to: ${exchangeProperty[policyState].getStateName()}" />
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('Policy state set to: ${exchangeProperty[policyState].getStateName()}','INFO','POLICY',${exchangeProperty[loopObject]})" />
+ </route>
+ <route id="update-dcae-status-for-loop">
+ <from uri="direct:update-dcae-status-for-loop" />
+ <log loggingLevel="INFO"
+ message="Updating DCAE status for loop: ${exchangeProperty[loopObject].getName()}" />
+ <choice>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == true
+ </simple>
+ <setProperty name="dcaeComponent">
+ <simple>${exchangeProperty[loopObject].getComponent('DCAE')}</simple>
+ </setProperty>
+ <when>
+ <simple>${exchangeProperty[loopObject].getDcaeDeploymentStatusUrl()} != null
+ </simple>
+ <setProperty name="getStatusUrl">
+ <simple>${exchangeProperty[loopObject].getDcaeDeploymentStatusUrl()}</simple>
+ </setProperty>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:get-dcae-deployment-status" />
+ <when>
+ <simple> ${header.CamelHttpResponseCode} == 200 </simple>
+ <convertBodyTo type="java.lang.String" />
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})" />
+ </setProperty>
+ </when>
+ </when>
+ <setProperty name="dcaeState">
+ <simple> ${exchangeProperty[dcaeComponent].computeState(*)}
+ </simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="DCAE state set to: ${exchangeProperty[dcaeState].getStateName()} - DCAE message: ${exchangeProperty[dcaeResponse].getError()}" />
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('DCAE state set to: ${exchangeProperty[dcaeState].getStateName()} - message: ${exchangeProperty[dcaeResponse].getError()}','INFO','DCAE',${exchangeProperty[loopObject]})" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['loopObject'].getLoopTemplate().getUniqueBlueprint()} == false
+ </simple>
+ <split>
+ <simple>${exchangeProperty[loopObject].getMicroServicePolicies()}
+ </simple>
+ <setProperty name="microServicePolicy">
+ <simple>${body}</simple>
+ </setProperty>
+ <setProperty name="dcaeComponent">
+ <simple>${exchangeProperty[loopObject].getComponent('DCAE_' + ${exchangeProperty[microServicePolicy].getName()})}</simple>
+ </setProperty>
+ <when>
+ <simple>${exchangeProperty[microServicePolicy].getDcaeDeploymentStatusUrl()} != null
+ </simple>
+ <setProperty name="getStatusUrl">
+ <simple>${exchangeProperty[microServicePolicy].getDcaeDeploymentStatusUrl()}</simple>
+ </setProperty>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:get-dcae-deployment-status" />
+ <when>
+ <simple> ${header.CamelHttpResponseCode} == 200 </simple>
+ <convertBodyTo type="java.lang.String" />
+ <setProperty name="dcaeResponse">
+ <method ref="org.onap.policy.clamp.loop.components.external.DcaeComponent"
+ method="convertDcaeResponse(${body})" />
+ </setProperty>
+ </when>
+ </when>
+ <setProperty name="dcaeState">
+ <simple> ${exchangeProperty[dcaeComponent].computeState(*)}
+ </simple>
+ </setProperty>
+ <log loggingLevel="INFO"
+ message="DCAE state set to: ${exchangeProperty[dcaeState].getStateName()} - DCAE message: ${exchangeProperty[dcaeResponse].getError()}" />
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('DCAE state set to: ${exchangeProperty[dcaeState].getStateName()} - message: ${exchangeProperty[dcaeResponse].getError()}','INFO','DCAE',${exchangeProperty[microServicePolicy]})" />
+ </split>>
+ </when>
+ </choice>
+ </route>
+ <route id="direct:update-loop-state">
+ <from uri="direct:update-loop-state" />
+ <log loggingLevel="INFO"
+ message="Updating status for loop: ${exchangeProperty[loopObject].getName()}" />
+ <choice>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'BLUEPRINT_DEPLOYED' &amp;&amp; ${exchangeProperty['policyState'].getStateName()}
+ == 'NOT_SENT'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'DESIGN')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} == 'IN_ERROR' ||
+ ${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_INSTALLATION_FAILED'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'IN_ERROR')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_UNINSTALLATION_FAILED' ||
+ ${exchangeProperty['policyState'].getStateName()} == 'IN_ERROR'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'IN_ERROR')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_INSTALLED_SUCCESSFULLY' &amp;&amp;
+ ${exchangeProperty['policyState'].getStateName()} == 'SENT_AND_DEPLOYED'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'RUNNING')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_INSTALLED_SUCCESSFULLY' &amp;&amp;
+ ${exchangeProperty['policyState'].getStateName()} == 'SENT'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'STOPPED')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'BLUEPRINT_DEPLOYED' || ${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_UNINSTALLED_SUCCESSFULLY' &amp;&amp;
+ ${exchangeProperty['policyState'].getStateName()} == 'SENT_AND_DEPLOYED'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'SUBMITTED')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'PROCESSING_MICROSERVICE_INSTALLATION' ||
+ ${exchangeProperty['dcaeState'].getStateName()} ==
+ 'PROCESSING_MICROSERVICE_UNINSTALLATION' &amp;&amp;
+ ${exchangeProperty['policyState'].getStateName()} == 'SENT_AND_DEPLOYED'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'WAITING')" />
+ </when>
+ <when>
+ <simple>${exchangeProperty['dcaeState'].getStateName()} ==
+ 'MICROSERVICE_INSTALLED_SUCCESSFULLY' &amp;&amp;
+ ${exchangeProperty['policyState'].getStateName()} != 'NOT_SENT'
+ </simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.LoopService?method=updateLoopState(${exchangeProperty[loopObject]},'DEPLOYED')" />
+ </when>
+ </choice>
+ <log loggingLevel="INFO"
+ message="New loop state is: ${exchangeProperty[loopObject].getLastComputedState().toString()}" />
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('New loop state is: ${exchangeProperty[loopObject].getLastComputedState().toString()}','INFO',${exchangeProperty[loopObject]})" />
+
+ </route>
+</routes> \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/camel/routes/policy-flows.xml b/runtime/src/main/resources/clds/camel/routes/policy-flows.xml
new file mode 100644
index 000000000..01862692c
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/routes/policy-flows.xml
@@ -0,0 +1,654 @@
+<routes xmlns="http://camel.apache.org/schema/spring">
+ <route id="verify-one-policy">
+ <from uri="direct:verify-one-policy"/>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:get-policy"/>
+ <when>
+ <simple>${header.CamelHttpResponseCode} != 200</simple>
+ <setProperty name="policyFound">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <log loggingLevel="WARN"
+ message="At least one policy has not been found on policy engine: ${exchangeProperty[policyName]}"/>
+ </when>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <to uri="direct:get-deployment-policy"/>
+ <when>
+ <simple>${header.CamelHttpResponseCode} != 200</simple>
+ <setProperty name="policyDeployed">
+ <simple resultType="java.lang.Boolean">false</simple>
+ </setProperty>
+ <log loggingLevel="WARN"
+ message="At least one policy has not been deployed on policy engine: ${exchangeProperty[policyName]}"/>
+ </when>
+ <setProperty name="newPolicyState">
+ <simple>${exchangeProperty[policyComponent].computeState(*)}</simple>
+ </setProperty>
+ </route>
+
+ <route id="get-policy">
+ <from uri="direct:get-policy"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Getting Policy: ${exchangeProperty[policyName]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Get Policy')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get policy: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyType]}/versions/${exchangeProperty[policyTypeVersion]}/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyType]}/versions/${exchangeProperty[policyTypeVersion]}/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+
+ <log loggingLevel="ERROR"
+ message="GET policy request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET policy request failed, Error reported: ${exception.message}','ERROR',${exchangeProperty[loopObject]})"/>
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>${exchangeProperty[policyName]} GET
+ Policy status
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="get-deployment-policy">
+ <from uri="direct:get-deployment-policy"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Getting the policy deployment in PDP: ${exchangeProperty[policyName]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Getting the policy deployment in PDP')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get policy deployment status: {{clamp.config.policy.pap.url}}/policy/pap/v1/policies/status/${exchangeProperty[policyPdpGroup]}/${exchangeProperty[policyName]}/1.0.0"></log>
+ <toD
+ uri="{{clamp.config.policy.pap.url}}/policy/pap/v1/policies/status/${exchangeProperty[policyPdpGroup]}/${exchangeProperty[policyName]}/1.0.0?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.pap.userName}}&amp;authPassword={{clamp.config.policy.pap.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>true</constant>
+ </handled>
+
+ <log loggingLevel="ERROR"
+ message="GET policy request FAILED for loop: ${header.loopName}, ${exception.stacktrace}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('GET policy request failed, Error reported: ${exception.message}','ERROR',${exchangeProperty[loopObject]})"/>
+ </doCatch>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>${exchangeProperty[policyName]} GET Policy deployment
+ status
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="create-policy-from-loop-object">
+ <from uri="direct:create-policy-from-loop-object"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Creating Policy from loop object: ${exchangeProperty[policy].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Creating Policy from loop object')"/>
+ <setBody>
+ <simple>${exchangeProperty[policy].createPolicyPayload()}
+ </simple>
+ </setBody>
+ <setProperty name="policyModelType">
+ <simple>${exchangeProperty[policy].getPolicyModel().getPolicyModelType()}</simple>
+ </setProperty>
+ <setProperty name="policyModelVersion">
+ <simple>${exchangeProperty[policy].getPolicyModel().getVersion()}</simple>
+ </setProperty>
+ <to uri="direct:create-policy"/>
+ <doFinally>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>${exchangeProperty[policy].getName()} creation
+ status
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="delete-policy-from-loop-object">
+ <from uri="direct:delete-policy-from-loop-object"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Deleting Policy in a loop: ${exchangeProperty[policy].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Delete Policy in a loop')"/>
+ <setProperty name="policyModelType">
+ <simple>${exchangeProperty[policy].getPolicyModel().getPolicyModelType()}</simple>
+ </setProperty>
+ <setProperty name="policyModelVersion">
+ <simple>${exchangeProperty[policy].getPolicyModel().getVersion()}</simple>
+ </setProperty>
+ <setProperty name="policyName">
+ <simple>${exchangeProperty[policy].getName()}</simple>
+ </setProperty>
+ <setProperty name="policyVersion">
+ <simple>1.0.0</simple>
+ </setProperty>
+ <to uri="direct:delete-policy"/>
+ <doFinally>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>${exchangeProperty[policy].getName()} removal
+ status
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="add-policies-from-loop-to-pdp-group">
+ <from uri="direct:add-policies-from-loop-to-pdp-group"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Adding loop policies to PDP Group: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Add policies to PDP group')"/>
+ <setBody>
+ <simple>
+ ${exchangeProperty[loopObject].getComponent("POLICY").createPoliciesPayloadPdpGroup(exchangeProperty[loopObject],"POST")}
+ </simple>
+ </setBody>
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ <to uri="direct:add-multiple-policies-to-pdp-group"/>
+ <doFinally>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>PDP Group push ALL status</simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="remove-all-policy-from-active-pdp-group">
+ <from uri="direct:remove-all-policy-from-active-pdp-group"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Removing loop policies from PDP Group: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Remove policies from PDP group')"/>
+ <setBody>
+ <simple>
+ ${exchangeProperty[loopObject].getComponent("POLICY").createPoliciesPayloadPdpGroup(exchangeProperty[loopObject],"DELETE")}
+ </simple>
+ </setBody>
+ <setHeader name="CamelHttpMethod">
+ <constant>POST</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to remove policies from PDP Group: {{clamp.config.policy.pap.url}}/policy/pap/v1/pdps/deployments/batch"></log>
+ <toD
+ uri="{{clamp.config.policy.pap.url}}/policy/pap/v1/pdps/deployments/batch?bridgeEndpoint=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;useSystemProperties=true&amp;authUsername={{clamp.config.policy.pap.userName}}&amp;authPassword={{clamp.config.policy.pap.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ <setProperty name="logMessage">
+ <simple>PDP Group remove ALL status</simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="remove-one-policy-from-active-pdp-group">
+ <from uri="direct:remove-one-policy-from-active-pdp-group"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Removing policy from active PDP group for loop: ${exchangeProperty[loopObject].getName()}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Removing one policy PDP group')"/>
+ <setProperty name="policyVersion">
+ <simple>1.0.0</simple>
+ </setProperty>
+ <to uri="direct:undeploy-one-policy-from-pap"/>
+ <setProperty name="logMessage">
+ <simple>${exchangeProperty[policyName]} PDP Group removal status
+ </simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ <doCatch>
+ <exception>java.lang.Exception</exception>
+ <handled>
+ <constant>false</constant>
+ </handled>
+ <setProperty name="logMessage">
+ <simple>PDP Group removal, Error reported: ${exception}</simple>
+ </setProperty>
+ <setProperty name="logComponent">
+ <simple>POLICY</simple>
+ </setProperty>
+ <to uri="direct:dump-loop-log-http-response"/>
+ </doCatch>
+ <doFinally>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <!-- Camel routes not related to Loop context -->
+ <route id="get-all-policy-models">
+ <from uri="direct:get-all-policy-models"/>
+ <doTry>
+ <log loggingLevel="INFO" message="Getting all the policy models"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Getting all the policy models')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get all policy models: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="get-policy-tosca-model">
+ <from uri="direct:get-policy-tosca-model"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Getting the policy tosca model: ${exchangeProperty[policyModelType]}/${exchangeProperty[policyModelVersion]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Getting the policy model')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get policy model: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="get-all-pdp-groups">
+ <from uri="direct:get-all-pdp-groups"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Getting the list of PDP Groups"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Getting the PDP Group list')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get policy model: {{clamp.config.policy.pap.url}}/policy/pap/v1/pdps"></log>
+ <toD
+ uri="{{clamp.config.policy.pap.url}}/policy/pap/v1/pdps?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.pap.userName}}&amp;authPassword={{clamp.config.policy.pap.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="get-all-policies">
+ <from uri="direct:get-all-policies"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Getting the policies list"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Getting the policies list')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>GET</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to get policies list: {{clamp.config.policy.api.url}}/policy/api/v1/policies"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policies?bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <convertBodyTo type="java.lang.String"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="add-multiple-policies-to-pdp-group">
+ <from uri="direct:add-multiple-policies-to-pdp-group"/>
+ <!-- Body should come from outside, expect a json describing the policy -->
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Add policies to PDP group"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Add policies to PDP group')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>POST</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to add/remove policies in batch to PDP Group: {{clamp.config.policy.pap.url}}/policy/pap/v1/pdps/deployments/batch"></log>
+ <toD
+ uri="{{clamp.config.policy.pap.url}}/policy/pap/v1/pdps/deployments/batch?bridgeEndpoint=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;useSystemProperties=true&amp;authUsername={{clamp.config.policy.pap.userName}}&amp;authPassword={{clamp.config.policy.pap.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="undeploy-one-policy-from-pap">
+ <from uri="direct:undeploy-one-policy-from-pap"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Undeploy POLICY from PAP: ${exchangeProperty[policyName]}/${exchangeProperty[policyVersion]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Undeploy POLICY from PAP')"/>
+ <setBody>
+ <constant>null</constant>
+ </setBody>
+ <setHeader name="CamelHttpMethod">
+ <constant>DELETE</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to delete policy from PDP Group: {{clamp.config.policy.pap.url}}/pdps/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}"></log>
+ <toD
+ uri="{{clamp.config.policy.pap.url}}/policy/pap/v1/pdps/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.policy.pap.userName}}&amp;authPassword={{clamp.config.policy.pap.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+
+ <route id="create-policy">
+ <!-- Body should come from outside, expect a json describing the policy -->
+ <from uri="direct:create-policy"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Create Policy from model ${exchangeProperty[policyModelType]}/${exchangeProperty[policyModelVersion]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Create Policy')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>POST</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/json</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to create policy: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}/policies"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}/policies?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="delete-policy">
+ <from uri="direct:delete-policy"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Deleting Policy: ${exchangeProperty[policyName]}"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Delete Policy')"/>
+ <setBody>
+ <constant>null</constant>
+ </setBody>
+ <setHeader name="CamelHttpMethod">
+ <constant>DELETE</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to delete policy: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes/${exchangeProperty[policyModelType]}/versions/${exchangeProperty[policyModelVersion]}/policies/${exchangeProperty[policyName]}/versions/${exchangeProperty[policyVersion]}?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;deleteWithBody=false&amp;mapHttpMessageBody=false&amp;mapHttpMessageFormUrlEncodedBody=false&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+ <route id="create-policy-type">
+ <from uri="direct:create-policy-type"/>
+ <doTry>
+ <log loggingLevel="INFO"
+ message="Creating Policy type"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('Policy', 'Create policy typ')"/>
+ <setHeader name="CamelHttpMethod">
+ <constant>POST</constant>
+ </setHeader>
+ <setHeader name="Content-Type">
+ <constant>application/yaml</constant>
+ </setHeader>
+ <setHeader name="X-ONAP-RequestID">
+ <simple>${exchangeProperty[X-ONAP-RequestID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-InvocationID">
+ <simple>${exchangeProperty[X-ONAP-InvocationID]}
+ </simple>
+ </setHeader>
+ <setHeader name="X-ONAP-PartnerName">
+ <simple>${exchangeProperty[X-ONAP-PartnerName]}
+ </simple>
+ </setHeader>
+ <log loggingLevel="INFO"
+ message="Endpoint to create policy type: {{clamp.config.policy.api.url}}/policy/api/v1/policytypes"></log>
+ <toD
+ uri="{{clamp.config.policy.api.url}}/policy/api/v1/policytypes?bridgeEndpoint=true&amp;useSystemProperties=true&amp;mapHttpMessageHeaders=false&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authUsername={{clamp.config.policy.api.userName}}&amp;authPassword={{clamp.config.policy.api.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+
+ <doFinally>
+ <to uri="direct:reset-raise-http-exception-flag"/>
+ <to
+ uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+ </doFinally>
+ </doTry>
+ </route>
+</routes> \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/camel/routes/utils-flows.xml b/runtime/src/main/resources/clds/camel/routes/utils-flows.xml
new file mode 100644
index 000000000..90900f842
--- /dev/null
+++ b/runtime/src/main/resources/clds/camel/routes/utils-flows.xml
@@ -0,0 +1,28 @@
+<routes xmlns="http://camel.apache.org/schema/spring">
+ <route id="reset-raise-http-exception-flag">
+ <from uri="direct:reset-raise-http-exception-flag" />
+ <setProperty name="raiseHttpExceptionFlag">
+ <simple resultType="java.lang.Boolean">true</simple>
+ </setProperty>
+ </route>
+
+ <route id="dump-loop-log-http-response">
+ <from uri="direct:dump-loop-log-http-response" />
+ <log loggingLevel="INFO"
+ message="${exchangeProperty[logMessage]} - ${header.CamelHttpResponseCode} : ${header.CamelHttpResponseText}" />
+ <choice>
+ <when>
+ <simple>${exchangeProperty[logComponent]} == null</simple>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLog('${exchangeProperty[logMessage]} - ${header.CamelHttpResponseCode} : ${header.CamelHttpResponseText}','INFO',${exchangeProperty[loopObject]})" />
+ </when>
+ <otherwise>
+ <to
+ uri="bean:org.onap.policy.clamp.loop.log.LoopLogService?method=addLogForComponent('${exchangeProperty[logMessage]} - ${header.CamelHttpResponseCode} : ${header.CamelHttpResponseText}','INFO','${exchangeProperty[logComponent]}',${exchangeProperty[loopObject]})" />
+ <setProperty name="logComponent">
+ <constant>null</constant>
+ </setProperty>
+ </otherwise>
+ </choice>
+ </route>
+</routes> \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/clds-users.json b/runtime/src/main/resources/clds/clds-users.json
new file mode 100644
index 000000000..5a7f43841
--- /dev/null
+++ b/runtime/src/main/resources/clds/clds-users.json
@@ -0,0 +1,33 @@
+[
+ {
+ "user": "admin",
+ "password": "$2a$10$H/e21kl04Dw9C978CHuM7OewyMGUN5WGzAAx7SgIaR4ix8.wTcssi",
+ "permissions": [
+ "org.onap.clamp.clds.cl|dev|read",
+ "org.onap.clamp.clds.cl|dev|update",
+ "org.onap.clamp.clds.cl.manage|dev|*",
+ "org.onap.clamp.clds.cl.event|dev|*",
+ "org.onap.clamp.clds.filter.vf|dev|*",
+ "org.onap.clamp.clds.template|dev|read",
+ "org.onap.clamp.clds.template|dev|update",
+ "org.onap.clamp.clds.tosca|dev|read",
+ "org.onap.clamp.clds.tosca|dev|update",
+ "org.onap.clamp.clds.policies|dev|read",
+ "org.onap.clamp.clds.policies|dev|update"
+ ]
+ },
+ {
+ "user": "cs0008",
+ "password": "$2a$10$H/e21kl04Dw9C978CHuM7OewyMGUN5WGzAAx7SgIaR4ix8.wTcssi",
+ "permissions": [
+ "org.onap.clamp.clds.cl|dev|read",
+ "org.onap.clamp.clds.cl|dev|update",
+ "org.onap.clamp.clds.cl.manage|dev|*",
+ "org.onap.clamp.clds.filter.vf|dev|*",
+ "org.onap.clamp.clds.template|dev|read",
+ "org.onap.clamp.clds.template|dev|update",
+ "org.onap.clamp.clds.tosca|dev|read",
+ "org.onap.clamp.clds.tosca|dev|update"
+ ]
+ }
+]
diff --git a/runtime/src/main/resources/clds/json-schema/operational_policies/operational_policy.json b/runtime/src/main/resources/clds/json-schema/operational_policies/operational_policy.json
new file mode 100644
index 000000000..973028316
--- /dev/null
+++ b/runtime/src/main/resources/clds/json-schema/operational_policies/operational_policy.json
@@ -0,0 +1,320 @@
+{
+ "type": "object",
+ "title": "Configuration",
+ "required": [
+ "operational_policy"
+ ],
+ "properties": {
+ "operational_policy": {
+ "type": "object",
+ "title": "Related Parameters",
+ "required": [
+ "controlLoop",
+ "policies"
+ ],
+ "properties": {
+ "controlLoop": {
+ "type": "object",
+ "title": "Control Loop details",
+ "required": [
+ "timeout",
+ "abatement",
+ "trigger_policy",
+ "controlLoopName"
+ ],
+ "properties": {
+ "timeout": {
+ "type": "string",
+ "title": "Overall Time Limit",
+ "default": "0",
+ "format": "number"
+ },
+ "abatement": {
+ "type": "string",
+ "title": "Abatement",
+ "enum": [
+ "True",
+ "False"
+ ]
+ },
+ "trigger_policy": {
+ "type": "string",
+ "title": "Policy Decision Entry"
+ },
+ "controlLoopName": {
+ "type": "string",
+ "title": "Control loop name",
+ "readOnly": "True"
+ }
+ }
+ },
+ "policies": {
+ "uniqueItems": "true",
+ "id": "policies_array",
+ "type": "array",
+ "title": "Policy Decision Tree",
+ "format": "tabs-top",
+ "items": {
+ "title": "Policy Decision",
+ "type": "object",
+ "id": "policy_item",
+ "headerTemplate": "{{self.id}} - {{self.recipe}}",
+ "format": "categories",
+ "basicCategoryTitle": "recipe",
+ "required": [
+ "id",
+ "retry",
+ "timeout",
+ "actor",
+ "success",
+ "failure",
+ "failure_timeout",
+ "failure_retries",
+ "failure_exception",
+ "failure_guard",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "default": "Policy 1",
+ "title": "Policy ID",
+ "type": "string"
+ },
+ "retry": {
+ "default": "0",
+ "title": "Number of Retry",
+ "type": "string",
+ "format": "number"
+ },
+ "timeout": {
+ "default": "0",
+ "title": "Timeout",
+ "type": "string",
+ "format": "number"
+ },
+ "actor": {
+ "type": "object",
+ "title": "Actor",
+ "anyOf": [
+ {
+ "title": "APPC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "APPC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SO",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SO",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VF Module Create",
+ "VF Module Delete"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SDNC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SDNC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Reroute",
+ "BandwidthOnDemand"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "VFC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "VFC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "CDS",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "CDS",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "object",
+ "anyOf": [
+ {
+ "title": "user-defined",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "user-defined",
+ "format": "textarea"
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "default": "",
+ "format": "textarea"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "success": {
+ "default": "final_success",
+ "title": "When Success",
+ "type": "string"
+ },
+ "failure": {
+ "default": "final_failure",
+ "title": "When Failure",
+ "type": "string"
+ },
+ "failure_timeout": {
+ "default": "final_failure_timeout",
+ "title": "When Failure Timeout",
+ "type": "string"
+ },
+ "failure_retries": {
+ "default": "final_failure_retries",
+ "title": "When Failure Retries",
+ "type": "string"
+ },
+ "failure_exception": {
+ "default": "final_failure_exception",
+ "title": "When Failure Exception",
+ "type": "string"
+ },
+ "failure_guard": {
+ "default": "final_failure_guard",
+ "title": "When Failure Guard",
+ "type": "string"
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "resourceID"
+ ],
+ "anyOf": [
+ {
+ "title": "User Defined",
+ "additionalProperties": "True",
+ "properties": {
+ "type": {
+ "title": "Target type",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VNF",
+ "VFMODULE",
+ "VM"
+ ]
+ },
+ "resourceID": {
+ "title": "Target type",
+ "type": "string",
+ "default": ""
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/runtime/src/main/resources/clds/sdc-controllers-config.json b/runtime/src/main/resources/clds/sdc-controllers-config.json
new file mode 100644
index 000000000..be9d02c8d
--- /dev/null
+++ b/runtime/src/main/resources/clds/sdc-controllers-config.json
@@ -0,0 +1,18 @@
+{
+ "sdc-connections":{
+ "sdc-controller":{
+ "user": "clamp",
+ "consumerGroup": "clamp",
+ "consumerId": "clamp",
+ "environmentName": "AUTO",
+ "sdcAddress": "sdc.api.simpledemo.onap.org:8443",
+ "password": "enc:JPV4p067JlSXt2Fet9bfuI8JpkS4ZGYVcgypcPs98gXjgjCjTze_d3JxqmlKaaakdiOjIcEC_MJh6-5pJTLgdc",
+ "pollingInterval":30,
+ "pollingTimeout":30,
+ "activateServerTLSAuth":"false",
+ "keyStorePassword":"",
+ "keyStorePath":"",
+ "messageBusAddresses":["ueb.api.simpledemo.onap.org"]
+ }
+ }
+}
diff --git a/runtime/src/main/resources/clds/tosca-converter/default-tosca-types.yaml b/runtime/src/main/resources/clds/tosca-converter/default-tosca-types.yaml
new file mode 100644
index 000000000..a11a73698
--- /dev/null
+++ b/runtime/src/main/resources/clds/tosca-converter/default-tosca-types.yaml
@@ -0,0 +1,87 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+data_types:
+ tosca.datatypes.Root:
+ description: The TOSCA root Data Type all other TOSCA base Data Types derive from
+ tosca.datatypes.Credential:
+ derived_from: tosca.datatypes.Root
+ properties:
+ protocol:
+ type: string
+ required: false
+ token_type:
+ type: string
+ default: password
+ token:
+ type: string
+ keys:
+ type: map
+ required: false
+ entry_schema:
+ type: string
+ user:
+ type: string
+ required: false
+ tosca.datatypes.TimeInterval:
+ derived_from: tosca.datatypes.Root
+ properties:
+ start_time:
+ type: timestamp
+ required: true
+ end_time:
+ type: timestamp
+ required: true
+ tosca.datatypes.network.NetworkInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ network_name:
+ type: string
+ network_id:
+ type: string
+ addresses:
+ type: list
+ entry_schema:
+ type: string
+ tosca.datatypes.network.PortInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ port_name:
+ type: string
+ port_id:
+ type: string
+ network_id:
+ type: string
+ mac_address:
+ type: string
+ addresses:
+ type: list
+ entry_schema:
+ type: string
+ # tosca.datatypes.network.PortDef:
+ # derived_from: integer
+ # constraints:
+ # - in_range: [ 1, 65535 ]
+ # tosca.datatypes.network.PortSpec:
+ # derived_from: tosca.datatypes.Root
+ # properties:
+ # protocol:
+ # type: string
+ # required: true
+ # default: tcp
+ # constraints:
+ # - valid_values: [ udp, tcp, igmp ]
+ # target:
+ # type: PortDef
+ # required: false
+ # target_range:
+ # type: range
+ # required: false
+ # constraints:
+ # - in_range: [ 1, 65535 ]
+ # source:
+ # type: PortDef
+ # required: false
+ # source_range:
+ # type: range
+ # required: false
+ # constraints:
+ # - in_range: [ 1, 65535 ] \ No newline at end of file
diff --git a/runtime/src/main/resources/clds/tosca-converter/templates.json b/runtime/src/main/resources/clds/tosca-converter/templates.json
new file mode 100644
index 000000000..f709e2f6d
--- /dev/null
+++ b/runtime/src/main/resources/clds/tosca-converter/templates.json
@@ -0,0 +1,398 @@
+{
+ "integer":{
+ "type":{
+ "defaultValue":"integer",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "enum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "multipleOf":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maximum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "exclusiveMaximum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minimum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "exclusiveMinimum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "number":{
+ "type":{
+ "defaultValue":"number",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "enum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "multipleOf":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maximum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "exclusiveMaximum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minimum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "exclusiveMinimum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "boolean":{
+ "type":{
+ "defaultValue":"boolean",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "string":{
+ "type":{
+ "defaultValue":"string",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "enum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "length":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minLength":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maxLength":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "pattern":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "format":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "timestamp":{
+ "type":{
+ "defaultValue":"string",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "enum":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "length":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minLength":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maxLength":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "pattern":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "format":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "array":{
+ "type":{
+ "defaultValue":"array",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "deprecated":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "default":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "const":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "uniqueItems":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "properties":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minContains":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maxContains":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minItems":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maxItems":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ },
+ "object":{
+ "type":{
+ "defaultValue":"object",
+ "visible":true,
+ "static":false
+ },
+ "description":{
+ "defaultValue":"",
+ "visible":true,
+ "static":true
+ },
+ "title":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "format":{
+ "defaultValue":"tabs",
+ "visible":true,
+ "static":true
+ },
+ "required":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "minProperties":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "maxProperties":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "properties":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "dependentRequired":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ },
+ "dependencies":{
+ "defaultValue":"",
+ "visible":true,
+ "static":false
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/main/resources/logback-default.xml b/runtime/src/main/resources/logback-default.xml
new file mode 100644
index 000000000..5397eab04
--- /dev/null
+++ b/runtime/src/main/resources/logback-default.xml
@@ -0,0 +1,329 @@
+<included>
+ <jmxConfigurator />
+ <!-- Example evaluator filter applied against console appender -->
+ <property
+ name="p_tim"
+ value="%d{&quot;yyyy-MM-dd'T'HH:mm:ss.SSSXXX&quot;, UTC}" />
+ <property
+ name="p_lvl"
+ value="%level" />
+ <property
+ name="p_log"
+ value="%logger" />
+ <property
+ name="p_mdc"
+ value="%replace(%replace(%mdc){'\t','\\\\t'}){'\n', '\\\\n'}" />
+ <property
+ name="p_msg"
+ value="%replace(%replace(%msg){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_exc"
+ value="%replace(%replace(%rootException){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_mak"
+ value="%replace(%replace(%marker){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_thr"
+ value="%thread" />
+ <property
+ name="defaultPattern"
+ value="%nopexception${p_tim}\t${p_thr}\t${p_lvl}\t${p_log}\t${p_mdc}\t${p_msg}\t${p_exc}\t${p_mak}\t%n" />
+ <property
+ name="debugPattern"
+ value="%nopexception${p_tim}|${p_lvl}|${p_mdc}|${p_exc}|%msg%n" />
+
+ <property
+ name="errorPattern"
+ value="%X{EntryTimestamp}|%X{RequestID}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}||||%msg%n" />
+
+ <property
+ name="auditPattern"
+ value="%X{EntryTimestamp}|%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC}|%X{RequestID}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDesc}|%X{InstanceUUID}|%.-5level|%X{Severity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}||||%marker|%mdc|||%msg%n" />
+
+ <property
+ name="metricPattern"
+ value="%X{InvokeTimestamp}|%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC}|%X{RequestID}|%X{ServiceInstanceId}|%thread||%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDesc}|%X{InstanceUUID}|%.-5level|%X{Severity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}||||%X{TargetVirtualEntity}|%marker|%mdc|||%msg%n" />
+
+
+ <!-- Example evaluator filter applied against console appender -->
+ <appender
+ name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>INFO</level>
+ </filter>
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+
+ <appender
+ name="ERROR"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <level>ERROR</level>
+ <onMatch>ACCEPT</onMatch>
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ <file>${logDirectory}/error.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>${errorPattern}</pattern>
+ </encoder>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDirectory}/error.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ </appender>
+
+ <appender
+ name="DEBUG"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/debug.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - %msg%n
+ </pattern>
+ </encoder>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDirectory}/debug.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ </appender>
+
+
+ <appender
+ name="AUDIT"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">
+ <marker>ENTRY</marker>
+ <marker>EXIT</marker>
+ </evaluator>
+ <onMismatch>DENY</onMismatch>
+ <onMatch>ACCEPT</onMatch>
+ </filter>
+ <file>${logDirectory}/audit.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>${auditPattern}</pattern>
+ </encoder>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <FileNamePattern>${logDirectory}/audit.%d{yyyy-MM-dd}.%i.log.zip
+ </FileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ </appender>
+ <appender
+ name="asyncEELFAudit"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="AUDIT" />
+ </appender>
+
+ <appender
+ name="METRIC"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+ <evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">
+ <marker>INVOKE</marker>
+ <marker>INVOKE-RETURN</marker>
+ </evaluator>
+ <onMismatch>DENY</onMismatch>
+ <onMatch>ACCEPT</onMatch>
+ </filter>
+ <file>${logDirectory}/metric.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>${metricPattern}</pattern>
+ </encoder>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <FileNamePattern>${logDirectory}/metric.%d{yyyy-MM-dd}.%i.log.zip
+ </FileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ </appender>
+
+ <appender
+ name="asyncEELFMetrics"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="METRIC" />
+ </appender>
+
+ <!-- SECURITY related loggers -->
+ <appender
+ name="SECURITY"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/security.log</file>
+ <append>true</append>
+ <encoder>
+ <pattern>%X{EntryTimestamp}|%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC}|%X{RequestID}|%X{ServiceInstanceId}|%.20thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%msg%n
+ </pattern>
+ </encoder>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <FileNamePattern>${logDirectory}/security.%d{yyyy-MM-dd}.%i.log.zip
+ </FileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ </appender>
+
+ <appender
+ name="asyncEELFSecurity"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="SECURITY" />
+ </appender>
+ <!-- logback jms appenders & loggers definition starts here -->
+ <appender
+ name="auditLogs"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ </filter>
+ <file>${logDirectory}/Audits.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDirectory}/Audits-%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>"%d [%thread] %-5level %logger{1024} - %msg%n"</pattern>
+ </encoder>
+ </appender>
+
+ <appender
+ name="perfLogs"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ </filter>
+ <file>${logDirectory}/Perform.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDirectory}/Perform--%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>20</maxHistory>
+ <totalSizeCap>1GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>"%d [%thread] %-5level %logger{1024} - %msg%n"</pattern>
+ </encoder>
+ </appender>
+
+ <logger
+ name="org.onap.aaf"
+ level="DEBUG">
+ <appender-ref ref="DEBUG" />
+ </logger>
+ <logger
+ name="org.hibernate"
+ level="INFO">
+ <appender-ref ref="DEBUG" />
+ </logger>
+ <logger
+ name="org.apache.camel.Tracing"
+ level="INFO">
+ <appender-ref ref="DEBUG" />
+ </logger>
+
+ <logger
+ name="org.apache"
+ level="INFO">
+ <appender-ref ref="DEBUG" />
+ </logger>
+ <!-- Spring related loggers -->
+ <logger
+ name="org.springframework"
+ level="INFO">
+ <appender-ref ref="DEBUG" />
+ </logger>
+
+ <!-- CLAMP related loggers -->
+ <logger
+ name="org.onap.policy.clamp"
+ level="DEBUG">
+ <appender-ref ref="ERROR" />
+ <appender-ref ref="DEBUG" />
+ </logger>
+
+ <logger
+ name="com.att.eelf.error"
+ level="OFF">
+ <appender-ref ref="ERROR" />
+ </logger>
+ <!-- EELF related loggers -->
+ <logger
+ name="com.att.eelf.audit"
+ level="INFO"
+ additivity="false">
+ <appender-ref ref="asyncEELFAudit" />
+ </logger>
+ <logger
+ name="com.att.eelf.metrics"
+ level="DEBUG"
+ additivity="false">
+ <appender-ref ref="asyncEELFMetrics" />
+ </logger>
+ <logger
+ name="com.att.eelf.security"
+ level="DEBUG"
+ additivity="false">
+ <appender-ref ref="asyncEELFSecurity" />
+ </logger>
+
+ <!-- logback internals logging -->
+ <logger
+ name="ch.qos.logback.classic"
+ level="INFO" />
+ <logger
+ name="ch.qos.logback.core"
+ level="INFO" />
+ <logger
+ name="AuditRecord"
+ level="INFO"
+ additivity="false">
+ <appender-ref ref="auditLogs" />
+ </logger>
+ <logger
+ name="AuditRecord_DirectCall"
+ level="INFO"
+ additivity="false">
+ <appender-ref ref="auditLogs" />
+ </logger>
+ <logger
+ name="PerfTrackerRecord"
+ level="INFO"
+ additivity="false">
+ <appender-ref ref="perfLogs" />
+ </logger>
+ <!-- logback jms appenders & loggers definition ends here -->
+
+ <root level="DEBUG">
+ <appender-ref ref="DEBUG" />
+ <appender-ref ref="STDOUT" />
+ <appender-ref ref="AUDIT" />
+ <appender-ref ref="METRIC" />
+ <appender-ref ref="ERROR" />
+ </root>
+</included>
diff --git a/runtime/src/main/resources/logback-spring.xml b/runtime/src/main/resources/logback-spring.xml
new file mode 100644
index 000000000..ffa497f1d
--- /dev/null
+++ b/runtime/src/main/resources/logback-spring.xml
@@ -0,0 +1,19 @@
+<configuration debug="true">
+ <springProperty name="logbackFilePath"
+ source="clamp.config.logback.path" />
+ <springProperty name="logbackFileName"
+ source="clamp.config.logback.filename" />
+ <springProperty name="logDirectory"
+ source="clamp.config.log.path" />
+
+ <if condition='isNull("logbackFilePath")'>
+ <then>
+ <!-- Classpath case -->
+ <include resource="${logbackFileName}" />
+ </then>
+ <else>
+ <!-- File system case -->
+ <include file="${logbackFilePath}/${logbackFileName}" />
+ </else>
+ </if>
+</configuration> \ No newline at end of file
diff --git a/runtime/src/main/resources/logmessages.properties b/runtime/src/main/resources/logmessages.properties
new file mode 100644
index 000000000..fc9f74a36
--- /dev/null
+++ b/runtime/src/main/resources/logmessages.properties
@@ -0,0 +1,27 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+LOGSERVICE_EMAIL_ERROR=SERVICE0007I|Exception while sending e-mail:{0}|Resolution needed|action is required
+LOGSERVICE_EMAIL_CLASS=SERVICE0008I|classUrl.getFile:{0}|Resolution needed|action is required
+LOGSERVICE_EMAIL_CLASS_NULL=SERVICE0009I|classUrl is NULL|Resolution needed|action is required
+PROCESS_INSTANCE_ID=SERVICE0010I|Process Instance Id:{0}|No resolution needed|No action is required
diff --git a/runtime/src/main/resources/system.properties b/runtime/src/main/resources/system.properties
new file mode 100644
index 000000000..f95fc7009
--- /dev/null
+++ b/runtime/src/main/resources/system.properties
@@ -0,0 +1,27 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+### Static JVM parameters can be set here by the dev team
+### These will be loaded at Clamp startup
+#
+# JVM SSL/TLS properties
+jdk.tls.client.protocols=TLSv1.1,TLSv1.2
+https.protocols=TLSv1.1,TLSv1.2
diff --git a/runtime/src/main/script/SelectNpmRepo.groovy b/runtime/src/main/script/SelectNpmRepo.groovy
new file mode 100644
index 000000000..797d2d003
--- /dev/null
+++ b/runtime/src/main/script/SelectNpmRepo.groovy
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.maven.scripts
+
+println project.properties['clamp.project.version'];
+
+if ( project.properties['clamp.project.version'].endsWith("-SNAPSHOT") ) {
+ project.properties['npm.publish.url']="https://nexus3.onap.org/repository/npm.snapshot/"
+} else {
+ project.properties['npm.publish.url']="https://nexus3.onap.org/repository/npm.snapshot/"
+}
+
+println 'NPM repository: ' + project.properties['npm.publish.url'];
diff --git a/runtime/src/main/script/TagVersion.groovy b/runtime/src/main/script/TagVersion.groovy
new file mode 100644
index 000000000..271e2967f
--- /dev/null
+++ b/runtime/src/main/script/TagVersion.groovy
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.maven.scripts
+
+println project.properties['clamp.project.version'];
+def versionArray;
+if ( project.properties['clamp.project.version'] != null ) {
+ versionArray = project.properties['clamp.project.version'].split('\\.');
+}
+
+if ( project.properties['clamp.project.version'].endsWith("-SNAPSHOT") ) {
+ project.properties['project.docker.latesttag.version']=versionArray[0] + '.' + versionArray[1] + "-SNAPSHOT-latest";
+ project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + "-SNAPSHOT-"+project.properties['clamp.build.timestamp'];
+} else {
+ project.properties['project.docker.latesttag.version']=versionArray[0] + '.' + versionArray[1] + "-STAGING-latest";
+ project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + "-STAGING-"+project.properties['clamp.build.timestamp'];
+}
+
+println 'New Tag for docker:' + project.properties['project.docker.latesttag.version']; \ No newline at end of file
diff --git a/runtime/src/main/script/checkLibIndex.sh b/runtime/src/main/script/checkLibIndex.sh
new file mode 100644
index 000000000..fef9c1b7a
--- /dev/null
+++ b/runtime/src/main/script/checkLibIndex.sh
@@ -0,0 +1,122 @@
+#!/bin/bash
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+baseDir=$(git rev-parse --show-toplevel)
+
+if [[ ! -d $baseDir ]]
+then
+ echo "[ERROR] failed to determine git base directory"
+ exit 1
+fi
+
+tmpSrcFileList=/tmp/upldateLibIndex.$$.list
+reactUiBaseDir="${baseDir}/runtime/ui-react"
+reactLibIndexFile="runtime/ui-react-lib/libIndex.js"
+exclusionList="runtime/ui-react-lib/libExportExclusions.dat"
+
+
+if [[ ! -d "$reactUiBaseDir" ]]
+then
+ echo "[ERROR] reacUiBaseDir=$reacUiBaseDir is not accessible"
+ exit 1
+fi
+
+if [[ ! -d "$baseDir/$reactLibBaseDir" ]]
+then
+ echo "[ERROR] reactLibBaseDir=$baseDir/$reactLibBaseDir is not accessible"
+ exit 1
+fi
+
+if [[ ! -r "$baseDir/$reactLibIndexFile" ]]
+then
+ echo "[ERROR] file reactLibIndexFile=$baseDir/$reactLibIndexFile is not accessible"
+ exit 1
+fi
+
+
+if ! cd $reactUiBaseDir
+then
+ echo "[ERROR] could not cd to reactUiBaseDir=$reactUiBaseDir"
+ exit 1
+fi
+
+find ./src -name \*.js | egrep -v "__snapshot|\.test\." 2>/dev/null | sed 's/.js$//' > $tmpSrcFileList
+
+if [[ ! -s $tmpSrcFileList ]]
+then
+ echo "[ERROR] no source files found in reactUiBaseDir=$reactUiBaseDir"
+ rm -f $tmpSrcFileList
+ exit 1
+fi
+
+export nErrors=0
+
+# Verify that any .js file found within ui-react/src other than test related files
+# is also referenced in ui-react-lib/libIndex.js
+
+for srcFileName in `<$tmpSrcFileList`
+do
+ if [[ -r "$baseDir/$exclusionList" ]]
+ then
+ if grep $srcFileName $baseDir/$exclusionList >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+
+ if ! grep $srcFileName "$baseDir/$reactLibIndexFile" > /dev/null 2>&1
+ then
+ echo "[ERROR] file=${srcFileName}.js is not declared in $reactLibIndexFile"
+ echo "[ERROR] and not found in exclsionList=${exclusionList}."
+ echo "[ERROR] Please either add it to $reactLibIndexFile"
+ echo "[ERROR] or to the exclusion list in ${exclusionList}."
+ echo ""
+ (( nErrors++ ))
+ fi
+done
+
+# Verify for each entry in ui-react-lib/libIndex.js, that the referenced source file exists
+# in ui-react/src; if not, developer probably forgot to remove it from libIndex.js.
+
+egrep '^export ' $baseDir/$reactLibIndexFile |\
+sed -e "s+.*\./src+./src+" -e "s+'.*+.js+" > $tmpSrcFileList
+
+for srcFileName in `<$tmpSrcFileList`
+do
+ if [[ ! -r "$srcFileName" ]]
+ then
+ echo "[ERROR] source file=$srcFileName in libIndex.js is not accessible"
+ (( nErrors++ ))
+ fi
+done
+
+rm -f $tmpSrcFileList
+
+if (( nErrors == 0 ))
+then
+ echo "[INFO] $reactLibIndexFile passes sanity check"
+ exit 0
+fi
+
+exit $nErrors
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/client/CdsServicesTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/client/CdsServicesTest.java
new file mode 100644
index 000000000..6e5300e23
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/client/CdsServicesTest.java
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ * ================================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.client;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class CdsServicesTest {
+
+ @Test
+ public void testParseCdsListTypeProperties() throws IOException {
+ String cdsResponse = ResourceFileUtils
+ .getResourceAsString("example/cds-response/vFW-CDS-resource-assignment-workflow.json");
+ CdsServices services = new CdsServices();
+ JsonObject output = services.parseCdsResponse(cdsResponse);
+ JSONAssert.assertEquals(ResourceFileUtils
+ .getResourceAsString("example/cds-response/vFW-CDS-resource-assignment-wf-expected-result.json"),
+ JsonUtils.GSON.toJson(output), true);
+ }
+
+ @Test
+ public void testParseCdsResponse() throws IOException {
+ String cdsResponse = ResourceFileUtils
+ .getResourceAsString("example/cds-response/vFW-CDS-modify-config-workflow.json");
+ CdsServices services = new CdsServices();
+ JsonObject output = services.parseCdsResponse(cdsResponse);
+ JSONAssert.assertEquals(ResourceFileUtils
+ .getResourceAsString("example/cds-response/vFW-CDS-modify-config-wf-expected-result.json"),
+ JsonUtils.GSON.toJson(output), true);
+ }
+
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoderTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoderTest.java
new file mode 100644
index 000000000..605ab99ae
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/config/CldsUserJsonDecoderTest.java
@@ -0,0 +1,99 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * 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============================================
+ * Modifications copyright (c) 2018 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.onap.policy.clamp.authorization.CldsUser;
+import org.onap.policy.clamp.clds.exception.CldsUsersException;
+
+public class CldsUserJsonDecoderTest {
+
+ private String user1 = "admin1";
+ private String user2 = "admin2";
+ private String password = "5f4dcc3b5aa765d61d8327deb882cf99";
+ private String[] normalPermissionsArray = { "permission-type-cl|dev|read", "permission-type-cl|dev|update",
+ "permission-type-cl-manage|dev|*", "permission-type-filter-vf|dev|*", "permission-type-template|dev|read",
+ "permission-type-template|dev|update" };
+ private String[] incompletePermissionsArray = { "permission-type-cl|dev|*", "permission-type-cl|dev|*",
+ "permission-type-cl-manage|dev|*", "permission-type-filter-vf|dev|*", "permission-type-template|dev|read",
+ "permission-type-template|dev|update" };
+
+ @Test
+ public void testDecodingDoubleUsers() {
+
+ // when
+ CldsUser[] usersArray = CldsUserJsonDecoder
+ .decodeJson(CldsUserJsonDecoderTest.class.getResourceAsStream("/clds/clds-users-two-users.json"));
+
+ // then
+ assertThat(usersArray).hasSize(2);
+ assertThat(usersArray[0]).extracting(CldsUser::getUser, CldsUser::getPassword, CldsUser::getPermissionsString)
+ .containsExactly(user1, password, normalPermissionsArray);
+
+ assertThat(usersArray[1]).extracting(CldsUser::getUser, CldsUser::getPassword, CldsUser::getPermissionsString)
+ .containsExactly(user2, password, normalPermissionsArray);
+
+ }
+
+ @Test
+ public void testDecodingNoPermission() {
+ // when
+ CldsUser[] usersArray = CldsUserJsonDecoder
+ .decodeJson(this.getClass().getResourceAsStream("/clds/clds-users-no-permission.json"));
+
+ // then
+ assertThat(usersArray).hasSize(1);
+ CldsUser user = usersArray[0];
+ assertThat(user.getUser()).isEqualTo(user1);
+ assertThat(user.getPassword()).isEqualTo(null);
+ assertThat(user.getPermissionsString()).isEmpty();
+ }
+
+ @Test
+ public void testDecodingIncompletePermissions() {
+
+ // when
+ CldsUser[] usersArray = CldsUserJsonDecoder
+ .decodeJson(this.getClass().getResourceAsStream("/clds/clds-users-incomplete-permissions.json"));
+
+ // then
+ assertThat(usersArray).hasSize(1);
+ CldsUser user = usersArray[0];
+ assertThat(user.getUser()).isEqualTo(user1);
+ assertThat(user.getPassword()).isEqualTo(password);
+ assertThat(user.getPermissionsString()).isEqualTo(incompletePermissionsArray);
+ }
+
+ @Test(expected = CldsUsersException.class)
+ public void shouldThrowCldsUsersException() {
+ // when
+ CldsUserJsonDecoder.decodeJson(this.getClass().getResourceAsStream("/clds/clds-parse-exception.json"));
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfigurationTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfigurationTest.java
new file mode 100644
index 000000000..7390b65ba
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/config/sdc/SdcSingleControllerConfigurationTest.java
@@ -0,0 +1,108 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017, 2021 AT&T Intellectual Property. 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=========================================================
+ * Modifications copyright (c) 2018 Nokia
+ * ================================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.config.sdc;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+/**
+ * This class tests the SDC Controller config.
+ */
+public class SdcSingleControllerConfigurationTest {
+
+ /**
+ * This method loads the SDC controller configuration from a file located in the resource folder.
+ *
+ * @param fileName file for sdc controller configuration.
+ * @param sdcControllerName sdc controller name.
+ * @return instance of SdcSingleControllerConfiguration.
+ */
+ public static SdcSingleControllerConfiguration loadControllerConfiguration(String fileName,
+ String sdcControllerName) {
+
+ InputStreamReader streamReader = new InputStreamReader(ResourceFileUtils.getResourceAsStream(fileName),
+ StandardCharsets.UTF_8);
+ JsonObject jsonNode = JsonUtils.GSON.fromJson(streamReader, JsonObject.class);
+
+ return new SdcSingleControllerConfiguration(jsonNode, sdcControllerName,
+ "classpath:clds/aaf/org.onap.clamp.keyfile");
+ }
+
+ @Test
+ public final void testTheInit() throws SdcParametersException, IOException {
+ SdcSingleControllerConfiguration sdcConfig = loadControllerConfiguration("clds/sdc-controller-config-TLS.json",
+ "sdc-controller1");
+ assertEquals("User", sdcConfig.getUser());
+ assertEquals("ThePassword", sdcConfig.getPassword());
+ assertEquals("consumerGroup", sdcConfig.getConsumerGroup());
+ assertEquals("consumerId", sdcConfig.getConsumerID());
+ assertEquals("environmentName", sdcConfig.getEnvironmentName());
+ assertEquals("hostname:8080", sdcConfig.getAsdcAddress());
+ assertEquals(10, sdcConfig.getPollingInterval());
+ assertEquals(30, sdcConfig.getPollingTimeout());
+
+ assertThat(SdcSingleControllerConfiguration.SUPPORTED_ARTIFACT_TYPES_LIST)
+ .hasSameSizeAs(sdcConfig.getRelevantArtifactTypes());
+ assertEquals("ThePassword", sdcConfig.getKeyStorePassword());
+ assertTrue(sdcConfig.activateServerTLSAuth());
+ assertThat(sdcConfig.getMsgBusAddress()).contains("localhost");
+ }
+
+ @Test(expected = SdcParametersException.class)
+ public final void testAllRequiredParameters() throws IOException {
+ SdcSingleControllerConfiguration sdcConfig = loadControllerConfiguration("clds/sdc-controller-config-TLS.json",
+ "sdc-controller1");
+ // No exception should be raised
+ sdcConfig.testAllRequiredParameters();
+ sdcConfig = loadControllerConfiguration("clds/sdc-controller-config-bad.json", "sdc-controller1");
+ fail("Should have raised an exception");
+ }
+
+ @Test
+ public final void testAllRequiredParametersEmptyEncrypted() throws IOException {
+ SdcSingleControllerConfiguration sdcConfig = loadControllerConfiguration(
+ "clds/sdc-controller-config-empty-encrypted.json", "sdc-controller1");
+ sdcConfig.testAllRequiredParameters();
+ assertNull(sdcConfig.getKeyStorePassword());
+ }
+
+ @Test
+ public final void testConsumerGroupWithNull() throws IOException {
+ SdcSingleControllerConfiguration sdcConfig = loadControllerConfiguration("clds/sdc-controller-config-NULL.json",
+ "sdc-controller1");
+ assertTrue(sdcConfig.getConsumerGroup() == null);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/AuthorizationControllerItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/AuthorizationControllerItCase.java
new file mode 100644
index 000000000..557a2e96c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/AuthorizationControllerItCase.java
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * Modifications 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.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.apache.camel.Exchange;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.authorization.AuthorizationController;
+import org.onap.policy.clamp.authorization.SecureServicePermission;
+import org.onap.policy.clamp.clds.exception.NotAuthorizedException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * Test CldsDAO calls through CldsModel and CldsEvent. This really test the DB
+ * and stored procedures.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class AuthorizationControllerItCase {
+
+ @Autowired
+ private AuthorizationController auth;
+
+ private static SecurityContext sc = SecurityContextHolder.getContext();
+
+ /**
+ * Setup the variable before the tests execution.
+ */
+ @BeforeClass
+ public static void setupBefore() {
+
+ sc.setAuthentication(new Authentication() {
+ @Override
+ public Collection<? extends GrantedAuthority> getAuthorities() {
+ return Arrays.asList(new SimpleGrantedAuthority(
+ new SecureServicePermission("permission-type-cl", "dev", "read").getKey()),
+ new SimpleGrantedAuthority(new SecureServicePermission("permission-type-cl-manage", "dev",
+ "DEPLOY").getKey()),
+ new SimpleGrantedAuthority(new SecureServicePermission("permission-type-filter-vf", "dev",
+ "12345-55555-55555-5555").getKey()));
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getDetails() {
+ return null;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return "admin";
+ }
+
+ @Override
+ public boolean isAuthenticated() {
+ return true;
+ }
+
+ @Override
+ public void setAuthenticated(boolean authenticatedFlag) throws IllegalArgumentException {
+
+ }
+
+ @Override
+ public String getName() {
+ return "admin";
+ }
+ });
+
+ }
+
+ @AfterClass
+
+ public static void afterCleanup() {
+ sc.setAuthentication(null);
+ }
+
+ @Test
+ public void testIsUserPermitted() {
+ assertEquals(AuthorizationController.getPrincipalName(sc), "admin");
+ assertTrue(auth.isUserPermitted(new SecureServicePermission("permission-type-cl", "dev", "read")));
+ assertTrue(auth.isUserPermitted(new SecureServicePermission("permission-type-cl-manage", "dev", "DEPLOY")));
+ assertTrue(auth.isUserPermitted(
+ new SecureServicePermission("permission-type-filter-vf", "dev", "12345-55555-55555-5555")));
+ assertFalse(auth.isUserPermitted(new SecureServicePermission("permission-type-cl", "test", "read")));
+ }
+
+ @Test(expected = NotAuthorizedException.class)
+ public void testIfAuthorizeThrowException() {
+ Exchange ex = Mockito.mock(Exchange.class);
+ auth.authorize(ex, "cl", "test", "read");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/CldsHealthcheckServiceItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/CldsHealthcheckServiceItCase.java
new file mode 100644
index 000000000..52da63952
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/CldsHealthcheckServiceItCase.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.policy.clamp.clds.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.model.CldsHealthCheck;
+import org.onap.policy.clamp.clds.service.CldsHealthcheckService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Tests HealthCheck Service.
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+public class CldsHealthcheckServiceItCase {
+
+ @Autowired
+ private CldsHealthcheckService cldsHealthcheckService;
+
+ @Test
+ public void testGetHealthCheck() {
+ CldsHealthCheck cldsHealthCheck = cldsHealthcheckService.gethealthcheck();
+ assertNotNull(cldsHealthCheck);
+ assertEquals("UP", cldsHealthCheck.getHealthCheckStatus());
+ assertEquals("CLDS-APP", cldsHealthCheck.getHealthCheckComponent());
+ assertEquals("OK", cldsHealthCheck.getDescription());
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/HttpsItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/HttpsItCase.java
new file mode 100644
index 000000000..1a4a2ec5f
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/HttpsItCase.java
@@ -0,0 +1,106 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.it;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.io.FileUtils;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Test HTTP and HTTPS settings + redirection of HTTP to HTTPS.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
+@TestPropertySource(locations = "classpath:https/https-test.properties")
+@DirtiesContext
+public class HttpsItCase {
+
+ @Value("${server.port}")
+ private String httpsPort;
+ @Value("${server.http-to-https-redirection.port}")
+ private String httpPort;
+
+ @Test
+ public void testDesignerIndex() throws Exception {
+ ResponseEntity<String> entity =
+ new RestTemplate().getForEntity("http://localhost:" + this.httpPort + "/swagger.html",
+ String.class);
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
+ ResponseEntity<String> httpsEntity = getRestTemplate()
+ .getForEntity("https://localhost:" + this.httpsPort + "/swagger.html", String.class);
+ assertThat(httpsEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(httpsEntity.getBody()).contains("Clamp Rest API");
+ }
+
+ @Test
+ public void testSwaggerJson() throws Exception {
+ ResponseEntity<String> httpsEntity = getRestTemplate()
+ .getForEntity("https://localhost:" + this.httpsPort + "/restservices/clds/api-doc", String.class);
+ assertThat(httpsEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(httpsEntity.getBody()).contains("swagger");
+ FileUtils.writeStringToFile(new File("docs/swagger/swagger.json"), httpsEntity.getBody(),
+ Charset.defaultCharset());
+ }
+
+ private RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
+ SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
+ .loadTrustMaterial(null, new TrustStrategy() {
+ @Override
+ public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+ return true;
+ }
+ }).build();
+ SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
+ CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
+ HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
+ requestFactory.setHttpClient(httpClient);
+ RestTemplate restTemplate = new RestTemplate(requestFactory);
+ return restTemplate;
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/RobotItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/RobotItCase.java
new file mode 100644
index 000000000..017881ba7
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/RobotItCase.java
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.it;
+
+import static org.apache.commons.io.FileUtils.copyInputStreamToFile;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.command.BuildImageResultCallback;
+import com.github.dockerjava.api.command.CreateContainerResponse;
+import com.github.dockerjava.api.command.InspectContainerResponse;
+import com.github.dockerjava.api.command.LogContainerCmd;
+import com.github.dockerjava.api.model.AccessMode;
+import com.github.dockerjava.api.model.Bind;
+import com.github.dockerjava.api.model.BuildResponseItem;
+import com.github.dockerjava.api.model.Frame;
+import com.github.dockerjava.api.model.Volume;
+import com.github.dockerjava.core.DockerClientBuilder;
+import com.github.dockerjava.core.command.LogContainerResultCallback;
+import com.github.dockerjava.netty.NettyDockerCmdExecFactory;
+import java.io.File;
+import java.util.Objects;
+import org.codehaus.plexus.util.FileUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+@TestPropertySource(locations = "classpath:robotframework/robotframework-test.properties")
+@DirtiesContext
+public class RobotItCase {
+
+ @Value("${server.port}")
+ private String httpPort;
+ private static final int TIMEOUT_S = 150;
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(RobotItCase.class);
+
+ @Test
+ public void robotTests() throws Exception {
+ File robotFolder = new File(getClass().getClassLoader().getResource("robotframework").getFile());
+ Volume testsVolume = new Volume("/opt/robotframework/tests");
+ DockerClient client = DockerClientBuilder
+ .getInstance()
+ .withDockerCmdExecFactory(new NettyDockerCmdExecFactory())
+ .build();
+
+
+ BuildImageResultCallback callback = new BuildImageResultCallback() {
+ @Override
+ public void onNext(BuildResponseItem item) {
+ System.out.println("XXX ITEM " + item);
+ super.onNext(item);
+ }
+ };
+
+ String imageId = client.buildImageCmd(robotFolder).exec(callback).awaitImageId();
+ CreateContainerResponse createContainerResponse = client.createContainerCmd(imageId)
+ .withVolumes(testsVolume)
+ .withBinds(
+ new Bind(robotFolder.getAbsolutePath() + "/tests/", testsVolume, AccessMode.rw))
+ .withEnv("CLAMP_PORT=" + httpPort)
+ .withStopTimeout(TIMEOUT_S)
+ .withNetworkMode("host")
+ .exec();
+ String id = createContainerResponse.getId();
+ client.startContainerCmd(id).exec();
+ InspectContainerResponse exec;
+
+ int tries = 0;
+ do {
+ Thread.sleep(1000);
+ exec = client.inspectContainerCmd(id).exec();
+ tries++;
+ } while (exec.getState().getRunning() && tries < TIMEOUT_S);
+ logger.info("RobotFramework result:" + exec.getState());
+
+ LogContainerCmd logContainerCmd = client.logContainerCmd(id);
+ logContainerCmd.withStdOut(true).withStdErr(true);
+ try {
+ logContainerCmd.exec(new LogContainerResultCallback() {
+ @Override
+ public void onNext(Frame item) {
+ logger.info(item.toString());
+ }
+ }).awaitCompletion();
+ } catch (InterruptedException e) {
+ throw new Exception("Failed to retrieve logs of container " + id, e);
+ }
+
+ copyInputStreamToFile(client.copyArchiveFromContainerCmd(id, "/opt/robotframework/reports/output.xml").exec(),
+ new File("target/robotframework/output.xml"));
+ copyInputStreamToFile(client.copyArchiveFromContainerCmd(id, "/opt/robotframework/reports/log.html").exec(),
+ new File("target/robotframework/log.html"));
+ copyInputStreamToFile(client.copyArchiveFromContainerCmd(id, "/opt/robotframework/reports/report.html").exec(),
+ new File("target/robotframework/report.html"));
+ client.stopContainerCmd(id);
+
+ logger.info("RobotFramework output.xml file: " + FileUtils.fileRead("target/robotframework/output.xml"));
+
+ Assert.assertEquals(exec.getState().getError(), 0L,
+ Objects.requireNonNull(exec.getState().getExitCodeLong()).longValue());
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/CldsReferencePropertiesItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/CldsReferencePropertiesItCase.java
new file mode 100644
index 000000000..c8b9932cc
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/CldsReferencePropertiesItCase.java
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.it.config;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class CldsReferencePropertiesItCase {
+
+ @Autowired
+ private ClampProperties refProp;
+
+ /**
+ * Test getting a value the properties in string.
+ */
+ @Test
+ public void testGetStringValue() {
+ assertEquals("healthcheck", refProp.getStringValue("policy.api.userName"));
+ }
+
+ /**
+ * Test getting prop value as a JSON Node / template.
+ *
+ * @throws IOException when JSON parsing fails
+ */
+ @Test
+ public void testGetFileContent() throws IOException {
+ String users = ResourceFileUtils.getResourceAsString("clds/clds-users.json");
+ assertEquals(users, refProp.getFileContent("files.cldsUsers"));
+ // Test composite key
+ assertEquals(users, refProp.getFileContent("files", "cldsUsers"));
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/SdcControllersConfigurationItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/SdcControllersConfigurationItCase.java
new file mode 100644
index 000000000..70aeccf59
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/config/SdcControllersConfigurationItCase.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2017, 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.clds.it.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.gson.JsonSyntaxException;
+import java.io.IOException;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.config.sdc.SdcControllersConfiguration;
+import org.onap.policy.clamp.clds.config.sdc.SdcSingleControllerConfiguration;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcParametersException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+/**
+ * This class tests the SDC Controller config.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@ActiveProfiles({"clamp-default", "clamp-default-user", "clamp-sdc-controller"})
+public class SdcControllersConfigurationItCase {
+
+ @Autowired
+ private SdcControllersConfiguration sdcControllersConfiguration;
+
+ public final void loadFile(String fileName) throws IOException {
+ ReflectionTestUtils.setField(sdcControllersConfiguration, "sdcControllerFile", fileName);
+ sdcControllersConfiguration.loadConfiguration();
+ }
+
+ @Test
+ public void testGetAllDefinedControllers() throws IOException {
+ loadFile("classpath:clds/sdc-controllers-config.json");
+ Map<String, SdcSingleControllerConfiguration> mapResult = sdcControllersConfiguration
+ .getAllDefinedControllers();
+ assertTrue(mapResult.size() == 2);
+ assertEquals("sdc-controller1", mapResult.get("sdc-controller1").getSdcControllerName());
+ assertEquals("sdc-controller2", mapResult.get("sdc-controller2").getSdcControllerName());
+ }
+
+ @Test
+ public void testGetSdcSingleControllerConfiguration() throws IOException {
+ loadFile("classpath:clds/sdc-controllers-config.json");
+ assertEquals("sdc-controller1", sdcControllersConfiguration
+ .getSdcSingleControllerConfiguration("sdc-controller1").getSdcControllerName());
+ assertEquals("sdc-controller2", sdcControllersConfiguration
+ .getSdcSingleControllerConfiguration("sdc-controller2").getSdcControllerName());
+ }
+
+ @Test(expected = JsonSyntaxException.class)
+ public void testBadJsonLoading() throws IOException {
+ loadFile("classpath:clds/sdc-controllers-config-bad.json");
+ fail("Should have raised an exception");
+ }
+
+ @Test(expected = SdcParametersException.class)
+ public void testMissingParamInJsonLoading() throws IOException {
+ loadFile("classpath:clds/sdc-controllers-config-missing-param.json");
+ sdcControllersConfiguration.getAllDefinedControllers();
+ fail("Should have raised an exception");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/it/sdc/controller/SdcSingleControllerItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/it/sdc/controller/SdcSingleControllerItCase.java
new file mode 100644
index 000000000..787118902
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/it/sdc/controller/SdcSingleControllerItCase.java
@@ -0,0 +1,152 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.it.sdc.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.assertj.core.api.Assertions;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.config.ClampProperties;
+import org.onap.policy.clamp.clds.config.sdc.SdcSingleControllerConfigurationTest;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcControllerException;
+import org.onap.policy.clamp.clds.sdc.controller.SdcSingleController;
+import org.onap.policy.clamp.clds.sdc.controller.SdcSingleControllerStatus;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.loop.CsarInstaller;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.notification.IResourceInstance;
+import org.slf4j.MDC;
+import org.slf4j.spi.MDCAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@ActiveProfiles({"clamp-default", "clamp-default-user", "clamp-sdc-controller"})
+public class SdcSingleControllerItCase {
+
+ private static final String CSAR_ARTIFACT_NAME = "testArtifact.csar";
+ private static final String SERVICE_UUID = "serviceUUID";
+ private static final String RESOURCE1_UUID = "resource1UUID";
+ private static final String RESOURCE1_INSTANCE_NAME = "sim-1802 0";
+
+ @Autowired
+ private ClampProperties clampProp;
+
+ private SdcSingleController sdcSingleController;
+
+ private CsarInstaller csarInstaller = mock(CsarInstaller.class);
+
+ private INotificationData buildFakeSdcNotification() {
+ // BUild what is needed for CSAR
+ IArtifactInfo serviceArtifact = mock(IArtifactInfo.class);
+ Mockito.when(serviceArtifact.getArtifactType()).thenReturn(CsarHandler.CSAR_TYPE);
+ Mockito.when(serviceArtifact.getArtifactName()).thenReturn(CSAR_ARTIFACT_NAME);
+ List<IArtifactInfo> servicesList = new ArrayList<>();
+ servicesList.add(serviceArtifact);
+ INotificationData notifData = mock(INotificationData.class);
+ Mockito.when(notifData.getServiceArtifacts()).thenReturn(servicesList);
+ // Build what is needed for UUID
+ Mockito.when(notifData.getServiceInvariantUUID()).thenReturn(SERVICE_UUID);
+ // Build fake resource with one artifact BLUEPRINT
+ IResourceInstance resource1 = mock(IResourceInstance.class);
+ Mockito.when(resource1.getResourceType()).thenReturn("VF");
+ Mockito.when(resource1.getResourceInvariantUUID()).thenReturn(RESOURCE1_UUID);
+ Mockito.when(resource1.getResourceInstanceName()).thenReturn(RESOURCE1_INSTANCE_NAME);
+ // Create a fake artifact for resource
+ IArtifactInfo blueprintArtifact = mock(IArtifactInfo.class);
+ Mockito.when(blueprintArtifact.getArtifactType()).thenReturn(CsarHandler.BLUEPRINT_TYPE);
+ List<IArtifactInfo> artifactsListForResource = new ArrayList<>();
+ artifactsListForResource.add(blueprintArtifact);
+ Mockito.when(resource1.getArtifacts()).thenReturn(artifactsListForResource);
+ List<IResourceInstance> resourcesList = new ArrayList<>();
+ resourcesList.add(resource1);
+ Mockito.when(notifData.getResources()).thenReturn(resourcesList);
+ return notifData;
+ }
+
+ /**
+ * Initialization method.
+ */
+ @Before
+ public void init() {
+ sdcSingleController = new SdcSingleController(clampProp, csarInstaller, SdcSingleControllerConfigurationTest
+ .loadControllerConfiguration("clds/sdc-controller-config-TLS.json", "sdc-controller1"), null) {
+ };
+ }
+
+ @Test
+ public void testTreatNotification() {
+ // when
+ sdcSingleController.treatNotification(buildFakeSdcNotification());
+ // then
+ Assertions.assertThat(sdcSingleController.getNbOfNotificationsOngoing()).isEqualTo(0);
+ }
+
+ @Test
+ public void testCloseSdc() throws SdcControllerException {
+ // when
+ sdcSingleController.closeSdc();
+ // then
+ assertThat(sdcSingleController.getControllerStatus()).isEqualTo(SdcSingleControllerStatus.STOPPED);
+ }
+
+ @Test
+ public void testActivateCallback() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException,
+ InstantiationException, ClassNotFoundException {
+ // given
+
+ Class<?> innerClass = Class
+ .forName("org.onap.policy.clamp.clds.sdc.controller.SdcSingleController$SdcNotificationCallBack");
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(SdcSingleController.class,
+ SdcSingleController.class);
+ constructor.setAccessible(true);
+ Object child = constructor.newInstance(sdcSingleController, sdcSingleController);
+ Method method = child.getClass().getDeclaredMethod("activateCallback", INotificationData.class);
+ method.setAccessible(true);
+ MDCAdapter mdcAdapter = MDC.getMDCAdapter();
+ // when
+ method.invoke(child, buildFakeSdcNotification());
+ // then
+ assertThat(mdcAdapter.get("ResponseCode")).isEqualTo("0");
+ assertThat(mdcAdapter.get("StatusCode")).isEqualTo("COMPLETE");
+ assertThat(mdcAdapter.get("ResponseDescription"))
+ .isEqualTo("SDC Notification received and processed successfully");
+ assertThat(mdcAdapter.get("ClassName")).isEqualTo(child.getClass().getName());
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseCacheTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseCacheTestItCase.java
new file mode 100644
index 000000000..f406e5ed2
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseCacheTestItCase.java
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class DcaeInventoryResponseCacheTestItCase {
+
+ public static DcaeInventoryCache inventoryCache = new DcaeInventoryCache();
+
+ @Autowired
+ CamelContext camelContext;
+
+ /**
+ * Initialize the responses.
+ */
+ @BeforeClass
+ public static void createExample() {
+ DcaeInventoryResponse response1 = new DcaeInventoryResponse();
+ response1.setAsdcServiceId("id1");
+ response1.setAsdcResourceId("0");
+ DcaeInventoryResponse response2 = new DcaeInventoryResponse();
+ response2.setAsdcServiceId("id1");
+ response2.setAsdcResourceId("1");
+ DcaeInventoryResponse response3 = new DcaeInventoryResponse();
+ response3.setAsdcServiceId("id1");
+ response3.setAsdcResourceId("2");
+ DcaeInventoryResponse response4 = new DcaeInventoryResponse();
+ response4.setAsdcServiceId("id2");
+ response4.setAsdcResourceId("0");
+ DcaeInventoryResponse response5 = new DcaeInventoryResponse();
+ response5.setAsdcServiceId("id2");
+ response5.setAsdcResourceId("1");
+
+ inventoryCache.addDcaeInventoryResponse(response1);
+ inventoryCache.addDcaeInventoryResponse(response3);
+ inventoryCache.addDcaeInventoryResponse(response2);
+ inventoryCache.addDcaeInventoryResponse(response4);
+ inventoryCache.addDcaeInventoryResponse(response5);
+ }
+
+ @Test
+ public void testGetAllLoopIds() {
+ assertThat(inventoryCache.getAllLoopIds().size()).isEqualTo(2);
+ }
+
+ @Test
+ public void testGetAllBlueprintsPerLoopId() {
+ int value = 0;
+ for (DcaeInventoryResponse inventoryResponse : inventoryCache.getAllBlueprintsPerLoopId("id1")) {
+ assertThat(Integer.valueOf(inventoryResponse.getAsdcResourceId())).isEqualTo(value++);
+ }
+
+ value = 0;
+ for (DcaeInventoryResponse inventoryResponse : inventoryCache.getAllBlueprintsPerLoopId("id2")) {
+ assertThat(Integer.valueOf(inventoryResponse.getAsdcResourceId())).isEqualTo(value++);
+ }
+ }
+
+ @Test
+ public void testDcaeInventoryResponse() {
+ Exchange exchange = ExchangeBuilder.anExchange(camelContext).build();
+ Exchange exchangeResponse = camelContext.createProducerTemplate()
+ .send("direct:get-all-dcae-blueprint-inventory", exchange);
+ assertThat(HttpStatus.valueOf((Integer) exchangeResponse.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE))
+ .is2xxSuccessful()).isTrue();
+ Set<DcaeInventoryResponse> blueprint = inventoryCache.getAllBlueprintsPerLoopId("testAsdcServiceId");
+ assertThat(blueprint.size()).isEqualTo(2);
+
+ DcaeInventoryResponse response1 = new DcaeInventoryResponse();
+ response1.setAsdcResourceId("0");
+ response1.setTypeName("testTypeName");
+ response1.setAsdcServiceId("testAsdcServiceId");
+ response1.setBlueprintTemplate("testBlueprintTemplate");
+ response1.setTypeId("testtypeId");
+ DcaeInventoryResponse response2 = new DcaeInventoryResponse();
+ response2.setAsdcResourceId("1");
+ response2.setTypeName("testTypeName2");
+ response2.setAsdcServiceId("testAsdcServiceId");
+ response2.setBlueprintTemplate("testBlueprintTemplate2");
+ response2.setTypeId("testtypeId2");
+
+ Set<DcaeInventoryResponse> expectedBlueprint = new HashSet<>();
+ expectedBlueprint.add(response1);
+ expectedBlueprint.add(response2);
+
+ assertEquals(blueprint, expectedBlueprint);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseTest.java
new file mode 100644
index 000000000..a246e0efa
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/model/dcae/DcaeInventoryResponseTest.java
@@ -0,0 +1,59 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.dcae;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.TreeSet;
+import org.junit.Test;
+
+public class DcaeInventoryResponseTest {
+
+ @Test
+ public void testComparator() {
+ DcaeInventoryResponse response1 = new DcaeInventoryResponse();
+ response1.setAsdcServiceId("id1");
+ response1.setAsdcResourceId("0");
+ DcaeInventoryResponse response2 = new DcaeInventoryResponse();
+ response2.setAsdcServiceId("id2");
+ response2.setAsdcResourceId("1");
+ DcaeInventoryResponse response3 = new DcaeInventoryResponse();
+ response3.setAsdcServiceId("id3");
+ response3.setAsdcResourceId("2");
+ DcaeInventoryResponse response4 = new DcaeInventoryResponse();
+ response4.setAsdcServiceId("id4");
+ response4.setAsdcResourceId("3");
+
+ TreeSet<DcaeInventoryResponse> responseSet = new TreeSet<>();
+ responseSet.add(response4);
+ responseSet.add(response3);
+ responseSet.add(response1);
+ responseSet.add(response2);
+
+ int value = 0;
+ for (DcaeInventoryResponse inventoryResponse : responseSet) {
+ assertThat(Integer.valueOf(inventoryResponse.getAsdcResourceId()) == value++).isTrue();
+ }
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/model/jsontype/JsonTypeDescriptorTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/model/jsontype/JsonTypeDescriptorTest.java
new file mode 100644
index 000000000..7999709c2
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/model/jsontype/JsonTypeDescriptorTest.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Samsung. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.model.jsontype;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import org.hibernate.HibernateException;
+import org.junit.Test;
+import org.onap.policy.clamp.dao.model.jsontype.JsonTypeDescriptor;
+
+public class JsonTypeDescriptorTest {
+
+ private JsonTypeDescriptor descriptor = new JsonTypeDescriptor();
+
+ @Test
+ public void testFromString() {
+ JsonObject object = new JsonObject();
+ object.addProperty("one", "oneValue");
+ JsonObject child = new JsonObject();
+ child.addProperty("two", "twoValue");
+ object.add("child", child);
+
+ JsonObject jsonResult = descriptor.fromString("{\"one\":\"oneValue\",\"child\":{\"two\":\"twoValue\"}}");
+
+ assertThat(jsonResult).isEqualTo(object);
+ }
+
+ @Test
+ public void testUnwrap() {
+ JsonObject res1 = descriptor.unwrap(null, null, null);
+ assertThat(res1).isNull();
+
+ JsonObject object = new JsonObject();
+ object.addProperty("one", "oneValue");
+ JsonObject child = new JsonObject();
+ child.addProperty("two", "twoValue");
+ object.add("child", child);
+ String res2 = descriptor.unwrap(object, String.class, null);
+ assertThat(res2.replace("\n", "").replace(" ", ""))
+ .isEqualTo("{\"one\":\"oneValue\",\"child\":{\"two\":\"twoValue\"}}");
+
+ Object res3 = descriptor.unwrap(object, JsonObject.class, null);
+ String res3Str = ((String) res3).replace(" ", "").replace("\\n", "").replace("\\", "")
+ .replace("\"{", "{").replace("}\"", "}");
+ assertThat(res3Str).isEqualTo("{\"one\":\"oneValue\",\"child\":{\"two\":\"twoValue\"}}");
+ }
+
+ @Test(expected = HibernateException.class)
+ public void testUnwrapExpectationThrown() {
+ JsonObject object = new JsonObject();
+ object.addProperty("one", "oneValue");
+
+ descriptor.unwrap(object, Integer.class, null);
+ }
+
+ @Test
+ public void testWrap() {
+ JsonObject res1 = descriptor.wrap(null, null);
+ assertThat(res1).isNull();
+
+ JsonObject object = new JsonObject();
+ object.addProperty("one", "oneValue");
+ JsonObject child = new JsonObject();
+ child.addProperty("two", "twoValue");
+ object.add("child", child);
+ JsonObject res2 = descriptor.wrap("{\"one\":\"oneValue\",\"child\":{\"two\":\"twoValue\"}}", null);
+ assertThat(res2).isEqualTo(object);
+ }
+
+ @Test(expected = HibernateException.class)
+ public void testWrapExpectationThrown() {
+ descriptor.wrap(1, null);
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParserTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParserTest.java
new file mode 100644
index 000000000..085b3d187
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/BlueprintParserTest.java
@@ -0,0 +1,208 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.json.JSONObject;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.yaml.snakeyaml.Yaml;
+
+public class BlueprintParserTest {
+ private static final Gson GSON = new Gson();
+ private static final String FIRST_APPP = "first_app";
+ private static final String SECOND_APPP = "second_app";
+ private static final String THIRD_APPP = "third_app";
+ private static final String MODEL_TYPE1 = "type1";
+ private static final String MODEL_TYPE_TCA = "onap.policies.monitoring.cdap.tca.hi.lo.app";
+ private static final String VERSION = "1.0.0";
+
+ private static String microServiceTheWholeBlueprintValid;
+ private static String newMicroServiceBlueprint;
+ private static JsonObject jsonObjectBlueprintInvalid;
+ private static JsonObject jsonObjectBlueprintWithoutName;
+ private static JsonObject jsonObjectBlueprintWithoutProperties;
+ private static JsonObject jsonObjectBlueprintWithoutRelationships;
+ private static JsonObject jsonObjectBlueprintValidWithVersion;
+
+ /**
+ * Method to load Blueprints before all test.
+ *
+ * @throws IOException In case of issues when opening the files
+ */
+ @BeforeClass
+ public static void loadBlueprints() throws IOException {
+ microServiceTheWholeBlueprintValid = ResourceFileUtils
+ .getResourceAsString("clds/blueprint-with-microservice-chain.yaml");
+
+ newMicroServiceBlueprint = ResourceFileUtils.getResourceAsString("clds/new-microservice.yaml");
+
+ String microServiceBlueprintInvalid = ResourceFileUtils
+ .getResourceAsString("clds/single-microservice-fragment-invalid.yaml");
+ jsonObjectBlueprintInvalid = yamlToJson(microServiceBlueprintInvalid);
+ String microServiceBlueprintWithoutName = ResourceFileUtils
+ .getResourceAsString("clds/single-microservice-fragment-without-name.yaml");
+ jsonObjectBlueprintWithoutName = yamlToJson(microServiceBlueprintWithoutName);
+ String microServiceBlueprintWithoutProperties = ResourceFileUtils
+ .getResourceAsString("clds/single-microservice-fragment-without-properties.yaml");
+ jsonObjectBlueprintWithoutProperties = yamlToJson(microServiceBlueprintWithoutProperties);
+ String microServiceBlueprintValidWithVersion = ResourceFileUtils
+ .getResourceAsString("clds/single-microservice-fragment-valid-with-version.yaml");
+ jsonObjectBlueprintValidWithVersion = yamlToJson(microServiceBlueprintValidWithVersion);
+
+ String microServiceBlueprintWithoutRelationships = ResourceFileUtils
+ .getResourceAsString("clds/single-microservice-fragment-without-relationships.yaml");
+ jsonObjectBlueprintWithoutRelationships = yamlToJson(microServiceBlueprintWithoutRelationships);
+
+ }
+
+ @Test
+ public void getNameShouldReturnDefinedName() {
+ final JsonObject jsonObject = jsonObjectBlueprintInvalid;
+ String expectedName = jsonObject.get(jsonObject.keySet().iterator().next()).getAsJsonObject().get("properties")
+ .getAsJsonObject().get("name").getAsString();
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ String actualName = BlueprintParser.getName(entry);
+
+ Assert.assertEquals(expectedName, actualName);
+ }
+
+ @Test
+ public void getNameShouldReturnServiceNameWhenNoNameDefined() {
+ final JsonObject jsonObject = jsonObjectBlueprintWithoutName;
+
+ String expectedName = jsonObject.keySet().iterator().next();
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ String actualName = BlueprintParser.getName(entry);
+
+ Assert.assertEquals(expectedName, actualName);
+ }
+
+ @Test
+ public void getNameShouldReturnServiceNameWhenNoPropertiesDefined() {
+ final JsonObject jsonObject = jsonObjectBlueprintWithoutProperties;
+
+ String expectedName = jsonObject.keySet().iterator().next();
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ String actualName = BlueprintParser.getName(entry);
+
+ Assert.assertEquals(expectedName, actualName);
+ }
+
+ @Test
+ public void getInputShouldReturnInputWhenPresent() {
+ final JsonObject jsonObject = jsonObjectBlueprintInvalid;
+
+ String expected = FIRST_APPP;
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ String actual = BlueprintParser.getInput(entry);
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void getInputShouldReturnEmptyStringWhenAbsent() {
+ final JsonObject jsonObject = jsonObjectBlueprintWithoutRelationships;
+
+ String expected = "";
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ String actual = BlueprintParser.getInput(entry);
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test(expected = BlueprintParserException.class)
+ public void getNodeRepresentationFromIncompleteYaml() throws BlueprintParserException {
+ BlueprintParser.getNodeRepresentation(jsonObjectBlueprintInvalid.entrySet().iterator().next(),
+ jsonObjectBlueprintInvalid, null);
+ }
+
+ @Test
+ public void getNodeRepresentationFromCompleteYamlWithModelVersion() throws BlueprintParserException {
+ final JsonObject jsonObject = jsonObjectBlueprintValidWithVersion;
+
+ BlueprintMicroService expected = new BlueprintMicroService(SECOND_APPP, MODEL_TYPE1, "", "10.0.0");
+ Entry<String, JsonElement> entry = jsonObject.entrySet().iterator().next();
+ BlueprintMicroService actual = BlueprintParser.getNodeRepresentation(entry, jsonObject, null);
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void getMicroServicesFromBlueprintTest() throws BlueprintParserException {
+ BlueprintMicroService thirdApp = new BlueprintMicroService(THIRD_APPP, MODEL_TYPE_TCA, SECOND_APPP, VERSION);
+ BlueprintMicroService firstApp = new BlueprintMicroService(FIRST_APPP, MODEL_TYPE_TCA, "", VERSION);
+ BlueprintMicroService secondApp = new BlueprintMicroService(SECOND_APPP, MODEL_TYPE_TCA, FIRST_APPP, VERSION);
+
+ Set<BlueprintMicroService> expected = new HashSet<>(Arrays.asList(firstApp, secondApp, thirdApp));
+ Set<BlueprintMicroService> actual = BlueprintParser.getMicroServices(microServiceTheWholeBlueprintValid);
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void fallBackToOneMicroServiceTcaTest() {
+ BlueprintMicroService tcaMs = new BlueprintMicroService(BlueprintParser.TCA,
+ "onap.policies.monitoring.cdap.tca.hi.lo.app", "", VERSION);
+ List<BlueprintMicroService> expected = Collections.singletonList(tcaMs);
+ List<BlueprintMicroService> actual = BlueprintParser.fallbackToOneMicroService();
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void newMicroServiceTest() throws BlueprintParserException {
+ List<BlueprintMicroService> microServicesChain = new ChainGenerator()
+ .getChainOfMicroServices(BlueprintParser.getMicroServices(newMicroServiceBlueprint));
+ if (microServicesChain.isEmpty()) {
+ microServicesChain = BlueprintParser.fallbackToOneMicroService();
+ }
+ assertThat(microServicesChain.size()).isEqualTo(1);
+ assertThat(microServicesChain.get(0).getName()).isEqualTo("pmsh");
+ }
+
+ private static JsonObject yamlToJson(String yamlString) {
+ Yaml yaml = new Yaml();
+ Map<String, Object> map = yaml.load(yamlString);
+ JSONObject jsonObject = new JSONObject(map);
+ return GSON.fromJson(jsonObject.toString(), JsonObject.class);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGeneratorTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGeneratorTest.java
new file mode 100644
index 000000000..d7a3b3823
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/ChainGeneratorTest.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ChainGeneratorTest {
+ private static final String FIRST_APPP = "first_app";
+ private static final String SECOND_APPP = "second_app";
+ private static final String THIRD_APPP = "third_app";
+ private static final String FOURTH_APPP = "fourth_app";
+ private static final String DEFAULT_VERSION = "1.0.0";
+
+ @Test
+ public void getChainOfMicroServicesTest() {
+ BlueprintMicroService ms1 = new BlueprintMicroService(FIRST_APPP, "", "", DEFAULT_VERSION);
+ BlueprintMicroService ms2 = new BlueprintMicroService(SECOND_APPP, "", FIRST_APPP, DEFAULT_VERSION);
+ BlueprintMicroService ms3 = new BlueprintMicroService(THIRD_APPP, "", SECOND_APPP, DEFAULT_VERSION);
+ BlueprintMicroService ms4 = new BlueprintMicroService(FOURTH_APPP, "", THIRD_APPP, DEFAULT_VERSION);
+
+ List<BlueprintMicroService> expectedList = Arrays.asList(ms1, ms2, ms3, ms4);
+ Set<BlueprintMicroService> inputSet = new HashSet<>(expectedList);
+
+ List<BlueprintMicroService> actualList = new ChainGenerator().getChainOfMicroServices(inputSet);
+ Assert.assertEquals(expectedList, actualList);
+ }
+
+ @Test
+ public void getChainOfMicroServicesTwiceNoInputTest() {
+ BlueprintMicroService ms1 = new BlueprintMicroService(FIRST_APPP, "", "", DEFAULT_VERSION);
+ BlueprintMicroService ms2 = new BlueprintMicroService(SECOND_APPP, "", "", DEFAULT_VERSION);
+ BlueprintMicroService ms3 = new BlueprintMicroService(THIRD_APPP, "", SECOND_APPP, DEFAULT_VERSION);
+ BlueprintMicroService ms4 = new BlueprintMicroService(FOURTH_APPP, "", FIRST_APPP, DEFAULT_VERSION);
+
+ Set<BlueprintMicroService> inputSet = new HashSet<>(Arrays.asList(ms1, ms2, ms3, ms4));
+ List<BlueprintMicroService> actualList = new ChainGenerator().getChainOfMicroServices(inputSet);
+ Assert.assertTrue(actualList.isEmpty());
+ }
+
+ @Test
+ public void getChainOfMicroServicesBranchingTest() {
+ BlueprintMicroService ms1 = new BlueprintMicroService(FIRST_APPP, "", "", DEFAULT_VERSION);
+ BlueprintMicroService ms2 = new BlueprintMicroService(SECOND_APPP, "", FIRST_APPP, DEFAULT_VERSION);
+ BlueprintMicroService ms3 = new BlueprintMicroService(THIRD_APPP, "", FIRST_APPP, DEFAULT_VERSION);
+ BlueprintMicroService ms4 = new BlueprintMicroService(FOURTH_APPP, "", FIRST_APPP, DEFAULT_VERSION);
+
+ Set<BlueprintMicroService> inputSet = new HashSet<>(Arrays.asList(ms1, ms2, ms3, ms4));
+ List<BlueprintMicroService> actualList = new ChainGenerator().getChainOfMicroServices(inputSet);
+ Assert.assertTrue(actualList.isEmpty());
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandlerTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandlerTest.java
new file mode 100644
index 000000000..08e425abf
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/sdc/controller/installer/CsarHandlerTest.java
@@ -0,0 +1,199 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.sdc.controller.installer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.notification.IResourceInstance;
+import org.onap.sdc.api.results.IDistributionClientDownloadResult;
+import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
+
+public class CsarHandlerTest {
+
+ private static final String SDC_FOLDER = "/tmp/csar-handler-tests";
+ private static final String CSAR_ARTIFACT_NAME = "testArtifact.csar";
+ private static final String SERVICE_UUID = "serviceUUID";
+ private static final String RESOURCE1_UUID = "resource1UUID";
+ private static final String RESOURCE1_INSTANCE_NAME = "sim-1802 0";
+ private static final String RESOURCE1_INSTANCE_NAME_IN_CSAR = "sim18020";
+ private static final String BLUEPRINT1_NAME = "FOI.Simfoimap223S0112.event_proc_bp.yaml";
+ private static final String BLUEPRINT2_NAME = "FOI.Simfoimap223S0112.event_proc_bp2.yaml";
+
+ @Test
+ public void testConstructor() throws CsarHandlerException {
+ IArtifactInfo serviceArtifact = Mockito.mock(IArtifactInfo.class);
+ Mockito.when(serviceArtifact.getArtifactType()).thenReturn(CsarHandler.CSAR_TYPE);
+ Mockito.when(serviceArtifact.getArtifactName()).thenReturn(CSAR_ARTIFACT_NAME);
+ List<IArtifactInfo> servicesList = new ArrayList<>();
+ servicesList.add(serviceArtifact);
+ INotificationData notifData = Mockito.mock(INotificationData.class);
+ Mockito.when(notifData.getServiceArtifacts()).thenReturn(servicesList);
+ CsarHandler csar = new CsarHandler(notifData, "test-controller", SDC_FOLDER);
+ assertEquals(SDC_FOLDER + "/test-controller" + "/" + CSAR_ARTIFACT_NAME, csar.getFilePath());
+ }
+
+ @Test(expected = CsarHandlerException.class)
+ public void testFailingConstructor() throws CsarHandlerException {
+ INotificationData notifData = Mockito.mock(INotificationData.class);
+ Mockito.when(notifData.getServiceArtifacts()).thenReturn(new ArrayList<>());
+ new CsarHandler(notifData, "test-controller", "/tmp/csar-handler-tests");
+ fail("Exception should have been raised");
+ }
+
+ private INotificationData buildFakeSdcNotification() {
+ // BUild what is needed for CSAR
+ IArtifactInfo serviceArtifact = Mockito.mock(IArtifactInfo.class);
+ Mockito.when(serviceArtifact.getArtifactType()).thenReturn(CsarHandler.CSAR_TYPE);
+ Mockito.when(serviceArtifact.getArtifactName()).thenReturn(CSAR_ARTIFACT_NAME);
+ List<IArtifactInfo> servicesList = new ArrayList<>();
+ servicesList.add(serviceArtifact);
+ INotificationData notifData = Mockito.mock(INotificationData.class);
+ Mockito.when(notifData.getServiceArtifacts()).thenReturn(servicesList);
+ // Build what is needed for UUID
+ Mockito.when(notifData.getServiceInvariantUUID()).thenReturn(SERVICE_UUID);
+ // Build fake resource with one artifact BLUEPRINT
+ IResourceInstance resource1 = Mockito.mock(IResourceInstance.class);
+ Mockito.when(resource1.getResourceType()).thenReturn("VF");
+ Mockito.when(resource1.getResourceInvariantUUID()).thenReturn(RESOURCE1_UUID);
+ Mockito.when(resource1.getResourceInstanceName()).thenReturn(RESOURCE1_INSTANCE_NAME);
+ // Create a fake artifact for resource
+ IArtifactInfo blueprintArtifact = Mockito.mock(IArtifactInfo.class);
+ Mockito.when(blueprintArtifact.getArtifactType()).thenReturn(CsarHandler.BLUEPRINT_TYPE);
+ List<IArtifactInfo> artifactsListForResource = new ArrayList<>();
+ artifactsListForResource.add(blueprintArtifact);
+ Mockito.when(resource1.getArtifacts()).thenReturn(artifactsListForResource);
+ List<IResourceInstance> resourcesList = new ArrayList<>();
+ resourcesList.add(resource1);
+ Mockito.when(notifData.getResources()).thenReturn(resourcesList);
+ return notifData;
+ }
+
+ private IDistributionClientDownloadResult buildFakeSdcResut() throws IOException {
+ IDistributionClientDownloadResult resultArtifact = Mockito.mock(IDistributionClientDownloadResult.class);
+ Mockito.when(resultArtifact.getArtifactPayload()).thenReturn(
+ IOUtils.toByteArray(ResourceFileUtils.getResourceAsStream("example/sdc/service-Simsfoimap0112.csar")));
+ return resultArtifact;
+ }
+
+ private IDistributionClientDownloadResult buildFakeSdcResultWithoutPolicyModel() throws IOException {
+ IDistributionClientDownloadResult resultArtifact = Mockito.mock(IDistributionClientDownloadResult.class);
+ Mockito.when(resultArtifact.getArtifactPayload()).thenReturn(
+ IOUtils.toByteArray(ResourceFileUtils.getResourceAsStream("example/sdc/service-without-policy.csar")));
+ return resultArtifact;
+ }
+
+ @Test
+ public void testSave()
+ throws SdcArtifactInstallerException, SdcToscaParserException, CsarHandlerException, IOException {
+ CsarHandler csar = new CsarHandler(buildFakeSdcNotification(), "test-controller", "/tmp/csar-handler-tests");
+ // Test the save
+ csar.save(buildFakeSdcResut());
+ assertTrue((new File(SDC_FOLDER + "/test-controller/" + CSAR_ARTIFACT_NAME)).exists());
+ assertEquals(CSAR_ARTIFACT_NAME, csar.getArtifactElement().getArtifactName());
+ assertNotNull(csar.getSdcCsarHelper());
+ // Test dcaeBlueprint
+ String blueprint = csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getDcaeBlueprint();
+ assertNotNull(blueprint);
+ assertTrue(!blueprint.isEmpty());
+ assertTrue(blueprint.contains("DCAE-VES-PM-EVENT-v1"));
+ // Test additional properties from Sdc notif
+ assertEquals(BLUEPRINT1_NAME, csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getBlueprintArtifactName());
+ assertEquals(RESOURCE1_UUID,
+ csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getResourceAttached().getResourceInvariantUUID());
+ assertEquals(SERVICE_UUID, csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getBlueprintInvariantServiceUuid());
+
+ // Just check the second one is there as well
+ assertEquals(BLUEPRINT2_NAME, csar.getMapOfBlueprints().get(BLUEPRINT2_NAME).getBlueprintArtifactName());
+ blueprint = csar.getMapOfBlueprints().get(BLUEPRINT2_NAME).getDcaeBlueprint();
+ assertNotNull(blueprint);
+ assertTrue(!blueprint.isEmpty());
+ assertTrue(blueprint.contains("DCAE-VES-PM-EVENT-v1"));
+ // Do some cleanup
+ Path path = Paths.get(SDC_FOLDER + "/test-controller/" + CSAR_ARTIFACT_NAME);
+ Files.deleteIfExists(path);
+
+ }
+
+ @Test
+ public void testLoadingOfPolicyModelFromCsar()
+ throws CsarHandlerException, IOException, SdcArtifactInstallerException, SdcToscaParserException {
+ CsarHandler csar = new CsarHandler(buildFakeSdcNotification(), "test-controller", "/tmp/csar-handler-tests");
+ csar.save(buildFakeSdcResut());
+ String policyModelYaml = csar.getPolicyModelYaml().get();
+ assertTrue(policyModelYaml.contains("tosca_simple_yaml_1_0_0"));
+ }
+
+ @Test
+ public void testLoadingOfNonexistentPolicyModelFromCsar()
+ throws CsarHandlerException, IOException, SdcArtifactInstallerException, SdcToscaParserException {
+ CsarHandler csar = new CsarHandler(buildFakeSdcNotification(), "test-controller", "/tmp/csar-handler-tests");
+ csar.save(buildFakeSdcResultWithoutPolicyModel());
+ assertFalse(csar.getPolicyModelYaml().isPresent());
+ }
+
+ @Test
+ public void testDoubleSave()
+ throws SdcArtifactInstallerException, SdcToscaParserException, CsarHandlerException, IOException {
+ CsarHandler csar = new CsarHandler(buildFakeSdcNotification(), "test-controller", "/tmp/csar-handler-tests");
+ // Test the save
+ csar.save(buildFakeSdcResut());
+ assertTrue((new File(SDC_FOLDER + "/test-controller/" + CSAR_ARTIFACT_NAME)).exists());
+ assertEquals(CSAR_ARTIFACT_NAME, csar.getArtifactElement().getArtifactName());
+ assertNotNull(csar.getSdcCsarHelper());
+ // Test dcaeBlueprint
+ String blueprint = csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getDcaeBlueprint();
+ assertNotNull(blueprint);
+ assertTrue(!blueprint.isEmpty());
+ assertTrue(blueprint.contains("DCAE-VES-PM-EVENT-v1"));
+ // Test additional properties from Sdc notif
+ assertEquals(BLUEPRINT1_NAME, csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getBlueprintArtifactName());
+ assertEquals(RESOURCE1_UUID,
+ csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getResourceAttached().getResourceInvariantUUID());
+ assertEquals(SERVICE_UUID, csar.getMapOfBlueprints().get(BLUEPRINT1_NAME).getBlueprintInvariantServiceUuid());
+ Path path = Paths.get(SDC_FOLDER + "/test-controller/" + CSAR_ARTIFACT_NAME);
+ // A double save should simply overwrite the existing
+ csar.save(buildFakeSdcResut());
+ // Do some cleanup
+ Files.deleteIfExists(path);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/DictionaryRepositoriesTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/DictionaryRepositoriesTestItCase.java
new file mode 100644
index 000000000..f70e74cd6
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/DictionaryRepositoriesTestItCase.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.tosca.Dictionary;
+import org.onap.policy.clamp.tosca.DictionaryElement;
+import org.onap.policy.clamp.tosca.DictionaryRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = Application.class)
+public class DictionaryRepositoriesTestItCase {
+ @Autowired
+ private DictionaryRepository dictionaryRepository;
+
+ @Test
+ @Transactional
+ public void crudTest() {
+ // Setup
+ Dictionary dictionaryTest1 = new Dictionary();
+ dictionaryTest1.setName("testDictionary1");
+ dictionaryTest1.setSecondLevelDictionary(1);
+ dictionaryTest1.setSubDictionaryType("testType");
+
+ DictionaryElement element1 = new DictionaryElement();
+ element1.setName("element1");
+ element1.setShortName("shortName1");
+ element1.setType("type1");
+ element1.setDescription("description1");
+
+ dictionaryTest1.addDictionaryElements(element1);
+
+ Dictionary dictionaryTest2 = new Dictionary();
+ dictionaryTest2.setName("testDictionary2");
+ dictionaryTest2.setSecondLevelDictionary(1);
+ dictionaryTest2.setSubDictionaryType("testType");
+
+ DictionaryElement element2 = new DictionaryElement();
+ element2.setName("element2");
+ element2.setShortName("shortName2");
+ element2.setSubDictionary("testDictionary1");
+ element2.setType("type2");
+ element2.setDescription("description2");
+
+ dictionaryTest2.addDictionaryElements(element2);
+
+ dictionaryRepository.save(dictionaryTest1);
+ List<String> res1 = dictionaryRepository.getAllDictionaryNames();
+ assertThat(res1.size()).isGreaterThanOrEqualTo(1);
+ assertThat(res1).contains("testDictionary1");
+
+ dictionaryRepository.save(dictionaryTest2);
+ List<String> res2 = dictionaryRepository.getAllDictionaryNames();
+ assertThat(res2.size()).isGreaterThanOrEqualTo(2);
+ assertThat(res2).contains("testDictionary1");
+ assertThat(res2).contains("testDictionary2");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ArrayFieldTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ArrayFieldTest.java
new file mode 100644
index 000000000..6f6f5c104
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ArrayFieldTest.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import com.google.gson.JsonArray;
+import java.io.IOException;
+import java.util.ArrayList;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.elements.ArrayField;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+public class ArrayFieldTest extends TestCase {
+
+ /**
+ * Test the deploy method.
+ *
+ * @throws IOException in case of failure
+ */
+ public void testDeploy() throws IOException {
+ JsonTemplateManager jsonTemplateManager = new JsonTemplateManager(ResourceFileUtils.getResourceAsString(
+ "tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml"), ResourceFileUtils.getResourceAsString(
+ "clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ ToscaElement toscaElement = jsonTemplateManager.getToscaElements().get("onap.datatype.controlloop.Actor");
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("actor");
+ ArrayField arrayParser = new ArrayField((ArrayList<Object>) toscaElementProperty.getItems().get("default"));
+ JsonArray toTest = arrayParser.deploy();
+ String reference = "[1,\"String\",5.5,true]";
+ assertEquals(reference, String.valueOf(toTest));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ConstraintTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ConstraintTest.java
new file mode 100644
index 000000000..493ee992c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ConstraintTest.java
@@ -0,0 +1,106 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.ArrayList;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+public class ConstraintTest extends TestCase {
+
+ JsonTemplateManager jsonTemplateManager = new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/constraints.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+
+ ToscaElement toscaElement = jsonTemplateManager.getToscaElements().get("onap.datatype.controlloop.Operation");
+
+ public ConstraintTest() throws IOException {
+ }
+
+ /**
+ * Test get value array.
+ */
+ public void testGetValuesArray() {
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("timeout");
+ JsonTemplate jsonTemplate = jsonTemplateManager.getJsonSchemaTemplates().get("integer");
+ JsonObject resultProcess = new JsonObject();
+ toscaElementProperty.addConstraintsAsJson(resultProcess,
+ (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ jsonTemplate);
+ String reference = "{\"enum\":[3,4,5.5,6,10]}";
+ assertEquals(reference, String.valueOf(resultProcess));
+ toscaElementProperty = toscaElement.getProperties().get("success");
+ jsonTemplate = jsonTemplateManager.getJsonSchemaTemplates().get("string");
+ resultProcess = new JsonObject();
+ toscaElementProperty.addConstraintsAsJson(resultProcess,
+ (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ jsonTemplate);
+ reference = "{\"enum\":[\"VALID\",\"TERMINATED\"]}";
+ assertEquals(reference, String.valueOf(resultProcess));
+ }
+
+ /**
+ * Test get Specific length.
+ */
+ public void testGetSpecificLength() {
+ //Test for string type, same process for array
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("id");
+ JsonTemplate jsonTemplate = jsonTemplateManager.getJsonSchemaTemplates().get("string");
+ JsonObject resultProcess = new JsonObject();
+ toscaElementProperty.addConstraintsAsJson(resultProcess,
+ (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ jsonTemplate);
+ int specificLength = 8;
+ int toTest = resultProcess.get("minLength").getAsInt();
+ assertEquals(specificLength, toTest);
+ toTest = resultProcess.get("maxLength").getAsInt();
+ assertEquals(specificLength, toTest);
+ }
+
+ /**
+ * Test get limit value.
+ */
+ public void testGetLimitValue() {
+ //Test for array type, same process for string
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("description");
+ JsonTemplate jsonTemplate = jsonTemplateManager.getJsonSchemaTemplates().get("array");
+ JsonObject resultProcess = new JsonObject();
+ toscaElementProperty.addConstraintsAsJson(resultProcess,
+ (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ jsonTemplate);
+
+ int toTest = resultProcess.get("minItems").getAsInt();
+ assertEquals(5, toTest);
+ toTest = resultProcess.get("maxItems").getAsInt();
+ assertEquals(7, toTest);
+ }
+
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateFieldTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateFieldTest.java
new file mode 100644
index 000000000..3eaa0ce51
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateFieldTest.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateField;
+
+public class JsonTemplateFieldTest extends TestCase {
+
+ JsonTemplateField field1 = new JsonTemplateField("type", "testType", true, true);
+ JsonTemplateField field2 = new JsonTemplateField("type");
+ JsonTemplateField field3 = new JsonTemplateField("type", "testType1", true, true);
+ JsonTemplateField field4 = new JsonTemplateField("type", "testType", false, true);
+ JsonTemplateField field5 = new JsonTemplateField("type", "testType", true, false);
+ JsonTemplateField field6 = new JsonTemplateField("type", "testType", true, true);
+
+ /**
+ * Test fieldsEqual method.
+ */
+ public void testFieldsEqualsMethod() {
+ assertFalse(JsonTemplateField.fieldsEquals(field1, field3));
+ assertFalse(JsonTemplateField.fieldsEquals(field1, field4));
+ assertFalse(JsonTemplateField.fieldsEquals(field1, field5));
+ assertTrue(JsonTemplateField.fieldsEquals(field1, field6));
+ }
+
+ /**
+ * Test equals method.
+ */
+ public void testEqualsMethod() {
+ assertTrue(field1.equals(field2));
+ assertTrue(field1.equals(field3));
+ assertTrue(field1.equals(field4));
+ assertTrue(field1.equals(field5));
+ assertTrue(field1.equals(field6));
+ }
+
+ /**
+ * Test compareWithField method.
+ */
+ public void testCompareWithFieldMethod() {
+ assertFalse(field1.compareWithField(field2));
+ assertFalse(field1.compareWithField(field3));
+ assertFalse(field1.compareWithField(field4));
+ assertFalse(field1.compareWithField(field5));
+ assertTrue(field1.equals(field6));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateManagerTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateManagerTest.java
new file mode 100644
index 000000000..2c8744f33
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateManagerTest.java
@@ -0,0 +1,203 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateField;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+public class JsonTemplateManagerTest extends TestCase {
+
+ /**
+ * Test the launch translation wit operational policies.
+ *
+ * @throws IOException In case of failure
+ * @throws UnknownComponentException In case of failure
+ */
+ public void testLaunchTranslationTca() throws IOException, UnknownComponentException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policytypes/onap"
+ + ".policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file"),
+ ResourceFileUtils.getResourceAsString(
+ "clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ String componentName = "onap.policies.monitoring.cdap.tca.hi.lo.app";
+ jsonTemplateManager.getJsonSchemaForPolicyType(componentName, null, null);
+ }
+
+ /**
+ * Test the launch translation wit operational policies.
+ *
+ * @throws IOException In case of failure
+ * @throws UnknownComponentException In case of failure
+ */
+ public void testLaunchTranslationFrequencyLimiter() throws IOException, UnknownComponentException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policytypes/onap"
+ + ".policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.file"),
+ ResourceFileUtils.getResourceAsString(
+ "clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ String componentName = "onap.policies.controlloop.guard.common.FrequencyLimiter";
+ jsonTemplateManager.getJsonSchemaForPolicyType(componentName, null, null);
+ }
+
+ /**
+ * Test the launch translation wit operational policies.
+ *
+ * @throws IOException In case of failure
+ * @throws UnknownComponentException In case of failure
+ */
+ public void testLaunchTranslationApex() throws IOException, UnknownComponentException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policytypes/onap"
+ + ".policies.controlloop.operational.common.Apex/versions/1.0.0/.file"),
+ ResourceFileUtils.getResourceAsString(
+ "clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ String componentName = "onap.policies.controlloop.operational.common.Apex";
+ jsonTemplateManager.getJsonSchemaForPolicyType(componentName, null, null);
+ }
+
+ /**
+ * Test the launch translation wit operational policies.
+ *
+ * @throws IOException In case of failure
+ * @throws UnknownComponentException In case of failure
+ */
+ public void testLaunchTranslationDrools() throws IOException, UnknownComponentException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policytypes/onap"
+ + ".policies.controlloop.operational.common.Drools/versions/1.0.0/.file"),
+ ResourceFileUtils.getResourceAsString(
+ "clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ String componentName = "onap.policies.controlloop.operational.common.Drools";
+ jsonTemplateManager.getJsonSchemaForPolicyType(componentName, null, null);
+ }
+
+
+ /**
+ * Test the launch translation.
+ *
+ * @throws IOException In case of failure
+ * @throws UnknownComponentException In case of failure
+ */
+ public void testLaunchTranslation() throws IOException, UnknownComponentException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ String componentName = "onap.policies.controlloop.operational.common.Drools";
+ jsonTemplateManager.getJsonSchemaForPolicyType(componentName, null, null);
+ }
+
+ /**
+ * Test addTemplate.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testAddTemplate() throws IOException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ int count = jsonTemplateManager.getJsonSchemaTemplates().size();
+ List<JsonTemplateField>
+ jsonTemplateFields =
+ new ArrayList<>(Arrays.asList(new JsonTemplateField("type"), new JsonTemplateField("description"),
+ new JsonTemplateField(
+ "required"),
+ new JsonTemplateField("metadata"), new JsonTemplateField("constraints")));
+ jsonTemplateManager.addTemplate("test", jsonTemplateFields);
+ assertNotSame(count, jsonTemplateManager.getJsonSchemaTemplates().size());
+ }
+
+ /**
+ * test Remove template.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testRemoveTemplate() throws IOException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ int count = jsonTemplateManager.getJsonSchemaTemplates().size();
+ jsonTemplateManager.removeTemplate("string");
+ assertNotSame(count, jsonTemplateManager.getJsonSchemaTemplates().size());
+ }
+
+ /**
+ * Test update template.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testUpdateTemplate() throws IOException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ int count = jsonTemplateManager.getJsonSchemaTemplates().get("integer").getJsonTemplateFields().size();
+ jsonTemplateManager.updateTemplate("integer", new JsonTemplateField("type"), false);
+ assertNotSame(count,
+ jsonTemplateManager.getJsonSchemaTemplates().get("integer").getJsonTemplateFields().size());
+ }
+
+ /**
+ * Test has template.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testHasTemplate() throws IOException {
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ boolean has = true;
+ List<JsonTemplateField> jsonTemplateFieldsString =
+ new ArrayList<>(Arrays.asList(new JsonTemplateField("type"), new JsonTemplateField("description"),
+ new JsonTemplateField("required"),
+ new JsonTemplateField("metadata"), new JsonTemplateField("constraints")));
+ JsonTemplate jsonTemplateTest = new JsonTemplate("String", jsonTemplateFieldsString);
+ has = jsonTemplateManager.hasTemplate(jsonTemplateTest);
+ assertEquals(false, has);
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateTest.java
new file mode 100644
index 000000000..dc27d8aaa
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/JsonTemplateTest.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateField;
+
+public class JsonTemplateTest extends TestCase {
+
+ JsonTemplate toTest = new JsonTemplate("toTest");
+ List<JsonTemplateField>
+ jsonTemplateFields = new ArrayList<>(
+ Arrays.asList(new JsonTemplateField("type"), new JsonTemplateField("description"),
+ new JsonTemplateField(
+ "enum")));
+
+ /**
+ * Test check failed.
+ */
+ public void testCheckFields() {
+ toTest.setJsonTemplateFields(jsonTemplateFields);
+ JsonTemplate reference = new JsonTemplate("toTest");
+ reference.setJsonTemplateFields(jsonTemplateFields);
+ assertTrue(toTest.checkFields(reference));
+ }
+
+ /**
+ * Test other methods.
+ */
+ public void testOtherFields() {
+ toTest.setJsonTemplateFields(jsonTemplateFields);
+ toTest.addField(new JsonTemplateField("moreField"));
+ toTest.setVisibility("moreField", true);
+ toTest.setStatic("moreField", true);
+ toTest.updateValueField("moreField", "testValue");
+
+ assertTrue(toTest.isVisible("moreField"));
+ assertTrue(toTest.getSpecificField("moreField").getValue().equals("testValue"));
+ assertTrue(toTest.fieldStaticStatus("moreField"));
+ assertTrue(toTest.toString()
+ .equals(" templateFields : [type null null null, description null null null, "
+ + "enum null null null, moreField testValue true true]"));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupportItCase.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupportItCase.java
new file mode 100644
index 000000000..658419d4c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaConverterWithDictionarySupportItCase.java
@@ -0,0 +1,147 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import javax.transaction.Transactional;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.tosca.update.execution.ToscaMetadataExecutor;
+import org.onap.policy.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParserWithDictionarySupport;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.tosca.Dictionary;
+import org.onap.policy.clamp.tosca.DictionaryElement;
+import org.onap.policy.clamp.tosca.DictionaryService;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = Application.class)
+@ActiveProfiles({"clamp-default", "clamp-default-user", "default-dictionary-elements"})
+public class ToscaConverterWithDictionarySupportItCase {
+
+ @Autowired
+ private DictionaryService dictionaryService;
+
+ @Autowired
+ private ToscaMetadataParserWithDictionarySupport toscaMetadataParserWithDictionarySupport;
+
+ @Autowired
+ private ToscaMetadataExecutor toscaMetadataExecutor;
+
+ /**
+ * This Test validates Tosca yaml with metadata tag that contains policy_model_type and acronym
+ * parameters which defines the Tosca Policy name and its short name.
+ *
+ * @throws IOException In case of issue when opening the tosca yaml file and
+ * converted json file
+ */
+ @Test
+ @Transactional
+ public final void testMetadataClampPossibleValues() throws IOException, UnknownComponentException {
+
+ // Set up dictionary elements
+ Dictionary dictionaryTest = new Dictionary();
+ dictionaryTest.setName("Context");
+ dictionaryTest.setSecondLevelDictionary(0);
+
+ DictionaryElement element = new DictionaryElement();
+ element.setName("PROD");
+ element.setShortName("PROD");
+ element.setType("string");
+ element.setDescription("Production");
+ dictionaryTest.addDictionaryElements(element);
+
+ dictionaryService.saveOrUpdateDictionary(dictionaryTest);
+
+ Dictionary dictionaryTest1 = new Dictionary();
+ dictionaryTest1.setName("EventDictionary");
+ dictionaryTest1.setSecondLevelDictionary(0);
+
+ DictionaryElement element1 = new DictionaryElement();
+ element1.setName("alarmCondition");
+ element1.setShortName("alarmCondition");
+ element1.setType("string");
+ element1.setDescription("Alarm Condition");
+ dictionaryTest1.addDictionaryElements(element1);
+
+ dictionaryService.saveOrUpdateDictionary(dictionaryTest1);
+
+ Dictionary dictionaryTest2 = new Dictionary();
+ dictionaryTest2.setName("Operators");
+ dictionaryTest2.setSecondLevelDictionary(0);
+
+ DictionaryElement element2 = new DictionaryElement();
+ element2.setName("equals");
+ element2.setShortName("equals");
+ element2.setType("string");
+ element2.setDescription("equals");
+ dictionaryTest2.addDictionaryElements(element2);
+ dictionaryService.saveOrUpdateDictionary(dictionaryTest2);
+
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils
+ .getResourceAsString("tosca/new-converter/tosca_metadata_clamp_possible_values.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+
+ JsonObject jsonSchema = jsonTemplateManager.getJsonSchemaForPolicyType(
+ "onap.policies.monitoring.cdap.tca.hi.lo.app", toscaMetadataParserWithDictionarySupport, null);
+
+ JSONAssert.assertEquals(
+ ResourceFileUtils
+ .getResourceAsString("tosca/new-converter/tca-with-metadata.json"),
+ JsonUtils.GSON.toJson(jsonSchema), true);
+ }
+
+ @Test
+ @Transactional
+ public final void testMetadataClampPossibleValueWithExecutor() throws IOException, UnknownComponentException {
+ Service service = new Service(ResourceFileUtils.getResourceAsString("tosca/service-details.json"),
+ ResourceFileUtils.getResourceAsString("tosca/resource-details-cds.json"));
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policytypes/onap"
+ + ".policies.controlloop.operational.common.Apex/versions/1.0.0/.file"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+
+ JsonObject jsonSchema = jsonTemplateManager.getJsonSchemaForPolicyType(
+ "onap.policies.controlloop.operational.common.Apex", toscaMetadataParserWithDictionarySupport, service);
+
+ JSONAssert.assertEquals(
+ ResourceFileUtils
+ .getResourceAsString("tosca/new-converter/tosca_apex_with_metadata.json"),
+ JsonUtils.GSON.toJson(jsonSchema), true);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementPropertyTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementPropertyTest.java
new file mode 100644
index 000000000..5652fa9cd
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementPropertyTest.java
@@ -0,0 +1,79 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.ArrayList;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElementProperty;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplate;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+public class ToscaElementPropertyTest extends TestCase {
+ public ToscaElementPropertyTest() throws IOException {
+ }
+
+ /**
+ * Test Parse array.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testParseArray() throws IOException {
+ JsonTemplateManager jsonTemplateManager = new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ ToscaElement toscaElement = jsonTemplateManager.getToscaElements().get("onap.datatype.controlloop.Actor");
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("actor");
+ JsonArray toTest =
+ toscaElementProperty.parseArray((ArrayList<Object>) toscaElementProperty.getItems().get("default"));
+ assertNotNull(toTest);
+ }
+
+ /**
+ * Test add constraint as json.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testAddConstraintsAsJson() throws IOException {
+ JsonTemplateManager jsonTemplateManager = new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ ToscaElement toscaElement =
+ jsonTemplateManager.getToscaElements().get("onap.datatype.controlloop.operation.Failure");
+ ToscaElementProperty toscaElementProperty = toscaElement.getProperties().get("category");
+ JsonTemplate jsonTemplate = jsonTemplateManager.getJsonSchemaTemplates().get("string");
+ JsonObject toTest = new JsonObject();
+ toscaElementProperty
+ .addConstraintsAsJson(toTest, (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"),
+ jsonTemplate);
+ String test = "{\"enum\":[\"error\",\"timeout\",\"retries\",\"guard\",\"exception\"]}";
+ assertEquals(test, String.valueOf(toTest));
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementTest.java
new file mode 100644
index 000000000..0ea2146b4
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/tosca/update/ToscaElementTest.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.tosca.update;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import junit.framework.TestCase;
+import org.onap.policy.clamp.clds.tosca.update.elements.ToscaElement;
+import org.onap.policy.clamp.clds.tosca.update.templates.JsonTemplateManager;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+
+public class ToscaElementTest extends TestCase {
+
+ /**
+ * Test propertiesName.
+ *
+ * @throws IOException In case of failure
+ */
+ public void testPropertiesNames() throws IOException {
+ ArrayList<String> reference = new ArrayList<>(Arrays.asList("actor", "operation", "target", "payload"));
+ JsonTemplateManager jsonTemplateManager =
+ new JsonTemplateManager(
+ ResourceFileUtils.getResourceAsString("tosca/new-converter/sampleOperationalPolicies.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/default-tosca-types.yaml"),
+ ResourceFileUtils.getResourceAsString("clds/tosca-converter/templates.json"));
+ ToscaElement toscaElement = jsonTemplateManager.getToscaElements().get("onap.datatype.controlloop.Actor");
+ assertEquals(reference, toscaElement.propertiesNames());
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/util/JsonUtilsTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/util/JsonUtilsTest.java
new file mode 100644
index 000000000..b2c6d282a
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/util/JsonUtilsTest.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * 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============================================
+ * Modifications copyright (c) 2019 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import org.junit.Test;
+
+public class JsonUtilsTest {
+
+ public static class TestClass extends TestObject {
+
+ String test2;
+ TestObject2 object2;
+
+ TestClass(String value1, String value2) {
+ super(value1);
+ test2 = value2;
+ }
+
+ void setObject2(TestObject2 object2) {
+ this.object2 = object2;
+ }
+ }
+
+ @Test
+ public void testGetObjectMapperInstance() {
+ assertNotNull(JsonUtils.GSON);
+ }
+
+ /**
+ * This method test that the security hole in GSON is not enabled in the default
+ * ObjectMapper.
+ */
+ @Test
+ public void testCreateBeanDeserializer() {
+ TestClass test = new TestClass("value1", "value2");
+ test.setObject2(new TestObject2("test3"));
+ Object testObject = JsonUtils.GSON.fromJson("[\"org.onap.policy.clamp.clds.util.JsonUtilsTest$TestClass\""
+ + ",{\"test\":\"value1\",\"test2\":\"value2\","
+ + "\"object2\":[\"org.onap.policy.clamp.clds.util.TestObject2\","
+ + "{\"test3\":\"test3\"}]}]", Object.class);
+ assertNotNull(testObject);
+ assertFalse(testObject instanceof TestObject);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowExceptionFileNotExists() throws IOException {
+ ResourceFileUtils.getResourceAsString("example/notExist.json");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/util/LoggingUtilsTest.java b/runtime/src/test/java/org/onap/policy/clamp/clds/util/LoggingUtilsTest.java
new file mode 100644
index 000000000..ab6a41bca
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/util/LoggingUtilsTest.java
@@ -0,0 +1,138 @@
+/*-
+* ============LICENSE_START=======================================================
+* ONAP CLAMP
+* Copyright (C) 2019 Samsung. All rights reserved.
+* ================================================================================
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END============================================
+* ===================================================================
+*
+*/
+
+package org.onap.policy.clamp.clds.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Map;
+import javax.net.ssl.HttpsURLConnection;
+import javax.servlet.http.HttpServletRequest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.event.Level;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * Test Logging Utils.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class LoggingUtilsTest {
+
+ protected static final Logger logger = LoggerFactory.getLogger(LoggingUtilsTest.class);
+
+ private static final String SERVICE_NAME = "LogginUtilsTest: Test Entering method";
+
+ private LoggingUtils util;
+
+ @Before
+ public void setup() {
+ this.util = new LoggingUtils(logger);
+ }
+
+ @Test
+ public void testEnteringLoggingUtils() {
+ // given
+ final String userName = "test";
+
+ UserDetails userDetails = Mockito.mock(UserDetails.class);
+ Mockito.when(userDetails.getUsername()).thenReturn(userName);
+
+ Authentication localAuth = Mockito.mock(Authentication.class);
+ Mockito.when(localAuth.getPrincipal()).thenReturn(userDetails);
+
+ SecurityContext securityContext = Mockito.mock(SecurityContext.class);
+ Mockito.when(securityContext.getAuthentication()).thenReturn(localAuth);
+ SecurityContextHolder.setContext(securityContext);
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ // when
+ util.entering(request, SERVICE_NAME);
+
+ // then
+ String[] keys = {OnapLogConstants.Mdcs.PARTNER_NAME, OnapLogConstants.Mdcs.ENTRY_TIMESTAMP,
+ OnapLogConstants.Mdcs.REQUEST_ID, OnapLogConstants.Mdcs.INVOCATION_ID,
+ OnapLogConstants.Mdcs.CLIENT_IP_ADDRESS, OnapLogConstants.Mdcs.SERVER_FQDN,
+ OnapLogConstants.Mdcs.INSTANCE_UUID, OnapLogConstants.Mdcs.SERVICE_NAME};
+ Map<String, String> mdc = MDC.getMDCAdapter().getCopyOfContextMap();
+
+ assertTrue(checkMapKeys(mdc, keys));
+ assertEquals(userName, mdc.get(OnapLogConstants.Mdcs.PARTNER_NAME));
+ }
+
+ @Test
+ public void testExistingLoggingUtils() {
+ // given
+ MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP,
+ ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT));
+
+ // when
+ util.exiting(HttpStatus.OK.value(), SERVICE_NAME, Level.INFO,
+ OnapLogConstants.ResponseStatus.COMPLETE);
+
+ // then
+ Map<String, String> mdc = MDC.getMDCAdapter().getCopyOfContextMap();
+ assertNull(mdc);
+ }
+
+ @Test
+ public void testInvokeTestUtils() {
+ // given
+ final String targetEntity = "LoggingUtilsTest";
+ final String targetServiceName = "testInvokeTestUtils";
+ HttpsURLConnection secureConnection = Mockito.mock(HttpsURLConnection.class);
+
+ // when
+ secureConnection = util.invokeHttps(secureConnection, targetEntity, targetServiceName);
+
+ // then
+ assertNotNull(secureConnection);
+ String[] keys =
+ {OnapLogConstants.Mdcs.TARGET_ENTITY, OnapLogConstants.Mdcs.TARGET_SERVICE_NAME,
+ OnapLogConstants.Mdcs.INVOCATIONID_OUT, OnapLogConstants.Mdcs.INVOKE_TIMESTAMP};
+ Map<String, String> mdc = MDC.getMDCAdapter().getCopyOfContextMap();
+
+ assertTrue(checkMapKeys(mdc, keys));
+ assertEquals(targetEntity, mdc.get(OnapLogConstants.Mdcs.TARGET_ENTITY));
+ assertEquals(targetServiceName, mdc.get(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME));
+ }
+
+ private boolean checkMapKeys(Map map, String[] keys) {
+ return Arrays.stream(keys).allMatch(key -> map.get(key) != null);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject.java b/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject.java
new file mode 100644
index 000000000..02cabd270
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject.java
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+public class TestObject {
+
+ private String test;
+
+ public String getTest() {
+ return test;
+ }
+
+ public void setTest(String test) {
+ this.test = test;
+ }
+
+ // @JsonProperty("test"), @JsonCreator
+ public TestObject(String theString) {
+ this.setTest(theString);
+ }
+
+ public TestObject() {
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject2.java b/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject2.java
new file mode 100644
index 000000000..d5abf41d0
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/clds/util/TestObject2.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.clds.util;
+
+public class TestObject2 {
+
+ private String test3;
+
+ public String getTest3() {
+ return test3;
+ }
+
+ public void setTest3(String test) {
+ this.test3 = test;
+ }
+
+ public TestObject2(String theString) {
+ this.setTest3(theString);
+ }
+
+ public TestObject2() {
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/flow/FlowLogOperationTest.java b/runtime/src/test/java/org/onap/policy/clamp/flow/FlowLogOperationTest.java
new file mode 100644
index 000000000..622fd5999
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/flow/FlowLogOperationTest.java
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Samsung. All rights reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2021 AT&T
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.flow;
+
+import static junit.framework.Assert.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.util.LoggingUtils;
+import org.onap.policy.clamp.clds.util.OnapLogConstants;
+import org.onap.policy.clamp.flow.log.FlowLogOperation;
+import org.slf4j.MDC;
+import org.slf4j.spi.MDCAdapter;
+import org.springframework.test.util.ReflectionTestUtils;
+
+public class FlowLogOperationTest {
+
+ private FlowLogOperation flowLogOperation = new FlowLogOperation();
+
+ @Test
+ public void testStartLog() {
+ // given
+ LoggingUtils loggingUtils = mock(LoggingUtils.class);
+ ReflectionTestUtils.setField(flowLogOperation, "util", loggingUtils);
+
+ // when
+ Mockito.when(loggingUtils.getProperties(OnapLogConstants.Mdcs.REQUEST_ID)).thenReturn("MockRequestId");
+ Mockito.when(loggingUtils.getProperties(OnapLogConstants.Mdcs.INVOCATION_ID)).thenReturn("MockInvocationId");
+ Mockito.when(loggingUtils.getProperties(OnapLogConstants.Mdcs.PARTNER_NAME)).thenReturn("MockPartnerName");
+ Exchange exchange = new DefaultExchange(mock(CamelContext.class));
+ flowLogOperation.startLog(exchange, "serviceName");
+
+ // then
+ assertThat(exchange.getProperty(OnapLogConstants.Headers.REQUEST_ID)).isEqualTo("MockRequestId");
+ assertThat(exchange.getProperty(OnapLogConstants.Headers.INVOCATION_ID)).isEqualTo("MockInvocationId");
+ assertThat(exchange.getProperty(OnapLogConstants.Headers.PARTNER_NAME)).isEqualTo("MockPartnerName");
+ }
+
+ @Test
+ public void testInvokeLog() {
+ // given
+ final String mockEntity = "mockEntity";
+ final String mockServiceName = "mockServiceName";
+ MDCAdapter mdcAdapter = MDC.getMDCAdapter();
+ // when
+ flowLogOperation.invokeLog(mockEntity, mockServiceName);
+ // then
+ String entity = mdcAdapter.get(OnapLogConstants.Mdcs.TARGET_ENTITY);
+ String serviceName = mdcAdapter.get(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME);
+ assertEquals(entity, mockEntity);
+ assertEquals(serviceName, mockServiceName);
+ }
+
+ @Test
+ public void testEndLog() {
+ // given
+ MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP, "2019-05-19T00:00:00.007Z");
+ MDCAdapter mdcAdapter = MDC.getMDCAdapter();
+ /// when
+ flowLogOperation.endLog();
+ // then
+ assertThat(mdcAdapter.get(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP)).isNull();
+ }
+
+ @Test
+ public void testErrorLog() {
+ // given
+ MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP, "2019-05-19T00:00:00.007Z");
+ MDCAdapter mdcAdapter = MDC.getMDCAdapter();
+ // when
+ flowLogOperation.errorLog();
+ // then
+ assertThat(mdcAdapter.get(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP)).isNull();
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/CsarInstallerItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/CsarInstallerItCase.java
new file mode 100644
index 000000000..b0abf832b
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/CsarInstallerItCase.java
@@ -0,0 +1,322 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications copyright (c) 2019 Nokia
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.transaction.Transactional;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.assertj.core.api.Assertions;
+import org.json.JSONException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.exception.sdc.controller.BlueprintParserException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.CsarHandlerException;
+import org.onap.policy.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException;
+import org.onap.policy.clamp.clds.sdc.controller.installer.BlueprintArtifact;
+import org.onap.policy.clamp.clds.sdc.controller.installer.CsarHandler;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.cds.CdsDataInstaller;
+import org.onap.policy.clamp.loop.service.ServicesRepository;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.LoopTemplateLoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplatesRepository;
+import org.onap.policy.clamp.loop.template.PolicyModelId;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.sdc.api.notification.IArtifactInfo;
+import org.onap.sdc.api.notification.INotificationData;
+import org.onap.sdc.api.notification.IResourceInstance;
+import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
+import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
+import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory;
+import org.onap.sdc.toscaparser.api.elements.Metadata;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.Commit;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+@ActiveProfiles({"clamp-default", "clamp-default-user", "clamp-sdc-controller"})
+public class CsarInstallerItCase {
+
+ private static final String CSAR_ARTIFACT_NAME_CDS = "example/sdc/service_Vloadbalancerms_cds.csar";
+ private static final String CSAR_ARTIFACT_NAME_NO_CDS = "example/sdc/service_Vloadbalancerms_no_cds.csar";
+ private static final String INVARIANT_SERVICE_UUID = "4cc5b45a-1f63-4194-8100-cd8e14248c92";
+ private static final String INVARIANT_RESOURCE1_UUID = "07e266fc-49ab-4cd7-8378-ca4676f1b9ec";
+ private static final String INVARIANT_RESOURCE2_UUID = "023a3f0d-1161-45ff-b4cf-8918a8ccf3ad";
+ private static final String RESOURCE_INSTANCE_NAME_RESOURCE1 = "ResourceInstanceName1";
+ private static final String RESOURCE_INSTANCE_NAME_RESOURCE2 = "ResourceInstanceName2";
+
+ @Autowired
+ private LoopTemplatesRepository loopTemplatesRepo;
+
+ @Autowired
+ ServicesRepository serviceRepository;
+
+ @Autowired
+ PolicyModelsRepository policyModelsRepository;
+
+ @Autowired
+ @Qualifier("csarInstaller")
+ private CsarInstaller csarInstaller;
+
+ private BlueprintArtifact buildFakeBlueprintArtifact(String instanceName, String invariantResourceUuid,
+ String blueprintFilePath, String artifactName,
+ String invariantServiceUuid) throws IOException {
+ IResourceInstance resource = Mockito.mock(IResourceInstance.class);
+ Mockito.when(resource.getResourceInstanceName()).thenReturn(instanceName);
+ Mockito.when(resource.getResourceInvariantUUID()).thenReturn(invariantResourceUuid);
+ BlueprintArtifact blueprintArtifact = Mockito.mock(BlueprintArtifact.class);
+ Mockito.when(blueprintArtifact.getDcaeBlueprint())
+ .thenReturn(ResourceFileUtils.getResourceAsString(blueprintFilePath));
+ Mockito.when(blueprintArtifact.getBlueprintArtifactName()).thenReturn(artifactName);
+ Mockito.when(blueprintArtifact.getBlueprintInvariantServiceUuid()).thenReturn(invariantServiceUuid);
+ Mockito.when(blueprintArtifact.getResourceAttached()).thenReturn(resource);
+ return blueprintArtifact;
+ }
+
+ private CsarHandler buildBadFakeCsarHandler(String generatedName, String csarFileName) throws IOException,
+ SdcToscaParserException {
+
+ // Build a Bad csar because the blueprint contains a link to a microservice that does not exist in the emulator
+ // Create fake notification
+ INotificationData notificationData = Mockito.mock(INotificationData.class);
+ Mockito.when(notificationData.getServiceVersion()).thenReturn("1.0");
+ // Create fake resource in notification
+ CsarHandler csarHandler = Mockito.mock(CsarHandler.class);
+ List<IResourceInstance> listResources = new ArrayList<>();
+ Mockito.when(notificationData.getResources()).thenReturn(listResources);
+ Map<String, BlueprintArtifact> blueprintMap = new HashMap<>();
+ Mockito.when(csarHandler.getMapOfBlueprints()).thenReturn(blueprintMap);
+ // Create fake blueprint artifact 1 on resource1
+ BlueprintArtifact blueprintArtifact = buildFakeBlueprintArtifact(RESOURCE_INSTANCE_NAME_RESOURCE1,
+ INVARIANT_RESOURCE1_UUID, "example/sdc/blueprint-dcae/tca-bad-policy.yaml", "tca-bad-policy.yaml",
+ INVARIANT_SERVICE_UUID);
+ listResources.add(blueprintArtifact.getResourceAttached());
+ blueprintMap.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+
+ // Build fake csarhandler
+ Mockito.when(csarHandler.getSdcNotification()).thenReturn(notificationData);
+ // Build fake csar Helper
+ ISdcCsarHelper csarHelper = Mockito.mock(ISdcCsarHelper.class);
+ Metadata data = Mockito.mock(Metadata.class);
+ Mockito.when(data.getValue("name")).thenReturn(generatedName);
+ Mockito.when(notificationData.getServiceName()).thenReturn(generatedName);
+ Mockito.when(csarHelper.getServiceMetadata()).thenReturn(data);
+
+ // Create helper based on real csar to test policy yaml and global properties
+ // set
+ SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance();
+ String path = Thread.currentThread().getContextClassLoader().getResource(csarFileName).getFile();
+ ISdcCsarHelper sdcHelper = factory.getSdcCsarHelper(path);
+ Mockito.when(csarHandler.getSdcCsarHelper()).thenReturn(sdcHelper);
+
+ // Mockito.when(csarHandler.getSdcCsarHelper()).thenReturn(csarHelper);
+ Mockito.when(csarHandler.getPolicyModelYaml())
+ .thenReturn(Optional.ofNullable(ResourceFileUtils.getResourceAsString("tosca/tosca_example.yaml")));
+ return csarHandler;
+ }
+
+ private CsarHandler buildFakeCsarHandler(String generatedName, String csarFileName) throws IOException,
+ SdcToscaParserException {
+ // Create fake notification
+ INotificationData notificationData = Mockito.mock(INotificationData.class);
+ Mockito.when(notificationData.getServiceVersion()).thenReturn("1.0");
+ // Create fake resource in notification
+ CsarHandler csarHandler = Mockito.mock(CsarHandler.class);
+ List<IResourceInstance> listResources = new ArrayList<>();
+ Mockito.when(notificationData.getResources()).thenReturn(listResources);
+ Map<String, BlueprintArtifact> blueprintMap = new HashMap<>();
+ Mockito.when(csarHandler.getMapOfBlueprints()).thenReturn(blueprintMap);
+ // Create fake blueprint artifact 1 on resource1
+ BlueprintArtifact blueprintArtifact = buildFakeBlueprintArtifact(RESOURCE_INSTANCE_NAME_RESOURCE1,
+ INVARIANT_RESOURCE1_UUID, "example/sdc/blueprint-dcae/tca.yaml", "tca.yaml", INVARIANT_SERVICE_UUID);
+ listResources.add(blueprintArtifact.getResourceAttached());
+ blueprintMap.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+ // Create fake blueprint artifact 2 on resource2
+ blueprintArtifact = buildFakeBlueprintArtifact(RESOURCE_INSTANCE_NAME_RESOURCE2, INVARIANT_RESOURCE2_UUID,
+ "example/sdc/blueprint-dcae/tca_2.yaml", "tca_2.yaml", INVARIANT_SERVICE_UUID);
+ listResources.add(blueprintArtifact.getResourceAttached());
+ blueprintMap.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+
+ // Create fake blueprint artifact 3 on resource 1 so that it's possible to
+ // test multiple CL deployment per Service/vnf
+ blueprintArtifact = buildFakeBlueprintArtifact(RESOURCE_INSTANCE_NAME_RESOURCE1, INVARIANT_RESOURCE1_UUID,
+ "example/sdc/blueprint-dcae/tca_3.yaml", "tca_3.yaml", INVARIANT_SERVICE_UUID);
+ blueprintMap.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+
+ // Create fake blueprint artifact 3 on resource 1 so that it's possible to
+ // test multiple CL deployment per Service/vnf
+ blueprintArtifact = buildFakeBlueprintArtifact(RESOURCE_INSTANCE_NAME_RESOURCE1, INVARIANT_RESOURCE1_UUID,
+ "example/sdc/blueprint-dcae/tca-guilin.yaml", "tca-guilin.yaml", INVARIANT_SERVICE_UUID);
+ blueprintMap.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact);
+
+
+ // Build fake csarhandler
+ Mockito.when(csarHandler.getSdcNotification()).thenReturn(notificationData);
+ // Build fake csar Helper
+ ISdcCsarHelper csarHelper = Mockito.mock(ISdcCsarHelper.class);
+ Metadata data = Mockito.mock(Metadata.class);
+ Mockito.when(data.getValue("name")).thenReturn(generatedName);
+ Mockito.when(notificationData.getServiceName()).thenReturn(generatedName);
+ Mockito.when(csarHelper.getServiceMetadata()).thenReturn(data);
+
+ // Create helper based on real csar to test policy yaml and global properties
+ // set
+ SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance();
+ String path = Thread.currentThread().getContextClassLoader().getResource(csarFileName).getFile();
+ ISdcCsarHelper sdcHelper = factory.getSdcCsarHelper(path);
+ Mockito.when(csarHandler.getSdcCsarHelper()).thenReturn(sdcHelper);
+
+ // Mockito.when(csarHandler.getSdcCsarHelper()).thenReturn(csarHelper);
+ Mockito.when(csarHandler.getPolicyModelYaml())
+ .thenReturn(Optional.ofNullable(ResourceFileUtils.getResourceAsString("tosca/tosca_example.yaml")));
+ return csarHandler;
+ }
+
+ @Test
+ @Transactional
+ public void testGetPolicyModelYaml() throws IOException, SdcToscaParserException, CsarHandlerException {
+ INotificationData notificationData = Mockito.mock(INotificationData.class);
+ IArtifactInfo serviceArtifacts = Mockito.mock(IArtifactInfo.class);
+ Mockito.when(serviceArtifacts.getArtifactType()).thenReturn("TOSCA_CSAR");
+ List<IArtifactInfo> serviceArtifactsList = new ArrayList<>();
+ serviceArtifactsList.add(serviceArtifacts);
+ Mockito.when(notificationData.getServiceArtifacts()).thenReturn(serviceArtifactsList);
+
+ CsarHandler csarHandler = new CsarHandler(notificationData, "", "");
+ csarHandler.setFilePath(Thread.currentThread().getContextClassLoader().getResource(CSAR_ARTIFACT_NAME_CDS)
+ .getFile());
+ Assert.assertEquals(csarHandler.getPolicyModelYaml(), Optional
+ .ofNullable(ResourceFileUtils.getResourceAsString("example/sdc/expected-result/policy-data.yaml")));
+ }
+
+ @Test
+ @Transactional
+ public void testIsCsarAlreadyDeployedTca() throws SdcArtifactInstallerException, SdcToscaParserException,
+ CsarHandlerException, IOException, InterruptedException, BlueprintParserException {
+ String generatedName = RandomStringUtils.randomAlphanumeric(5);
+ CsarHandler csarHandler = buildFakeCsarHandler(generatedName, CSAR_ARTIFACT_NAME_CDS);
+ assertThat(csarInstaller.isCsarAlreadyDeployed(csarHandler)).isFalse();
+ csarInstaller.installTheCsar(csarHandler);
+ assertThat(csarInstaller.isCsarAlreadyDeployed(csarHandler)).isTrue();
+ }
+
+ @Test
+ @Transactional
+ public void testWithoutCdsTca() throws SdcArtifactInstallerException, SdcToscaParserException,
+ CsarHandlerException, IOException, InterruptedException, BlueprintParserException {
+ String generatedName = RandomStringUtils.randomAlphanumeric(5);
+ CsarHandler csarHandler = buildFakeCsarHandler(generatedName, CSAR_ARTIFACT_NAME_NO_CDS);
+
+ assertThat(csarInstaller.isCsarAlreadyDeployed(csarHandler)).isFalse();
+ csarInstaller.installTheCsar(csarHandler);
+ assertThat(csarInstaller.isCsarAlreadyDeployed(csarHandler)).isTrue();
+ }
+
+ @Test(expected = SdcArtifactInstallerException.class)
+ @Transactional
+ public void testInstallTheBadCsarTca()
+ throws IOException, SdcToscaParserException, InterruptedException, BlueprintParserException,
+ SdcArtifactInstallerException {
+ // This test validates that the blueprint is well rejected because the blueprint contains a link
+ // to a policy that does not exist on the policy engine emulator.
+ String generatedName = RandomStringUtils.randomAlphanumeric(5);
+ csarInstaller.installTheCsar(buildBadFakeCsarHandler(generatedName, CSAR_ARTIFACT_NAME_NO_CDS));
+ }
+
+ @Test
+ @Transactional
+ @Commit
+ public void testInstallTheCsarTca() throws SdcArtifactInstallerException, SdcToscaParserException,
+ CsarHandlerException, IOException, JSONException, InterruptedException, BlueprintParserException {
+ String generatedName = RandomStringUtils.randomAlphanumeric(5);
+ csarInstaller.installTheCsar(buildFakeCsarHandler(generatedName, CSAR_ARTIFACT_NAME_CDS));
+
+ assertThat(serviceRepository.existsById("63cac700-ab9a-4115-a74f-7eac85e3fce0")).isTrue();
+ // We should have CDS info
+ assertThat(serviceRepository.findById("63cac700-ab9a-4115-a74f-7eac85e3fce0").get().getResourceByType("VF")
+ .getAsJsonObject("vLoadBalancerMS 0").getAsJsonObject(
+ CdsDataInstaller.CONTROLLER_PROPERTIES)).isNotNull();
+ assertThat(loopTemplatesRepo.existsById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE1, "tca.yaml"))).isTrue();
+ assertThat(loopTemplatesRepo.existsById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE1, "tca_3.yaml"))).isTrue();
+ assertThat(loopTemplatesRepo.existsById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE2, "tca_2.yaml"))).isTrue();
+ assertThat(loopTemplatesRepo.existsById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE1, "tca-guilin.yaml"))).isTrue();
+ // Verify now that policy and json representation, global properties are well
+ // set
+ LoopTemplate loopTemplate = loopTemplatesRepo.findById(LoopTemplate.generateLoopTemplateName(generatedName,
+ "1.0", RESOURCE_INSTANCE_NAME_RESOURCE1, "tca.yaml")).get();
+ assertThat(loopTemplate.getLoopElementModelsUsed()).hasSize(1);
+ Assertions.assertThat(loopTemplate.getModelService().getServiceUuid())
+ .isEqualTo("63cac700-ab9a-4115-a74f-7eac85e3fce0");
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/model-properties.json"),
+ JsonUtils.GSON_JPA_MODEL.toJson(loopTemplate.getModelService()), true);
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/service-details.json"),
+ JsonUtils.GSON_JPA_MODEL.toJson(loopTemplate.getModelService().getServiceDetails()), true);
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/resource-details.json"),
+ JsonUtils.GSON_JPA_MODEL.toJson(loopTemplate.getModelService().getResourceDetails()), true);
+ Assertions.assertThat(((LoopTemplateLoopElementModel) (loopTemplate.getLoopElementModelsUsed().toArray()[0]))
+ .getLoopElementModel().getName()).isNotEmpty();
+
+ loopTemplate = loopTemplatesRepo.findById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE1, "tca_3.yaml")).get();
+ assertThat(((LoopTemplateLoopElementModel) (loopTemplate.getLoopElementModelsUsed().toArray()[0]))
+ .getLoopElementModel().getName()).isNotEmpty();
+ assertThat(((LoopTemplateLoopElementModel) (loopTemplate.getLoopElementModelsUsed().toArray()[0]))
+ .getLoopElementModel().getName()).isNotEmpty();
+ assertThat(loopTemplate.getMaximumInstancesAllowed()).isEqualByComparingTo(Integer.valueOf(0));
+ loopTemplate = loopTemplatesRepo.findById(LoopTemplate.generateLoopTemplateName(generatedName, "1.0",
+ RESOURCE_INSTANCE_NAME_RESOURCE2, "tca_2.yaml")).get();
+ assertThat(((LoopTemplateLoopElementModel) (loopTemplate.getLoopElementModelsUsed().toArray()[0]))
+ .getLoopElementModel().getName()).isNotEmpty();
+
+ assertThat(policyModelsRepository.findAll().size()).isGreaterThanOrEqualTo(1);
+ assertThat(policyModelsRepository
+ .existsById(new PolicyModelId("onap.policies.monitoring.cdap.tca.hi.lo.app", "1.0.0"))).isTrue();
+ assertThat(policyModelsRepository
+ .getOne((new PolicyModelId("onap.policies.monitoring.cdap.tca.hi.lo.app", "1.0.0")))
+ .getPolicyModelTosca()).isNotBlank();
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/DcaeComponentTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/DcaeComponentTest.java
new file mode 100644
index 000000000..c95725457
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/DcaeComponentTest.java
@@ -0,0 +1,189 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.List;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.json.simple.parser.ParseException;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.model.dcae.DcaeInventoryResponse;
+import org.onap.policy.clamp.clds.model.dcae.DcaeOperationStatusResponse;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.components.external.DcaeComponent;
+import org.onap.policy.clamp.loop.components.external.ExternalComponentState;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+
+public class DcaeComponentTest {
+
+ private Loop createTestLoop() {
+ Loop loopTest = new Loop("ControlLoopTest");
+ loopTest.setGlobalPropertiesJson(
+ new Gson().fromJson(
+ "{\"dcaeDeployParameters\":{\"uniqueBlueprintParameters\": {\"policy_id\": \"name\"}}}",
+ JsonObject.class));
+ loopTest.setLastComputedState(LoopState.DESIGN);
+ loopTest.setDcaeDeploymentId("123456789");
+ loopTest.setDcaeDeploymentStatusUrl("http://localhost:8085");
+
+ MicroServicePolicy microServicePolicy = new MicroServicePolicy("configPolicyTest", new PolicyModel("policy1",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0"), true,
+ new Gson().fromJson("{\"configtype\":\"json\"}", JsonObject.class), null, null, null);
+ microServicePolicy.setConfigurationsJson(new Gson().fromJson("{\"param1\":\"value1\"}", JsonObject.class));
+
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ LoopTemplate loopTemplate = new LoopTemplate("test", "yaml", 1, null);
+ loopTemplate.setDcaeBlueprintId("UUID-blueprint");
+ loopTest.setLoopTemplate(loopTemplate);
+
+ return loopTest;
+ }
+
+ /**
+ * Test the DcaeReponse roughly.
+ *
+ * @throws IOException In case of issues
+ */
+ @Test
+ public void convertDcaeResponseTest() throws IOException {
+ String dcaeFakeResponse = "{'requestId':'testId','operationType':'install','status':'state',"
+ + "'error':'errorMessage', 'links':{'self':'selfUrl','uninstall':'uninstallUrl'}}";
+ DcaeOperationStatusResponse responseObject = DcaeComponent.convertDcaeResponse(dcaeFakeResponse);
+ assertThat(responseObject.getRequestId()).isEqualTo("testId");
+ assertThat(responseObject.getOperationType()).isEqualTo("install");
+ assertThat(responseObject.getStatus()).isEqualTo("state");
+ assertThat(responseObject.getError()).isEqualTo("errorMessage");
+ assertThat(responseObject.getLinks()).isNotNull();
+ assertThat(responseObject.getLinks().getSelf()).isEqualTo("selfUrl");
+ assertThat(responseObject.getLinks().getUninstall()).isEqualTo("uninstallUrl");
+
+ assertThat(responseObject.getLinks().getStatus()).isNull();
+ }
+
+ @Test
+ public void testGetDeployPayload() throws IOException {
+ Loop loop = this.createTestLoop();
+ String deploymentPayload = DcaeComponent.getDeployPayload(loop);
+ String expectedPayload = "{\"serviceTypeId\":\"UUID-blueprint\",\"inputs\":{\"policy_id\":\"name\"}}";
+ assertThat(deploymentPayload).isEqualTo(expectedPayload);
+ }
+
+ @Test
+ public void testGetUndeployPayload() throws IOException {
+ Loop loop = this.createTestLoop();
+ String unDeploymentPayload = DcaeComponent.getUndeployPayload(loop);
+ String expectedPayload = "{\"serviceTypeId\":\"UUID-blueprint\"}";
+ assertThat(unDeploymentPayload).isEqualTo(expectedPayload);
+ }
+
+ /**
+ * Test the computeState method of the DcaeComponent roughly.
+ *
+ * @throws IOException In case of issues
+ */
+ @Test
+ public void computeStateTest() throws IOException {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ Mockito.when(exchange2.getProperty("dcaeResponse")).thenReturn(null);
+
+ DcaeComponent dcae = new DcaeComponent();
+
+ // initial state
+ ExternalComponentState state = dcae.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("BLUEPRINT_DEPLOYED");
+
+ // OperationalType = install
+ DcaeOperationStatusResponse dcaeResponse = Mockito.mock(DcaeOperationStatusResponse.class);
+ Mockito.when(dcaeResponse.getOperationType()).thenReturn("install");
+
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("succeeded");
+ Mockito.when(exchange2.getProperty("dcaeResponse")).thenReturn(dcaeResponse);
+ ExternalComponentState state2 = dcae.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("MICROSERVICE_INSTALLED_SUCCESSFULLY");
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("processing");
+ ExternalComponentState state3 = dcae.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("PROCESSING_MICROSERVICE_INSTALLATION");
+
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("failed");
+ ExternalComponentState state4 = dcae.computeState(exchange);
+ assertThat(state4.getStateName()).isEqualTo("MICROSERVICE_INSTALLATION_FAILED");
+
+ // OperationalType = uninstall
+ Mockito.when(dcaeResponse.getOperationType()).thenReturn("uninstall");
+
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("succeeded");
+ Mockito.when(exchange2.getProperty("dcaeResponse")).thenReturn(dcaeResponse);
+ ExternalComponentState state5 = dcae.computeState(exchange);
+ assertThat(state5.getStateName()).isEqualTo("MICROSERVICE_UNINSTALLED_SUCCESSFULLY");
+
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("processing");
+ ExternalComponentState state6 = dcae.computeState(exchange);
+ assertThat(state6.getStateName()).isEqualTo("PROCESSING_MICROSERVICE_UNINSTALLATION");
+
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("failed");
+ ExternalComponentState state7 = dcae.computeState(exchange);
+ assertThat(state7.getStateName()).isEqualTo("MICROSERVICE_UNINSTALLATION_FAILED");
+
+ // error cases
+ Mockito.when(dcaeResponse.getOperationType()).thenReturn("whatever");
+ ExternalComponentState state8 = dcae.computeState(exchange);
+ assertThat(state8.getStateName()).isEqualTo("IN_ERROR");
+
+ Mockito.when(dcaeResponse.getOperationType()).thenReturn("install");
+ Mockito.when(dcaeResponse.getStatus()).thenReturn("anythingelse");
+ ExternalComponentState state9 = dcae.computeState(exchange);
+ assertThat(state9.getStateName()).isEqualTo("IN_ERROR");
+ }
+
+ /**
+ * Test the Converter to DcaeInventoryResponse method.
+ *
+ * @throws IOException In case of failure
+ * @throws ParseException In case of failure
+ */
+ @Test
+ public void convertToDcaeInventoryResponseTest() throws IOException, ParseException {
+
+ List<DcaeInventoryResponse> responseObject = DcaeComponent
+ .convertToDcaeInventoryResponse(
+ ResourceFileUtils.getResourceAsString("example/dcae/inventory-response.json"));
+ assertThat(responseObject.get(0).getAsdcResourceId()).isEqualTo("testAsdcResourceId");
+ assertThat(responseObject.get(0).getAsdcServiceId()).isEqualTo("testAsdcServiceId");
+ assertThat(responseObject.get(0).getTypeName()).isEqualTo("testTypeName");
+ assertThat(responseObject.get(0).getTypeId()).isEqualTo("testTypeId");
+ assertThat(responseObject.get(0).getBlueprintTemplate()).isEqualTo("testBlueprintTemplate");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/DeployFlowTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/DeployFlowTestItCase.java
new file mode 100644
index 000000000..4d02b10dc
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/DeployFlowTestItCase.java
@@ -0,0 +1,321 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import java.io.IOException;
+import java.util.Set;
+import javax.transaction.Transactional;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class DeployFlowTestItCase {
+ private Gson gson = new Gson();
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Autowired
+ PolicyModelsService policyModelsService;
+
+ @Autowired
+ LoopService loopService;
+
+ @Autowired
+ LoopsRepository loopsRepository;
+
+ /**
+ * This method tests a deployment a single blueprint.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void deployWithSingleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest = createLoop("ControlLoopTest", "yamlcontent",
+ "{\"dcaeDeployParameters\":{\"uniqueBlueprintParameters\": {\"policy_id\": \"name\"}}}",
+ "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ template.setBlueprint("yamlcontent");
+ loopTest.setLoopTemplate(template);
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ loopService.saveOrUpdateLoop(loopTest);
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:deploy-loop", myCamelExchange);
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest");
+ assertThat(loopAfterTest.getDcaeDeploymentStatusUrl()).isNotNull();
+ assertThat(loopAfterTest.getDcaeDeploymentId()).isNotNull();
+ }
+
+ /**
+ * This method tests the deployment of multiple separated blueprints.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void deployWithMultipleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest2 = createLoop("ControlLoopTest2", "yamlcontent", "{\"dcaeDeployParameters\": {"
+ + "\"microService1\": {\"location_id\": \"\", \"policy_id\": \"TCA_ResourceInstanceName1_tca\"},"
+ + "\"microService2\": {\"location_id\": \"\", \"policy_id\": \"TCA_ResourceInstanceName2_tca\"}"
+ + "}}", "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ loopTest2.setLoopTemplate(template);
+ MicroServicePolicy microServicePolicy1 = getMicroServicePolicy("microService1", "", "{\"configtype\":\"json\"}",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "{\"param1\":\"value1\"}", true);
+ MicroServicePolicy microServicePolicy2 = getMicroServicePolicy("microService2", "", "{\"configtype\":\"json\"}",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "{\"param1\":\"value1\"}", true);
+ loopTest2.addMicroServicePolicy(microServicePolicy1);
+ loopTest2.addMicroServicePolicy(microServicePolicy2);
+ loopsRepository.saveAndFlush(loopTest2);
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest2)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:deploy-loop", myCamelExchange);
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest2");
+ Set<MicroServicePolicy> policyList = loopAfterTest.getMicroServicePolicies();
+ for (MicroServicePolicy policy : policyList) {
+ assertThat(policy.getDcaeDeploymentStatusUrl()).isNotNull();
+ assertThat(policy.getDcaeDeploymentId()).isNotNull();
+ }
+ assertThat(loopAfterTest.getDcaeDeploymentStatusUrl()).isNull();
+ assertThat(loopAfterTest.getDcaeDeploymentId()).isNull();
+ }
+
+ /**
+ * This method tests the undeployment of a single blueprint.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void undeployWithSingleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest = createLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ template.setBlueprint("yamlcontent");
+ loopTest.setLoopTemplate(template);
+ loopTest.setDcaeDeploymentId("testDeploymentId");
+ loopTest.setDcaeDeploymentStatusUrl("testUrl");
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ loopService.saveOrUpdateLoop(loopTest);
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:undeploy-loop", myCamelExchange);
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest");
+ assertThat(loopAfterTest.getDcaeDeploymentStatusUrl().contains("/uninstall")).isTrue();
+ assertThat(loopAfterTest.getDcaeDeploymentId()).isNull();
+ }
+
+ /**
+ * This method tests the undeployment of multiple separated blueprints.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void undeployWithMultipleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest2 = createLoop("ControlLoopTest2", "yamlcontent", "{\"dcaeDeployParameters\": {"
+ + "\"microService1\": {\"location_id\": \"\", \"policy_id\": \"TCA_ResourceInstanceName1_tca\"},"
+ + "\"microService2\": {\"location_id\": \"\", \"policy_id\": \"TCA_ResourceInstanceName2_tca\"}"
+ + "}}", "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ loopTest2.setLoopTemplate(template);
+ MicroServicePolicy microServicePolicy1 = getMicroServicePolicy("microService1", "", "{\"configtype\":\"json\"}",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "{\"param1\":\"value1\"}", true,
+ "testDeploymentId1", "testDeploymentStatusUrl1");
+ MicroServicePolicy microServicePolicy2 = getMicroServicePolicy("microService2", "", "{\"configtype\":\"json\"}",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "{\"param1\":\"value1\"}", true,
+ "testDeploymentId2", "testDeploymentStatusUrl2");
+ loopTest2.addMicroServicePolicy(microServicePolicy1);
+ loopTest2.addMicroServicePolicy(microServicePolicy2);
+ loopsRepository.saveAndFlush(loopTest2);
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest2)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:undeploy-loop", myCamelExchange);
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest2");
+ Set<MicroServicePolicy> policyList = loopAfterTest.getMicroServicePolicies();
+ for (MicroServicePolicy policy : policyList) {
+ assertThat(policy.getDcaeDeploymentStatusUrl().contains("/uninstall")).isTrue();
+ assertThat(policy.getDcaeDeploymentId()).isNull();
+
+ }
+ assertThat(loopAfterTest.getDcaeDeploymentStatusUrl()).isNull();
+ assertThat(loopAfterTest.getDcaeDeploymentId()).isNull();
+ }
+
+ /**
+ * This method tests the DCAE get status for a single blueprint.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void getStatusWithSingleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest = createLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ template.setBlueprint("yamlcontent");
+ loopTest.setLoopTemplate(template);
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ loopService.saveOrUpdateLoop(loopTest);
+ assertThat(loopTest.getComponents().size()).isEqualTo(2);
+ assertThat(loopTest.getComponent("DCAE")).isNotNull();
+ assertThat(loopTest.getComponent("POLICY")).isNotNull();
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:update-dcae-status-for-loop", myCamelExchange);
+
+ assertThat(loopTest.getComponent("DCAE").getState().getStateName()).isEqualTo("BLUEPRINT_DEPLOYED");
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest");
+ assertThat(loopAfterTest.getComponents().size()).isEqualTo(2);
+ assertThat(loopAfterTest.getComponent("DCAE")).isNotNull();
+ assertThat(loopAfterTest.getComponent("POLICY")).isNotNull();
+ }
+
+ /**
+ * This method tests the dcae get status for multiple blueprints.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ */
+ @Test
+ @Transactional
+ public void getStatusWithMultipleBlueprintTest() throws JsonSyntaxException, IOException {
+ Loop loopTest = createLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "UUID-blueprint");
+ LoopTemplate template = new LoopTemplate();
+ template.setName("templateName");
+ loopTest.setLoopTemplate(template);
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ MicroServicePolicy microServicePolicy2 = getMicroServicePolicy("configPolicyTest2", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ loopTest.addMicroServicePolicy(microServicePolicy2);
+ loopService.saveOrUpdateLoop(loopTest);
+ assertThat(loopTest.getComponents().size()).isEqualTo(3);
+ assertThat(loopTest.getComponent("DCAE")).isNull();
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest")).isNotNull();
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest2")).isNotNull();
+ assertThat(loopTest.getComponent("POLICY")).isNotNull();
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext).withProperty("loopObject", loopTest)
+ .build();
+
+ camelContext.createProducerTemplate().send("direct:update-dcae-status-for-loop", myCamelExchange);
+
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest").getState().getStateName())
+ .isEqualTo("BLUEPRINT_DEPLOYED");
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest2").getState().getStateName())
+ .isEqualTo("BLUEPRINT_DEPLOYED");
+
+ Loop loopAfterTest = loopService.getLoop("ControlLoopTest");
+ assertThat(loopAfterTest.getComponents().size()).isEqualTo(3);
+ assertThat(loopAfterTest.getComponent("DCAE")).isNull();
+ assertThat(loopAfterTest.getComponent("POLICY")).isNotNull();
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest")).isNotNull();
+ assertThat(loopTest.getComponent("DCAE_configPolicyTest2")).isNotNull();
+ }
+
+ private Loop createLoop(String name, String blueprint, String globalPropertiesJson,
+ String dcaeBlueprintId) throws JsonSyntaxException, IOException {
+ Loop loop = new Loop(name);
+ loop.setGlobalPropertiesJson(new Gson().fromJson(globalPropertiesJson, JsonObject.class));
+ loop.setLastComputedState(LoopState.DESIGN);
+ return loop;
+ }
+
+ private MicroServicePolicy getMicroServicePolicy(String name, String modelType, String jsonRepresentation,
+ String policyTosca, String jsonProperties, boolean shared) {
+
+ PolicyModel policyModel = new PolicyModel(modelType, policyTosca, "1.0.0");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+ MicroServicePolicy microService = new MicroServicePolicy(name, policyModel,
+ shared,
+ gson.fromJson(jsonRepresentation, JsonObject.class), null, null, null);
+
+ microService.setConfigurationsJson(new Gson().fromJson(jsonProperties, JsonObject.class));
+ return microService;
+ }
+
+ private MicroServicePolicy getMicroServicePolicy(String name, String modelType, String jsonRepresentation,
+ String policyTosca, String jsonProperties, boolean shared,
+ String deploymengId,
+ String deploymentStatusUrl) {
+ MicroServicePolicy microService = getMicroServicePolicy(name, modelType, jsonRepresentation, policyTosca,
+ jsonProperties, shared);
+
+ microService.setDcaeDeploymentId(deploymengId);
+ microService.setDcaeDeploymentStatusUrl(deploymentStatusUrl);
+ return microService;
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/ExternalComponentStateTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/ExternalComponentStateTest.java
new file mode 100644
index 000000000..a73b2784b
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/ExternalComponentStateTest.java
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.onap.policy.clamp.loop.components.external.ExternalComponentState;
+
+public class ExternalComponentStateTest {
+ private ExternalComponentState state = new ExternalComponentState("NOT_SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+
+ @Test
+ public void generalTest() {
+ assertThat(state.toString()).isEqualTo("NOT_SENT");
+ state.setLevel(70);
+ assertThat(state.getLevel()).isEqualTo(70);
+ }
+
+ @Test
+ public void equalsTest() {
+ assertThat(state.equals(null)).isEqualTo(false);
+
+ ExternalComponentState state2 = new ExternalComponentState("NOT_SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ assertThat(state.equals(state2)).isEqualTo(true);
+
+ assertThat(state.equals(12)).isEqualTo(false);
+
+ state2.setLevel(70);
+ assertThat(state.equals(state2)).isEqualTo(true);
+
+ ExternalComponentState state3 = new ExternalComponentState("SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ assertThat(state.equals(state3)).isEqualTo(false);
+
+ ExternalComponentState state4 = new ExternalComponentState(null,
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ ExternalComponentState state5 = new ExternalComponentState(null,
+ "The policies defined have NOT yet been", 50);
+ assertThat(state4.equals(state3)).isEqualTo(false);
+ assertThat(state4.equals(state5)).isEqualTo(true);
+ }
+
+ @Test
+ public void compareToTest() {
+ ExternalComponentState state2 = new ExternalComponentState("NOT_SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ assertThat(state.compareTo(state2)).isEqualTo(0);
+
+ ExternalComponentState state3 = new ExternalComponentState("SENT",
+ "The policies defined have NOT yet been created on the policy engine", 50);
+ assertThat(state.compareTo(state3)).isEqualTo(1);
+
+ ExternalComponentState state4 = new ExternalComponentState(null,
+ "The policies defined have NOT yet been created on the policy engine", 100);
+ assertThat(state.compareTo(state4)).isEqualTo(-1);
+
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopControllerTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopControllerTestItCase.java
new file mode 100644
index 000000000..6728d292c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopControllerTestItCase.java
@@ -0,0 +1,175 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * Modifications Copyright (C) 2019 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.util.Set;
+import javax.transaction.Transactional;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class LoopControllerTestItCase {
+
+ private static final String EXAMPLE_LOOP_NAME = "ClosedLoopTest";
+ private static final String EXAMPLE_JSON = "{\"testName\":\"testValue\"}";
+
+ @Autowired
+ LoopService loopService;
+
+ @Autowired
+ LoopsRepository loopsRepository;
+
+ @Autowired
+ MicroServicePolicyService microServicePolicyService;
+
+ @Autowired
+ OperationalPolicyService operationalPolicyService;
+
+ @Autowired
+ PolicyModelsService policyModelsService;
+
+ @Autowired
+ LoopController loopController;
+
+ private void saveTestLoopToDb() {
+ Loop testLoop = createTestLoop(EXAMPLE_LOOP_NAME, "blueprint", "representation");
+ testLoop.setGlobalPropertiesJson(JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class));
+ LoopTemplate template = new LoopTemplate();
+ template.setName("testTemplate");
+ testLoop.setLoopTemplate(template);
+ Service modelService = new Service("{\"name\":\"serviceName\",\"UUID\":\"uuid\"}", "{}");
+ testLoop.setModelService(modelService);
+ loopService.saveOrUpdateLoop(testLoop);
+ }
+
+ private Loop createTestLoop(String loopName, String loopBlueprint, String loopSvg) {
+ return new Loop(loopName);
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateOperationalPolicies() {
+ saveTestLoopToDb();
+ String policy = "[{\"name\":\"OPERATIONAL_CLholmes31_v1_0_vFW_PG_T10_k8s-holmes-rules\","
+ + "\"configurationsJson\":{"
+ + "\"operational_policy\":{\"controlLoop\":{\"trigger_policy\":\"unique-policy-id-1-modifyConfig\","
+ + "\"timeout\":\"3600\",\"abatement\":\"false\","
+ + "\"controlLoopName\":\"LOOP_CLholmes31_v1_0_vFW_PG_T10_k8s-holmes-rules\"},"
+ + "\"policies\":[{\"id\":\"unique-policy-id-1-modifyConfig\",\"recipe\":\"ModifyConfig\","
+ + "\"retry\":\"2\",\"timeout\":\"1200\",\"actor\":\"APPC\",\"payload\":\"{\\\"active-streams\\\":5}\","
+ + "\"success\":\"\",\"failure\":\"\",\"failure_timeout\":\"\",\"failure_retries\":\"\","
+ + "\"failure_exception\":\"\",\"failure_guard\":\"\",\"target\":{\"type\":\"VNF\","
+ + "\"resourceID\":\"vFW_PG_T1\"}}]}}}]";
+ JsonParser parser = new JsonParser();
+ JsonElement ele = parser.parse(policy);
+ JsonArray arr = ele.getAsJsonArray();
+ Loop loop = loopController.updateOperationalPolicies(EXAMPLE_LOOP_NAME, arr);
+ assertThat(loop.getOperationalPolicies()).hasSize(1);
+ Set<OperationalPolicy> opSet = loop.getOperationalPolicies();
+ OperationalPolicy op = opSet.iterator().next();
+ assertThat(op.getName()).isEqualTo("OPERATIONAL_CLholmes31_v1_0_vFW_PG_T10_k8s-holmes-rules");
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateGlobalProperties() {
+ saveTestLoopToDb();
+ String policy = "{\"dcaeDeployParameters\":{\"aaiEnrichmentHost\":\"aai.onap.svc.cluster.local\","
+ + "\"aaiEnrichmentPort\":\"8443\",\"enableAAIEnrichment\":\"false\",\"dmaap_host\":\"message-router"
+ + ".onap\",\"dmaap_port\":\"3904\",\"enableRedisCaching\":\"false\",\"redisHosts\":\"dcae-redis.onap"
+ + ".svc.cluster.local:6379\",\"tag_version\":\"nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments"
+ + ".tca-cdap-container:1.1.1\",\"consul_host\":\"consul-server.onap\",\"consul_port\":\"8500\","
+ + "\"cbs_host\":\"config-binding-service\",\"cbs_port\":\"10000\",\"external_port\":\"32012\","
+ + "\"policy_model_id\":\"onap.policies.monitoring.cdap.tca.hi.lo.app\","
+ + "\"policy_id\":\"tca_k8s_CLTCA_v1_0_vFW_PG_T10_k8s-tca-clamp-policy-05162019\"}}";
+ JsonParser parser = new JsonParser();
+ JsonElement ele = parser.parse(policy);
+ JsonObject obj = ele.getAsJsonObject();
+ loopController.updateGlobalPropertiesJson(EXAMPLE_LOOP_NAME, obj);
+ Loop loop = loopController.getLoop(EXAMPLE_LOOP_NAME);
+ JsonObject globalPropertiesJson = loop.getGlobalPropertiesJson();
+ JsonObject prop = globalPropertiesJson.getAsJsonObject("dcaeDeployParameters");
+ assertThat(prop.get("aaiEnrichmentHost").getAsString()).isEqualTo("aai.onap.svc.cluster.local");
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateMicroservicePolicy() {
+ saveTestLoopToDb();
+ PolicyModel policyModel = new PolicyModel("testPolicyModel",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+ MicroServicePolicy policy = new MicroServicePolicy("policyName", policyModel, false,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+ loopController.updateMicroservicePolicy(EXAMPLE_LOOP_NAME, policy);
+ assertThat(microServicePolicyService.isExisting("policyName")).isTrue();
+ }
+
+ @Test
+ @Transactional
+ public void testAddAndRemoveOperationalPolicies() throws IOException {
+ saveTestLoopToDb();
+ PolicyModel policyModel = new PolicyModel("testPolicyModel",
+ null, "1.0.0");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+
+ loopController.addOperationalPolicy(EXAMPLE_LOOP_NAME, "testPolicyModel", "1.0.0");
+
+ Loop newLoop = loopController.getLoop(EXAMPLE_LOOP_NAME);
+ Set<OperationalPolicy> opPolicyList = newLoop.getOperationalPolicies();
+ assertThat(opPolicyList.size()).isEqualTo(1);
+ for (OperationalPolicy policy : opPolicyList) {
+ assertThat(policy.getName().contains("OPERATIONAL_serviceName")).isTrue();
+ Assertions.assertThat(policy.getPolicyModel().getPolicyModelType()).isEqualTo("testPolicyModel");
+ Assertions.assertThat(policy.getPolicyModel().getVersion()).isEqualTo("1.0.0");
+ }
+
+ loopController.removeOperationalPolicy(EXAMPLE_LOOP_NAME, "testPolicyModel", "1.0.0");
+ Loop newLoop2 = loopController.getLoop(EXAMPLE_LOOP_NAME);
+ assertThat(newLoop2.getOperationalPolicies().size()).isEqualTo(0);
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopLogServiceTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopLogServiceTestItCase.java
new file mode 100644
index 000000000..7b0ab8614
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopLogServiceTestItCase.java
@@ -0,0 +1,96 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import java.util.Set;
+import javax.transaction.Transactional;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.log.LogType;
+import org.onap.policy.clamp.loop.log.LoopLog;
+import org.onap.policy.clamp.loop.log.LoopLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class LoopLogServiceTestItCase {
+
+ private static final String EXAMPLE_LOOP_NAME = "ClosedLoopTest";
+ private static final String EXAMPLE_JSON = "{\"testName\":\"testValue\"}";
+ private static final String CLAMP_COMPONENT = "CLAMP";
+ private static final String SAMPLE_LOG_MESSAGE = "Sample log";
+ private static final String BLUEPRINT = "blueprint";
+
+ @Autowired
+ LoopService loopService;
+
+ @Autowired
+ LoopsRepository loopsRepository;
+
+ @Autowired
+ LoopLogService loopLogService;
+
+ private void saveTestLoopToDb() {
+ Loop testLoop = new Loop(EXAMPLE_LOOP_NAME);
+ testLoop.setGlobalPropertiesJson(JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class));
+ loopService.saveOrUpdateLoop(testLoop);
+ }
+
+ @Test
+ @Transactional
+ public void testAddLog() {
+ saveTestLoopToDb();
+ Loop loop = loopService.getLoop(EXAMPLE_LOOP_NAME);
+ loopLogService.addLog(SAMPLE_LOG_MESSAGE, "INFO", loop);
+ Set<LoopLog> loopLogs = loop.getLoopLogs();
+ assertThat(loopLogs).hasSize(1);
+ LoopLog loopLog = loopLogs.iterator().next();
+ assertThat(loopLog.getMessage()).isEqualTo(SAMPLE_LOG_MESSAGE);
+ }
+
+ @Test
+ @Transactional
+ public void testLoopLog() {
+ LoopLog log = new LoopLog();
+ Long id = Long.valueOf(100);
+ log.setId(id);
+ log.setLogComponent(CLAMP_COMPONENT);
+ log.setLogType(LogType.INFO);
+ log.setMessage(SAMPLE_LOG_MESSAGE);
+ Loop testLoop = new Loop(EXAMPLE_LOOP_NAME);
+ log.setLoop(testLoop);
+ assertThat(log.getMessage()).isEqualTo(SAMPLE_LOG_MESSAGE);
+ assertThat(log.getLogType()).isEqualTo(LogType.INFO);
+ assertThat(log.getLogComponent()).isEqualTo(CLAMP_COMPONENT);
+ assertThat(log.getId()).isEqualTo(id);
+ Assertions.assertThat(log.getLoop()).isEqualTo(testLoop);
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopRepositoriesItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopRepositoriesItCase.java
new file mode 100644
index 000000000..e18dd2475
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopRepositoriesItCase.java
@@ -0,0 +1,258 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import java.time.Instant;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.loop.log.LogType;
+import org.onap.policy.clamp.loop.log.LoopLog;
+import org.onap.policy.clamp.loop.log.LoopLogRepository;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.service.ServicesRepository;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopElementModelsRepository;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.LoopTemplatesRepository;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelId;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = Application.class)
+public class LoopRepositoriesItCase {
+
+ private Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
+
+ @Autowired
+ private LoopsRepository loopRepository;
+
+ @Autowired
+ private MicroServicePolicyService microServicePolicyService;
+
+ @Autowired
+ private OperationalPolicyService operationalPolicyService;
+
+ @Autowired
+ private LoopLogRepository loopLogRepository;
+
+ @Autowired
+ private LoopTemplatesRepository loopTemplateRepository;
+
+ @Autowired
+ private LoopElementModelsRepository microServiceModelsRepository;
+
+ @Autowired
+ private PolicyModelsRepository policyModelsRepository;
+
+ @Autowired
+ private ServicesRepository servicesRepository;
+
+ private Service getService(String serviceDetails, String resourceDetails) {
+ return new Service(serviceDetails, resourceDetails);
+ }
+
+ private OperationalPolicy getOperationalPolicy(String configJson, String name, PolicyModel policyModel) {
+ return new OperationalPolicy(name, null, new Gson().fromJson(configJson, JsonObject.class), policyModel,
+ null, null, null);
+ }
+
+ private LoopElementModel getLoopElementModel(String yaml, String name, String policyType, String createdBy,
+ PolicyModel policyModel) {
+ LoopElementModel model = new LoopElementModel(name, policyType, yaml);
+ model.addPolicyModel(policyModel);
+ return model;
+ }
+
+ private PolicyModel getPolicyModel(String policyType, String policyModelTosca, String version,
+ String policyAcronym) {
+ return new PolicyModel(policyType, policyModelTosca, version, policyAcronym);
+ }
+
+ private LoopTemplate getLoopTemplates(String name, String blueprint, String createdBy,
+ Integer maxInstancesAllowed) {
+ LoopTemplate template = new LoopTemplate(name, blueprint, maxInstancesAllowed, null);
+ template.addLoopElementModel(getLoopElementModel("yaml", "microService1", "org.onap.policy.drools", createdBy,
+ getPolicyModel("org.onap.policy.drools", "yaml", "1.0.0", "Drools")));
+ template.addLoopElementModel(getLoopElementModel("yaml", "oppolicy1", "org.onap.policy.drools.legacy",
+ createdBy, getPolicyModel("org.onap.policy.drools.legacy", "yaml", "1.0.0", "DroolsLegacy")));
+ loopTemplateRepository.save(template);
+ return template;
+ }
+
+ private Loop getLoop(String name, String blueprint, String globalPropertiesJson,
+ String dcaeId, String dcaeUrl, String dcaeBlueprintId) {
+ Loop loop = new Loop();
+ loop.setName(name);
+ loop.setGlobalPropertiesJson(new Gson().fromJson(globalPropertiesJson, JsonObject.class));
+ loop.setLastComputedState(LoopState.DESIGN);
+ loop.setDcaeDeploymentId(dcaeId);
+ loop.setDcaeDeploymentStatusUrl(dcaeUrl);
+ loop.setLoopTemplate(getLoopTemplates("templateName", "yaml", "toto", 1));
+ return loop;
+ }
+
+ private MicroServicePolicy getMicroServicePolicy(String name, String jsonRepresentation, String jsonProperties,
+ boolean shared, PolicyModel policyModel) {
+ MicroServicePolicy microService = new MicroServicePolicy(name, policyModel, shared,
+ gson.fromJson(jsonRepresentation, JsonObject.class), null, null, null);
+ microService.setConfigurationsJson(new Gson().fromJson(jsonProperties, JsonObject.class));
+ return microService;
+ }
+
+ private LoopLog getLoopLog(LogType type, String message, Loop loop) {
+ return new LoopLog(message, type, "CLAMP", loop);
+ }
+
+ /**
+ * This method does a crud test and save a loop template and a loop object in db.
+ */
+ @Test
+ @Transactional
+ public void crudTest() {
+ // Setup
+ Loop loopTest = getLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "123456789", "https://dcaetest.org", "UUID-blueprint");
+ OperationalPolicy opPolicy = this.getOperationalPolicy("{\"type\":\"GUARD\"}", "GuardOpPolicyTest",
+ getPolicyModel("org.onap.policy.drools.legacy", "yaml", "1.0.0", "DroolsLegacy"));
+ loopTest.addOperationalPolicy(opPolicy);
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "{\"configtype\":\"json\"}",
+ "{\"param1\":\"value1\"}", true, getPolicyModel("org.onap.policy.drools", "yaml", "1.0.0", "Drools"));
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ LoopLog loopLog = getLoopLog(LogType.INFO, "test message", loopTest);
+ loopTest.addLog(loopLog);
+ Service service = getService(
+ "{\"name\": \"vLoadBalancerMS\", \"UUID\": \"63cac700-ab9a-4115-a74f-7eac85e3fce0\"}", "{\"CP\": {}}");
+ loopTest.setModelService(service);
+
+ // Attempt to save into the database the entire loop
+ Loop loopInDb = loopRepository.save(loopTest);
+ assertThat(loopInDb).isNotNull();
+ assertThat(loopRepository.findById(loopInDb.getName()).get()).isNotNull();
+ assertThat(loopInDb.getCreatedDate()).isNotNull();
+ assertThat(loopInDb.getUpdatedDate()).isNotNull();
+ assertThat(loopInDb.getUpdatedDate()).isEqualTo(loopInDb.getCreatedDate());
+ assertThat(loopInDb.getName()).isEqualTo("ControlLoopTest");
+ // Autogen id so now set the ID in the previous model so that we can compare the
+ // objects
+ loopLog.setId(((LoopLog) loopInDb.getLoopLogs().toArray()[0]).getId());
+
+ assertThat(loopInDb).isEqualToIgnoringGivenFields(loopTest, "components", "createdDate", "updatedDate",
+ "createdBy", "updatedBy");
+ assertThat(loopRepository.existsById(loopTest.getName())).isEqualTo(true);
+ assertThat(operationalPolicyService.isExisting(opPolicy.getName())).isEqualTo(true);
+ assertThat(microServicePolicyService.isExisting(microServicePolicy.getName())).isEqualTo(true);
+ assertThat(loopLogRepository.existsById(loopLog.getId())).isEqualTo(true);
+ assertThat(loopTemplateRepository.existsById(loopInDb.getLoopTemplate().getName())).isEqualTo(true);
+ assertThat(loopTemplateRepository.existsById(loopInDb.getLoopTemplate().getName())).isEqualTo(true);
+ assertThat(servicesRepository.existsById(loopInDb.getModelService().getServiceUuid())).isEqualTo(true);
+ assertThat(microServiceModelsRepository.existsById(
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getName()))
+ .isEqualTo(true);
+ assertThat(policyModelsRepository.existsById(new PolicyModelId(
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getPolicyModels()
+ .first().getPolicyModelType(),
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getPolicyModels()
+ .first().getVersion()))).isEqualTo(true);
+
+ // Now attempt to read from database
+ Loop loopInDbRetrieved = loopRepository.findById(loopTest.getName()).get();
+ assertThat(loopInDbRetrieved).isEqualToIgnoringGivenFields(loopTest, "components", "createdDate", "updatedDate",
+ "createdBy", "updatedBy");
+ assertThat(loopInDbRetrieved).isEqualToComparingOnlyGivenFields(loopInDb, "createdDate", "updatedDate",
+ "createdBy", "updatedBy");
+ assertThat((LoopLog) loopInDbRetrieved.getLoopLogs().toArray()[0]).isEqualToComparingFieldByField(loopLog);
+ assertThat((OperationalPolicy) loopInDbRetrieved.getOperationalPolicies().toArray()[0])
+ .isEqualToIgnoringGivenFields(opPolicy, "createdDate", "updatedDate", "createdBy", "updatedBy");
+ Assertions.assertThat(
+ ((OperationalPolicy) loopInDbRetrieved.getOperationalPolicies().toArray()[0]).getCreatedDate())
+ .isNotNull();
+ Assertions.assertThat(
+ ((OperationalPolicy) loopInDbRetrieved.getOperationalPolicies().toArray()[0]).getUpdatedDate())
+ .isNotNull();
+ Assertions.assertThat(
+ ((OperationalPolicy) loopInDbRetrieved.getOperationalPolicies().toArray()[0]).getCreatedBy())
+ .isNotNull();
+ Assertions.assertThat(
+ ((OperationalPolicy) loopInDbRetrieved.getOperationalPolicies().toArray()[0]).getUpdatedBy())
+ .isNotNull();
+
+ assertThat((MicroServicePolicy) loopInDbRetrieved.getMicroServicePolicies().toArray()[0])
+ .isEqualToIgnoringGivenFields(microServicePolicy, "createdDate", "updatedDate", "createdBy",
+ "updatedBy");
+
+ // Attempt an update
+ ((LoopLog) loopInDbRetrieved.getLoopLogs().toArray()[0]).setLogInstant(Instant.now());
+ loopInDbRetrieved.setLastComputedState(LoopState.RUNNING);
+ Loop loopInDbRetrievedUpdated = loopRepository.saveAndFlush(loopInDbRetrieved);
+ // Loop loopInDbRetrievedUpdated =
+ // loopRepository.findById(loopTest.getName()).get();
+ assertThat((LoopLog) loopInDbRetrievedUpdated.getLoopLogs().toArray()[0])
+ .isEqualToComparingFieldByField(loopInDbRetrieved.getLoopLogs().toArray()[0]);
+ // UpdatedDate should have been changed
+ assertThat(loopInDbRetrievedUpdated.getUpdatedDate()).isNotEqualTo(loopInDbRetrievedUpdated.getCreatedDate());
+ // createdDate should have NOT been changed
+ assertThat(loopInDbRetrievedUpdated.getCreatedDate()).isEqualTo(loopInDb.getCreatedDate());
+ // other audit are the same
+ assertThat(loopInDbRetrievedUpdated.getCreatedBy()).isEqualTo("Not found");
+ assertThat(loopInDbRetrievedUpdated.getUpdatedBy()).isEqualTo("Not found");
+
+ // Attempt to delete the object and check it has well been cascaded
+
+ loopRepository.delete(loopInDbRetrieved);
+ assertThat(loopRepository.existsById(loopTest.getName())).isEqualTo(false);
+ assertThat(operationalPolicyService.isExisting(opPolicy.getName())).isEqualTo(false);
+ assertThat(microServicePolicyService.isExisting(microServicePolicy.getName())).isEqualTo(true);
+ assertThat(loopLogRepository.existsById(loopLog.getId())).isEqualTo(false);
+ assertThat(loopTemplateRepository.existsById(loopInDb.getLoopTemplate().getName())).isEqualTo(true);
+ assertThat(servicesRepository.existsById(loopInDb.getModelService().getServiceUuid())).isEqualTo(true);
+ assertThat(microServiceModelsRepository.existsById(
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getName()))
+ .isEqualTo(true);
+
+ assertThat(policyModelsRepository.existsById(new PolicyModelId(
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getPolicyModels()
+ .first().getPolicyModelType(),
+ loopInDb.getLoopTemplate().getLoopElementModelsUsed().first().getLoopElementModel().getPolicyModels()
+ .first().getVersion()))).isEqualTo(true);
+
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopServiceTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopServiceTestItCase.java
new file mode 100644
index 000000000..74092727c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopServiceTestItCase.java
@@ -0,0 +1,381 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 Nokia Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.transaction.Transactional;
+import org.assertj.core.api.Assertions;
+import org.assertj.core.util.Lists;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.log.LogType;
+import org.onap.policy.clamp.loop.log.LoopLog;
+import org.onap.policy.clamp.loop.log.LoopLogService;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicyService;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicyService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class LoopServiceTestItCase {
+
+ private static final String EXAMPLE_LOOP_NAME = "ClosedLoopTest";
+ private static final String EXAMPLE_JSON = "{\"testName\":\"testValue\"}";
+
+ @Autowired
+ LoopService loopService;
+
+ @Autowired
+ LoopsRepository loopsRepository;
+
+ @Autowired
+ MicroServicePolicyService microServicePolicyService;
+
+ @Autowired
+ OperationalPolicyService operationalPolicyService;
+
+ @Autowired
+ LoopLogService loopLogService;
+
+ @Autowired
+ PolicyModelsService policyModelsService;
+
+ @Test
+ @Transactional
+ public void shouldCreateEmptyLoop() {
+ // given
+ String loopBlueprint = "blueprint";
+ Loop testLoop = createTestLoop(EXAMPLE_LOOP_NAME, loopBlueprint);
+ testLoop.setGlobalPropertiesJson(JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class));
+ testLoop.setLastComputedState(LoopState.DESIGN);
+
+ // when
+ Loop actualLoop = loopService.saveOrUpdateLoop(testLoop);
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop).isEqualTo(loopsRepository.findById(actualLoop.getName()).get());
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ assertThat(actualLoop.getGlobalPropertiesJson().getAsJsonPrimitive("testName").getAsString())
+ .isEqualTo("testValue");
+ }
+
+ @Test
+ @Transactional
+ public void shouldAddOperationalPolicyToLoop() {
+ // given
+ saveTestLoopToDb();
+ OperationalPolicy operationalPolicy = new OperationalPolicy("policyName", null,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null, null);
+
+ // when
+ Loop actualLoop = loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(operationalPolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<OperationalPolicy> savedPolicies = actualLoop.getOperationalPolicies();
+ assertThat(savedPolicies).hasSize(1);
+ assertThat(savedPolicies)
+ .usingElementComparatorIgnoringFields("loop", "createdBy", "createdDate", "updatedBy", "updatedDate")
+ .contains(operationalPolicy);
+ OperationalPolicy savedPolicy = savedPolicies.iterator().next();
+ Assertions.assertThat(savedPolicy.getLoop().getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+
+ }
+
+ @Test
+ @Transactional
+ public void shouldAddMicroservicePolicyToLoop() {
+ // given
+ saveTestLoopToDb();
+ PolicyModel policyModel = new PolicyModel("org.policies.policyModel1",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "policyModel1");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+ MicroServicePolicy microServicePolicy = new MicroServicePolicy("policyName", policyModel,
+ false, JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+
+ // when
+ Loop actualLoop = loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(microServicePolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<MicroServicePolicy> savedPolicies = actualLoop.getMicroServicePolicies();
+ assertThat(savedPolicies).hasSize(1);
+ assertThat(savedPolicies).usingElementComparatorIgnoringFields("usedByLoops", "createdDate", "updatedDate",
+ "createdBy", "updatedBy").containsExactly(microServicePolicy);
+ assertThat(savedPolicies).extracting("usedByLoops").hasSize(1);
+
+ }
+
+ @Test
+ @Transactional
+ //@Commit
+ public void shouldCreateNewMicroservicePolicyAndUpdateJsonRepresentationOfOldOne() {
+ // given
+ saveTestLoopToDb();
+ PolicyModel policyModel1 = new PolicyModel("org.policies.firstPolicyName",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "firstPolicyName");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = new PolicyModel("org.policies.secondPolicyName",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "secondPolicyName");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+ MicroServicePolicy firstMicroServicePolicy = new MicroServicePolicy("firstPolicyName", policyModel1, false,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+
+ loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(firstMicroServicePolicy));
+ MicroServicePolicy secondMicroServicePolicy = new MicroServicePolicy("secondPolicyName", policyModel2, false,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+
+ // when
+ firstMicroServicePolicy
+ .setConfigurationsJson(JsonUtils.GSON.fromJson("{\"name1\":\"value1\"}", JsonObject.class));
+ Loop actualLoop = loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(firstMicroServicePolicy, secondMicroServicePolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<MicroServicePolicy> savedPolicies = actualLoop.getMicroServicePolicies();
+ assertThat(savedPolicies).hasSize(2);
+ assertThat(savedPolicies).contains(firstMicroServicePolicy);
+ assertThat(savedPolicies).contains(secondMicroServicePolicy);
+ assertThat(savedPolicies).usingElementComparatorIgnoringFields("usedByLoops", "createdDate", "updatedDate",
+ "createdBy", "updatedBy").containsExactlyInAnyOrder(firstMicroServicePolicy, secondMicroServicePolicy);
+ }
+
+ private void saveTestLoopToDb() {
+ Loop testLoop = createTestLoop(EXAMPLE_LOOP_NAME, "blueprint");
+ testLoop.setGlobalPropertiesJson(JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class));
+ LoopTemplate template = new LoopTemplate();
+ template.setName("testTemplate");
+ testLoop.setLoopTemplate(template);
+ loopService.saveOrUpdateLoop(testLoop);
+ }
+
+ @Test
+ @Transactional
+ public void shouldRemoveOldMicroservicePolicyIfNotInUpdatedList() {
+ // given
+ saveTestLoopToDb();
+ PolicyModel policyModel1 = new PolicyModel("org.policies.firstPolicyName",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "firstPolicyName");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = new PolicyModel("org.policies.secondPolicyName",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "secondPolicyName");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+ MicroServicePolicy firstMicroServicePolicy = new MicroServicePolicy("firstPolicyName", policyModel1,
+ false, JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+ loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(firstMicroServicePolicy));
+
+ MicroServicePolicy secondMicroServicePolicy = new MicroServicePolicy("secondPolicyName", policyModel2,
+ false, JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+
+ // when
+ Loop actualLoop = loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(secondMicroServicePolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<MicroServicePolicy> savedPolicies = actualLoop.getMicroServicePolicies();
+ assertThat(savedPolicies).hasSize(1);
+ assertThat(savedPolicies).usingElementComparatorIgnoringFields("usedByLoops", "createdDate", "updatedDate",
+ "createdBy", "updatedBy").containsExactly(secondMicroServicePolicy);
+
+ }
+
+ @Test
+ @Transactional
+ public void shouldCreateNewOperationalPolicyAndUpdateJsonRepresentationOfOldOne() {
+ // given
+ saveTestLoopToDb();
+
+ JsonObject newJsonConfiguration = JsonUtils.GSON.fromJson("{}", JsonObject.class);
+
+ OperationalPolicy firstOperationalPolicy = new OperationalPolicy("firstPolicyName", null,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null, null);
+ loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(firstOperationalPolicy));
+
+ OperationalPolicy secondOperationalPolicy = new OperationalPolicy("secondPolicyName", null,
+ newJsonConfiguration, null, null, null, null);
+
+ // when
+ firstOperationalPolicy.setConfigurationsJson(newJsonConfiguration);
+ Loop actualLoop = loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(firstOperationalPolicy, secondOperationalPolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<OperationalPolicy> savedPolicies = actualLoop.getOperationalPolicies();
+ assertThat(savedPolicies).hasSize(2);
+ assertThat(savedPolicies)
+ .usingElementComparatorIgnoringFields("loop", "createdDate", "updatedDate", "createdBy", "updatedBy")
+ .containsExactlyInAnyOrder(firstOperationalPolicy, secondOperationalPolicy);
+ Set<String> policiesLoops = Lists.newArrayList(savedPolicies).stream().map(OperationalPolicy::getLoop)
+ .map(Loop::getName).collect(Collectors.toSet());
+ assertThat(policiesLoops).containsExactly(EXAMPLE_LOOP_NAME);
+ }
+
+ @Test
+ @Transactional
+ public void shouldRemoveOldOperationalPolicyIfNotInUpdatedList() {
+ // given
+ saveTestLoopToDb();
+
+ OperationalPolicy firstOperationalPolicy = new OperationalPolicy("firstPolicyName", null,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null, null);
+ loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(firstOperationalPolicy));
+
+ OperationalPolicy secondOperationalPolicy = new OperationalPolicy("policyName", null,
+ JsonUtils.GSON.fromJson("{}", JsonObject.class), null, null, "pdpGroup1", "pdpSubgroup1");
+
+ // when
+ Loop actualLoop = loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME,
+ Lists.newArrayList(secondOperationalPolicy));
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ Set<OperationalPolicy> savedPolicies = actualLoop.getOperationalPolicies();
+ assertThat(savedPolicies).hasSize(1);
+ assertThat(savedPolicies)
+ .usingElementComparatorIgnoringFields("loop", "createdDate", "updatedDate", "createdBy", "updatedBy")
+ .containsExactly(secondOperationalPolicy);
+ OperationalPolicy savedPolicy = savedPolicies.iterator().next();
+ Assertions.assertThat(savedPolicy.getLoop().getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+
+ }
+
+ @Test
+ @Transactional
+ public void shouldCreateModelPropertiesAndUpdateJsonRepresentationOfOldOne() {
+ // given
+ saveTestLoopToDb();
+ String expectedJson = "{\"test\":\"test\"}";
+ JsonObject baseGlobalProperites = JsonUtils.GSON.fromJson("{}", JsonObject.class);
+ JsonObject updatedGlobalProperites = JsonUtils.GSON.fromJson(expectedJson, JsonObject.class);
+ loopService.updateAndSaveGlobalPropertiesJson(EXAMPLE_LOOP_NAME, baseGlobalProperites);
+
+ // when
+ Loop actualLoop = loopService.updateAndSaveGlobalPropertiesJson(EXAMPLE_LOOP_NAME, updatedGlobalProperites);
+
+ // then
+ assertThat(actualLoop).isNotNull();
+ assertThat(actualLoop.getName()).isEqualTo(EXAMPLE_LOOP_NAME);
+ JsonObject returnedGlobalProperties = actualLoop.getGlobalPropertiesJson();
+ assertThat(returnedGlobalProperties.getAsJsonObject()).isEqualTo(updatedGlobalProperites);
+ }
+
+ @Test
+ @Transactional
+ public void deleteAttempt() {
+ saveTestLoopToDb();
+ // Add log
+ Loop loop = loopsRepository.findById(EXAMPLE_LOOP_NAME).orElse(null);
+ loop.addLog(new LoopLog("test", LogType.INFO, "CLAMP", loop));
+ LoopTemplate template = new LoopTemplate();
+ template.setName("testTemplate");
+ loop.setLoopTemplate(template);
+ loop = loopService.saveOrUpdateLoop(loop);
+ // Add op policy
+ OperationalPolicy operationalPolicy = new OperationalPolicy("opPolicy", null,
+ JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null, null);
+ loopService.updateAndSaveOperationalPolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(operationalPolicy));
+
+ PolicyModel policyModel = new PolicyModel("org.policies.microPolicy",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "microPolicy");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+ // Add Micro service policy
+ MicroServicePolicy microServicePolicy = new MicroServicePolicy("microPolicy", policyModel,
+ false, JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+ loopService.updateAndSaveMicroservicePolicies(EXAMPLE_LOOP_NAME, Lists.newArrayList(microServicePolicy));
+
+ // Verify it's there
+ assertThat(loopsRepository.findById(EXAMPLE_LOOP_NAME).orElse(null)).isNotNull();
+ loopService.deleteLoop(EXAMPLE_LOOP_NAME);
+ // Verify it's well deleted and has been cascaded, except for Microservice
+ assertThat(loopsRepository.findById(EXAMPLE_LOOP_NAME).orElse(null)).isNull();
+ assertThat(microServicePolicyService.isExisting("microPolicy")).isTrue();
+ assertThat(operationalPolicyService.isExisting("opPolicy")).isFalse();
+ assertThat(loopLogService.isExisting(((LoopLog) loop.getLoopLogs().toArray()[0]).getId())).isFalse();
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateLoopState() {
+ saveTestLoopToDb();
+ Loop loop = loopService.getLoop(EXAMPLE_LOOP_NAME);
+ loopService.updateLoopState(loop, "SUBMITTED");
+ Loop updatedLoop = loopService.getLoop(EXAMPLE_LOOP_NAME);
+ assertThat(updatedLoop.getLastComputedState()).isEqualTo(LoopState.SUBMITTED);
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateDcaeDeploymentFields() {
+ saveTestLoopToDb();
+ Loop loop = loopService.getLoop(EXAMPLE_LOOP_NAME);
+ loopService.updateDcaeDeploymentFields(loop, "CLAMP_c5ce429a-f570-48c5-a7ea-53bed8f86f85",
+ "https://deployment-handler.onap:8443");
+ loop = loopService.getLoop(EXAMPLE_LOOP_NAME);
+ assertThat(loop.getDcaeDeploymentId()).isEqualTo("CLAMP_c5ce429a-f570-48c5-a7ea-53bed8f86f85");
+ assertThat(loop.getDcaeDeploymentStatusUrl()).isEqualTo("https://deployment-handler.onap:8443");
+ }
+
+ @Test
+ @Transactional
+ public void testUpdateMicroservicePolicy() {
+ saveTestLoopToDb();
+ assertThat(microServicePolicyService.isExisting("policyName")).isFalse();
+ PolicyModel policyModel = new PolicyModel("org.policies.policyName",
+ "tosca_definitions_version: tosca_simple_yaml_1_0_0", "1.0.0", "policyName");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+ MicroServicePolicy microServicePolicy = new MicroServicePolicy("policyName", policyModel,
+ false, JsonUtils.GSON.fromJson(EXAMPLE_JSON, JsonObject.class), null, null, null);
+ loopService.updateMicroservicePolicy(EXAMPLE_LOOP_NAME, microServicePolicy);
+ assertThat(microServicePolicyService.isExisting("policyName")).isTrue();
+ }
+
+ private Loop createTestLoop(String loopName, String loopBlueprint) {
+ return new Loop(loopName);
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplateLoopElementModelTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplateLoopElementModelTest.java
new file mode 100644
index 000000000..9dcd71ef1
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplateLoopElementModelTest.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.LoopTemplateLoopElementModel;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+
+
+public class LoopTemplateLoopElementModelTest {
+
+ private LoopElementModel loopElementModel = getLoopElementModel("yaml", "microService1",
+ getPolicyModel("org.onap.policy.drools", "yaml", "1.0.0", "Drools", "type1"));
+ private LoopTemplate loopTemplate = getLoopTemplate("templateName", "yaml", 1);
+
+ private LoopElementModel getLoopElementModel(String yaml, String name, PolicyModel policyModel) {
+ LoopElementModel model = new LoopElementModel();
+ model.setBlueprint(yaml);
+ model.setName(name);
+ model.addPolicyModel(policyModel);
+ model.setLoopElementType("OPERATIONAL_POLICY");
+ return model;
+ }
+
+ private PolicyModel getPolicyModel(String policyType, String policyModelTosca, String version, String policyAcronym,
+ String policyVariant) {
+ return new PolicyModel(policyType, policyModelTosca, version, policyAcronym);
+ }
+
+ private LoopTemplate getLoopTemplate(String name, String blueprint, Integer maxInstancesAllowed) {
+ LoopTemplate template = new LoopTemplate(name, blueprint, maxInstancesAllowed, null);
+ template.addLoopElementModel(loopElementModel);
+ return template;
+ }
+
+ /**
+ * This tests compareTo method.
+ */
+ @Test
+ public void compareToTest() {
+ LoopTemplateLoopElementModel model1 = new LoopTemplateLoopElementModel();
+ LoopTemplateLoopElementModel model2 = new LoopTemplateLoopElementModel();
+ assertThat(model1.compareTo(model2)).isEqualTo(1);
+
+ model1.setFlowOrder(2);
+ assertThat(model1.compareTo(model2)).isEqualTo(-1);
+
+ model2.setFlowOrder(3);
+ assertThat(model1.compareTo(model2)).isEqualTo(1);
+ }
+
+ /**
+ * This tests equals method.
+ */
+ @Test
+ public void equalsTest() {
+ LoopTemplateLoopElementModel model1 = new LoopTemplateLoopElementModel();
+ LoopTemplateLoopElementModel model2 = new LoopTemplateLoopElementModel();
+
+ assertThat(model1.equals(model2)).isTrue();
+
+ model1.setLoopTemplate(loopTemplate);
+ assertThat(model1.equals(model2)).isFalse();
+ model2.setLoopTemplate(loopTemplate);
+ assertThat(model1.equals(model2)).isTrue();
+
+ model1.setLoopElementModel(loopElementModel);
+ assertThat(model1.equals(model2)).isFalse();
+ model2.setLoopElementModel(loopElementModel);
+ assertThat(model1.equals(model2)).isTrue();
+
+ model1.setFlowOrder(1);
+ assertThat(model1.equals(model2)).isTrue();
+ model2.setFlowOrder(2);
+ assertThat(model1.equals(model2)).isTrue();
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplatesServiceItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplatesServiceItCase.java
new file mode 100644
index 000000000..dba7c39a9
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopTemplatesServiceItCase.java
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.List;
+import java.util.SortedSet;
+import javax.transaction.Transactional;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.LoopTemplateLoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplatesService;
+import org.onap.policy.clamp.loop.template.LoopType;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class LoopTemplatesServiceItCase {
+
+ @Autowired
+ LoopTemplatesService loopTemplatesService;
+
+ private static final String POLICY_MODEL_TYPE_1 = "org.onap.test";
+ private static final String VERSION = "1.0.0";
+
+ private LoopElementModel getLoopElementModel(String yaml, String name, String loopElementType,
+ String createdBy, PolicyModel policyModel) {
+ LoopElementModel model = new LoopElementModel(name, loopElementType, yaml);
+ model.setBlueprint("");
+ model.setDcaeBlueprintId("");
+ model.addPolicyModel(policyModel);
+ return model;
+ }
+
+ private PolicyModel getPolicyModel(String policyType, String policyModelTosca, String version,
+ String policyAcronym, String createdBy) {
+ return new PolicyModel(policyType, policyModelTosca, version, policyAcronym);
+ }
+
+ private LoopTemplate getLoopTemplate(String name, String blueprint, String createdBy, Integer maxInstancesAllowed) {
+ LoopTemplate template =
+ new LoopTemplate(name, blueprint, maxInstancesAllowed, null);
+ template.addLoopElementModel(getLoopElementModel("yaml", "microService1", "MicroService",
+ createdBy, getPolicyModel(POLICY_MODEL_TYPE_1, "yaml", VERSION, "MS1", createdBy)));
+ template.setAllowedLoopType(LoopType.OPEN);
+ return template;
+ }
+
+ @Test
+ @Transactional
+ public void shouldSaveOrUpdateLoopTemplate() {
+ LoopTemplate loopTemplate = getLoopTemplate("TemplateName", null, "xyz", -1);
+ LoopTemplate actualLoopTemplate =
+ loopTemplatesService.saveOrUpdateLoopTemplate(loopTemplate);
+
+ assertNotNull(actualLoopTemplate);
+ assertThat(loopTemplate.getName()).isEqualTo("TemplateName");
+ assertThat(loopTemplate.getAllowedLoopType()).isEqualTo(LoopType.OPEN);
+ }
+
+ @Test
+ @Transactional
+ public void shouldReturnAllLoopTemplates() {
+ LoopTemplate loopTemplate = getLoopTemplate("TemplateName", null, "xyz", -1);
+ loopTemplatesService.saveOrUpdateLoopTemplate(loopTemplate);
+ List<LoopTemplate> loopTemplateList = loopTemplatesService.getAllLoopTemplates();
+
+ assertNotNull(loopTemplateList);
+ }
+
+ @Test
+ @Transactional
+ public void shouldReturnLoopTemplateNames() {
+ LoopTemplate loopTemplate = getLoopTemplate("TemplateName", null, "xyz", -1);
+ loopTemplatesService.saveOrUpdateLoopTemplate(loopTemplate);
+ List<String> loopTemplateNames = loopTemplatesService.getLoopTemplateNames();
+
+ assertNotNull(loopTemplateNames);
+ assertEquals("TemplateName", loopTemplateNames.get(0));
+ }
+
+ @Test
+ @Transactional
+ public void shouldReturnLoopTemplate() {
+ LoopTemplate loopTemplate = getLoopTemplate("TemplateName", null, "xyz", -1);
+ loopTemplatesService.saveOrUpdateLoopTemplate(loopTemplate);
+ LoopTemplate actualLoopTemplate = loopTemplatesService.getLoopTemplate("TemplateName");
+
+ assertNotNull(actualLoopTemplate);
+ assertThat(loopTemplate).isEqualTo(actualLoopTemplate);
+ assertThat(loopTemplate.getName()).isEqualTo(actualLoopTemplate.getName());
+ assertThat(loopTemplate.getMaximumInstancesAllowed())
+ .isEqualTo(actualLoopTemplate.getMaximumInstancesAllowed());
+ SortedSet<LoopTemplateLoopElementModel> loopElementModelsUsed =
+ loopTemplate.getLoopElementModelsUsed();
+ LoopTemplateLoopElementModel loopTemplateLoopElementModel = loopElementModelsUsed.first();
+ assertThat(loopTemplateLoopElementModel.getLoopElementModel().getName())
+ .isEqualTo("microService1");
+ assertThat(loopTemplateLoopElementModel.getLoopTemplate().getName())
+ .isEqualTo("TemplateName");
+ assertNull(actualLoopTemplate.getBlueprint());
+ assertNull(actualLoopTemplate.getModelService());
+ }
+
+ @Test
+ @Transactional
+ public void shouldDeleteLoopTemplate() {
+ LoopTemplate loopTemplate = getLoopTemplate("TemplateName", null, "xyz", -1);
+ loopTemplatesService.saveOrUpdateLoopTemplate(loopTemplate);
+ loopTemplatesService.deleteLoopTemplate("TemplateName");
+ LoopTemplate actualLoopTemplate = loopTemplatesService.getLoopTemplate("TemplateName");
+ assertNull(actualLoopTemplate);
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/LoopToJsonTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopToJsonTest.java
new file mode 100644
index 000000000..0fc4b0b5c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/LoopToJsonTest.java
@@ -0,0 +1,173 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import java.io.IOException;
+import java.util.Random;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.log.LogType;
+import org.onap.policy.clamp.loop.log.LoopLog;
+import org.onap.policy.clamp.loop.service.Service;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+
+public class LoopToJsonTest {
+
+ private Gson gson = new Gson();
+
+ private OperationalPolicy getOperationalPolicy(String configJson, String name) {
+ return new OperationalPolicy(name, null, gson.fromJson(configJson, JsonObject.class),
+ getPolicyModel("org.onap.policy.drools.legacy", "yaml", "1.0.0", "Drools", "type1"), null, null, null);
+ }
+
+ private Loop getLoop(String name, String blueprint, String globalPropertiesJson,
+ String dcaeId, String dcaeUrl, String dcaeBlueprintId)
+ throws JsonSyntaxException, IOException {
+ Loop loop = new Loop(name);
+ loop.setGlobalPropertiesJson(new Gson().fromJson(globalPropertiesJson, JsonObject.class));
+ loop.setLastComputedState(LoopState.DESIGN);
+ loop.setDcaeDeploymentId(dcaeId);
+ loop.setDcaeDeploymentStatusUrl(dcaeUrl);
+ return loop;
+ }
+
+ private MicroServicePolicy getMicroServicePolicy(String name, String modelType, String jsonRepresentation,
+ String policyTosca, String jsonProperties, boolean shared) {
+ MicroServicePolicy microService = new MicroServicePolicy(name, new PolicyModel(modelType, policyTosca, "1.0.0"),
+ shared,
+ gson.fromJson(jsonRepresentation, JsonObject.class), null, null, null);
+ microService.setConfigurationsJson(new Gson().fromJson(jsonProperties, JsonObject.class));
+ return microService;
+ }
+
+ private LoopElementModel getLoopElementModel(String yaml, String name, PolicyModel policyModel) {
+ LoopElementModel model = new LoopElementModel();
+ model.setBlueprint(yaml);
+ model.setName(name);
+ model.addPolicyModel(policyModel);
+ model.setLoopElementType("OPERATIONAL_POLICY");
+ return model;
+ }
+
+ private PolicyModel getPolicyModel(String policyType, String policyModelTosca, String version, String policyAcronym,
+ String policyVariant) {
+ return new PolicyModel(policyType, policyModelTosca, version, policyAcronym);
+ }
+
+ private LoopTemplate getLoopTemplate(String name, String blueprint, Integer maxInstancesAllowed) {
+ LoopTemplate template = new LoopTemplate(name, blueprint, maxInstancesAllowed, null);
+ template.addLoopElementModel(getLoopElementModel("yaml", "microService1",
+ getPolicyModel("org.onap.policy.drools", "yaml", "1.0.0", "Drools", "type1")));
+ return template;
+ }
+
+ private LoopLog getLoopLog(LogType type, String message, Loop loop) {
+ LoopLog log = new LoopLog(message, type, "CLAMP", loop);
+ log.setId(Long.valueOf(new Random().nextInt()));
+ return log;
+ }
+
+ /**
+ * This tests a GSON encode/decode.
+ *
+ * @throws IOException In case of failure
+ */
+ @Test
+ public void loopGsonTest() throws IOException {
+ Loop loopTest = getLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "123456789", "https://dcaetest.org", "UUID-blueprint");
+ OperationalPolicy opPolicy = this.getOperationalPolicy(
+ ResourceFileUtils.getResourceAsString("tosca/operational-policy-properties.json"), "GuardOpPolicyTest");
+ loopTest.addOperationalPolicy(opPolicy);
+ MicroServicePolicy microServicePolicy = getMicroServicePolicy("configPolicyTest", "",
+ "{\"configtype\":\"json\"}", "tosca_definitions_version: tosca_simple_yaml_1_0_0",
+ "{\"param1\":\"value1\"}", true);
+ loopTest.addMicroServicePolicy(microServicePolicy);
+ LoopLog loopLog = getLoopLog(LogType.INFO, "test message", loopTest);
+ loopTest.addLog(loopLog);
+ LoopTemplate loopTemplate = getLoopTemplate("templateName", "yaml", 1);
+ loopTest.setLoopTemplate(loopTemplate);
+
+ String jsonSerialized = JsonUtils.GSON_JPA_MODEL.toJson(loopTest);
+ assertThat(jsonSerialized).isNotNull().isNotEmpty();
+ System.out.println(jsonSerialized);
+ Loop loopTestDeserialized = JsonUtils.GSON_JPA_MODEL.fromJson(jsonSerialized, Loop.class);
+ assertNotNull(loopTestDeserialized);
+ assertThat(loopTestDeserialized).isEqualToIgnoringGivenFields(loopTest, "svgRepresentation", "blueprint",
+ "components");
+ assertThat(loopTestDeserialized.getComponent("DCAE").getState())
+ .isEqualToComparingFieldByField(loopTest.getComponent("DCAE").getState());
+ assertThat(loopTestDeserialized.getComponent("POLICY").getState()).isEqualToComparingOnlyGivenFields(
+ loopTest.getComponent("POLICY").getState(), "stateName", "description");
+ // blueprint not exposed so wont be deserialized
+
+ assertThat(loopTestDeserialized.getOperationalPolicies()).containsExactly(opPolicy);
+ assertThat(loopTestDeserialized.getMicroServicePolicies()).containsExactly(microServicePolicy);
+ assertThat(loopTestDeserialized.getLoopLogs()).containsExactly(loopLog);
+ assertThat((LoopLog) loopTestDeserialized.getLoopLogs().toArray()[0]).isEqualToIgnoringGivenFields(loopLog,
+ "loop");
+
+ // Verify the loop template
+ assertThat(loopTestDeserialized.getLoopTemplate()).isEqualTo(loopTemplate);
+ }
+
+ /**
+ * This tests the service object GSON encode/decode.
+ *
+ * @throws IOException In case of issues
+ */
+ @Test
+ public void loopServiceTest() throws IOException {
+ Loop loopTest2 = getLoop("ControlLoopTest", "yamlcontent", "{\"testname\":\"testvalue\"}",
+ "123456789", "https://dcaetest.org", "UUID-blueprint");
+
+ JsonObject jsonModel = new GsonBuilder().create()
+ .fromJson(ResourceFileUtils.getResourceAsString("tosca/model-properties.json"), JsonObject.class);
+ Service service = new Service(jsonModel.get("serviceDetails").getAsJsonObject(),
+ jsonModel.get("resourceDetails").getAsJsonObject(), "1.0");
+ loopTest2.setModelService(service);
+ String jsonSerialized = JsonUtils.GSON_JPA_MODEL.toJson(loopTest2);
+ assertThat(jsonSerialized).isNotNull().isNotEmpty();
+ System.out.println(jsonSerialized);
+
+ Loop loopTestDeserialized = JsonUtils.GSON_JPA_MODEL.fromJson(jsonSerialized, Loop.class);
+ assertNotNull(loopTestDeserialized);
+ assertThat(loopTestDeserialized).isEqualToIgnoringGivenFields(loopTest2, "modelService", "svgRepresentation",
+ "blueprint", "components");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyComponentTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyComponentTest.java
new file mode 100644
index 000000000..5b4e405bb
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyComponentTest.java
@@ -0,0 +1,296 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.components.external.ExternalComponentState;
+import org.onap.policy.clamp.loop.components.external.PolicyComponent;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.policy.clamp.policy.operational.OperationalPolicy;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class PolicyComponentTest {
+
+ /**
+ * Test the computeState method.
+ * oldState newState expectedFinalState
+ * NOT_SENT SENT_AND_DEPLOYED NOT_SENT
+ * NOT_SENT SENT NOT_SENT
+ * NOT_SENT NOT_SENT NOT_SENT
+ * NOT_SENT IN_ERROR IN_ERROR
+ */
+ @Test
+ public void computeStateTestOriginalStateUnknown() {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ // policy found + deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ PolicyComponent policy = new PolicyComponent();
+
+ ExternalComponentState state = policy.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("SENT_AND_DEPLOYED");
+ // policy found + not deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state2 = policy.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("SENT");
+ // policy not found + not deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state4 = policy.computeState(exchange);
+ assertThat(state4.getStateName()).isEqualTo("NOT_SENT");
+ // policy not found + deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state3 = policy.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("IN_ERROR");
+ }
+
+ /**
+ * Test the computeState method.
+ * oldState newState expectedFinalState
+ * NOT_SENT SENT_AND_DEPLOYED NOT_SENT
+ * NOT_SENT SENT NOT_SENT
+ * NOT_SENT NOT_SENT NOT_SENT
+ * NOT_SENT IN_ERROR IN_ERROR
+ */
+ @Test
+ public void computeStateTestOriginalStateNotSent() {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ // policy found + deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ PolicyComponent policy = new PolicyComponent();
+ ExternalComponentState notSent = new ExternalComponentState("NOT_SENT",
+ "The policies defined have NOT yet been created on the policy engine", 90);
+ policy.setState(notSent);
+ ExternalComponentState state = policy.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("NOT_SENT");
+ // policy found + not deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state2 = policy.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("NOT_SENT");
+ // policy not found + not deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state4 = policy.computeState(exchange);
+ assertThat(state4.getStateName()).isEqualTo("NOT_SENT");
+ // policy not found + deployed
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state3 = policy.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("IN_ERROR");
+ }
+
+
+ /**
+ * Test the computeState method.
+ * oldState newState expectedFinalState
+ * SENT SENT SENT
+ * SENT SENT_AND_DEPLOYED SENT
+ * SENT IN_ERROR IN_ERROR
+ * SENT NOT_SENT NOT_SENT
+ */
+ @Test
+ public void computeStateTestOriginalStateSent() throws IOException {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ PolicyComponent policy = new PolicyComponent();
+ ExternalComponentState sent = new ExternalComponentState("SENT",
+ "The policies defined have been created but NOT deployed on the policy engine", 50);
+ policy.setState(sent);
+ // new policy state SENT
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state = policy.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("SENT");
+ // new policy state SENT_AND_DEPLOYED
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state2 = policy.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("SENT");
+ // new policy state IN_ERROR
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state3 = policy.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("IN_ERROR");
+ // new policy state NOT_SENT
+ policy.setState(sent);
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state4 = policy.computeState(exchange);
+ assertThat(state4.getStateName()).isEqualTo("NOT_SENT");
+ }
+
+ /**
+ * Test the computeState method.
+ * oldState newState expectedFinalState
+ * SENT_AND_DEPLOYED SENT_AND_DEPLOYED SENT_AND_DEPLOYED
+ * SENT_AND_DEPLOYED SENT SENT
+ * SENT_AND_DEPLOYED IN_ERROR IN_ERROR
+ * SENT_AND_DEPLOYED NOT_SENT NOT_SENT
+ */
+ @Test
+ public void computeStateTestOriginalStateSentAndDeployed() throws IOException {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ PolicyComponent policy = new PolicyComponent();
+ ExternalComponentState sendDeployed = new ExternalComponentState("SENT_AND_DEPLOYED",
+ "The policies defined have been created and deployed on the policy engine", 10);
+ policy.setState(sendDeployed);
+ // new policy state SENT_AND_DEPLOYED
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state = policy.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("SENT_AND_DEPLOYED");
+ // new policy state SENT
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state2 = policy.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("SENT");
+ // new policy state IN_ERROR
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state3 = policy.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("IN_ERROR");
+ // new policy state NOT_SENT
+ policy.setState(sendDeployed);
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state4 = policy.computeState(exchange);
+ assertThat(state4.getStateName()).isEqualTo("NOT_SENT");
+ }
+
+
+ /**
+ * Test the computeState method.
+ * oldState newState expectedFinalState
+ * IN_ERROR SENT_AND_DEPLOYED IN_ERROR
+ * IN_ERROR SENT IN_ERROR
+ * IN_ERROR IN_ERROR IN_ERROR
+ * IN_ERROR NOT_SENT IN_ERROR
+ */
+ @Test
+ public void computeStateTestOriginalStateInError() throws IOException {
+ Exchange exchange = Mockito.mock(Exchange.class);
+ Message message = Mockito.mock(Message.class);
+ Exchange exchange2 = Mockito.mock(Exchange.class);
+ Mockito.when(exchange.getIn()).thenReturn(message);
+ Mockito.when(message.getExchange()).thenReturn(exchange2);
+ PolicyComponent policy = new PolicyComponent();
+ ExternalComponentState inError = new ExternalComponentState("IN_ERROR",
+ "There was an error during the sending to policy, the policy engine may be corrupted or inconsistent",
+ 100);
+ policy.setState(inError);
+ // new policy state SENT_AND_DEPLOYED
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state = policy.computeState(exchange);
+ assertThat(state.getStateName()).isEqualTo("IN_ERROR");
+ // new policy state SENT
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(true);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state2 = policy.computeState(exchange);
+ assertThat(state2.getStateName()).isEqualTo("IN_ERROR");
+ // new policy state IN_ERROR
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(true);
+ ExternalComponentState state3 = policy.computeState(exchange);
+ assertThat(state3.getStateName()).isEqualTo("IN_ERROR");
+ // new policy state NOT_SENT
+ Mockito.when(exchange2.getProperty("policyFound")).thenReturn(false);
+ Mockito.when(exchange2.getProperty("policyDeployed")).thenReturn(false);
+ ExternalComponentState state4 = policy.computeState(exchange);
+
+ assertThat(state4.getStateName()).isEqualTo("IN_ERROR");
+ }
+
+ /**
+ * Test the create policies payload PdpGroup test.
+ */
+ @Test
+ public void createPoliciesPayloadPdpGroupTest() throws IOException {
+ Loop loopTest = new Loop("ControlLoopTest");
+ PolicyModel policyModel1 = new PolicyModel("onap.policies.monitoring.test", null, "1.0.0");
+
+ MicroServicePolicy microServicePolicy = new MicroServicePolicy("configPolicyTest", policyModel1, true,
+ new Gson().fromJson("{\"configtype\":\"json\"}", JsonObject.class), null, "pdpGroup1", "pdpSubgroup1");
+ loopTest.addMicroServicePolicy(microServicePolicy);
+
+ MicroServicePolicy microServicePolicy2 = new MicroServicePolicy("configPolicyTest2", policyModel1, true,
+ new Gson().fromJson("{\"configtype\":\"json\"}", JsonObject.class), null, "pdpGroup2", "pdpSubgroup1");
+ loopTest.addMicroServicePolicy(microServicePolicy2);
+
+ PolicyModel policyModel2 = new PolicyModel("onap.policies.monitoring.test2", null,
+ "1.0.0");
+ OperationalPolicy opPolicy =
+ new OperationalPolicy("opPolicy", new Gson().fromJson("{\"configtype\":\"json\"}", JsonObject.class),
+ new Gson().fromJson("{\"jsonschema\":\"schema\"}", JsonObject.class), policyModel2, null,
+ "pdpGroup2",
+ "pdpSubgroup2");
+
+ loopTest.addOperationalPolicy(opPolicy);
+ OperationalPolicy opLegacyPolicy =
+ new OperationalPolicy("opLegacyPolicy", new Gson().fromJson(
+ "{\"guard_policies\":[{\"policy-id\":\"guard1\"}]}", JsonObject.class),
+ new Gson().fromJson("{\"jsonschema\":\"schema\"}", JsonObject.class), policyModel2, null,
+ "pdpGroup2",
+ "pdpSubgroup2");
+
+ loopTest.addOperationalPolicy(opLegacyPolicy);
+
+ LoopTemplate loopTemplate = new LoopTemplate("test", "yaml", 1, null);
+ loopTemplate.setDcaeBlueprintId("UUID-blueprint");
+ loopTest.setLoopTemplate(loopTemplate);
+
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("example/policy/pdp-group-policy-payload.json"),
+ PolicyComponent.createPoliciesPayloadPdpGroup(loopTest, "POST"), false);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyModelServiceItCase.java b/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyModelServiceItCase.java
new file mode 100644
index 000000000..a2563b8d3
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/PolicyModelServiceItCase.java
@@ -0,0 +1,300 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+import javax.transaction.Transactional;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelId;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.onap.policy.clamp.loop.template.PolicyModelsService;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.enums.PdpState;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class PolicyModelServiceItCase {
+
+ @Autowired
+ PolicyModelsService policyModelsService;
+
+ @Autowired
+ PolicyModelsRepository policyModelsRepository;
+
+ private static final String POLICY_MODEL_TYPE_1 = "org.onap.testos";
+ private static final String POLICY_MODEL_TYPE_1_VERSION_1 = "1.0.0";
+
+ private static final String POLICY_MODEL_TYPE_2 = "org.onap.testos2";
+ private static final String POLICY_MODEL_TYPE_3 = "org.onap.testos3";
+ private static final String POLICY_MODEL_TYPE_2_VERSION_1 = "1.0.0";
+ private static final String POLICY_MODEL_TYPE_3_VERSION_1 = "1.0.0";
+ private static final String POLICY_MODEL_TYPE_2_VERSION_2 = "2.0.0";
+
+ private PolicyModel getPolicyModel(String policyType, String policyModelTosca, String version,
+ String policyAcronym, String policyVariant, String createdBy) {
+ PolicyModel policyModel = new PolicyModel();
+ policyModel.setCreatedBy(createdBy);
+ policyModel.setPolicyAcronym(policyAcronym);
+ policyModel.setPolicyModelTosca(policyModelTosca);
+ policyModel.setPolicyModelType(policyType);
+ policyModel.setUpdatedBy(createdBy);
+ policyModel.setVersion(version);
+ return policyModel;
+ }
+
+ /**
+ * This test the create policy Model.
+ */
+ @Test
+ @Transactional
+ public void shouldCreatePolicyModel() {
+ // given
+ PolicyModel policyModel = getPolicyModel(POLICY_MODEL_TYPE_1, "yaml",
+ POLICY_MODEL_TYPE_1_VERSION_1, "TEST", "VARIANT", "user");
+
+ // when
+ PolicyModel actualPolicyModel = policyModelsService.saveOrUpdatePolicyModel(policyModel);
+
+ // then
+ assertThat(actualPolicyModel).isNotNull();
+ assertThat(actualPolicyModel).isEqualTo(policyModelsRepository
+ .findById(new PolicyModelId(actualPolicyModel.getPolicyModelType(),
+ actualPolicyModel.getVersion()))
+ .get());
+ assertThat(actualPolicyModel.getPolicyModelType())
+ .isEqualTo(policyModel.getPolicyModelType());
+ Assertions.assertThat(actualPolicyModel.getCreatedBy()).isEqualTo("Not found");
+ Assertions.assertThat(actualPolicyModel.getCreatedDate()).isNotNull();
+ assertThat(actualPolicyModel.getPolicyAcronym()).isEqualTo(policyModel.getPolicyAcronym());
+ assertThat(actualPolicyModel.getPolicyModelTosca())
+ .isEqualTo(policyModel.getPolicyModelTosca());
+ Assertions.assertThat(actualPolicyModel.getUpdatedBy()).isEqualTo("Not found");
+ Assertions.assertThat(actualPolicyModel.getUpdatedDate()).isNotNull();
+ assertThat(actualPolicyModel.getVersion()).isEqualTo(policyModel.getVersion());
+
+ assertThat(
+ policyModelsService.getPolicyModel(POLICY_MODEL_TYPE_1, POLICY_MODEL_TYPE_1_VERSION_1))
+ .isEqualToIgnoringGivenFields(policyModel, "createdDate", "updatedDate",
+ "createdBy", "updatedBy");
+ }
+
+ /**
+ * This tests the getPolicyModelJson. A json is expected.
+ *
+ * @throws IOException In case of failure
+ */
+ @Test
+ @Transactional
+ public void shouldGetPolicyModelInJson() throws IOException {
+ PolicyModel policyModel = getPolicyModel("onap.policies.monitoring.cdap.tca.hi.lo.app",
+ ResourceFileUtils.getResourceAsString(
+ "http-cache/example/policy/api/v1/policytypes/"
+ + "onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file"),
+ "1.0.0", "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel);
+
+ JsonObject policyTypeJson =
+ policyModelsService.getPolicyModelJson("onap.policies.monitoring.cdap.tca.hi.lo.app", "1.0.0");
+ assertThat(policyTypeJson).isNotNull();
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/tca_hi_lo.json"),
+ policyTypeJson.toString(),
+ true);
+ }
+
+ /**
+ * This tests a getAllPolicyModelTypes get.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnAllPolicyModelTypes() {
+ // given
+ PolicyModel policyModel1 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_1, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_2, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+ List<String> policyModelTypesList = policyModelsService.getAllPolicyModelTypes();
+
+ assertThat(policyModelTypesList).contains(policyModel1.getPolicyModelType(),
+ policyModel2.getPolicyModelType());
+ }
+
+ /**
+ * This tests a getAllPolicyModels get.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnAllPolicyModels() {
+ PolicyModel policyModel1 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_1, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_2, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+
+ assertThat(policyModelsService.getAllPolicyModels()).contains(policyModel1, policyModel2);
+ }
+
+ /**
+ * This tests a getAllPolicyModelsByType get.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnAllModelsByType() {
+ PolicyModel policyModel1 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_1, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_2, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+
+ assertThat(policyModelsService.getAllPolicyModelsByType(POLICY_MODEL_TYPE_2))
+ .contains(policyModel1, policyModel2);
+ }
+
+ /**
+ * This tests the sorting of policyModel.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnSortedSet() {
+ PolicyModel policyModel1 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_1, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel1);
+ PolicyModel policyModel2 = getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_2, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel2);
+ PolicyModel policyModel3 = getPolicyModel(POLICY_MODEL_TYPE_3, "yaml",
+ POLICY_MODEL_TYPE_3_VERSION_1, "TEST", "VARIANT", "user");
+ policyModelsService.saveOrUpdatePolicyModel(policyModel3);
+
+ SortedSet<PolicyModel> sortedSet = new TreeSet<>();
+ policyModelsService.getAllPolicyModels().forEach(sortedSet::add);
+ List<PolicyModel> listToCheck =
+ sortedSet
+ .stream().filter(policy -> policy.equals(policyModel3)
+ || policy.equals(policyModel2) || policy.equals(policyModel1))
+ .collect(Collectors.toList());
+ assertThat(listToCheck.get(0)).isEqualByComparingTo(policyModel2);
+ assertThat(listToCheck.get(1)).isEqualByComparingTo(policyModel1);
+ assertThat(listToCheck.get(2)).isEqualByComparingTo(policyModel3);
+ }
+
+ /**
+ * This tests the pdpgroup GSON encode/decode and saving.
+ */
+ @Test
+ @Transactional
+ public void shouldAddPdpGroupInfo() {
+ policyModelsService.saveOrUpdatePolicyModel(getPolicyModel(POLICY_MODEL_TYPE_1, "yaml",
+ POLICY_MODEL_TYPE_1_VERSION_1, "TEST", "VARIANT", "user"));
+ policyModelsService.saveOrUpdatePolicyModel(getPolicyModel(POLICY_MODEL_TYPE_2, "yaml",
+ POLICY_MODEL_TYPE_2_VERSION_2, "TEST", "VARIANT", "user"));
+ policyModelsService.saveOrUpdatePolicyModel(getPolicyModel(POLICY_MODEL_TYPE_3, "yaml",
+ POLICY_MODEL_TYPE_3_VERSION_1, "TEST", "VARIANT", "user"));
+
+ ToscaConceptIdentifier type1 = new ToscaConceptIdentifier("org.onap.testos", "1.0.0");
+ ToscaConceptIdentifier type2 = new ToscaConceptIdentifier("org.onap.testos2", "2.0.0");
+
+ PdpSubGroup pdpSubgroup1 = new PdpSubGroup();
+ pdpSubgroup1.setPdpType("subGroup1");
+ List<ToscaConceptIdentifier> pdpTypeList = new LinkedList<>();
+ pdpTypeList.add(type1);
+ pdpTypeList.add(type2);
+ pdpSubgroup1.setSupportedPolicyTypes(pdpTypeList);
+
+ ToscaConceptIdentifier type3 = new ToscaConceptIdentifier("org.onap.testos3", "2.0.0");
+ PdpSubGroup pdpSubgroup2 = new PdpSubGroup();
+ pdpSubgroup2.setPdpType("subGroup2");
+ List<ToscaConceptIdentifier> pdpTypeList2 = new LinkedList<>();
+ pdpTypeList2.add(type2);
+ pdpTypeList2.add(type3);
+ pdpSubgroup2.setSupportedPolicyTypes(pdpTypeList2);
+
+ List<PdpSubGroup> pdpSubgroupList = new LinkedList<>();
+ pdpSubgroupList.add(pdpSubgroup1);
+
+ PdpGroup pdpGroup1 = new PdpGroup();
+ pdpGroup1.setName("pdpGroup1");
+ pdpGroup1.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup1.setPdpSubgroups(pdpSubgroupList);
+
+ List<PdpSubGroup> pdpSubgroupList2 = new LinkedList<>();
+ pdpSubgroupList2.add(pdpSubgroup1);
+ pdpSubgroupList2.add(pdpSubgroup2);
+ PdpGroup pdpGroup2 = new PdpGroup();
+ pdpGroup2.setName("pdpGroup2");
+ pdpGroup2.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup2.setPdpSubgroups(pdpSubgroupList2);
+
+ List<PdpGroup> pdpGroupsList = new LinkedList<>();
+ pdpGroupsList.add(pdpGroup1);
+ pdpGroupsList.add(pdpGroup2);
+
+ PdpGroups pdpGroups = new PdpGroups();
+ pdpGroups.setGroups(pdpGroupsList);
+ policyModelsService.updatePdpGroupInfo(pdpGroups);
+
+ JsonObject res1 =
+ policyModelsService.getPolicyModel("org.onap.testos", "1.0.0").getPolicyPdpGroup();
+ String expectedRes1 =
+ "{\"supportedPdpGroups\":[{\"pdpGroup1\":[\"subGroup1\"]},{\"pdpGroup2\":[\"subGroup1\"]}]}";
+ JsonObject expectedJson1 = JsonUtils.GSON.fromJson(expectedRes1, JsonObject.class);
+ assertThat(res1).isEqualTo(expectedJson1);
+
+ JsonObject res2 =
+ policyModelsService.getPolicyModel("org.onap.testos2", "2.0.0").getPolicyPdpGroup();
+ String expectedRes2 =
+ "{\"supportedPdpGroups\":[{\"pdpGroup1\":[\"subGroup1\"]},"
+ + "{\"pdpGroup2\":[\"subGroup1\",\"subGroup2\"]}]}";
+ JsonObject expectedJson2 = JsonUtils.GSON.fromJson(expectedRes2, JsonObject.class);
+ assertThat(res2).isEqualTo(expectedJson2);
+
+ JsonObject res3 =
+ policyModelsService.getPolicyModel("org.onap.testos3", "1.0.0").getPolicyPdpGroup();
+ assertThat(res3).isNull();
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/ServiceTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/ServiceTest.java
new file mode 100644
index 000000000..8f28299fd
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/ServiceTest.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.service.Service;
+
+public class ServiceTest {
+
+ @Test
+ public void equalMethodTest() {
+ String serviceStr1 = "{\"name\": \"vLoadBalancerMS\", \"UUID\": \"63cac700-ab9a-4115-a74f-7eac85e3fce0\"}";
+ String serviceStr2 = "{\"name\": \"vLoadBalancerMS2\", \"UUID\": \"63cac700-ab9a-4115-a74f-7eac85e3fce0\"}";
+ String serviceStr3 = "{\"name\": \"vLoadBalancerMS\",\"UUID\": \"63cac700-ab9a-4115-a74f-7eac85e3fc11\"}";
+ String resourceStr = "{\"CP\": {}}";
+
+ Service service1 = new Service(JsonUtils.GSON.fromJson(serviceStr1, JsonObject.class),
+ JsonUtils.GSON.fromJson(resourceStr, JsonObject.class), "1.0");
+
+ Service service2 = new Service(JsonUtils.GSON.fromJson(serviceStr2, JsonObject.class), null, "1.0");
+
+ Service service3 = new Service(JsonUtils.GSON.fromJson(serviceStr3, JsonObject.class),
+ JsonUtils.GSON.fromJson(resourceStr, JsonObject.class), "1.0");
+
+ assertThat(service1.equals(service2)).isEqualTo(true);
+ assertThat(service1.equals(service3)).isEqualTo(false);
+ }
+
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/loop/deploy/BlueprintInputParametersTest.java b/runtime/src/test/java/org/onap/policy/clamp/loop/deploy/BlueprintInputParametersTest.java
new file mode 100644
index 000000000..f7f6baa0c
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/loop/deploy/BlueprintInputParametersTest.java
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Modifications copyright (c) 2019 Nokia
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.loop.deploy;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.Loop;
+import org.onap.policy.clamp.loop.template.LoopElementModel;
+import org.onap.policy.clamp.loop.template.LoopTemplate;
+import org.onap.policy.clamp.policy.microservice.MicroServicePolicy;
+import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
+
+public class BlueprintInputParametersTest {
+
+ /**
+ * getDeploymentParametersinJsonMultiBlueprintsTest.
+ *
+ * @throws IOException in case of failure
+ * @throws SdcToscaParserException in case of failure
+ */
+ @Test
+ public void getDeploymentParametersinJsonMultiBlueprintsTest() throws IOException, SdcToscaParserException {
+
+
+ MicroServicePolicy umService1 = Mockito.mock(MicroServicePolicy.class);
+ Mockito.when(umService1.getName()).thenReturn("testName1");
+
+ LoopElementModel loopElement = Mockito.mock(LoopElementModel.class);
+ String blueprint1 = ResourceFileUtils.getResourceAsString("example/sdc/blueprint-dcae/tca.yaml");
+ Mockito.when(loopElement.getBlueprint()).thenReturn(blueprint1);
+ Mockito.when(umService1.getLoopElementModel()).thenReturn(loopElement);
+
+ MicroServicePolicy umService2 = Mockito.mock(MicroServicePolicy.class);
+ Mockito.when(umService2.getName()).thenReturn("testName2");
+
+ LoopElementModel loopElement2 = Mockito.mock(LoopElementModel.class);
+ String blueprint2 = ResourceFileUtils.getResourceAsString("example/sdc/blueprint-dcae/tca_2.yaml");
+ Mockito.when(loopElement2.getBlueprint()).thenReturn(blueprint2);
+ Mockito.when(umService2.getLoopElementModel()).thenReturn(loopElement2);
+
+ MicroServicePolicy umService3 = Mockito.mock(MicroServicePolicy.class);
+ Mockito.when(umService3.getName()).thenReturn("testName3");
+
+ LoopElementModel loopElement3 = Mockito.mock(LoopElementModel.class);
+ String blueprint3 = ResourceFileUtils.getResourceAsString("example/sdc/blueprint-dcae/tca_3.yaml");
+ Mockito.when(loopElement3.getBlueprint()).thenReturn(blueprint3);
+ Mockito.when(umService3.getLoopElementModel()).thenReturn(loopElement3);
+
+ LinkedHashSet<MicroServicePolicy> umServiceSet = new LinkedHashSet<>();
+ umServiceSet.add(umService1);
+ umServiceSet.add(umService2);
+ umServiceSet.add(umService3);
+ Loop loop = Mockito.mock(Loop.class);
+ Mockito.when(loop.getMicroServicePolicies()).thenReturn(umServiceSet);
+
+ LoopTemplate template = Mockito.mock(LoopTemplate.class);
+ Mockito.when(template.getUniqueBlueprint()).thenReturn(false);
+ Mockito.when(loop.getLoopTemplate()).thenReturn(template);
+
+ JsonObject paramJson = DcaeDeployParameters.getDcaeDeploymentParametersInJson(loop);
+
+ Assert.assertEquals(JsonUtils.GSON_JPA_MODEL.toJson(paramJson),
+ ResourceFileUtils.getResourceAsString(
+ "example/sdc/expected-result/deployment-parameters-multi-blueprints.json"));
+ }
+
+ /**
+ * getDeploymentParametersInJsonSingleBlueprintTest.
+ *
+ * @throws IOException In case of failure
+ * @throws SdcToscaParserException In case of failure
+ */
+ @Test
+ public void getDeploymentParametersInJsonSingleBlueprintTest() throws IOException, SdcToscaParserException {
+ Loop loop = Mockito.mock(Loop.class);
+
+ MicroServicePolicy umService1 = Mockito.mock(MicroServicePolicy.class);
+ Mockito.when(umService1.getName()).thenReturn("testName1");
+ LinkedHashSet<MicroServicePolicy> umServiceSet = new LinkedHashSet<MicroServicePolicy>();
+ umServiceSet.add(umService1);
+ Mockito.when(loop.getMicroServicePolicies()).thenReturn(umServiceSet);
+
+ LoopTemplate template = Mockito.mock(LoopTemplate.class);
+ Mockito.when(template.getUniqueBlueprint()).thenReturn(true);
+ String blueprint = ResourceFileUtils.getResourceAsString("example/sdc/blueprint-dcae/tca.yaml");
+ Mockito.when(template.getBlueprint()).thenReturn(blueprint);
+ Mockito.when(loop.getLoopTemplate()).thenReturn(template);
+
+ JsonObject paramJson = DcaeDeployParameters.getDcaeDeploymentParametersInJson(loop);
+
+ Assert.assertEquals(JsonUtils.GSON_JPA_MODEL.toJson(paramJson),
+ ResourceFileUtils.getResourceAsString(
+ "example/sdc/expected-result/deployment-parameters-single-blueprint.json"));
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/downloader/PolicyEngineControllerTestItCase.java b/runtime/src/test/java/org/onap/policy/clamp/policy/downloader/PolicyEngineControllerTestItCase.java
new file mode 100644
index 000000000..657adf1d1
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/downloader/PolicyEngineControllerTestItCase.java
@@ -0,0 +1,117 @@
+package org.onap.policy.clamp.policy.downloader;
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.List;
+import javax.transaction.Transactional;
+import org.json.simple.parser.ParseException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.clamp.loop.template.PolicyModelId;
+import org.onap.policy.clamp.loop.template.PolicyModelsRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+@ActiveProfiles({"clamp-default", "clamp-policy-controller"})
+public class PolicyEngineControllerTestItCase {
+
+ @Autowired
+ PolicyEngineController policyController;
+
+ @Autowired
+ PolicyModelsRepository policyModelsRepository;
+
+ /**
+ * This method tests a fake synchronization with the emulator.
+ *
+ * @throws JsonSyntaxException In case of issues
+ * @throws IOException In case of issues
+ * @throws InterruptedException In case of issues
+ */
+ @Test
+ @Transactional
+ public void synchronizeAllPoliciesTest() throws JsonSyntaxException, IOException, InterruptedException {
+ policyController.synchronizeAllPolicies();
+ Instant firstExecution = policyController.getLastInstantExecuted();
+ assertThat(firstExecution).isNotNull();
+ List<PolicyModel> policyModelsList = policyModelsRepository.findAll();
+ assertThat(policyModelsList.size()).isGreaterThanOrEqualTo(5);
+ assertThat(policyModelsList).contains(new PolicyModel("onap.policies.controlloop.operational.common.Drools",
+ null, "1.0.0"));
+ assertThat(policyModelsList).contains(new PolicyModel("onap.policies.controlloop.operational.common.Apex",
+ null, "1.0.0"));
+ assertThat(policyModelsList)
+ .contains(new PolicyModel("onap.policies.controlloop.guard.common.FrequencyLimiter", null, "1.0.0"));
+ assertThat(policyModelsList)
+ .contains(new PolicyModel("onap.policies.controlloop.guard.common.Blacklist", null, "1.0.0"));
+ assertThat(policyModelsList)
+ .contains(new PolicyModel("onap.policies.controlloop.guard.common.MinMax", null, "2.0.0"));
+
+ // Re-do it to check that there is no issue with duplicate key
+ policyController.synchronizeAllPolicies();
+ Instant secondExecution = policyController.getLastInstantExecuted();
+ assertThat(secondExecution).isNotNull();
+
+ assertThat(firstExecution).isBefore(secondExecution);
+ }
+
+ @Test
+ @Transactional
+ public void downloadPdpGroupsTest() throws JsonSyntaxException, IOException, InterruptedException, ParseException {
+ PolicyModel policyModel1 = new PolicyModel("onap.policies.monitoring.test", null, "1.0.0");
+ policyModelsRepository.saveAndFlush(policyModel1);
+ PolicyModel policyModel2 = new PolicyModel("onap.policies.controlloop.Operational", null, "1.0.0");
+ policyModelsRepository.saveAndFlush(policyModel2);
+
+ policyController.downloadPdpGroups();
+
+ List<PolicyModel> policyModelsList = policyModelsRepository.findAll();
+ assertThat(policyModelsList.size()).isGreaterThanOrEqualTo(2);
+
+ PolicyModel policy1 = policyModelsRepository
+ .getOne(new PolicyModelId("onap.policies.monitoring.test", "1.0.0"));
+ PolicyModel policy2 = policyModelsRepository
+ .getOne(new PolicyModelId("onap.policies.controlloop.Operational", "1.0.0"));
+
+ String expectedRes1 = "{\"supportedPdpGroups\":[{\"monitoring\":[\"xacml\"]}]}";
+ JsonObject expectedJson1 = JsonUtils.GSON.fromJson(expectedRes1, JsonObject.class);
+ assertThat(policy1.getPolicyPdpGroup()).isEqualTo(expectedJson1);
+ String expectedRes2 = "{\"supportedPdpGroups\":[{\"controlloop\":[\"apex\",\"drools\"]}]}";
+ JsonObject expectedJson2 = JsonUtils.GSON.fromJson(expectedRes2, JsonObject.class);
+ assertThat(policy2.getPolicyPdpGroup()).isEqualTo(expectedJson2);
+
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/microservice/MicroServicePayloadTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/microservice/MicroServicePayloadTest.java
new file mode 100644
index 000000000..4bb850c35
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/microservice/MicroServicePayloadTest.java
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.microservice;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class MicroServicePayloadTest {
+
+ @Test
+ public void testPayloadConstruction() throws IOException {
+ MicroServicePolicy policy = new MicroServicePolicy("testPolicy", new PolicyModel(
+ "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ ResourceFileUtils.getResourceAsString("tosca/tosca_example.yaml"), "1.0.0"), false, null, null, null,
+ null);
+ policy.setConfigurationsJson(JsonUtils.GSON.fromJson(
+ ResourceFileUtils.getResourceAsString("tosca/micro-service-policy-properties.json"), JsonObject.class));
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/micro-service-policy-payload.json"),
+ policy.createPolicyPayload(), false);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java
new file mode 100644
index 000000000..136430c8f
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/operational/OperationalPolicyRepresentationBuilderTest.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.operational;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.service.Service;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+public class OperationalPolicyRepresentationBuilderTest {
+
+ @Test
+ public void testOperationalPolicyPayloadConstruction() throws IOException {
+ JsonObject jsonModel = new GsonBuilder().create().fromJson(ResourceFileUtils
+ .getResourceAsString("tosca/model-properties-operational-policy.json"), JsonObject.class);
+ Service service = new Service(jsonModel.get("serviceDetails").getAsJsonObject(),
+ jsonModel.get("resourceDetails").getAsJsonObject(), "1.0");
+
+ JsonObject jsonSchema = OperationalPolicyRepresentationBuilder.generateOperationalPolicySchema(service);
+
+ assertThat(jsonSchema).isNotNull();
+
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("tosca/operational-policy-json-schema.json"),
+ new GsonBuilder().create().toJson(jsonSchema), false);
+ }
+
+ @Test
+ public void testOperationalPolicyPayloadConstructionForCds() throws IOException {
+ JsonObject jsonModel = new GsonBuilder().create()
+ .fromJson(ResourceFileUtils.getResourceAsString("tosca/model-properties-cds.json"), JsonObject.class);
+ Service service = new Service(jsonModel.get("serviceDetails").getAsJsonObject(),
+ jsonModel.get("resourceDetails").getAsJsonObject(),
+ "1.0");
+
+ JsonObject jsonSchema = OperationalPolicyRepresentationBuilder.generateOperationalPolicySchema(service);
+ assertThat(jsonSchema).isNotNull();
+ JSONAssert.assertEquals(
+ ResourceFileUtils.getResourceAsString("tosca/operational-policy-cds-payload-with-list.json"),
+ new GsonBuilder().create().toJson(jsonSchema), false);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupAnalyzerTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupAnalyzerTest.java
new file mode 100644
index 000000000..30d4ebe28
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupAnalyzerTest.java
@@ -0,0 +1,231 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.clamp.loop.template.PolicyModel;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.enums.PdpState;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+/**
+ * This test class validates the PdpGroupAnalyzer class.
+ */
+public class PdpGroupAnalyzerTest {
+
+ private static PdpGroups pdpGroups;
+ private static PdpGroup pdpGroup1;
+ private static PdpGroup pdpGroup2;
+ private static PdpGroup pdpGroup3;
+ private static PdpGroup pdpGroup4;
+
+ private static PdpSubGroup pdpSubgroupBad;
+ private static PdpSubGroup pdpSubgroup1;
+ private static PdpSubGroup pdpSubgroup2;
+ private static PdpSubGroup pdpSubgroup3;
+
+ /**
+ * This method preloads the pdpGroups for the tests.
+ */
+ @BeforeClass
+ public static void setupPdpGroup() {
+ // Create Pdp Groups
+ // Those that do not work first
+ pdpSubgroupBad = new PdpSubGroup();
+ pdpSubgroupBad.setPdpType("subGroupBad");
+ pdpSubgroupBad.setSupportedPolicyTypes(Arrays.asList(new ToscaConceptIdentifier("org.onap.test", "2.0.0"),
+ new ToscaConceptIdentifier("org.onap.test.*", "1.0.0"),
+ new ToscaConceptIdentifier("org.onip.testos", "1.0.0"),
+ new ToscaConceptIdentifier("org.onap.testos3", "2.0.0"),
+ new ToscaConceptIdentifier("org.onap.tes", "1.0.0"),
+ new ToscaConceptIdentifier("org.onap", "1.0.0")
+ ));
+ pdpSubgroupBad.setPolicies(Arrays.asList(new ToscaConceptIdentifier("org.onap", "1.0.0"),
+ new ToscaConceptIdentifier("org.onap.testos", "2.0.0"),
+ new ToscaConceptIdentifier("org.onap.testos", "1.0.1"),
+ new ToscaConceptIdentifier("org.onap.testos.new", "1.0.0"),
+ new ToscaConceptIdentifier("org.onap.", "1.0.0")));
+ pdpSubgroupBad.setPdpInstances(Collections.emptyList());
+
+ pdpSubgroup1 = new PdpSubGroup();
+ pdpSubgroup1.setPdpType("subGroup1");
+ pdpSubgroup1.setSupportedPolicyTypes(
+ Arrays.asList(new ToscaConceptIdentifier("org.onap.*", "1.0.0")));
+ pdpSubgroup1.setPdpInstances(Collections.emptyList());
+
+ pdpSubgroup2 = new PdpSubGroup();
+ pdpSubgroup2.setPdpType("subGroup2");
+ pdpSubgroup2.setSupportedPolicyTypes(Arrays.asList(new ToscaConceptIdentifier("org.onap.test", "1.0.0")));
+ pdpSubgroup2.setPolicies(Arrays.asList(new ToscaConceptIdentifier("org.onap.testos", "1.0.0")));
+ pdpSubgroup2.setPdpInstances(Collections.emptyList());
+
+ pdpSubgroup3 = new PdpSubGroup();
+ pdpSubgroup3.setPdpType("subGroup3");
+ pdpSubgroup3.setSupportedPolicyTypes(Arrays.asList(new ToscaConceptIdentifier("org.onap.test*", "1.0.0")));
+ pdpSubgroup3.setPolicies(Arrays.asList(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")));
+ pdpSubgroup3.setPdpInstances(Collections.emptyList());
+
+ // Should match pdpSubgroup1
+ pdpGroup1 = new PdpGroup();
+ pdpGroup1.setName("pdpGroup1");
+ pdpGroup1.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup1.setPdpSubgroups(Arrays.asList(pdpSubgroup1, pdpSubgroupBad));
+
+ // Should match pdpSubgroup1, pdpSubgroup2, pdpSubgroup3
+ // Should match also for the policy (pdpSubgroup2)
+ pdpGroup2 = new PdpGroup();
+ pdpGroup2.setName("pdpGroup2");
+ pdpGroup2.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup2.setPdpSubgroups(Arrays.asList(pdpSubgroup1, pdpSubgroup2, pdpSubgroup3, pdpSubgroupBad));
+
+ /// Should not match
+ pdpGroup3 = new PdpGroup();
+ pdpGroup3.setName("pdpGroup3");
+ pdpGroup3.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup3.setPdpSubgroups(Arrays.asList(pdpSubgroupBad));
+
+ // Should not match
+ pdpGroup4 = new PdpGroup();
+ pdpGroup4.setName("pdpGroup4");
+ pdpGroup4.setPdpGroupState(PdpState.TERMINATED);
+ pdpGroup4.setPdpSubgroups(Arrays.asList(pdpSubgroup1));
+
+ pdpGroups = new PdpGroups();
+ pdpGroups.setGroups(Arrays.asList(pdpGroup1, pdpGroup2, pdpGroup3, pdpGroup4));
+ }
+
+ @Test
+ public void testStructuresConstruction() {
+ PdpGroupsAnalyzer pdpGroupsAnalyzer = new PdpGroupsAnalyzer(pdpGroups);
+ assertThat(pdpGroupsAnalyzer).isNotNull();
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()).hasSize(6);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0"))).hasSize(3);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup1").getPdpSubgroups().size())
+ .isEqualTo(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup1").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup2").getPdpSubgroups().size())
+ .isEqualTo(2);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup2").getPdpSubgroups())
+ .contains(pdpSubgroup3);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup2").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup3").getPdpSubgroups().size())
+ .isEqualTo(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "2.0.0")).get("pdpGroup3").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.0"))).hasSize(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.0")).get("pdpGroup2").getPdpSubgroups())
+ .hasSize(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.0")).get("pdpGroup2").getPdpSubgroups())
+ .contains(pdpSubgroup2);
+
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1"))).hasSize(3);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup1").getPdpSubgroups())
+ .hasSize(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup1").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup2").getPdpSubgroups())
+ .hasSize(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup2").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup3").getPdpSubgroups())
+ .hasSize(1);
+ assertThat(pdpGroupsAnalyzer.getPdpGroupsDeploymentPerPolicy()
+ .get(new ToscaConceptIdentifier("org.onap.testos", "1.0.1")).get("pdpGroup3").getPdpSubgroups())
+ .contains(pdpSubgroupBad);
+ }
+
+ @Test
+ public void testGetSupportedPdpGroupsForPolicy() throws IOException {
+ PolicyModel policyModel = new PolicyModel();
+ policyModel.setCreatedBy("user");
+ policyModel.setPolicyAcronym("TEST");
+ policyModel.setPolicyModelTosca("yaml");
+ policyModel.setPolicyModelType("org.onap.test");
+ policyModel.setUpdatedBy("user");
+ policyModel.setVersion("1.0.0");
+
+ PdpGroupsAnalyzer pdpGroupsAnalyzer = new PdpGroupsAnalyzer(pdpGroups);
+ assertThat(pdpGroupsAnalyzer).isNotNull();
+
+ assertThat(
+ JsonUtils.GSON.toJson(pdpGroupsAnalyzer.getPdpGroupsForPolicy("org.onap.testos", "2.0.0")))
+ .isEqualTo(ResourceFileUtils.getResourceAsString("example/policy/pdp-deployment-testos-2_0_0.json"));
+
+ assertThat(
+ JsonUtils.GSON.toJson(pdpGroupsAnalyzer.getPdpGroupsForPolicy("org.onap.testos", "1.0.0")))
+ .isEqualTo(ResourceFileUtils.getResourceAsString("example/policy/pdp-deployment-testos-1_0_0.json"));
+
+ assertThat(
+ pdpGroupsAnalyzer.getPdpGroupsForPolicy("org.onap.donotexist", "1.0.0"))
+ .isNull();
+ }
+
+ @Test
+ public void testUpdatePdpGroupOfPolicyModels() {
+ // Create policyModel
+ PolicyModel policyModel = new PolicyModel();
+ policyModel.setCreatedBy("user");
+ policyModel.setPolicyAcronym("TEST");
+ policyModel.setPolicyModelTosca("yaml");
+ policyModel.setPolicyModelType("org.onap.test");
+ policyModel.setUpdatedBy("user");
+ policyModel.setVersion("1.0.0");
+ PdpGroupsAnalyzer.updatePdpGroupOfPolicyModels(Arrays.asList(policyModel), pdpGroups);
+
+ assertThat(policyModel.getPolicyPdpGroup()).hasToString(
+ "{\"supportedPdpGroups\":[{\"pdpGroup1\":[\"subGroup1\"]},"
+ + "{\"pdpGroup2\":[\"subGroup1\",\"subGroup2\",\"subGroup3\"]}]}");
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadExceptionTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadExceptionTest.java
new file mode 100644
index 000000000..f3c3fc6cd
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadExceptionTest.java
@@ -0,0 +1,33 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import org.junit.Test;
+import org.onap.policy.clamp.policy.pdpgroup.PdpGroupPayloadException;
+import org.onap.policy.common.utils.test.ExceptionsTester;
+
+public class PdpGroupPayloadExceptionTest extends ExceptionsTester {
+
+ @Test
+ public void testPdpGroupPayloadException() {
+ test(PdpGroupPayloadException.class);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadTest.java
new file mode 100644
index 000000000..34674e3ec
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PdpGroupPayloadTest.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+/**
+ * This class tests the PdpGroupPayload features.
+ */
+public class PdpGroupPayloadTest {
+
+ @Test
+ public void testGeneratePdpGroupPayload() throws IOException, PdpGroupPayloadException {
+ JsonArray operations = new JsonArray();
+ operations.add("POST/pdpgroup1/pdpsubgroup1/policyname1/1.0.0");
+ operations.add("POST/pdpgroup1/pdpsubgroup1/policyname2/1.0.0");
+ operations.add("POST/pdpgroup1/pdpsubgroup1/policyname1/2.0.0");
+ operations.add("DELETE/pdpgroup2/pdpsubgroup2/policyname1/1.0.0");
+ operations.add("POST/pdpgroup2/pdpsubgroup2/policyname1/2.0.0");
+ operations.add("DELETE/pdpgroup2/pdpsubgroup2/policyname2/1.0.0");
+ JsonObject listOfOperations = new JsonObject();
+ listOfOperations.add(PdpGroupPayload.PDP_ACTIONS, operations);
+
+ PdpGroupPayload pdpGroupPayload = new PdpGroupPayload(listOfOperations);
+ JSONAssert.assertEquals(
+ ResourceFileUtils.getResourceAsString("example/policy/pdp-group-multi-policies-payload.json"),
+ pdpGroupPayload.generatePdpGroupPayload(), false);
+ }
+
+ @Test
+ public void testGeneratePdpGroupPayload_WithEmptyList() throws PdpGroupPayloadException {
+ JsonArray operations = new JsonArray();
+ JsonObject listOfOperations = new JsonObject();
+ listOfOperations.add(PdpGroupPayload.PDP_ACTIONS, operations);
+
+ PdpGroupPayload pdpGroupPayload = new PdpGroupPayload(listOfOperations);
+ JSONAssert.assertEquals("{}", pdpGroupPayload.generatePdpGroupPayload(), false);
+ }
+
+ @Test(expected = PdpGroupPayloadException.class)
+ public void testUpdatePdpGroupMap_WithEmptyEntry() throws PdpGroupPayloadException {
+ JsonArray operations = new JsonArray();
+ operations.add("");
+ JsonObject listOfOperations = new JsonObject();
+ listOfOperations.add(PdpGroupPayload.PDP_ACTIONS, operations);
+
+ PdpGroupPayload pdpGroupPayload = new PdpGroupPayload(listOfOperations);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java
new file mode 100644
index 000000000..be7a9d674
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.policy.pdpgroup;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Arrays;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.clamp.clds.util.JsonUtils;
+import org.onap.policy.clamp.clds.util.ResourceFileUtils;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpGroups;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.enums.PdpState;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+/**
+ * This test class validates the PdpGroupAnalyzer class.
+ */
+public class PoliciesPdpMergerTest {
+
+ private static String pdpGroupsJson;
+
+ /**
+ * This method setups the pdpGroups required for the tests.
+ */
+ @BeforeClass
+ public static void setupPdpGroup() {
+ // Create Pdp Groups
+ PdpSubGroup pdpSubgroup1 = new PdpSubGroup();
+ pdpSubgroup1.setPdpType("subGroup1");
+ pdpSubgroup1.setSupportedPolicyTypes(
+ Arrays.asList(new ToscaConceptIdentifier("org.onap.*", "1.0.0")));
+
+ PdpSubGroup pdpSubgroup2 = new PdpSubGroup();
+ pdpSubgroup2.setPdpType("subGroup2");
+ pdpSubgroup2.setSupportedPolicyTypes(
+ Arrays.asList(new ToscaConceptIdentifier("onap.policies.monitoring.tcagen2", "1.0.0"),
+ new ToscaConceptIdentifier("onap.policies.controlloop.operational.common.Drools", "1.0.0")));
+ pdpSubgroup2.setPolicies(Arrays.asList(
+ new ToscaConceptIdentifier("MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0", "1.0.0")));
+
+ PdpSubGroup pdpSubgroup3 = new PdpSubGroup();
+ pdpSubgroup3.setPdpType("subGroup3");
+ pdpSubgroup3.setSupportedPolicyTypes(
+ Arrays.asList(new ToscaConceptIdentifier("onap.policies.monitoring.tcagen2", "1.0.0"),
+ new ToscaConceptIdentifier("onap.policies.controlloop.operational.common.Drools", "1.0.0")));
+ pdpSubgroup3.setPolicies(Arrays.asList(new ToscaConceptIdentifier("org.onap.testos", "2.0.0"),
+ new ToscaConceptIdentifier("OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd", "1.0.0")));
+
+ // Should match pdpSubgroup1
+ PdpGroup pdpGroup1 = new PdpGroup();
+ pdpGroup1.setName("pdpGroup1");
+ pdpGroup1.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup1.setPdpSubgroups(Arrays.asList(pdpSubgroup1));
+
+ // Should match pdpSubgroup1, pdpSubgroup2, pdpSubgroup3
+ // Should match also for the policy (pdpSubgroup2)
+ PdpGroup pdpGroup2 = new PdpGroup();
+ pdpGroup2.setName("pdpGroup2");
+ pdpGroup2.setPdpGroupState(PdpState.ACTIVE);
+ pdpGroup2.setPdpSubgroups(Arrays.asList(pdpSubgroup1, pdpSubgroup2, pdpSubgroup3));
+
+ PdpGroups pdpGroups = new PdpGroups();
+ pdpGroups.setGroups(Arrays.asList(pdpGroup1, pdpGroup2));
+
+ pdpGroupsJson = JsonUtils.GSON.toJson(pdpGroups);
+ }
+
+ @Test
+ public void testMergePoliciesAndPdpGroupStates() throws IOException {
+ JSONAssert.assertEquals(ResourceFileUtils.getResourceAsString("example/policy/policy-merger.json"),
+ PoliciesPdpMerger.mergePoliciesAndPdpGroupStates(
+ ResourceFileUtils.getResourceAsString("http-cache/example/policy/api/v1/policies/.file"),
+ pdpGroupsJson).toString(), true);
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/tosca/DictionaryServiceItCase.java b/runtime/src/test/java/org/onap/policy/clamp/tosca/DictionaryServiceItCase.java
new file mode 100644
index 000000000..fdde53a21
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/tosca/DictionaryServiceItCase.java
@@ -0,0 +1,247 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.tosca;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import javax.persistence.EntityNotFoundException;
+import javax.transaction.Transactional;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.policy.clamp.clds.Application;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class DictionaryServiceItCase {
+
+ @Autowired
+ private DictionaryService dictionaryService;
+
+ @Autowired
+ private DictionaryElementsRepository dictionaryElementsRepository;
+
+ private DictionaryElement getDictionaryElement(String shortName, String name,
+ String description, String type, String subDictionaryName) {
+
+ return new DictionaryElement(name, shortName, description, type, subDictionaryName);
+
+ }
+
+ private Dictionary getSimpleDictionaryExample() {
+
+ Dictionary dictionary = new Dictionary("Dictionary1", 0, null);
+
+ dictionary.addDictionaryElements(getDictionaryElement("DE1", "DictionaryElement1",
+ "DictionaryElement1", "string", null));
+
+ dictionary.addDictionaryElements(getDictionaryElement("DE2", "DictionaryElement2",
+ "DictionaryElement2", "number", null));
+
+ return dictionary;
+ }
+
+ private Dictionary getSecondaryDictionaryExample() {
+
+ Dictionary dictionary = new Dictionary("SecondaryDict", 1, "string");
+
+ dictionary.addDictionaryElements(getDictionaryElement("SDE1", "SecondaryDictElement1",
+ "SecondaryDictElement1", "string", null));
+
+ dictionary.addDictionaryElements(getDictionaryElement("SDE2", "SecondaryDictElement2",
+ "SecondaryDictElement2", "string", null));
+
+ return dictionary;
+ }
+
+ /**
+ * Test to validate that Dictionary is created.
+ */
+ @Test
+ @Transactional
+ public void shouldCreateDictionary() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ Dictionary actualDictionary = dictionaryService.saveOrUpdateDictionary(dictionary);
+ assertNotNull(actualDictionary);
+ assertThat(actualDictionary).isEqualTo(dictionary);
+ assertThat(actualDictionary.getName()).isEqualTo(dictionary.getName());
+
+ assertThat(actualDictionary.getDictionaryElements()).contains(
+ dictionaryElementsRepository.findById("DE1").get(),
+ dictionaryElementsRepository.findById("DE2").get());
+ }
+
+ /**
+ * Test to validate a DictionaryElement is created for a Dictionary.
+ */
+ @Test
+ @Transactional
+ public void shouldCreateorUpdateDictionaryElement() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ Dictionary actualDictionary = dictionaryService.saveOrUpdateDictionary(dictionary);
+ DictionaryElement dictionaryElement =
+ getDictionaryElement("DictionaryElement3", "DE3", "DictionaryElement3", "date", null);
+ actualDictionary.addDictionaryElements(dictionaryElement);
+ Dictionary updatedDictionary = dictionaryService
+ .saveOrUpdateDictionaryElement(actualDictionary.getName(), actualDictionary);
+ assertNotNull(updatedDictionary);
+ assertTrue(updatedDictionary.getDictionaryElements().contains(dictionaryElement));
+ assertThat(updatedDictionary.getName()).isEqualTo(actualDictionary.getName());
+ // update the dictionary element.
+ dictionaryElement.setDescription("DictionaryElement3 New Description");
+ Dictionary dictionary3 = new Dictionary("Dictionary1", 0, null);
+ dictionary3.addDictionaryElements(dictionaryElement);
+ Dictionary updatedDictionary2 =
+ dictionaryService.saveOrUpdateDictionaryElement(dictionary3.getName(), dictionary3);
+
+ assertNotNull(updatedDictionary2);
+ assertTrue(updatedDictionary2.getDictionaryElements().contains(dictionaryElement));
+ updatedDictionary2.getDictionaryElements().forEach(element -> {
+ if (element.equals(dictionaryElement)) {
+ assertTrue(element.getDescription().equals(dictionaryElement.getDescription()));
+ }
+ });
+
+ }
+
+ /**
+ * Test to validate that All Dictionaries are retrieved.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnAllDictionaries() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ Dictionary secondaryDictionary = getSecondaryDictionaryExample();
+ dictionaryService.saveOrUpdateDictionary(dictionary);
+ dictionaryService.saveOrUpdateDictionary(secondaryDictionary);
+
+ List<Dictionary> list = dictionaryService.getAllDictionaries();
+ assertNotNull(list);
+ assertThat(list).contains(dictionary, secondaryDictionary);
+ }
+
+ /**
+ * Test to validate one Dictionary is returned.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnOneDictionary() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ dictionaryService.saveOrUpdateDictionary(dictionary);
+
+ Dictionary returnedDictionary = dictionaryService.getDictionary("Dictionary1");
+ assertNotNull(returnedDictionary);
+ assertThat(returnedDictionary).isEqualTo(dictionary);
+ assertThat(returnedDictionary.getDictionaryElements())
+ .isEqualTo(dictionary.getDictionaryElements());
+ }
+
+ /**
+ * Test to validate one Dictionary is returned.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnEntityNotFoundException() {
+ try {
+ dictionaryService.getDictionary("Test");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(EntityNotFoundException.class);
+ assertTrue(e.getMessage().equals("Couldn't find Dictionary named: Test"));
+ }
+ }
+
+ /**
+ * Test to validate Dictionary is deleted.
+ */
+ @Test
+ @Transactional
+ public void shouldDeleteDictionaryByObject() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ Dictionary returnedDictionary = dictionaryService.saveOrUpdateDictionary(dictionary);
+
+ dictionaryService.deleteDictionary(returnedDictionary);
+ try {
+ dictionaryService.getDictionary("Dictionary1");
+ } catch (EntityNotFoundException e) {
+ assertTrue(e.getMessage().equals("Couldn't find Dictionary named: Dictionary1"));
+ }
+ }
+
+ /**
+ * Test to validate Dictionary is deleted by Name.
+ */
+ @Test
+ @Transactional
+ public void shouldDeleteDictionaryByName() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ dictionaryService.saveOrUpdateDictionary(dictionary);
+ dictionaryService.deleteDictionary(dictionary.getName());
+ try {
+ dictionaryService.getDictionary("Dictionary1");
+ } catch (EntityNotFoundException e) {
+ assertTrue(e.getMessage().equals("Couldn't find Dictionary named: Dictionary1"));
+ }
+ }
+
+ /**
+ * Test to validate DictionaryElements is deleted by Name.
+ */
+ @Test
+ @Transactional
+ public void shouldDeleteDictionaryElementsByName() {
+ Dictionary dictionary = getSimpleDictionaryExample();
+ dictionaryService.saveOrUpdateDictionary(dictionary);
+ DictionaryElement dictionaryElement =
+ dictionaryElementsRepository.findById("DE1").orElse(null);
+ assertNotNull(dictionaryElement);
+ dictionaryService.deleteDictionaryElement("Dictionary1", "DE1");
+ dictionary = dictionaryService.getDictionary("Dictionary1");
+ DictionaryElement deletedDictionaryElement =
+ dictionaryElementsRepository.findById("DE1").orElse(null);
+ assertThat(deletedDictionaryElement).isNotIn(dictionary.getDictionaryElements());
+ }
+
+ /**
+ * Test to validate all secondary level dictionary names are returned.
+ */
+ @Test
+ @Transactional
+ public void shouldReturnAllSecondaryLevelDictionaryNames() {
+ Dictionary dictionary = getSecondaryDictionaryExample();
+ dictionaryService.saveOrUpdateDictionary(dictionary);
+
+ Dictionary dictionary2 = new Dictionary("SecondaryDict2", 1, "string");
+ dictionaryService.saveOrUpdateDictionary(dictionary2);
+ List<String> secondaryDictionaryNames =
+ dictionaryService.getAllSecondaryLevelDictionaryNames();
+
+ assertNotNull(secondaryDictionaryNames);
+ assertThat(secondaryDictionaryNames).contains(dictionary.getName(), dictionary2.getName());
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/util/PassDecoderTest.java b/runtime/src/test/java/org/onap/policy/clamp/util/PassDecoderTest.java
new file mode 100644
index 000000000..7fd0cb91d
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/util/PassDecoderTest.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class PassDecoderTest {
+
+ private final String encrypted = "enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc";
+
+ @Test
+ public final void testDecryptionNoKeyfile() throws Exception {
+ String decodedPass = PassDecoder.decode(encrypted, null);
+ assertEquals(decodedPass, encrypted);
+ }
+
+ @Test
+ public final void testDecryptionNoPassword() throws Exception {
+ String decodedPass = PassDecoder.decode(null, "classpath:clds/aaf/org.onap.clamp.keyfile");
+ assertNull(decodedPass);
+ }
+
+ @Test
+ public final void testDecryption() throws Exception {
+ String decodedPass = PassDecoder.decode(encrypted, "classpath:clds/aaf/org.onap.clamp.keyfile");
+ assertEquals(decodedPass, "China in the Spring");
+ assertEquals("Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U", PassDecoder
+ .decode("enc:JPV4p067JlSXt2Fet9bfuI8JpkS4ZGYVcgypcPs98gXjgjCjTze_d3JxqmlKaaakdiOjIcEC_MJh6-5pJTLgdc",
+ "classpath:clds/aaf/org.onap.clamp.keyfile"));
+ }
+}
diff --git a/runtime/src/test/java/org/onap/policy/clamp/util/SemanticVersioningTest.java b/runtime/src/test/java/org/onap/policy/clamp/util/SemanticVersioningTest.java
new file mode 100644
index 000000000..604ce55db
--- /dev/null
+++ b/runtime/src/test/java/org/onap/policy/clamp/util/SemanticVersioningTest.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.policy.clamp.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class SemanticVersioningTest {
+
+ /**
+ * compare test.
+ */
+ @Test
+ public void compareTest() {
+ assertThat(SemanticVersioning.compare("1.0.0", "2.0.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("1.5.0", "2.0.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("1.5.0", "2.1.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("1.5.3", "2.0.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("2.5.3", "2.6.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("2.5", "2.5.1")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("2.5.0", "2.5.1")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("2.5.0.0", "2.5.1")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("2.5.1.0", "2.5.1")).isEqualTo(1);
+
+ assertThat(SemanticVersioning.compare("2.0.0", "1.0.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.0.0", "1.5.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.1.0", "1.5.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.0.0", "1.5.3")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.6.0", "2.5.3")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.5.1", "2.5")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.5.1", "2.5.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("2.5.1", "2.5.0.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("1", "1.2.3.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("1.2", "1")).isEqualTo(1);
+ }
+
+ /**
+ * Compare test.
+ */
+ @Test
+ public void compareEqualsTest() {
+ assertThat(SemanticVersioning.compare("1.0.0", "1.0.0")).isEqualTo(0);
+ assertThat(SemanticVersioning.compare("1.0.0.0", "1.0.0")).isEqualTo(1);
+ assertThat(SemanticVersioning.compare("1.2.3", "1.2.3")).isEqualTo(0);
+ assertThat(SemanticVersioning.compare("1.2.3", "1.2.3.0")).isEqualTo(-1);
+
+ }
+
+ /**
+ * Compare with null.
+ */
+ @Test
+ public void compareNullTest() {
+ assertThat(SemanticVersioning.compare(null, null)).isEqualTo(0);
+ assertThat(SemanticVersioning.compare(null, "1.0")).isEqualTo(-1);
+ assertThat(SemanticVersioning.compare("1.0", null)).isEqualTo(1);
+ }
+
+ /**
+ * Increment major version test.
+ */
+ @Test
+ public void incrementVersionTest() {
+ assertThat(SemanticVersioning.incrementMajorVersion("1.0")).isEqualTo("2.0.0");
+ assertThat(SemanticVersioning.incrementMajorVersion("1.0.0")).isEqualTo("2.0.0");
+ assertThat(SemanticVersioning.incrementMajorVersion("1")).isEqualTo("2.0.0");
+ assertThat(SemanticVersioning.incrementMajorVersion("1.2.3")).isEqualTo("2.0.0");
+ }
+}
diff --git a/runtime/src/test/resources/application.properties b/runtime/src/test/resources/application.properties
new file mode 100644
index 000000000..bc513e9e4
--- /dev/null
+++ b/runtime/src/test/resources/application.properties
@@ -0,0 +1,180 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP POLICY-CLAMP
+# ================================================================================
+# Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+### Set the port for HTTP or HTTPS protocol (Controlled by Spring framework, only one at a time).
+### (See below for the parameter 'server.http.port' if you want to have both enabled)
+### To have only HTTP, keep the lines server.ssl.* commented
+### To have only HTTPS enabled, uncomment the server.ssl.* lines and specify a right keystore location
+server.port=${clamp.it.tests.http}
+### Settings for HTTPS (this automatically enables the HTTPS on the port 'server.port')
+#server.ssl.key-store=file:/tmp/mykey.jks
+#server.ssl.key-store-password=pass
+#server.ssl.key-password=pass
+
+clamp.config.keyFile=classpath:clds/aaf/org.onap.clamp.keyfile
+
+### In order to be user friendly when HTTPS is enabled,
+### you can add another HTTP port that will be automatically redirected to HTTPS
+### by enabling this parameter (server.http.port) and set it to another port (80 or 8080, 8090, etc ...)
+#server.http-to-https-redirection.port=8090
+
+### HTTP Example:
+###--------------
+### server.port=8080
+
+### HTTPS Example:
+### --------------
+### server.port=8443
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+
+### HTTP (Redirected to HTTPS) and HTTPS Example:
+### --------------------------------------------
+### server.port=8443 <-- The HTTPS port
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+### server.http-to-https-redirection.port=8090 <-- The HTTP port
+
+server.servlet.context-path=/
+#Modified engine-rest applicationpath
+spring.profiles.active=clamp-default,clamp-default-user
+spring.http.converters.preferred-json-mapper=gson
+
+#The max number of active threads in this pool
+server.tomcat.max-threads=200
+#The minimum number of threads always kept alive
+server.tomcat.min-Spare-Threads=25
+#The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads
+server.tomcat.max-idle-time=60000
+
+#Servlet context parameters
+server.context_parameters.p-name=value #context parameter with p-name as key and value as value.
+
+camel.springboot.consumer-template-cache-size=1000
+camel.springboot.producer-template-cache-size=1000
+# JMX enabled to have Camel Swagger runtime working
+camel.springboot.jmx-enabled=true
+camel.defaultthreadpool.poolsize=10
+camel.defaultthreadpool.maxpoolsize=20
+camel.defaultthreadpool.maxqueuesize=1000
+camel.defaultthreadpool.keepaliveTime=60
+camel.defaultthreadpool.rejectpolicy=CallerRuns
+camel.springboot.xml-routes=classpath:/clds/camel/routes/*.xml
+camel.springboot.xml-rests=classpath:/clds/camel/rest/*.xml
+camel.springboot.backlog-tracing=true
+camel.springboot.tracing=true
+camel.springboot.message-history=true
+
+#clds datasource connection details
+spring.datasource.driverClassName=org.mariadb.jdbc.Driver
+spring.datasource.url=jdbc:mariadb:sequential://localhost:3306,localhost:${docker.mariadb.port.host}/cldsdb4?autoReconnect=true&connectTimeout=10000&socketTimeout=10000&retriesAllDown=3
+spring.datasource.username=clds
+spring.datasource.password=sidnnd83K
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.validationQueryTimeout=20000
+spring.datasource.validationInterval=30000
+spring.datasource.testWhileIdle = true
+spring.datasource.minIdle = 0
+spring.datasource.initialSize=0
+# Automatically test whether a connection provided is good or not
+spring.datasource.testOnBorrow=true
+spring.datasource.ignoreExceptionOnPreLoad=true
+
+spring.jpa.properties.javax.persistence.schema-generation.database.action=none
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+# disable Hibernate DDL generation because the schema will be generated from a sql script
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+spring.jpa.properties.hibernate.ddl-auto=validate
+spring.jpa.properties.hibernate.hbm2ddl.delimiter=;
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
+
+# Whether to enable logging of SQL statements.
+#spring.jpa.show-sql=true
+
+#Async Executor default Parameters
+async.core.pool.size=10
+async.max.pool.size=20
+async.queue.capacity=500
+
+#For EELF logback file
+#com.att.eelf.logging.path=
+clamp.config.logback.filename=logback-default.xml
+#The log folder that will be used in logback.xml file
+clamp.config.log.path=log
+clamp.config.files.systemProperties=classpath:/system.properties
+clamp.config.files.cldsUsers=classpath:/clds/clds-users.json
+clamp.config.files.globalProperties=classpath:/clds/templates/globalProperties.json
+clamp.config.files.sdcController=classpath:/clds/sdc-controllers-config.json
+
+clamp.config.httpclient.socketTimeout=20000
+clamp.config.httpclient.connectTimeout=10000
+
+#
+# Configuration Settings for Policy Engine Components
+clamp.config.policy.api.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.policy.api.userName=healthcheck
+clamp.config.policy.api.password=zb!XztG34
+clamp.config.policy.pap.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.policy.pap.userName=healthcheck
+clamp.config.policy.pap.password=zb!XztG34
+
+# Sdc service properties
+#
+clamp.config.sdc.csarFolder = ${project.build.directory}/sdc-tests
+
+#DCAE Inventory Url Properties
+clamp.config.dcae.inventory.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.dcae.intentory.retry.interval=100
+clamp.config.dcae.intentory.retry.limit=1
+
+#DCAE Deployment Url Properties
+clamp.config.dcae.deployment.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.dcae.deployment.userName=test
+clamp.config.dcae.deployment.password=test
+
+#Define user permission related parameters, the permission type can be changed but MUST be redefined in clds-users.properties in that case !
+clamp.config.security.permission.type.cl=org.onap.clamp.clds.cl
+clamp.config.security.permission.type.cl.manage=org.onap.clamp.clds.cl.manage
+clamp.config.security.permission.type.cl.event=org.onap.clamp.clds.cl.event
+clamp.config.security.permission.type.filter.vf=org.onap.clamp.clds.filter.vf
+clamp.config.security.permission.type.template=org.onap.clamp.clds.template
+clamp.config.security.permission.type.tosca=org.onap.clamp.clds.tosca
+clamp.config.security.permission.type.policies=org.onap.clamp.clds.policies
+#This one indicates the type of instances (dev|prod|perf...), this must be set accordingly in clds-users.properties
+clamp.config.security.permission.instance=dev
+clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal, org.onap.aaf.cadi.principal.CachedBasicPrincipal
+
+# Configuration settings for CDS
+clamp.config.cds.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.cds.userName=ccsdkapps
+clamp.config.cds.password=ccsdkapps
+
+## Tosca converter
+clamp.config.tosca.converter.json.schema.templates=classpath:/clds/tosca-converter/templates.json
+clamp.config.tosca.converter.default.datatypes=classpath:/clds/tosca-converter/default-tosca-types.yaml
+clamp.config.tosca.converter.dictionary.support.enabled=true \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/blueprint-with-microservice-chain.yaml b/runtime/src/test/resources/clds/blueprint-with-microservice-chain.yaml
new file mode 100644
index 000000000..0e9e4bc8c
--- /dev/null
+++ b/runtime/src/test/resources/clds/blueprint-with-microservice-chain.yaml
@@ -0,0 +1,202 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+description: >
+ This blueprint deploys/manages the TCA module as a Docker container
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/k8splugin/1.4.12/k8splugin_types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/dcaepolicyplugin/2.3.0/dcaepolicyplugin_types.yaml
+inputs:
+ aaiEnrichmentHost:
+ type: string
+ default: "aai.onap.svc.cluster.local"
+ aaiEnrichmentPort:
+ type: string
+ default: "8443"
+ enableAAIEnrichment:
+ type: string
+ default: true
+ dmaap_host:
+ type: string
+ default: message-router.onap.svc.cluster.local
+ dmaap_port:
+ type: string
+ default: "3904"
+ enableRedisCaching:
+ type: string
+ default: false
+ redisHosts:
+ type: string
+ default: dcae-redis.onap.svc.cluster.local:6379
+ tag_version:
+ type: string
+ default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.1.0-STAGING-latest"
+ consul_host:
+ type: string
+ default: consul-server.onap.svc.cluster.local
+ consul_port:
+ type: string
+ default: "8500"
+ cbs_host:
+ type: string
+ default: "config-binding-service.dcae.svc.cluster.local"
+ cbs_port:
+ type: string
+ default: "10000"
+ policy_id:
+ type: string
+ default: "none"
+ external_port:
+ type: string
+ description: Kubernetes node port on which CDAPgui is exposed
+ default: "32012"
+ policy_model_id:
+ type: string
+ default: "onap.policies.monitoring.cdap.tca.hi.lo.app"
+
+node_templates:
+ first_app:
+ type: dcae.nodes.ContainerizedServiceComponent
+ properties:
+ service_component_type: 'dcaegen2-analytics-tca'
+ application_config: {}
+ docker_config: {}
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory: "/opt/app/TCAnalytics/logs"
+ relationships:
+ - target: tca_policy_1
+ type: cloudify.relationships.depends_on
+ second_app:
+ type: dcae.nodes.ContainerizedServiceComponent
+ relationships:
+ - target: tca_policy_2
+ type: cloudify.relationships.depends_on
+ - type: clamp_node.relationships.gets_input_from
+ target: first_app
+ properties:
+ service_component_type: 'dcaegen2-analytics-tca'
+ application_config: {}
+ docker_config: {}
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory: "/opt/app/TCAnalytics/logs"
+ application_config:
+ app_config:
+ appDescription: DCAE Analytics Threshold Crossing Alert Application
+ appName: dcae-tca
+ tcaAlertsAbatementTableName: TCAAlertsAbatementTable
+ tcaAlertsAbatementTableTTLSeconds: '1728000'
+ tcaSubscriberOutputStreamName: TCASubscriberOutputStream
+ tcaVESAlertsTableName: TCAVESAlertsTable
+ tcaVESAlertsTableTTLSeconds: '1728000'
+ tcaVESMessageStatusTableName: TCAVESMessageStatusTable
+ tcaVESMessageStatusTableTTLSeconds: '86400'
+ thresholdCalculatorFlowletInstances: '2'
+ app_preferences:
+ aaiEnrichmentHost:
+ get_input: aaiEnrichmentHost
+ aaiEnrichmentIgnoreSSLCertificateErrors: 'true'
+ aaiEnrichmentPortNumber: '8443'
+ aaiEnrichmentProtocol: https
+ aaiEnrichmentUserName: dcae@dcae.onap.org
+ aaiEnrichmentUserPassword: demo123456!
+ aaiVMEnrichmentAPIPath: /aai/v11/search/nodes-query
+ aaiVNFEnrichmentAPIPath: /aai/v11/network/generic-vnfs/generic-vnf
+ enableAAIEnrichment:
+ get_input: enableAAIEnrichment
+ enableRedisCaching:
+ get_input: enableRedisCaching
+ redisHosts:
+ get_input: redisHosts
+ enableAlertCEFFormat: 'false'
+ publisherContentType: application/json
+ publisherHostName:
+ get_input: dmaap_host
+ publisherHostPort:
+ get_input: dmaap_port
+ publisherMaxBatchSize: '1'
+ publisherMaxRecoveryQueueSize: '100000'
+ publisherPollingInterval: '20000'
+ publisherProtocol: http
+ publisherTopicName: unauthenticated.DCAE_CL_OUTPUT
+ subscriberConsumerGroup: OpenDCAE-c12
+ subscriberConsumerId: c12
+ subscriberContentType: application/json
+ subscriberHostName:
+ get_input: dmaap_host
+ subscriberHostPort:
+ get_input: dmaap_port
+ subscriberMessageLimit: '-1'
+ subscriberPollingInterval: '30000'
+ subscriberProtocol: http
+ subscriberTimeoutMS: '-1'
+ subscriberTopicName: unauthenticated.VES_MEASUREMENT_OUTPUT
+ tca_policy: ''
+ service_component_type: dcaegen2-analytics_tca
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ DMAAPHOST:
+ { get_input: dmaap_host }
+ DMAAPPORT:
+ { get_input: dmaap_port }
+ DMAAPPUBTOPIC: "unauthenticated.DCAE_CL_OUTPUT"
+ DMAAPSUBTOPIC: "unauthenticated.VES_MEASUREMENT_OUTPUT"
+ AAIHOST:
+ { get_input: aaiEnrichmentHost }
+ AAIPORT:
+ { get_input: aaiEnrichmentPort }
+ CONSUL_HOST:
+ { get_input: consul_host }
+ CONSUL_PORT:
+ { get_input: consul_port }
+ CBS_HOST:
+ { get_input: cbs_host }
+ CBS_PORT:
+ { get_input: cbs_port }
+ CONFIG_BINDING_SERVICE: "config_binding_service"
+ ports:
+ - concat: ["11011:", { get_input: external_port }]
+ third_app:
+ type: dcae.nodes.ContainerizedServiceComponent
+ properties:
+ service_component_type: 'dcaegen2-analytics-tca'
+ application_config: {}
+ docker_config: {}
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory: "/opt/app/TCAnalytics/logs"
+ relationships:
+ - target: tca_policy_3
+ type: cloudify.relationships.depends_on
+ - type: clamp_node.relationships.gets_input_from
+ target: second_app
+ tca_policy_1:
+ type: dcae.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
+ tca_policy_2:
+ type: dcae.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
+
+ tca_policy_3:
+ type: dcae.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
diff --git a/runtime/src/test/resources/clds/clds-parse-exception.json b/runtime/src/test/resources/clds/clds-parse-exception.json
new file mode 100644
index 000000000..1c06a3947
--- /dev/null
+++ b/runtime/src/test/resources/clds/clds-parse-exception.json
@@ -0,0 +1 @@
+This is not json \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/clds-users-incomplete-permissions.json b/runtime/src/test/resources/clds/clds-users-incomplete-permissions.json
new file mode 100644
index 000000000..9e3534ff4
--- /dev/null
+++ b/runtime/src/test/resources/clds/clds-users-incomplete-permissions.json
@@ -0,0 +1,14 @@
+[
+ {
+ "user": "admin1",
+ "password": "5f4dcc3b5aa765d61d8327deb882cf99",
+ "permissions": [
+ "permission-type-cl|dev|",
+ "permission-type-cl|dev",
+ "permission-type-cl-manage|dev|*",
+ "permission-type-filter-vf|dev|*",
+ "permission-type-template|dev|read",
+ "permission-type-template|dev|update"
+ ]
+ }
+]
diff --git a/runtime/src/test/resources/clds/clds-users-no-permission.json b/runtime/src/test/resources/clds/clds-users-no-permission.json
new file mode 100644
index 000000000..ac91540f2
--- /dev/null
+++ b/runtime/src/test/resources/clds/clds-users-no-permission.json
@@ -0,0 +1,7 @@
+[
+ {
+ "user": "admin1",
+ "permissions": [
+ ]
+ }
+]
diff --git a/runtime/src/test/resources/clds/clds-users-two-users.json b/runtime/src/test/resources/clds/clds-users-two-users.json
new file mode 100644
index 000000000..b3721946a
--- /dev/null
+++ b/runtime/src/test/resources/clds/clds-users-two-users.json
@@ -0,0 +1,26 @@
+[
+ {
+ "user": "admin1",
+ "password": "5f4dcc3b5aa765d61d8327deb882cf99",
+ "permissions": [
+ "permission-type-cl|dev|read",
+ "permission-type-cl|dev|update",
+ "permission-type-cl-manage|dev|*",
+ "permission-type-filter-vf|dev|*",
+ "permission-type-template|dev|read",
+ "permission-type-template|dev|update"
+ ]
+ },
+ {
+ "user": "admin2",
+ "password": "5f4dcc3b5aa765d61d8327deb882cf99",
+ "permissions": [
+ "permission-type-cl|dev|read",
+ "permission-type-cl|dev|update",
+ "permission-type-cl-manage|dev|*",
+ "permission-type-filter-vf|dev|*",
+ "permission-type-template|dev|read",
+ "permission-type-template|dev|update"
+ ]
+ }
+]
diff --git a/runtime/src/test/resources/clds/new-microservice.yaml b/runtime/src/test/resources/clds/new-microservice.yaml
new file mode 100644
index 000000000..70c1eda46
--- /dev/null
+++ b/runtime/src/test/resources/clds/new-microservice.yaml
@@ -0,0 +1,46 @@
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ - "http://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml"
+ - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R5/k8splugin/1.4.13/k8splugin_types.yaml"
+ - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R5/clamppolicyplugin/1.0.0/clamppolicyplugin_types.yaml"
+
+inputs:
+ tag_version:
+ type: string
+ description: docker image
+ policy_model_id:
+ type: 'string'
+ default: 'onap.policies.monitoring.dcae-pm-initiation-handler'
+ policy_id:
+ type: 'string'
+ default: 'onap.policies.monitoring.dcae-pm-initiation-handler'
+
+node_templates:
+ pmsh:
+ relationships:
+ - type: cloudify.relationships.depends_on
+ target: pmsh-policy
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ ports:
+ - '8443:0'
+ - '8081:0'
+ properties:
+ image:
+ get_input: tag_version
+ replicas: 1
+ service_component_type: "pmsh"
+ service_component_name_override: "pmsh"
+ type: dcae.nodes.ContainerizedServiceComponent
+
+ pmsh-policy:
+ type: clamp.nodes.policy
+ properties:
+ policy_model_id:
+ get_input: policy_model_id
+ policy_id:
+ get_input: policy_id
diff --git a/runtime/src/test/resources/clds/policy-merger.json b/runtime/src/test/resources/clds/policy-merger.json
new file mode 100644
index 000000000..5c6bd5b6b
--- /dev/null
+++ b/runtime/src/test/resources/clds/policy-merger.json
@@ -0,0 +1,215 @@
+{
+ "policies": [
+ {
+ "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0": {
+ "type": "onap.policies.monitoring.tcagen2",
+ "type_version": "1.0.0",
+ "properties": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": {
+ "pdpGroup": "pdpGroup2",
+ "pdpSubGroup": "subGroup2"
+ },
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd": {
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "properties": {
+ "abatement": false,
+ "operations": [
+ {
+ "failure_retries": "final_failure_retries",
+ "id": "test1",
+ "failure_timeout": "final_failure_timeout",
+ "failure": "final_failure",
+ "operation": {
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": "{\"resource-assignment-properties\":{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}}"
+ },
+ "target": {
+ "entityIds": {
+ "resourceID": "Vloadbalancerms..vdns..module-3",
+ "modelInvariantId": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "modelVersionId": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "modelName": "Vloadbalancerms..vdns..module-3",
+ "modelVersion": "1",
+ "modelCustomizationId": "bafcdab0-801d-4d81-9ead-f464640a38b1"
+ },
+ "targetType": "VNF"
+ },
+ "actor": "SDNR",
+ "operation": "BandwidthOnDemand"
+ },
+ "failure_guard": "final_failure_guard",
+ "retries": 0,
+ "timeout": 0,
+ "failure_exception": "final_failure_exception",
+ "description": "test",
+ "success": "final_success"
+ }
+ ],
+ "trigger": "test1",
+ "timeout": 0,
+ "id": "LOOP_test"
+ },
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": {
+ "pdpGroup": "pdpGroup2",
+ "pdpSubGroup": "subGroup3"
+ },
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP": {
+ "type": "onap.policies.Naming",
+ "type_version": "1.0.0",
+ "properties": {
+ "naming-models": [
+ {
+ "naming-type": "VNF",
+ "naming-recipe": "AIC_CLOUD_REGION|DELIMITER|CONSTANT|DELIMITER|TIMESTAMP",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "AIC_CLOUD_REGION"
+ },
+ {
+ "property-name": "CONSTANT",
+ "property-value": "onap-nf"
+ },
+ {
+ "property-name": "TIMESTAMP"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VNFC",
+ "naming-recipe": "VNF_NAME|DELIMITER|NFC_NAMING_CODE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "ENTIRETY",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ },
+ {
+ "property-name": "NFC_NAMING_CODE"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VF-MODULE",
+ "naming-recipe": "VNF_NAME|DELIMITER|VF_MODULE_LABEL|DELIMITER|VF_MODULE_TYPE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ },
+ {
+ "property-name": "VF_MODULE_LABEL"
+ },
+ {
+ "property-name": "VF_MODULE_TYPE"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "PRECEEDING",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ }
+ ]
+ }
+ ],
+ "policy-instance-name": "ONAP_NF_NAMING_TIMESTAMP"
+ },
+ "name": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "policy-version": "1.0.0"
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/sdc-controller-config-NULL.json b/runtime/src/test/resources/clds/sdc-controller-config-NULL.json
new file mode 100644
index 000000000..bf310c706
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controller-config-NULL.json
@@ -0,0 +1,11 @@
+{
+ "user": "User",
+ "consumerGroup": "NULL",
+ "consumerId": "consumerId",
+ "environmentName": "environmentName",
+ "sdcAddress": "hostname:8080",
+ "password": "bb3871669d893c7fb8aaacda31b77b4f537E67A081C2726889548ED7BC4C2DE6",
+ "pollingInterval":10,
+ "pollingTimeout":30,
+ "messageBusAddresses":["localhost"]
+}
diff --git a/runtime/src/test/resources/clds/sdc-controller-config-TLS.json b/runtime/src/test/resources/clds/sdc-controller-config-TLS.json
new file mode 100644
index 000000000..4d5f02945
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controller-config-TLS.json
@@ -0,0 +1,14 @@
+{
+ "user": "User",
+ "consumerGroup": "consumerGroup",
+ "consumerId": "consumerId",
+ "environmentName": "environmentName",
+ "sdcAddress": "hostname:8080",
+ "password": "QpF2TcrdRSFADqDxH1HwDYdYUIbMxOj-TrGd6Vqvwzd",
+ "pollingInterval":10,
+ "pollingTimeout":30,
+ "activateServerTLSAuth": true,
+ "keyStorePassword":"QpF2TcrdRSFADqDxH1HwDYdYUIbMxOj-TrGd6Vqvwzd",
+ "keyStorePath": "/test",
+ "messageBusAddresses":["localhost"]
+}
diff --git a/runtime/src/test/resources/clds/sdc-controller-config-bad.json b/runtime/src/test/resources/clds/sdc-controller-config-bad.json
new file mode 100644
index 000000000..194ff5f4b
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controller-config-bad.json
@@ -0,0 +1,13 @@
+{
+ "sdc-connections": {
+ "sdc-controller1": {
+ "user": "testuser",
+ "consumerGroup": "consumerGroup",
+ "consumerId": "consumerId",
+ "environmentName": "environmentName",
+ "sdcAddress": "hostname1:8080",
+ "pollingInterval": 10,
+ "pollingTimeout": 30
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/sdc-controller-config-empty-encrypted.json b/runtime/src/test/resources/clds/sdc-controller-config-empty-encrypted.json
new file mode 100644
index 000000000..2a70b9edc
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controller-config-empty-encrypted.json
@@ -0,0 +1,14 @@
+{
+ "user": "User",
+ "consumerGroup": "consumerGroup",
+ "consumerId": "consumerId",
+ "environmentName": "environmentName",
+ "sdcAddress": "hostname:8080",
+ "password": "bb3871669d893c7fb8aaacda31b77b4f537E67A081C2726889548ED7BC4C2DE6",
+ "pollingInterval":10,
+ "pollingTimeout":30,
+ "activateServerTLSAuth": true,
+ "keyStorePassword":"",
+ "keyStorePath": "/test",
+ "messageBusAddresses":["localhost"]
+}
diff --git a/runtime/src/test/resources/clds/sdc-controllers-config-bad.json b/runtime/src/test/resources/clds/sdc-controllers-config-bad.json
new file mode 100644
index 000000000..0b417b745
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controllers-config-bad.json
@@ -0,0 +1,26 @@
+{
+ "sdc-connections":{,
+ "sdc-controller1":{
+ "user": "User1",
+ "consumerGroup": "consumerGroup1",
+ "consumerId": "consumerId1",
+ "environmentName": "environmentName1",
+ "sdcAddress": "hostname1",
+ "password": "bb3871669d893c7fb8aaacda31b77b4f537E67A081C2726889548ED7BC4C2DE6",
+ "pollingInterval":10,
+ "pollingTimeout":30
+
+ },
+ "sdc-controller2":{
+ "user": "User2",
+ "consumerGroup": "consumerGroup2",
+ "consumerId": "consumerId2",
+ "environmentName": "environmentName2",
+ "sdcAddress": "hostname2",
+ "password": "bb3871669d893c7fb8aaacda31b77b4f537E67A081C2726889548ED7BC4C2DE6",
+ "pollingInterval":10,
+ "pollingTimeout":30
+
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/sdc-controllers-config-missing-param.json b/runtime/src/test/resources/clds/sdc-controllers-config-missing-param.json
new file mode 100644
index 000000000..d99ed5801
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controllers-config-missing-param.json
@@ -0,0 +1,13 @@
+{
+ "sdc-connections": {
+ "sdc-controller1": {
+ "user": "testuser",
+ "consumerGroup": "consumerGroup",
+ "consumerId": "consumerId",
+ "environmentName": "environmentName",
+ "sdcAddress": "hostname1",
+ "pollingInterval": 10,
+ "pollingTimeout": 30
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/sdc-controllers-config.json b/runtime/src/test/resources/clds/sdc-controllers-config.json
new file mode 100644
index 000000000..aafd7d61d
--- /dev/null
+++ b/runtime/src/test/resources/clds/sdc-controllers-config.json
@@ -0,0 +1,30 @@
+{
+ "sdc-connections": {
+ "sdc-controller1": {
+ "user": "User1",
+ "consumerGroup": "consumerGroup1",
+ "consumerId": "consumerId1",
+ "environmentName": "environmentName1",
+ "sdcAddress": "localhost:${docker.http-cache.port.host}",
+ "password": "enc:QpF2TcrdRSFADqDxH1HwDYdYUIbMxOj-TrGd6Vqvwzd",
+ "pollingInterval": 10,
+ "pollingTimeout": 30,
+ "messageBusAddresses": [
+ "localhost"
+ ]
+ },
+ "sdc-controller2": {
+ "user": "User2",
+ "consumerGroup": "consumerGroup2",
+ "consumerId": "consumerId2",
+ "environmentName": "environmentName2",
+ "sdcAddress": "localhost:${docker.http-cache.port.host}",
+ "password": "enc:QpF2TcrdRSFADqDxH1HwDYdYUIbMxOj-TrGd6Vqvwzd",
+ "pollingInterval": 10,
+ "pollingTimeout": 30,
+ "messageBusAddresses": [
+ "localhost"
+ ]
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/single-microservice-fragment-invalid.yaml b/runtime/src/test/resources/clds/single-microservice-fragment-invalid.yaml
new file mode 100644
index 000000000..2c1680717
--- /dev/null
+++ b/runtime/src/test/resources/clds/single-microservice-fragment-invalid.yaml
@@ -0,0 +1,25 @@
+second_app:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ properties:
+ service_component_type: dcaegen2-analytics-tca
+ service_component_name_override: second_app
+ image: { get_input: second_app_docker_image }
+ name: second_app
+ policy_id:
+ policy_model_id: "type1"
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ grpc_server.host: "first_app.onap"
+ dmaap_ip: {get_input: dmaap_ip}
+ dmapp_topic: {get_input: dmaap_topic}
+ policy_id: {get_input: policy_id}
+ ports:
+ - 8080:8080
+ relationships:
+ - type: cloudify.relationships.connected_to
+ target: first_app
+ - type: clamp_node.relationships.gets_input_from
+ target: first_app \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/single-microservice-fragment-valid-with-version.yaml b/runtime/src/test/resources/clds/single-microservice-fragment-valid-with-version.yaml
new file mode 100644
index 000000000..ae31fb16a
--- /dev/null
+++ b/runtime/src/test/resources/clds/single-microservice-fragment-valid-with-version.yaml
@@ -0,0 +1,21 @@
+second_app:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ properties:
+ service_component_type: dcaegen2-analytics-tca
+ service_component_name_override: second_app
+ image: { get_input: second_app_docker_image }
+ name: second_app
+ policy_id:
+ policy_model_id: "type1"
+ policy_model_version: "10.0.0"
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ grpc_server.host: "first_app.onap"
+ dmaap_ip: {get_input: dmaap_ip}
+ dmapp_topic: {get_input: dmaap_topic}
+ policy_id: {get_input: policy_id}
+ ports:
+ - 8080:8080
diff --git a/runtime/src/test/resources/clds/single-microservice-fragment-without-name.yaml b/runtime/src/test/resources/clds/single-microservice-fragment-without-name.yaml
new file mode 100644
index 000000000..f9ac53cac
--- /dev/null
+++ b/runtime/src/test/resources/clds/single-microservice-fragment-without-name.yaml
@@ -0,0 +1,22 @@
+second_app:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ properties:
+ service_component_type: dcaegen2-analytics-tca
+ service_component_name_override: second_app
+ image: { get_input: second_app_docker_image }
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ grpc_server.host: "first_app.onap"
+ dmaap_ip: {get_input: dmaap_ip}
+ dmapp_topic: {get_input: dmaap_topic}
+ policy_id: {get_input: policy_id}
+ ports:
+ - 8080:8080
+ relationships:
+ - type: cloudify.relationships.connected_to
+ target: first_app
+ - type: clamp_node.relationships.gets_input_from
+ target: first_app \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/single-microservice-fragment-without-properties.yaml b/runtime/src/test/resources/clds/single-microservice-fragment-without-properties.yaml
new file mode 100644
index 000000000..a34ccc6d4
--- /dev/null
+++ b/runtime/src/test/resources/clds/single-microservice-fragment-without-properties.yaml
@@ -0,0 +1,18 @@
+second_app:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ grpc_server.host: "first_app.onap"
+ dmaap_ip: {get_input: dmaap_ip}
+ dmapp_topic: {get_input: dmaap_topic}
+ policy_id: {get_input: policy_id}
+ ports:
+ - 8080:8080
+ relationships:
+ - type: cloudify.relationships.connected_to
+ target: first_app
+ - type: clamp_node.relationships.gets_input_from
+ target: first_app \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/single-microservice-fragment-without-relationships.yaml b/runtime/src/test/resources/clds/single-microservice-fragment-without-relationships.yaml
new file mode 100644
index 000000000..0354acd69
--- /dev/null
+++ b/runtime/src/test/resources/clds/single-microservice-fragment-without-relationships.yaml
@@ -0,0 +1,18 @@
+second_app:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ properties:
+ service_component_type: dcaegen2-analytics-tca
+ service_component_name_override: second_app
+ image: { get_input: second_app_docker_image }
+ name: second_app
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ grpc_server.host: "first_app.onap"
+ dmaap_ip: {get_input: dmaap_ip}
+ dmapp_topic: {get_input: dmaap_topic}
+ policy_id: {get_input: policy_id}
+ ports:
+ - 8080:8080 \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/templates/dcae-deployment-template.json b/runtime/src/test/resources/clds/templates/dcae-deployment-template.json
new file mode 100644
index 000000000..d4891747e
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/dcae-deployment-template.json
@@ -0,0 +1,9 @@
+{
+ "serviceTypeId": "???",
+ "inputs": {
+ "aaiEnrichmentHost": "10.0.1.1",
+ "enableAAIEnrichment": "true",
+ "subscriberHostName": "10.0.11.1",
+ "publisherHostName": "10.0.11.1"
+ }
+}
diff --git a/runtime/src/test/resources/clds/templates/dcae-template.json b/runtime/src/test/resources/clds/templates/dcae-template.json
new file mode 100644
index 000000000..b76baf2d4
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/dcae-template.json
@@ -0,0 +1,26 @@
+{
+ "properties": {
+ "service_name": "",
+ "service_ids": [
+ ],
+ "vnf_ids": [
+ ],
+ "location_ids": [
+ ]
+ },
+ "template": {
+ "tca": {
+ "dcae": {
+ "inputTopic": "",
+ "outputTopic": "",
+ "closedLoopControlName": "",
+ "closedLoopEventClient": "configuration.dcae.microservice.tca.xml",
+ "policyName": "",
+ "policyScope": "DCAE",
+ "policyVersion": "v0.0.1",
+ "serviceConfigurations": {
+ }
+ }
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/templates/globalProperties.json b/runtime/src/test/resources/clds/templates/globalProperties.json
new file mode 100644
index 000000000..067063ea2
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/globalProperties.json
@@ -0,0 +1,104 @@
+{
+ "tca": {
+ "tname": "New_Set",
+ "tcaInt": "1",
+ "tcaVio": "1",
+ "eventName": {
+ "vLoadBalancer": "vLoadBalancer",
+ "vFirewallBroadcastPackets": "vFirewallBroadcastPackets",
+ "Measurement_vGMUX":"Measurement_vGMUX"
+ },
+ "fieldPathM": {
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value": "packetLossRate",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta":"receivedTotalPacketsDelta"
+ },
+ "operator": {
+ ">": "GREATER",
+ ">=": "GREATER_OR_EQUAL",
+ "=": "EQUAL",
+ "<=": "LESS_OR_EQUAL",
+ "<": "LESS"
+ },
+ "opsPolicy": {
+ "POLICY_test_X": "POLICY_test_X",
+ "POLICY_test_Y": "POLICY_test_Y"
+ },
+ "controlLoopSchemaType": {
+ "": "",
+ "VM": "VM",
+ "VNF": "VNF"
+ },
+ "closedLoopEventStatus": {
+ "": "",
+ "ONSET": "ONSET",
+ "ABATED": "ABATED"
+ }
+ },
+ "global": {
+ "actionSet": {
+ "vnfRecipe": "VNF"
+ },
+ "location": {
+ "DC1": "Data Center 1",
+ "DC2": "Data Center 2",
+ "DC3": "Data Center 3"
+ }
+ },
+ "policy": {
+ "pname": "0",
+ "timeout": 345,
+ "vnfRecipe": {
+ "": "",
+ "Restart": "Restart",
+ "Rebuild": "Rebuild",
+ "Migrate": "Migrate",
+ "HealthCheck": "Health Check",
+ "ModifyConfig": "Modify Config",
+ "VF Module Create":"VF Module Create",
+ "VF Module Delete":"VF Module Delete",
+ "Reroute":"Reroute"
+ },
+ "maxRetries": "3",
+ "retryTimeLimit": 180,
+ "resource": {
+ "vCTS": "vCTS",
+ "v3CDB": "v3CDB",
+ "vUDR": "vUDR",
+ "vCOM": "vCOM",
+ "vRAR": "vRAR",
+ "vLCS": "vLCS",
+ "vUDR-BE": "vUDR-BE",
+ "vDBE": "vDBE"
+ },
+ "parentPolicyConditions": {
+ "Failure_Retries": "Failure: Max Retries Exceeded",
+ "Failure_Timeout": "Failure: Time Limit Exceeded",
+ "Failure_Guard": "Failure: Guard",
+ "Failure_Exception": "Failure: Exception",
+ "Failure": "Failure: Other",
+ "Success": "Success"
+ }
+ },
+ "shared": {
+ "byService": {
+ "": {
+ "vf": {
+ "": ""
+ },
+ "location": {
+ "": ""
+ },
+ "alarmCondition": {
+ "": ""
+ }
+ }
+ },
+ "byVf": {
+ "": {
+ "vfc": {
+ "": ""
+ }
+ }
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/templates/sdc-decode-service_ids.json b/runtime/src/test/resources/clds/templates/sdc-decode-service_ids.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/sdc-decode-service_ids.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/templates/sdc-template.json b/runtime/src/test/resources/clds/templates/sdc-template.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/sdc-template.json
@@ -0,0 +1 @@
+{} \ No newline at end of file
diff --git a/runtime/src/test/resources/clds/templates/tca-policy-template.json b/runtime/src/test/resources/clds/templates/tca-policy-template.json
new file mode 100644
index 000000000..559aacb29
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/tca-policy-template.json
@@ -0,0 +1,19 @@
+{
+ "service": "tca_policy",
+ "version": "1.1.0",
+ "location": "SampleServiceLocation",
+ "configName": "SampleConfigName",
+ "uuid": "test",
+ "policyScope": "CLAMP",
+ "templateVersion": "OpenSource.version.1",
+ "policyName": "MicroService",
+ "description": "MicroService Policy",
+ "priority": "1",
+ "riskType": "SampleRiskType",
+ "riskLevel": "1",
+ "guard": "False",
+ "content": {
+ "tca_policy": {
+ }
+ }
+}
diff --git a/runtime/src/test/resources/clds/templates/tca-template.json b/runtime/src/test/resources/clds/templates/tca-template.json
new file mode 100644
index 000000000..892fc0d62
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/tca-template.json
@@ -0,0 +1,14 @@
+{
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "eventName": "???",
+ "controlLoopSchemaType": "VNF",
+ "policyScope": "DCAE",
+ "policyName": "???",
+ "policyVersion": "v0.0.1",
+ "thresholds": [
+ ]
+ }
+ ]
+}
diff --git a/runtime/src/test/resources/clds/templates/tca-thresholds-template.json b/runtime/src/test/resources/clds/templates/tca-thresholds-template.json
new file mode 100644
index 000000000..b67e96321
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/tca-thresholds-template.json
@@ -0,0 +1,9 @@
+{
+ "closedLoopControlName": "???",
+ "version": "1.0.2",
+ "fieldPath": "?????",
+ "thresholdValue": 0,
+ "direction": "???",
+ "severity": "MAJOR",
+ "closedLoopEventStatus": "???"
+}
diff --git a/runtime/src/test/resources/clds/templates/ui-location-default.json b/runtime/src/test/resources/clds/templates/ui-location-default.json
new file mode 100644
index 000000000..c0043d988
--- /dev/null
+++ b/runtime/src/test/resources/clds/templates/ui-location-default.json
@@ -0,0 +1,5 @@
+{
+ "DC1": "Data Center 1",
+ "DC2": "Data Center 2",
+ "DC3": "Data Center 3"
+}
diff --git a/runtime/src/test/resources/clds/util/file.xml b/runtime/src/test/resources/clds/util/file.xml
new file mode 100644
index 000000000..81560bab4
--- /dev/null
+++ b/runtime/src/test/resources/clds/util/file.xml
@@ -0,0 +1,6 @@
+<note>
+ <to>Tove</to>
+ <from>Jani</from>
+ <heading>Reminder</heading>
+ <body>Message body</body>
+</note>
diff --git a/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-wf-expected-result.json b/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-wf-expected-result.json
new file mode 100644
index 000000000..2b6493176
--- /dev/null
+++ b/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-wf-expected-result.json
@@ -0,0 +1,30 @@
+{
+ "inputs": {
+ "modify-config-properties": {
+ "type": "object",
+ "properties": {
+ "service-instance-id": {
+ "type": "string",
+ "input-param": true
+ },
+ "update-active-streams": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": "dt-data"
+ }
+ },
+ "generic-vnf.vnf-id": {
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-workflow.json b/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-workflow.json
new file mode 100644
index 000000000..115d79b1f
--- /dev/null
+++ b/runtime/src/test/resources/example/cds-response/vFW-CDS-modify-config-workflow.json
@@ -0,0 +1,78 @@
+{
+ "blueprintName": "vFW-CDS",
+ "version": "1.0.0",
+ "workFlowData": {
+ "workFlowName": "modify-config",
+ "inputs": {
+ "resolution-key": {
+ "required": true,
+ "type": "string"
+ },
+ "modify-config-properties": {
+ "description": "Dynamic PropertyDefinition for workflow(modify-config).",
+ "required": true,
+ "type": "dt-modify-config-properties"
+ }
+ }
+ },
+ "dataTypes": {
+ "dt-modify-config-properties": {
+ "description": "Dynamic DataType definition for workflow(modify-config).",
+ "version": "1.0.0",
+ "properties": {
+ "vpg_onap_private_ip_0": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ },
+ "service-instance.service-instance-id": {
+ "type": "string"
+ },
+ "vnf-id": {
+ "type": "string"
+ },
+ "data": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": "dt-data"
+ }
+ },
+ "service-instance-id": {
+ "type": "string",
+ "input-param": true
+ },
+ "update-active-streams": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": "dt-data"
+ }
+ },
+ "generic-vnf.vnf-id": {
+ "type": "string",
+ "input-param": true
+ }
+ },
+ "derived_from": "tosca.datatypes.Dynamic"
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-wf-expected-result.json b/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-wf-expected-result.json
new file mode 100644
index 000000000..07d851f38
--- /dev/null
+++ b/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-wf-expected-result.json
@@ -0,0 +1,40 @@
+{
+ "inputs": {
+ "template-prefix-with-complex-type": {
+ "type": "list",
+ "properties": {
+ "prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ }
+ },
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "private1-prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-workflow.json b/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-workflow.json
new file mode 100644
index 000000000..7f76c6cae
--- /dev/null
+++ b/runtime/src/test/resources/example/cds-response/vFW-CDS-resource-assignment-workflow.json
@@ -0,0 +1,80 @@
+{
+ "blueprintName": "vFW-CDS",
+ "version": "1.0.0",
+ "workFlowData": {
+ "workFlowName": "resource-assignment",
+ "inputs": {
+ "template-prefix": {
+ "required": true,
+ "type": "list",
+ "entry_schema": {
+ "type": "string"
+ }
+ },
+ "template-prefix-with-complex-type": {
+ "required": true,
+ "type": "list",
+ "entry_schema": {
+ "type": "dt-template-prefix-properties"
+ }
+ },
+ "resource-assignment-properties": {
+ "description": "Dynamic PropertyDefinition for workflow(resource-assignment).",
+ "required": true,
+ "type": "dt-resource-assignment-properties"
+ }
+ },
+ "outputs": {
+ "meshed-template": {
+ "type": "json",
+ "value": {
+ "get_attribute": [
+ "resource-assignment",
+ "assignment-params"
+ ]
+ }
+ }
+ }
+ },
+ "dataTypes": {
+ "dt-resource-assignment-properties": {
+ "description": "Dynamic DataType definition for workflow(resource-assignment).",
+ "version": "1.0.0",
+ "properties": {
+ "private1-prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ },
+ "derived_from": "tosca.datatypes.Dynamic"
+ },
+ "dt-template-prefix-properties": {
+ "description": "Dynamic DataType definition for workflow(template-prefix).",
+ "version": "1.0.0",
+ "properties": {
+ "prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "input-param": true,
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/dcae/inventory-response.json b/runtime/src/test/resources/example/dcae/inventory-response.json
new file mode 100644
index 000000000..1ebf068b8
--- /dev/null
+++ b/runtime/src/test/resources/example/dcae/inventory-response.json
@@ -0,0 +1,78 @@
+{
+ "links": {
+ "previousLink": {
+ "title": "string",
+ "rel": "string",
+ "uri": "string",
+ "uriBuilder": {},
+ "rels": [
+ "string"
+ ],
+ "params": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "type": "string"
+ },
+ "nextLink": {
+ "title": "string",
+ "rel": "string",
+ "uri": "string",
+ "uriBuilder": {},
+ "rels": [
+ "string"
+ ],
+ "params": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "type": "string"
+ }
+ },
+ "totalCount": 0,
+ "items": [
+ {
+ "owner": "testOwner",
+ "application": "testApplication",
+ "component": "testComponent",
+ "typeName": "testTypeName",
+ "typeVersion": 0,
+ "blueprintTemplate": "testBlueprintTemplate",
+ "serviceIds": [
+ "serviceId1",
+ "serviceId2"
+ ],
+ "vnfTypes": [
+ "vnfType1",
+ "vnfType2"
+ ],
+ "serviceLocations": [
+ "serviceLocation1",
+ "serviceLocation2"
+ ],
+ "asdcServiceId": "testAsdcServiceId",
+ "asdcResourceId": "testAsdcResourceId",
+ "asdcServiceURL": "testAsdcServiceURL",
+ "typeId": "testTypeId",
+ "selfLink": {
+ "title": "selfLinkTitle",
+ "rel": "selfLinkRel",
+ "uri": "selfLinkUri",
+ "uriBuilder": {},
+ "rels": [
+ "string"
+ ],
+ "params": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "type": "string"
+ },
+ "created": "2020-01-22T09:38:15.436Z",
+ "deactivated": "2020-01-22T09:38:15.437Z"
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/policy/pdp-deployment-testos-1_0_0.json b/runtime/src/test/resources/example/policy/pdp-deployment-testos-1_0_0.json
new file mode 100644
index 000000000..3b4a0eafc
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/pdp-deployment-testos-1_0_0.json
@@ -0,0 +1,30 @@
+{
+ "pdpGroupInfo": [
+ {
+ "pdpGroup2": {
+ "name": "pdpGroup2",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroup2",
+ "supportedPolicyTypes": [
+ {
+ "name": "org.onap.test",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap.testos",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/policy/pdp-deployment-testos-2_0_0.json b/runtime/src/test/resources/example/policy/pdp-deployment-testos-2_0_0.json
new file mode 100644
index 000000000..0040052f2
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/pdp-deployment-testos-2_0_0.json
@@ -0,0 +1,204 @@
+{
+ "pdpGroupInfo": [
+ {
+ "pdpGroup3": {
+ "name": "pdpGroup3",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroupBad",
+ "supportedPolicyTypes": [
+ {
+ "name": "org.onap.test",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.test.*",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onip.testos",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos3",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.tes",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "1.0.1"
+ },
+ {
+ "name": "org.onap.testos.new",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ },
+ "pdpGroup1": {
+ "name": "pdpGroup1",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroupBad",
+ "supportedPolicyTypes": [
+ {
+ "name": "org.onap.test",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.test.*",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onip.testos",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos3",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.tes",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "1.0.1"
+ },
+ {
+ "name": "org.onap.testos.new",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ },
+ "pdpGroup2": {
+ "name": "pdpGroup2",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroup3",
+ "supportedPolicyTypes": [
+ {
+ "name": "org.onap.test*",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap.testos",
+ "version": "2.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ },
+ {
+ "pdpType": "subGroupBad",
+ "supportedPolicyTypes": [
+ {
+ "name": "org.onap.test",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.test.*",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onip.testos",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos3",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.tes",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "2.0.0"
+ },
+ {
+ "name": "org.onap.testos",
+ "version": "1.0.1"
+ },
+ {
+ "name": "org.onap.testos.new",
+ "version": "1.0.0"
+ },
+ {
+ "name": "org.onap.",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/policy/pdp-group-multi-policies-payload.json b/runtime/src/test/resources/example/policy/pdp-group-multi-policies-payload.json
new file mode 100644
index 000000000..5e9c77f45
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/pdp-group-multi-policies-payload.json
@@ -0,0 +1,74 @@
+{
+ "groups": [
+ {
+ "name": "pdpgroup1",
+ "deploymentSubgroups": [
+ {
+ "pdpType": "pdpsubgroup1",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "policyname1",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpsubgroup1",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "policyname2",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpsubgroup1",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "policyname1",
+ "version": "2.0.0"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "pdpgroup2",
+ "deploymentSubgroups": [
+ {
+ "pdpType": "pdpsubgroup2",
+ "action": "DELETE",
+ "policies": [
+ {
+ "name": "policyname1",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpsubgroup2",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "policyname1",
+ "version": "2.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpsubgroup2",
+ "action": "DELETE",
+ "policies": [
+ {
+ "name": "policyname2",
+ "version": "1.0.0"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/runtime/src/test/resources/example/policy/pdp-group-policy-payload.json b/runtime/src/test/resources/example/policy/pdp-group-policy-payload.json
new file mode 100644
index 000000000..897fb43be
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/pdp-group-policy-payload.json
@@ -0,0 +1,54 @@
+{
+ "groups": [
+ {
+ "name": "pdpGroup2",
+ "deploymentSubgroups": [
+ {
+ "pdpType": "pdpSubgroup2",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "opLegacyPolicy",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpSubgroup2",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "opPolicy",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "pdpType": "pdpSubgroup1",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "configPolicyTest2",
+ "version": "1.0.0"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "pdpGroup1",
+ "deploymentSubgroups": [
+ {
+ "pdpType": "pdpSubgroup1",
+ "action": "POST",
+ "policies": [
+ {
+ "name": "configPolicyTest",
+ "version": "1.0.0"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/policy/policy-merger.json b/runtime/src/test/resources/example/policy/policy-merger.json
new file mode 100644
index 000000000..c3291ef71
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/policy-merger.json
@@ -0,0 +1,269 @@
+{
+ "policies": [
+ {
+ "type": "onap.policies.monitoring.tcagen2",
+ "type_version": "1.0.0",
+ "properties": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": [
+ {
+ "pdpGroup2": {
+ "name": "pdpGroup2",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroup2",
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.monitoring.tcagen2",
+ "version": "1.0.0"
+ },
+ {
+ "name": "onap.policies.controlloop.operational.common.Drools",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ }
+ }
+ ],
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ },
+ {
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "properties": {
+ "abatement": false,
+ "operations": [
+ {
+ "failure_retries": "final_failure_retries",
+ "id": "test1",
+ "failure_timeout": "final_failure_timeout",
+ "failure": "final_failure",
+ "operation": {
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": "{\"resource-assignment-properties\":{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}}"
+ },
+ "target": {
+ "entityIds": {
+ "resourceID": "Vloadbalancerms..vdns..module-3",
+ "modelInvariantId": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "modelVersionId": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "modelName": "Vloadbalancerms..vdns..module-3",
+ "modelVersion": "1",
+ "modelCustomizationId": "bafcdab0-801d-4d81-9ead-f464640a38b1"
+ },
+ "targetType": "VNF"
+ },
+ "actor": "SDNR",
+ "operation": "BandwidthOnDemand"
+ },
+ "failure_guard": "final_failure_guard",
+ "retries": 0,
+ "timeout": 0,
+ "failure_exception": "final_failure_exception",
+ "description": "test",
+ "success": "final_success"
+ }
+ ],
+ "trigger": "test1",
+ "timeout": 0,
+ "id": "LOOP_test"
+ },
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": [
+ {
+ "pdpGroup2": {
+ "name": "pdpGroup2",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "pdpType": "subGroup3",
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.monitoring.tcagen2",
+ "version": "1.0.0"
+ },
+ {
+ "name": "onap.policies.controlloop.operational.common.Drools",
+ "version": "1.0.0"
+ }
+ ],
+ "policies": [
+ {
+ "name": "org.onap.testos",
+ "version": "2.0.0"
+ },
+ {
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0"
+ }
+ ],
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 0,
+ "pdpInstances": []
+ }
+ ]
+ }
+ }
+ ],
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ },
+ {
+ "type": "onap.policies.Naming",
+ "type_version": "1.0.0",
+ "properties": {
+ "naming-models": [
+ {
+ "naming-type": "VNF",
+ "naming-recipe": "AIC_CLOUD_REGION|DELIMITER|CONSTANT|DELIMITER|TIMESTAMP",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "AIC_CLOUD_REGION"
+ },
+ {
+ "property-name": "CONSTANT",
+ "property-value": "onap-nf"
+ },
+ {
+ "property-name": "TIMESTAMP"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VNFC",
+ "naming-recipe": "VNF_NAME|DELIMITER|NFC_NAMING_CODE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "ENTIRETY",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ },
+ {
+ "property-name": "NFC_NAMING_CODE"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VF-MODULE",
+ "naming-recipe": "VNF_NAME|DELIMITER|VF_MODULE_LABEL|DELIMITER|VF_MODULE_TYPE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ },
+ {
+ "property-name": "VF_MODULE_LABEL"
+ },
+ {
+ "property-name": "VF_MODULE_TYPE"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "PRECEEDING",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ }
+ ]
+ }
+ ],
+ "policy-instance-name": "ONAP_NF_NAMING_TIMESTAMP"
+ },
+ "name": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "policy-version": "1.0.0"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/policy/single-policy-enriched.json b/runtime/src/test/resources/example/policy/single-policy-enriched.json
new file mode 100644
index 000000000..66355e589
--- /dev/null
+++ b/runtime/src/test/resources/example/policy/single-policy-enriched.json
@@ -0,0 +1,47 @@
+{
+ "type": "onap.policies.monitoring.tcagen2",
+ "type_version": "1.0.0",
+ "properties": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": {
+ "pdpGroup": "pdpGroup2",
+ "pdpSubGroup": "subGroup2"
+ },
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-bad-policy.yaml b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-bad-policy.yaml
new file mode 100644
index 000000000..bea4d2710
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-bad-policy.yaml
@@ -0,0 +1,141 @@
+# ============LICENSE_START====================================================
+# =============================================================================
+# Copyright (C) 2019-2020 AT&T Intellectual Property. 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======================================================
+#k8s-tca-gen2-v3.yaml
+
+tosca_definitions_version: cloudify_dsl_1_3
+imports:
+ - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml
+ - plugin:k8splugin?version=3.4.2
+ - plugin:clamppolicyplugin?version=1.1.0
+inputs:
+ service_name:
+ type: string
+ default: 'dcae-tcagen2'
+ log_directory:
+ type: string
+ default: "/opt/logs/dcae-analytics-tca"
+ replicas:
+ type: integer
+ description: number of instances
+ default: 1
+ spring.data.mongodb.uri:
+ type: string
+ default: "mongodb://dcae-mongohost/dcae-tcagen2"
+ tag_version:
+ type: string
+ default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.analytics.tca-gen2.dcae-analytics-tca-web:1.2.1"
+ tca.aai.password:
+ type: string
+ default: "DCAE"
+ tca.aai.url:
+ type: string
+ default: "http://aai.onap.svc.cluster.local"
+ tca.aai.username:
+ type: string
+ default: "DCAE"
+ tca_handle_in_subscribe_url:
+ type: string
+ default: "http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.VES_MEASUREMENT_OUTPUT"
+ tca_handle_out_publish_url:
+ type: string
+ default: "http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.DCAE_CL_OUTPUT"
+ tca_consumer_group:
+ type: string
+ default: "cg1"
+ policy_model_id:
+ type: string
+ default: "onap.policies.monitoring.tcagen2Bad"
+ policy_id:
+ type: string
+ default: "onap.restart.tca"
+node_templates:
+ docker.tca:
+ type: dcae.nodes.ContainerizedServiceComponent
+ relationships:
+ - target: tcagen2_policy
+ type: cloudify.relationships.depends_on
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ ports:
+ - concat: ["9091:", "0"]
+ properties:
+ application_config:
+ service_calls: []
+ streams_publishes:
+ tca_handle_out:
+ dmaap_info:
+ topic_url:
+ get_input: tca_handle_out_publish_url
+ type: message_router
+ streams_subscribes:
+ tca_handle_in:
+ dmaap_info:
+ topic_url:
+ get_input: tca_handle_in_subscribe_url
+ type: message_router
+ spring.data.mongodb.uri:
+ get_input: spring.data.mongodb.uri
+ streams_subscribes.tca_handle_in.consumer_group:
+ get_input: tca_consumer_group
+ streams_subscribes.tca_handle_in.consumer_ids[0]: c0
+ streams_subscribes.tca_handle_in.consumer_ids[1]: c1
+ streams_subscribes.tca_handle_in.message_limit: 50000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.max: 60000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.min: 30000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.step_down: 30000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.step_up: 10000
+ streams_subscribes.tca_handle_in.polling.fixed_rate: 0
+ streams_subscribes.tca_handle_in.timeout: -1
+ tca.aai.enable_enrichment: true
+ tca.aai.generic_vnf_path: aai/v11/network/generic-vnfs/generic-vnf
+ tca.aai.node_query_path: aai/v11/search/nodes-query
+ tca.aai.password:
+ get_input: tca.aai.password
+ tca.aai.url:
+ get_input: tca.aai.url
+ tca.aai.username:
+ get_input: tca.aai.username
+ tca.policy: '{"domain":"measurementsForVfScaling","metricsPerEventName":[{"eventName":"vFirewallBroadcastPackets","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"LESS_OR_EQUAL","severity":"MAJOR","closedLoopEventStatus":"ONSET"},{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":700,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"vLoadBalancer","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"Measurement_vGMUX","controlLoopSchemaType":"VNF","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"EQUAL","severity":"MAJOR","closedLoopEventStatus":"ABATED"},{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"GREATER","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]}]}'
+ tca.processing_batch_size: 10000
+ tca.enable_abatement: true
+ tca.enable_ecomp_logging: true
+ docker_config:
+ healthcheck:
+ endpoint: /actuator/health
+ interval: 30s
+ timeout: 10s
+ type: http
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory:
+ get_input: log_directory
+ tls_info:
+ use_tls: true
+ cert_directory: '/etc/tca-gen2/ssl'
+ replicas:
+ get_input: replicas
+ service_component_type: { get_input: service_name }
+ tcagen2_policy:
+ type: clamp.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
diff --git a/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-guilin.yaml b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-guilin.yaml
new file mode 100644
index 000000000..e7d967a26
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca-guilin.yaml
@@ -0,0 +1,141 @@
+# ============LICENSE_START====================================================
+# =============================================================================
+# Copyright (C) 2019-2020 AT&T Intellectual Property. 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======================================================
+#k8s-tca-gen2-v3.yaml
+
+tosca_definitions_version: cloudify_dsl_1_3
+imports:
+ - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml
+ - plugin:k8splugin?version=3.4.2
+ - plugin:clamppolicyplugin?version=1.1.0
+inputs:
+ service_name:
+ type: string
+ default: 'dcae-tcagen2'
+ log_directory:
+ type: string
+ default: "/opt/logs/dcae-analytics-tca"
+ replicas:
+ type: integer
+ description: number of instances
+ default: 1
+ spring.data.mongodb.uri:
+ type: string
+ default: "mongodb://dcae-mongohost/dcae-tcagen2"
+ tag_version:
+ type: string
+ default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.analytics.tca-gen2.dcae-analytics-tca-web:1.2.1"
+ tca.aai.password:
+ type: string
+ default: "DCAE"
+ tca.aai.url:
+ type: string
+ default: "http://aai.onap.svc.cluster.local"
+ tca.aai.username:
+ type: string
+ default: "DCAE"
+ tca_handle_in_subscribe_url:
+ type: string
+ default: "http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.VES_MEASUREMENT_OUTPUT"
+ tca_handle_out_publish_url:
+ type: string
+ default: "http://message-router.onap.svc.cluster.local:3904/events/unauthenticated.DCAE_CL_OUTPUT"
+ tca_consumer_group:
+ type: string
+ default: "cg1"
+ policy_model_id:
+ type: string
+ default: "onap.policies.monitoring.tcagen2"
+ policy_id:
+ type: string
+ default: "onap.restart.tca"
+node_templates:
+ docker.tca:
+ type: dcae.nodes.ContainerizedServiceComponent
+ relationships:
+ - target: tcagen2_policy
+ type: cloudify.relationships.depends_on
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ ports:
+ - concat: ["9091:", "0"]
+ properties:
+ application_config:
+ service_calls: []
+ streams_publishes:
+ tca_handle_out:
+ dmaap_info:
+ topic_url:
+ get_input: tca_handle_out_publish_url
+ type: message_router
+ streams_subscribes:
+ tca_handle_in:
+ dmaap_info:
+ topic_url:
+ get_input: tca_handle_in_subscribe_url
+ type: message_router
+ spring.data.mongodb.uri:
+ get_input: spring.data.mongodb.uri
+ streams_subscribes.tca_handle_in.consumer_group:
+ get_input: tca_consumer_group
+ streams_subscribes.tca_handle_in.consumer_ids[0]: c0
+ streams_subscribes.tca_handle_in.consumer_ids[1]: c1
+ streams_subscribes.tca_handle_in.message_limit: 50000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.max: 60000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.min: 30000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.step_down: 30000
+ streams_subscribes.tca_handle_in.polling.auto_adjusting.step_up: 10000
+ streams_subscribes.tca_handle_in.polling.fixed_rate: 0
+ streams_subscribes.tca_handle_in.timeout: -1
+ tca.aai.enable_enrichment: true
+ tca.aai.generic_vnf_path: aai/v11/network/generic-vnfs/generic-vnf
+ tca.aai.node_query_path: aai/v11/search/nodes-query
+ tca.aai.password:
+ get_input: tca.aai.password
+ tca.aai.url:
+ get_input: tca.aai.url
+ tca.aai.username:
+ get_input: tca.aai.username
+ tca.policy: '{"domain":"measurementsForVfScaling","metricsPerEventName":[{"eventName":"vFirewallBroadcastPackets","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"LESS_OR_EQUAL","severity":"MAJOR","closedLoopEventStatus":"ONSET"},{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":700,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"vLoadBalancer","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"Measurement_vGMUX","controlLoopSchemaType":"VNF","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"EQUAL","severity":"MAJOR","closedLoopEventStatus":"ABATED"},{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"GREATER","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]}]}'
+ tca.processing_batch_size: 10000
+ tca.enable_abatement: true
+ tca.enable_ecomp_logging: true
+ docker_config:
+ healthcheck:
+ endpoint: /actuator/health
+ interval: 30s
+ timeout: 10s
+ type: http
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory:
+ get_input: log_directory
+ tls_info:
+ use_tls: true
+ cert_directory: '/etc/tca-gen2/ssl'
+ replicas:
+ get_input: replicas
+ service_component_type: { get_input: service_name }
+ tcagen2_policy:
+ type: clamp.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
diff --git a/runtime/src/test/resources/example/sdc/blueprint-dcae/tca.yaml b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca.yaml
new file mode 100644
index 000000000..0cb9cdb68
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca.yaml
@@ -0,0 +1,105 @@
+tosca_definitions_version: cloudify_dsl_1_3
+imports:
+- http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+- https://onap.org:8443/repository/solutioning01-mte2-raw/type_files/docker/2.2.0/node-type.yaml
+- https://onap.org:8443/repository/solutioning01-mte2-raw/type_files/relationship/1.0.0/node-type.yaml
+- http://onap.org:8081/repository/solutioning01-mte2-raw/type_files/dmaap/dmaap_mr.yaml
+inputs:
+ location_id:
+ type: string
+ service_id:
+ type: string
+ policy_id:
+ type: string
+node_templates:
+ policy_0:
+ type: dcae.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id: "onap.policies.monitoring.cdap.tca.hi.lo.app"
+ cdap_host_host:
+ type: dcae.nodes.StreamingAnalytics.SelectedCDAPInfrastructure
+ properties:
+ location_id:
+ get_input: location_id
+ scn_override: cdap_broker.solutioning-central.dcae.onap.org
+ interfaces:
+ cloudify.interfaces.lifecycle: {
+ }
+ tca_tca:
+ type: dcae.nodes.MicroService.cdap
+ properties:
+ app_config:
+ appDescription: DCAE Analytics Threshold Crossing Alert Application
+ appName: dcae-tca
+ tcaSubscriberOutputStreamName: TCASubscriberOutputStream
+ tcaVESAlertsTableName: TCAVESAlertsTable
+ tcaVESAlertsTableTTLSeconds: '1728000'
+ tcaVESMessageStatusTableName: TCAVESMessageStatusTable
+ tcaVESMessageStatusTableTTLSeconds: '86400'
+ thresholdCalculatorFlowletInstances: '2'
+ app_preferences:
+ publisherContentType: application/json
+ publisherHostName: mrlocal-mtnjftle01.onap.org
+ publisherHostPort: '3905'
+ publisherMaxBatchSize: '10'
+ publisherMaxRecoveryQueueSize: '100000'
+ publisherPollingInterval: '20000'
+ publisherProtocol: https
+ publisherTopicName: org.onap.dcae.dmaap.mtnje2.DcaeTestVESPub
+ publisherUserName: test@tca.af.dcae.onap.org
+ publisherUserPassword: password
+ subscriberConsumerGroup: OpenDCAE-c12
+ subscriberConsumerId: c12
+ subscriberContentType: application/json
+ subscriberHostName: mrlocal-mtnjftle01.onap.org
+ subscriberHostPort: '3905'
+ subscriberMessageLimit: '-1'
+ subscriberPollingInterval: '20000'
+ subscriberProtocol: https
+ subscriberTimeoutMS: '-1'
+ subscriberTopicName: org.onap.dcae.dmaap.mtnje2.DcaeTestVESSub
+ subscriberUserName: test@tca.af.dcae.onap.org
+ subscriberUserPassword: password
+ tca_policy: null
+ artifact_name: dcae-analytics-tca
+ artifact_version: 1.0.0
+ connections:
+ streams_publishes: [
+ ]
+ streams_subscribes: [
+ ]
+ jar_url: http://somejar
+ location_id:
+ get_input: location_id
+ namespace: cdap_tca_hi_lo
+ programs:
+ - program_id: TCAVESCollectorFlow
+ program_type: flows
+ - program_id: TCADMaaPMRSubscriberWorker
+ program_type: workers
+ - program_id: TCADMaaPMRPublisherWorker
+ program_type: workers
+ service_component_type: cdap_app_tca
+ service_id:
+ get_input: service_id
+ streamname: TCASubscriberOutputStream
+ relationships:
+ - target: topic0
+ type: dcae.relationships.subscribe_to_events
+ - target: topic1
+ type: dcae.relationships.publish_events
+ - target: cdap_host_host
+ type: dcae.relationships.component_contained_in
+ - target: policy_0
+ type: dcae.relationships.depends_on
+ topic0:
+ type: dcae.nodes.Topic
+ properties:
+ topic_name: ''
+ topic1:
+ type: dcae.nodes.Topic
+ properties:
+ topic_name: ''
+
diff --git a/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_2.yaml b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_2.yaml
new file mode 100644
index 000000000..00ebfe7fe
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_2.yaml
@@ -0,0 +1,174 @@
+#
+# ============LICENSE_START====================================================
+# =============================================================================
+# Copyright (c) 2019 AT&T Intellectual Property. 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======================================================
+
+tosca_definitions_version: cloudify_dsl_1_3
+
+description: >
+ This blueprint deploys/manages the TCA module as a Docker container
+
+imports:
+ - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/k8splugin/1.4.12/k8splugin_types.yaml
+# - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/dcaepolicyplugin/2.3.0/dcaepolicyplugin_types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/clamppolicyplugin/1.0.0/clamppolicyplugin_types.yaml
+inputs:
+ aaiEnrichmentHost:
+ type: string
+ default: "aai.onap.svc.cluster.local"
+ aaiEnrichmentPort:
+ type: string
+ default: "8443"
+ enableAAIEnrichment:
+ type: string
+ default: true
+ dmaap_host:
+ type: string
+ default: message-router.onap
+ dmaap_port:
+ type: string
+ default: "3904"
+ enableRedisCaching:
+ type: string
+ default: false
+ redisHosts:
+ type: string
+ default: dcae-redis.onap.svc.cluster.local:6379
+ tag_version:
+ type: string
+ default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.1.1"
+ consul_host:
+ type: string
+ default: consul-server.onap
+ consul_port:
+ type: string
+ default: "8500"
+ cbs_host:
+ type: string
+ default: "config-binding-servicel"
+ cbs_port:
+ type: string
+ default: "10000"
+ policy_id:
+ type: string
+ default: "onap.restart.tca"
+ external_port:
+ type: string
+ description: Kubernetes node port on which CDAPgui is exposed
+ default: "32012"
+ policy_model_id:
+ type: string
+ default: "onap.policies.monitoring.cdap.tca.hi.lo.app"
+node_templates:
+ tca_k8s:
+ type: dcae.nodes.ContainerizedServiceComponent
+ relationships:
+ - target: tca_policy
+ type: cloudify.relationships.depends_on
+ properties:
+ service_component_type: 'dcaegen2-analytics-tca'
+ application_config: {}
+ docker_config: {}
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory: "/opt/app/TCAnalytics/logs"
+ application_config:
+ app_config:
+ appDescription: DCAE Analytics Threshold Crossing Alert Application
+ appName: dcae-tca
+ tcaAlertsAbatementTableName: TCAAlertsAbatementTable
+ tcaAlertsAbatementTableTTLSeconds: '1728000'
+ tcaSubscriberOutputStreamName: TCASubscriberOutputStream
+ tcaVESAlertsTableName: TCAVESAlertsTable
+ tcaVESAlertsTableTTLSeconds: '1728000'
+ tcaVESMessageStatusTableName: TCAVESMessageStatusTable
+ tcaVESMessageStatusTableTTLSeconds: '86400'
+ thresholdCalculatorFlowletInstances: '2'
+ app_preferences:
+ aaiEnrichmentHost:
+ get_input: aaiEnrichmentHost
+ aaiEnrichmentIgnoreSSLCertificateErrors: 'true'
+ aaiEnrichmentPortNumber: '8443'
+ aaiEnrichmentProtocol: https
+ aaiEnrichmentUserName: dcae@dcae.onap.org
+ aaiEnrichmentUserPassword: demo123456!
+ aaiVMEnrichmentAPIPath: /aai/v11/search/nodes-query
+ aaiVNFEnrichmentAPIPath: /aai/v11/network/generic-vnfs/generic-vnf
+ enableAAIEnrichment:
+ get_input: enableAAIEnrichment
+ enableRedisCaching:
+ get_input: enableRedisCaching
+ redisHosts:
+ get_input: redisHosts
+ enableAlertCEFFormat: 'false'
+ publisherContentType: application/json
+ publisherHostName:
+ get_input: dmaap_host
+ publisherHostPort:
+ get_input: dmaap_port
+ publisherMaxBatchSize: '1'
+ publisherMaxRecoveryQueueSize: '100000'
+ publisherPollingInterval: '20000'
+ publisherProtocol: http
+ publisherTopicName: unauthenticated.DCAE_CL_OUTPUT
+ subscriberConsumerGroup: OpenDCAE-clamp
+ subscriberConsumerId: c12
+ subscriberContentType: application/json
+ subscriberHostName:
+ get_input: dmaap_host
+ subscriberHostPort:
+ get_input: dmaap_port
+ subscriberMessageLimit: '-1'
+ subscriberPollingInterval: '30000'
+ subscriberProtocol: http
+ subscriberTimeoutMS: '-1'
+ subscriberTopicName: unauthenticated.VES_MEASUREMENT_OUTPUT
+# tca_policy: '{"domain":"measurementsForVfScaling","metricsPerEventName":[{"eventName":"vFirewallBroadcastPackets","controlLoopSchemaType":"VNF","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"LESS_OR_EQUAL","severity":"MAJOR","closedLoopEventStatus":"ONSET"},{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":700,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"vLoadBalancer","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"Measurement_vGMUX","controlLoopSchemaType":"VNF","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"EQUAL","severity":"MAJOR","closedLoopEventStatus":"ABATED"},{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"GREATER","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]}]}'
+ service_component_type: dcaegen2-analytics_tca
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ DMAAPHOST:
+ { get_input: dmaap_host }
+ DMAAPPORT:
+ { get_input: dmaap_port }
+ DMAAPPUBTOPIC: "unauthenticated.DCAE_CL_OUTPUT"
+ DMAAPSUBTOPIC: "unauthenticated.VES_MEASUREMENT_OUTPUT"
+ AAIHOST:
+ { get_input: aaiEnrichmentHost }
+ AAIPORT:
+ { get_input: aaiEnrichmentPort }
+ CONSUL_HOST:
+ { get_input: consul_host }
+ CONSUL_PORT:
+ { get_input: consul_port }
+ CBS_HOST:
+ { get_input: cbs_host }
+ CBS_PORT:
+ { get_input: cbs_port }
+ CONFIG_BINDING_SERVICE: "config_binding_service"
+ ports:
+ - concat: ["11011:", { get_input: external_port }]
+ tca_policy:
+ type: clamp.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id: "onap.policies.monitoring.cdap.tca.hi.lo.app"
diff --git a/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_3.yaml b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_3.yaml
new file mode 100644
index 000000000..929f36367
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/blueprint-dcae/tca_3.yaml
@@ -0,0 +1,171 @@
+#
+# ============LICENSE_START====================================================
+# =============================================================================
+# Copyright (c) 2019 AT&T Intellectual Property. 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======================================================
+
+tosca_definitions_version: cloudify_dsl_1_3
+
+description: >
+ This blueprint deploys/manages the TCA module as a Docker container
+
+imports:
+ - https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml
+ - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/k8splugin/1.7.2/k8splugin_types.yaml"
+ - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/clamppolicyplugin/1.1.0/clamppolicyplugin_types.yaml"
+inputs:
+ aaiEnrichmentHost:
+ type: string
+ default: "aai.onap.svc.cluster.local"
+ aaiEnrichmentPort:
+ type: string
+ default: "8443"
+ enableAAIEnrichment:
+ type: string
+ default: "true"
+ dmaap_host:
+ type: string
+ default: "message-router.onap.svc.cluster.local"
+ dmaap_port:
+ type: string
+ default: "3904"
+ enableRedisCaching:
+ type: string
+ default: "false"
+ redisHosts:
+ type: string
+ default: "dcae-redis.onap.svc.cluster.local:6379"
+ tag_version:
+ type: string
+ default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.2.2"
+ consul_host:
+ type: string
+ default: "consul-server.onap"
+ consul_port:
+ type: string
+ default: "8500"
+ cbs_host:
+ type: string
+ default: "config-binding-service"
+ cbs_port:
+ type: string
+ default: "10000"
+ policy_id:
+ type: string
+ default: "onap.restart.tca"
+ external_port:
+ type: string
+ description: Kubernetes node port on which CDAPgui is exposed
+ default: "32012"
+ policy_model_id:
+ type: string
+ default: "onap.policies.monitoring.cdap.tca.hi.lo.app"
+node_templates:
+ tca_k8s:
+ type: dcae.nodes.ContainerizedServiceComponent
+ relationships:
+ - target: tca_policy
+ type: cloudify.relationships.depends_on
+ properties:
+ service_component_type: 'dcaegen2-analytics-tca'
+ application_config: {}
+ docker_config: {}
+ image:
+ get_input: tag_version
+ log_info:
+ log_directory: "/opt/app/TCAnalytics/logs"
+ application_config:
+ app_config:
+ appDescription: DCAE Analytics Threshold Crossing Alert Application
+ appName: dcae-tca
+ tcaAlertsAbatementTableName: TCAAlertsAbatementTable
+ tcaAlertsAbatementTableTTLSeconds: '1728000'
+ tcaSubscriberOutputStreamName: TCASubscriberOutputStream
+ tcaVESAlertsTableName: TCAVESAlertsTable
+ tcaVESAlertsTableTTLSeconds: '1728000'
+ tcaVESMessageStatusTableName: TCAVESMessageStatusTable
+ tcaVESMessageStatusTableTTLSeconds: '86400'
+ thresholdCalculatorFlowletInstances: '2'
+ app_preferences:
+ aaiEnrichmentHost:
+ get_input: aaiEnrichmentHost
+ aaiEnrichmentIgnoreSSLCertificateErrors: 'true'
+ aaiEnrichmentPortNumber: '8443'
+ aaiEnrichmentProtocol: https
+ aaiEnrichmentUserName: dcae@dcae.onap.org
+ aaiEnrichmentUserPassword: demo123456!
+ aaiVMEnrichmentAPIPath: /aai/v11/search/nodes-query
+ aaiVNFEnrichmentAPIPath: /aai/v11/network/generic-vnfs/generic-vnf
+ enableAAIEnrichment:
+ get_input: enableAAIEnrichment
+ enableRedisCaching:
+ get_input: enableRedisCaching
+ redisHosts:
+ get_input: redisHosts
+ enableAlertCEFFormat: 'false'
+ publisherContentType: application/json
+ publisherHostName:
+ get_input: dmaap_host
+ publisherHostPort:
+ get_input: dmaap_port
+ publisherMaxBatchSize: '1'
+ publisherMaxRecoveryQueueSize: '100000'
+ publisherPollingInterval: '20000'
+ publisherProtocol: http
+ publisherTopicName: unauthenticated.DCAE_CL_OUTPUT
+ subscriberConsumerGroup: OpenDCAE-clamp
+ subscriberConsumerId: c12
+ subscriberContentType: application/json
+ subscriberHostName:
+ get_input: dmaap_host
+ subscriberHostPort:
+ get_input: dmaap_port
+ subscriberMessageLimit: '-1'
+ subscriberPollingInterval: '30000'
+ subscriberProtocol: http
+ subscriberTimeoutMS: '-1'
+ subscriberTopicName: unauthenticated.VES_MEASUREMENT_OUTPUT
+ #tca_policy: '{"domain":"measurementsForVfScaling","metricsPerEventName":[{"eventName":"vFirewallBroadcastPackets","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"LESS_OR_EQUAL","severity":"MAJOR","closedLoopEventStatus":"ONSET"},{"closedLoopControlName":"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":700,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"vLoadBalancer","controlLoopSchemaType":"VM","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta","thresholdValue":300,"direction":"GREATER_OR_EQUAL","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]},{"eventName":"Measurement_vGMUX","controlLoopSchemaType":"VNF","policyScope":"DCAE","policyName":"DCAE.Config_tca-hi-lo","policyVersion":"v0.0.1","thresholds":[{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"EQUAL","severity":"MAJOR","closedLoopEventStatus":"ABATED"},{"closedLoopControlName":"ControlLoop-vCPE-48f0c2c3-a172-4192-9ae3-052274181b6e","version":"1.0.2","fieldPath":"$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value","thresholdValue":0,"direction":"GREATER","severity":"CRITICAL","closedLoopEventStatus":"ONSET"}]}]}'
+ tca_policy: ''
+ service_component_type: dcaegen2-analytics_tca
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ DMAAPHOST:
+ { get_input: dmaap_host }
+ DMAAPPORT: "3904"
+ DMAAPPUBTOPIC: "unauthenticated.DCAE_CL_OUTPUT"
+ DMAAPSUBTOPIC: "unauthenticated.VES_MEASUREMENT_OUTPUT"
+ AAIHOST:
+ { get_input: aaiEnrichmentHost }
+ AAIPORT: "8443"
+ CONSUL_HOST:
+ { get_input: consul_host }
+ CONSUL_PORT: "8500"
+ CBS_HOST:
+ { get_input: cbs_host }
+ CBS_PORT: "10000"
+ CONFIG_BINDING_SERVICE: "config_binding_service"
+ ports:
+ - concat: ["11011:", { get_input: external_port }]
+ tca_policy:
+ type: clamp.nodes.policy
+ properties:
+ policy_id:
+ get_input: policy_id
+ policy_model_id:
+ get_input: policy_model_id
diff --git a/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-multi-blueprints.json b/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-multi-blueprints.json
new file mode 100644
index 000000000..58f4cf3b2
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-multi-blueprints.json
@@ -0,0 +1,43 @@
+{
+ "dcaeDeployParameters": {
+ "testName1": {
+ "location_id": "",
+ "service_id": "",
+ "policy_id": "testName1"
+ },
+ "testName2": {
+ "aaiEnrichmentHost": "aai.onap.svc.cluster.local",
+ "aaiEnrichmentPort": "8443",
+ "enableAAIEnrichment": true,
+ "dmaap_host": "message-router.onap",
+ "dmaap_port": "3904",
+ "enableRedisCaching": false,
+ "redisHosts": "dcae-redis.onap.svc.cluster.local:6379",
+ "tag_version": "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.1.1",
+ "consul_host": "consul-server.onap",
+ "consul_port": "8500",
+ "cbs_host": "config-binding-servicel",
+ "cbs_port": "10000",
+ "external_port": "32012",
+ "policy_model_id": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "policy_id": "testName2"
+ },
+ "testName3": {
+ "aaiEnrichmentHost": "aai.onap.svc.cluster.local",
+ "aaiEnrichmentPort": "8443",
+ "enableAAIEnrichment": "true",
+ "dmaap_host": "message-router.onap.svc.cluster.local",
+ "dmaap_port": "3904",
+ "enableRedisCaching": "false",
+ "redisHosts": "dcae-redis.onap.svc.cluster.local:6379",
+ "tag_version": "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tca-cdap-container:1.2.2",
+ "consul_host": "consul-server.onap",
+ "consul_port": "8500",
+ "cbs_host": "config-binding-service",
+ "cbs_port": "10000",
+ "external_port": "32012",
+ "policy_model_id": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "policy_id": "testName3"
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-single-blueprint.json b/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-single-blueprint.json
new file mode 100644
index 000000000..7140a4748
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/expected-result/deployment-parameters-single-blueprint.json
@@ -0,0 +1,9 @@
+{
+ "dcaeDeployParameters": {
+ "uniqueBlueprintParameters": {
+ "location_id": "",
+ "service_id": "",
+ "policy_id": "testName1"
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/example/sdc/expected-result/policy-data.yaml b/runtime/src/test/resources/example/sdc/expected-result/policy-data.yaml
new file mode 100644
index 000000000..3cf5e975c
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/expected-result/policy-data.yaml
@@ -0,0 +1,2859 @@
+#
+# 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.
+#
+tosca_definitions_version: tosca_simple_yaml_1_1
+imports:
+- data.yml
+policy_types:
+ tosca.policies.Root:
+ description: The TOSCA Policy Type all other TOSCA Policy Types derive from
+ tosca.policies.Placement:
+ derived_from: tosca.policies.Root
+ description: The TOSCA Policy Type definition that is used to govern placement of TOSCA nodes or groups of nodes.
+ tosca.policies.Scaling:
+ derived_from: tosca.policies.Root
+ description: The TOSCA Policy Type definition that is used to govern scaling of TOSCA nodes or groups of nodes.
+ tosca.policies.Update:
+ derived_from: tosca.policies.Root
+ description: The TOSCA Policy Type definition that is used to govern update of TOSCA nodes or groups of nodes.
+ tosca.policies.Performance:
+ derived_from: tosca.policies.Root
+ description: The TOSCA Policy Type definition that is used to declare performance requirements for TOSCA nodes or groups of nodes.
+ org.openecomp.policies.placement.Antilocate:
+ derived_from: tosca.policies.Placement
+ description: My placement policy for separation based upon container type value
+ properties:
+ name:
+ type: string
+ description: The name of the policy
+ required: false
+ status: SUPPORTED
+ container_type:
+ type: string
+ description: container type
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - host
+ - region
+ - compute
+ org.openecomp.policies.placement.Colocate:
+ derived_from: tosca.policies.Placement
+ description: Keep associated nodes (groups of nodes) based upon affinity value
+ properties:
+ name:
+ type: string
+ description: The name of the policy
+ required: false
+ status: SUPPORTED
+ affinity:
+ type: string
+ description: affinity
+ required: true
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - host
+ - region
+ - compute
+ org.openecomp.policies.placement.valet.Diversity:
+ derived_from: tosca.policies.Placement
+ description: Valet Diversity
+ properties:
+ level:
+ type: string
+ description: diversity
+ required: false
+ default: host
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - host
+ - rack
+ org.openecomp.policies.placement.valet.Exclusivity:
+ derived_from: tosca.policies.Placement
+ description: Valet Exclusivity
+ properties:
+ level:
+ type: string
+ description: exclusivity
+ required: false
+ default: host
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - host
+ - rack
+ org.openecomp.policies.placement.valet.Affinity:
+ derived_from: tosca.policies.Placement
+ description: Valet Affinity
+ properties:
+ level:
+ type: string
+ description: affinity
+ required: false
+ default: host
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - host
+ - rack
+ org.openecomp.policies.scaling.Fixed:
+ derived_from: tosca.policies.Scaling
+ properties:
+ quantity:
+ description: the exact number of instances to keep up
+ type: integer
+ required: true
+ org.openecomp.policies.External:
+ derived_from: tosca.policies.Root
+ description: externally managed policy (for example, type="network assignment", source="Policy Manager", name="route target")
+ properties:
+ source:
+ type: string
+ description: The name of the server that exposes the policy with predefined type and name.
+ required: false
+ type:
+ type: string
+ description: The type (category) of the policy same as it is defined in the source.
+ required: false
+ name:
+ type: string
+ description: The name of the policy, that related to specific type, same as it is defined in the source.
+ required: false
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ description: A base policy type for all policies that governs monitoring provisioning
+ onap.policies.monitoring.cdap.tca.hi.lo.app:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ properties:
+ tca_policy:
+ type: map
+ description: TCA Policy JSON
+ entry_schema:
+ type: onap.datatypes.monitoring.tca_policy
+ tosca.policies.nfv.InstantiationLevels:
+ derived_from: tosca.policies.Root
+ description: The InstantiationLevels type is a policy type representing all the instantiation levels of resources to be instantiated within a deployment flavour and including default instantiation level in term of the number of VNFC instances to be created as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ levels:
+ type: map
+ description: Describes the various levels of resources that can be used to instantiate the VNF using this flavour.
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.InstantiationLevel
+ default_level:
+ type: string
+ description: The default instantiation level for this flavour.
+ required: false
+ tosca.policies.nfv.VduInstantiationLevels:
+ derived_from: tosca.policies.Root
+ description: The VduInstantiationLevels type is a policy type representing all the instantiation levels of resources to be instantiated within a deployment flavour in term of the number of VNFC instances to be created from each vdu.Compute. as defined in ETSI GS NFV-IFA 011 [1]
+ properties:
+ levels:
+ type: map
+ description: Describes the Vdu.Compute levels of resources that can be used to instantiate the VNF using this flavour
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.VduLevel
+ targets:
+ - tosca.nodes.nfv.Vdu.Compute
+ tosca.policies.nfv.VirtualLinkInstantiationLevels:
+ derived_from: tosca.policies.Root
+ description: The VirtualLinkInstantiationLevels type is a policy type representing all the instantiation levels of virtual link resources to be instantiated within a deployment flavour as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ levels:
+ type: map
+ description: Describes the virtual link levels of resources that can be used to instantiate the VNF using this flavour.
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.VirtualLinkBitrateLevel
+ targets:
+ - tosca.nodes.nfv.VnfVirtualLink
+ tosca.policies.nfv.ScalingAspects:
+ derived_from: tosca.policies.Root
+ description: The ScalingAspects type is a policy type representing the scaling aspects used for horizontal scaling as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ aspects:
+ type: map
+ description: Describe maximum scale level for total number of scaling steps that can be applied to a particular aspect
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.ScalingAspect
+ tosca.policies.nfv.VduScalingAspectDeltas:
+ derived_from: tosca.policies.Root
+ description: The VduScalingAspectDeltas type is a policy type representing the Vdu.Compute detail of an aspect deltas used for horizontal scaling, as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ aspect:
+ type: string
+ description: Represents the scaling aspect to which this policy applies
+ required: true
+ deltas:
+ type: map
+ description: Describes the Vdu.Compute scaling deltas to be applied for every scaling steps of a particular aspect.
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.VduLevel
+ targets:
+ - tosca.nodes.nfv.Vdu.Compute
+ tosca.policies.nfv.VirtualLinkBitrateScalingAspectDeltas:
+ derived_from: tosca.policies.Root
+ description: The VirtualLinkBitrateScalingAspectDeltas type is a policy type representing the VnfVirtualLink detail of an aspect deltas used for horizontal scaling, as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ aspect:
+ type: string
+ description: Represents the scaling aspect to which this policy applies.
+ required: true
+ deltas:
+ type: map
+ description: Describes the VnfVirtualLink scaling deltas to be applied for every scaling steps of a particular aspect.
+ required: true
+ entry_schema:
+ type: tosca.datatypes.nfv.VirtualLinkBitrateLevel
+ targets:
+ - tosca.nodes.nfv.VnfVirtualLink
+ tosca.policies.nfv.VduInitialDelta:
+ derived_from: tosca.policies.Root
+ description: The VduInitialDelta type is a policy type representing the Vdu.Compute detail of an initial delta used for horizontal scaling, as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ initial_delta:
+ type: tosca.datatypes.nfv.VduLevel
+ description: Represents the initial minimum size of the VNF.
+ required: true
+ targets:
+ - tosca.nodes.nfv.Vdu.Compute
+ tosca.policies.nfv.VirtualLinkBitrateInitialDelta:
+ derived_from: tosca.policies.Root
+ description: The VirtualLinkBitrateInitialDelta type is a policy type representing the VnfVirtualLink detail of an initial deltas used for horizontal scaling, as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ initial_delta:
+ type: tosca.datatypes.nfv.VirtualLinkBitrateLevel
+ description: Represents the initial minimum size of the VNF.
+ required: true
+ targets:
+ - tosca.nodes.nfv.VnfVirtualLink
+ tosca.policies.nfv.SecurityGroupRule:
+ derived_from: tosca.policies.Root
+ description: The SecurityGroupRule type is a policy type specified the matching criteria for the ingress and/or egress traffic to/from visited connection points as defined in ETSI GS NFV-IFA 011 [1].
+ properties:
+ description:
+ type: string
+ description: Human readable description of the security group rule.
+ required: false
+ direction:
+ type: string
+ description: The direction in which the security group rule is applied. The direction of 'ingress' or 'egress' is specified against the associated CP. I.e., 'ingress' means the packets entering a CP, while 'egress' means the packets sent out of a CP.
+ required: false
+ constraints:
+ - valid_values:
+ - ingress
+ - egress
+ default: ingress
+ ether_type:
+ type: string
+ description: Indicates the protocol carried over the Ethernet layer.
+ required: false
+ constraints:
+ - valid_values:
+ - ipv4
+ - ipv6
+ default: ipv4
+ protocol:
+ type: string
+ description: Indicates the protocol carried over the IP layer. Permitted values include any protocol defined in the IANA protocol registry, e.g. TCP, UDP, ICMP, etc.
+ required: false
+ constraints:
+ - valid_values:
+ - hopopt
+ - icmp
+ - igmp
+ - ggp
+ - ipv4
+ - st
+ - tcp
+ - cbt
+ - egp
+ - igp
+ - bbn_rcc_mon
+ - nvp_ii
+ - pup
+ - argus
+ - emcon
+ - xnet
+ - chaos
+ - udp
+ - mux
+ - dcn_meas
+ - hmp
+ - prm
+ - xns_idp
+ - trunk_1
+ - trunk_2
+ - leaf_1
+ - leaf_2
+ - rdp
+ - irtp
+ - iso_tp4
+ - netblt
+ - mfe_nsp
+ - merit_inp
+ - dccp
+ - 3pc
+ - idpr
+ - xtp
+ - ddp
+ - idpr_cmtp
+ - tp++
+ - il
+ - ipv6
+ - sdrp
+ - ipv6_route
+ - ipv6_frag
+ - idrp
+ - rsvp
+ - gre
+ - dsr
+ - bna
+ - esp
+ - ah
+ - i_nlsp
+ - swipe
+ - narp
+ - mobile
+ - tlsp
+ - skip
+ - ipv6_icmp
+ - ipv6_no_nxt
+ - ipv6_opts
+ - cftp
+ - sat_expak
+ - kryptolan
+ - rvd
+ - ippc
+ - sat_mon
+ - visa
+ - ipcv
+ - cpnx
+ - cphb
+ - wsn
+ - pvp
+ - br_sat_mon
+ - sun_nd
+ - wb_mon
+ - wb_expak
+ - iso_ip
+ - vmtp
+ - secure_vmtp
+ - vines
+ - ttp
+ - iptm
+ - nsfnet_igp
+ - dgp
+ - tcf
+ - eigrp
+ - ospfigp
+ - sprite_rpc
+ - larp
+ - mtp
+ - ax.25
+ - ipip
+ - micp
+ - scc_sp
+ - etherip
+ - encap
+ - gmtp
+ - ifmp
+ - pnni
+ - pim
+ - aris
+ - scps
+ - qnx
+ - a/n
+ - ip_comp
+ - snp
+ - compaq_peer
+ - ipx_in_ip
+ - vrrp
+ - pgm
+ - l2tp
+ - ddx
+ - iatp
+ - stp
+ - srp
+ - uti
+ - smp
+ - sm
+ - ptp
+ - isis
+ - fire
+ - crtp
+ - crudp
+ - sscopmce
+ - iplt
+ - sps
+ - pipe
+ - sctp
+ - fc
+ - rsvp_e2e_ignore
+ - mobility
+ - udp_lite
+ - mpls_in_ip
+ - manet
+ - hip
+ - shim6
+ - wesp
+ - rohc
+ default: tcp
+ port_range_min:
+ type: integer
+ description: Indicates minimum port number in the range that is matched by the security group rule. If a value is provided at design-time, this value may be overridden at run-time based on other deployment requirements or constraints.
+ required: false
+ constraints:
+ - greater_or_equal: 0
+ - less_or_equal: 65535
+ default: 0
+ port_range_max:
+ type: integer
+ description: Indicates maximum port number in the range that is matched by the security group rule. If a value is provided at design-time, this value may be overridden at run-time based on other deployment requirements or constraints.
+ required: false
+ constraints:
+ - greater_or_equal: 0
+ - less_or_equal: 65535
+ default: 65535
+ targets:
+ - tosca.nodes.nfv.VduCp
+ - tosca.nodes.nfv.VnfExtCp
+ tosca.policies.nfv.SupportedVnfInterface:
+ derived_from: tosca.policies.Root
+ description: this policy type represents interfaces produced by a VNF, the details to access them and the applicable connection points to use to access these interfaces
+ properties:
+ interface_name:
+ type: string
+ description: Identifies an interface produced by the VNF.
+ required: true
+ constraints:
+ - valid_values:
+ - vnf_indicator
+ - vnf_configuration
+ details:
+ type: tosca.datatypes.nfv.InterfaceDetails
+ description: Provide additional data to access the interface endpoint
+ required: false
+ targets:
+ - tosca.nodes.nfv.VnfExtCp
+ - tosca.nodes.nfv.VduCp
+data_types:
+ tosca.datatypes.Root:
+ description: The TOSCA root Data Type all other TOSCA base Data Types derive from
+ integer:
+ derived_from: tosca.datatypes.Root
+ string:
+ derived_from: tosca.datatypes.Root
+ boolean:
+ derived_from: tosca.datatypes.Root
+ float:
+ derived_from: tosca.datatypes.Root
+ list:
+ derived_from: tosca.datatypes.Root
+ map:
+ derived_from: tosca.datatypes.Root
+ json:
+ derived_from: tosca.datatypes.Root
+ scalar-unit:
+ derived_from: tosca.datatypes.Root
+ scalar-unit.size:
+ derived_from: scalar-unit
+ scalar-unit.time:
+ derived_from: scalar-unit
+ scalar-unit.frequency:
+ derived_from: scalar-unit
+ tosca.datatypes.Credential:
+ derived_from: tosca.datatypes.Root
+ properties:
+ protocol:
+ type: string
+ required: false
+ token_type:
+ type: string
+ default: password
+ token:
+ type: string
+ keys:
+ type: map
+ required: false
+ entry_schema:
+ type: string
+ user:
+ type: string
+ required: false
+ org.openecomp.datatypes.PortMirroringConnectionPointDescription:
+ derived_from: tosca.datatypes.Root
+ properties:
+ nf_naming_code:
+ type: string
+ nfc_naming_code:
+ type: string
+ network_role:
+ type: string
+ pps_capacity:
+ type: string
+ nf_type:
+ type: string
+ description: deprecated
+ nfc_type:
+ type: string
+ description: deprecated
+ tosca.datatypes.TimeInterval:
+ derived_from: tosca.datatypes.Root
+ properties:
+ start_time:
+ type: timestamp
+ required: true
+ end_time:
+ type: timestamp
+ required: true
+ tosca.datatypes.network.NetworkInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ network_name:
+ type: string
+ network_id:
+ type: string
+ addresses:
+ type: list
+ entry_schema:
+ type: string
+ tosca.datatypes.network.PortInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ port_name:
+ type: string
+ port_id:
+ type: string
+ network_id:
+ type: string
+ mac_address:
+ type: string
+ addresses:
+ type: list
+ entry_schema:
+ type: string
+ tosca.datatypes.network.PortDef:
+ derived_from: integer
+ constraints:
+ - in_range:
+ - 1
+ - 65535
+ tosca.datatypes.network.PortSpec:
+ derived_from: tosca.datatypes.Root
+ properties:
+ protocol:
+ type: string
+ required: true
+ default: tcp
+ constraints:
+ - valid_values:
+ - udp
+ - tcp
+ - igmp
+ target:
+ type: tosca.datatypes.network.PortDef
+ target_range:
+ type: range
+ constraints:
+ - in_range:
+ - 1
+ - 65535
+ source:
+ type: tosca.datatypes.network.PortDef
+ source_range:
+ type: range
+ constraints:
+ - in_range:
+ - 1
+ - 65535
+ org.openecomp.datatypes.heat.network.AddressPair:
+ derived_from: tosca.datatypes.Root
+ description: MAC/IP address pairs
+ properties:
+ mac_address:
+ type: string
+ description: MAC address
+ required: false
+ status: SUPPORTED
+ ip_address:
+ type: string
+ description: IP address
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.subnet.HostRoute:
+ derived_from: tosca.datatypes.Root
+ description: Host route info for the subnet
+ properties:
+ destination:
+ type: string
+ description: The destination for static route
+ required: false
+ status: SUPPORTED
+ nexthop:
+ type: string
+ description: The next hop for the destination
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.AllocationPool:
+ derived_from: tosca.datatypes.Root
+ description: The start and end addresses for the allocation pool
+ properties:
+ start:
+ type: string
+ description: Start address for the allocation pool
+ required: false
+ status: SUPPORTED
+ end:
+ type: string
+ description: End address for the allocation pool
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.neutron.Subnet:
+ derived_from: tosca.datatypes.Root
+ description: A subnet represents an IP address block that can be used for assigning IP addresses to virtual instances
+ properties:
+ tenant_id:
+ type: string
+ description: The ID of the tenant who owns the network
+ required: false
+ status: SUPPORTED
+ enable_dhcp:
+ type: boolean
+ description: Set to true if DHCP is enabled and false if DHCP is disabled
+ required: false
+ default: true
+ status: SUPPORTED
+ ipv6_address_mode:
+ type: string
+ description: IPv6 address mode
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - dhcpv6-stateful
+ - dhcpv6-stateless
+ - slaac
+ ipv6_ra_mode:
+ type: string
+ description: IPv6 RA (Router Advertisement) mode
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - dhcpv6-stateful
+ - dhcpv6-stateless
+ - slaac
+ value_specs:
+ type: map
+ description: Extra parameters to include in the request
+ required: false
+ default: {}
+ status: SUPPORTED
+ entry_schema:
+ type: string
+ allocation_pools:
+ type: list
+ description: The start and end addresses for the allocation pools
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.network.AllocationPool
+ subnetpool:
+ type: string
+ description: The name or ID of the subnet pool
+ required: false
+ status: SUPPORTED
+ dns_nameservers:
+ type: list
+ description: A specified set of DNS name servers to be used
+ required: false
+ default: []
+ status: SUPPORTED
+ entry_schema:
+ type: string
+ host_routes:
+ type: list
+ description: The gateway IP address
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.network.subnet.HostRoute
+ ip_version:
+ type: integer
+ description: The gateway IP address
+ required: false
+ default: 4
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - '4'
+ - '6'
+ name:
+ type: string
+ description: The name of the subnet
+ required: false
+ status: SUPPORTED
+ prefixlen:
+ type: integer
+ description: Prefix length for subnet allocation from subnet pool
+ required: false
+ status: SUPPORTED
+ constraints:
+ - greater_or_equal: 0
+ cidr:
+ type: string
+ description: The CIDR
+ required: false
+ status: SUPPORTED
+ gateway_ip:
+ type: string
+ description: The gateway IP address
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.novaServer.network.PortExtraProperties:
+ derived_from: tosca.datatypes.Root
+ description: Nova server network expand properties for port
+ properties:
+ port_security_enabled:
+ type: boolean
+ description: Flag to enable/disable port security on the port
+ required: false
+ status: SUPPORTED
+ mac_address:
+ type: string
+ description: MAC address to give to this port
+ required: false
+ status: SUPPORTED
+ admin_state_up:
+ type: boolean
+ description: The administrative state of this port
+ required: false
+ default: true
+ status: SUPPORTED
+ qos_policy:
+ type: string
+ description: The name or ID of QoS policy to attach to this port
+ required: false
+ status: SUPPORTED
+ allowed_address_pairs:
+ type: list
+ description: Additional MAC/IP address pairs allowed to pass through the port
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.network.AddressPair
+ binding:vnic_type:
+ type: string
+ description: The vnic type to be bound on the neutron port
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - macvtap
+ - direct
+ - normal
+ value_specs:
+ type: map
+ description: Extra parameters to include in the request
+ required: false
+ default: {}
+ status: SUPPORTED
+ entry_schema:
+ type: string
+ org.openecomp.datatypes.heat.novaServer.network.AddressInfo:
+ derived_from: tosca.datatypes.network.NetworkInfo
+ description: Network addresses with corresponding port id
+ properties:
+ port_id:
+ type: string
+ description: Port id
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.neutron.port.FixedIps:
+ derived_from: tosca.datatypes.Root
+ description: subnet/ip_address
+ properties:
+ subnet:
+ type: string
+ description: Subnet in which to allocate the IP address for this port
+ required: false
+ status: SUPPORTED
+ ip_address:
+ type: string
+ description: IP address desired in the subnet for this port
+ required: false
+ status: SUPPORTED
+ subnet_id:
+ type: string
+ description: Subnet in which to allocate the IP address for this port
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.FileInfo:
+ derived_from: tosca.datatypes.Root
+ description: Heat File Info
+ properties:
+ file:
+ type: string
+ description: The required URI string (relative or absolute) which can be used to locate the file
+ required: true
+ status: SUPPORTED
+ file_type:
+ type: string
+ description: The type of the file
+ required: true
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - base
+ - env
+ - volume
+ - network
+ org.openecomp.datatypes.heat.contrail.network.rule.PortPairs:
+ derived_from: tosca.datatypes.Root
+ description: source and destination port pairs
+ properties:
+ start_port:
+ type: string
+ description: Start port
+ required: false
+ status: SUPPORTED
+ end_port:
+ type: string
+ description: End port
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrail.network.rule.Rule:
+ derived_from: tosca.datatypes.Root
+ description: policy rule
+ properties:
+ src_ports:
+ type: list
+ description: Source ports
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrail.network.rule.PortPairs
+ protocol:
+ type: string
+ description: Protocol
+ required: false
+ status: SUPPORTED
+ dst_addresses:
+ type: list
+ description: Destination addresses
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrail.network.rule.VirtualNetwork
+ apply_service:
+ type: string
+ description: Service to apply
+ required: false
+ status: SUPPORTED
+ dst_ports:
+ type: list
+ description: Destination ports
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrail.network.rule.PortPairs
+ src_addresses:
+ type: list
+ description: Source addresses
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrail.network.rule.VirtualNetwork
+ direction:
+ type: string
+ description: Direction
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrail.network.rule.RuleList:
+ derived_from: tosca.datatypes.Root
+ description: list of policy rules
+ properties:
+ policy_rule:
+ type: list
+ description: Contrail network rule
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrail.network.rule.Rule
+ org.openecomp.datatypes.heat.contrail.network.rule.VirtualNetwork:
+ derived_from: tosca.datatypes.Root
+ description: source and destination addresses
+ properties:
+ virtual_network:
+ type: string
+ description: Virtual network
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.neutron.SecurityRules.Rule:
+ derived_from: tosca.datatypes.Root
+ description: Rules Pairs
+ properties:
+ remote_group_id:
+ type: string
+ description: The remote group ID to be associated with this security group rule
+ required: false
+ status: SUPPORTED
+ protocol:
+ type: string
+ description: The protocol that is matched by the security group rule
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - tcp
+ - udp
+ - icmp
+ ethertype:
+ type: string
+ description: Ethertype of the traffic
+ required: false
+ default: IPv4
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - IPv4
+ - IPv6
+ port_range_max:
+ type: integer
+ description: 'The maximum port number in the range that is matched by the
+ security group rule. '
+ required: false
+ status: SUPPORTED
+ constraints:
+ - in_range:
+ - 0
+ - 65535
+ remote_ip_prefix:
+ type: string
+ description: The remote IP prefix (CIDR) to be associated with this security group rule
+ required: false
+ status: SUPPORTED
+ remote_mode:
+ type: string
+ description: Whether to specify a remote group or a remote IP prefix
+ required: false
+ default: remote_ip_prefix
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - remote_ip_prefix
+ - remote_group_id
+ direction:
+ type: string
+ description: The direction in which the security group rule is applied
+ required: false
+ default: ingress
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - egress
+ - ingress
+ port_range_min:
+ type: integer
+ description: The minimum port number in the range that is matched by the security group rule.
+ required: false
+ status: SUPPORTED
+ constraints:
+ - in_range:
+ - 0
+ - 65535
+ org.openecomp.datatypes.heat.substitution.SubstitutionFiltering:
+ derived_from: tosca.datatypes.Root
+ description: Substitution Filter
+ properties:
+ substitute_service_template:
+ type: string
+ description: Substitute Service Template
+ required: true
+ status: SUPPORTED
+ index_value:
+ type: integer
+ description: Index value of the substitution service template runtime instance
+ required: false
+ default: 0
+ status: SUPPORTED
+ constraints:
+ - greater_or_equal: 0
+ count:
+ type: string
+ description: Count
+ required: false
+ default: 1
+ status: SUPPORTED
+ scaling_enabled:
+ type: boolean
+ description: Indicates whether service scaling is enabled
+ required: false
+ default: true
+ status: SUPPORTED
+ mandatory:
+ type: boolean
+ description: Mandatory
+ required: false
+ default: true
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.RefDataSequence:
+ derived_from: tosca.datatypes.Root
+ description: network policy refs data sequence
+ properties:
+ network_policy_refs_data_sequence_major:
+ type: integer
+ description: Network Policy ref data sequence Major
+ required: false
+ status: SUPPORTED
+ network_policy_refs_data_sequence_minor:
+ type: integer
+ description: Network Policy ref data sequence Minor
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.RefData:
+ derived_from: tosca.datatypes.Root
+ description: network policy refs data
+ properties:
+ network_policy_refs_data_sequence:
+ type: org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.RefDataSequence
+ description: Network Policy ref data sequence
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.ref.data.IpamSubnet:
+ derived_from: tosca.datatypes.Root
+ description: Network Ipam Ref Data Subnet
+ properties:
+ network_ipam_refs_data_ipam_subnets_subnet_ip_prefix_len:
+ type: string
+ description: Network ipam refs data ipam subnets ip prefix len
+ required: false
+ status: SUPPORTED
+ network_ipam_refs_data_ipam_subnets_subnet_ip_prefix:
+ type: string
+ description: Network ipam refs data ipam subnets ip prefix
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.ref.data.IpamSubnetList:
+ derived_from: tosca.datatypes.Root
+ description: Network Ipam Ref Data Subnet List
+ properties:
+ network_ipam_refs_data_ipam_subnets_subnet:
+ type: org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.ref.data.IpamSubnet
+ description: Network ipam refs data ipam subnets
+ required: false
+ status: SUPPORTED
+ network_ipam_refs_data_ipam_subnets_addr_from_start:
+ type: string
+ description: Network ipam refs data ipam subnets addr from start
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.IpamRefData:
+ derived_from: tosca.datatypes.Root
+ description: Network Ipam Ref Data
+ properties:
+ network_ipam_refs_data_ipam_subnets:
+ type: list
+ description: Network ipam refs data ipam subnets
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.virtual.network.rule.ref.data.IpamSubnetList
+ org.openecomp.datatypes.heat.contrailV2.network.rule.SrcVirtualNetwork:
+ derived_from: tosca.datatypes.Root
+ description: source addresses
+ properties:
+ network_policy_entries_policy_rule_src_addresses_virtual_network:
+ type: string
+ description: Source addresses Virtual network
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.network.rule.DstVirtualNetwork:
+ derived_from: tosca.datatypes.Root
+ description: destination addresses
+ properties:
+ network_policy_entries_policy_rule_dst_addresses_virtual_network:
+ type: string
+ description: Destination addresses Virtual network
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.network.rule.DstPortPairs:
+ derived_from: tosca.datatypes.Root
+ description: destination port pairs
+ properties:
+ network_policy_entries_policy_rule_dst_ports_start_port:
+ type: string
+ description: Start port
+ required: false
+ status: SUPPORTED
+ network_policy_entries_policy_rule_dst_ports_end_port:
+ type: string
+ description: End port
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.network.rule.SrcPortPairs:
+ derived_from: tosca.datatypes.Root
+ description: source port pairs
+ properties:
+ network_policy_entries_policy_rule_src_ports_start_port:
+ type: string
+ description: Start port
+ required: false
+ status: SUPPORTED
+ network_policy_entries_policy_rule_src_ports_end_port:
+ type: string
+ description: End port
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.network.rule.ActionList:
+ derived_from: tosca.datatypes.Root
+ description: Action List
+ properties:
+ network_policy_entries_policy_rule_action_list_simple_action:
+ type: string
+ description: Simple Action
+ required: false
+ status: SUPPORTED
+ network_policy_entries_policy_rule_action_list_apply_service:
+ type: list
+ description: Apply Service
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: string
+ org.openecomp.datatypes.heat.contrailV2.network.rule.Rule:
+ derived_from: tosca.datatypes.Root
+ description: policy rule
+ properties:
+ network_policy_entries_policy_rule_dst_addresses:
+ type: list
+ description: Destination addresses
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.DstVirtualNetwork
+ network_policy_entries_policy_rule_dst_ports:
+ type: list
+ description: Destination ports
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.DstPortPairs
+ network_policy_entries_policy_rule_protocol:
+ type: string
+ description: Protocol
+ required: false
+ status: SUPPORTED
+ network_policy_entries_policy_rule_src_addresses:
+ type: list
+ description: Source addresses
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.SrcVirtualNetwork
+ network_policy_entries_policy_rule_direction:
+ type: string
+ description: Direction
+ required: false
+ status: SUPPORTED
+ network_policy_entries_policy_rule_src_ports:
+ type: list
+ description: Source ports
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.SrcPortPairs
+ network_policy_entries_policy_rule_action_list:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.ActionList
+ description: Action list
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList:
+ derived_from: tosca.datatypes.Root
+ description: list of policy rules
+ properties:
+ network_policy_entries_policy_rule:
+ type: list
+ description: Contrail network rule
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.network.rule.Rule
+ org.openecomp.datatypes.heat.network.contrail.port.StaticRoute:
+ derived_from: tosca.datatypes.Root
+ description: static route
+ properties:
+ prefix:
+ type: string
+ description: Route prefix
+ required: false
+ status: SUPPORTED
+ next_hop:
+ type: string
+ description: Next hop
+ required: false
+ status: SUPPORTED
+ next_hop_type:
+ type: string
+ description: Next hop type
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.contrail.AddressPair:
+ derived_from: tosca.datatypes.Root
+ description: Address Pair
+ properties:
+ address_mode:
+ type: string
+ description: Address mode active-active or active-standy
+ required: false
+ status: SUPPORTED
+ constraints:
+ - valid_values:
+ - active-active
+ - active-standby
+ prefix:
+ type: string
+ description: IP address prefix
+ required: false
+ status: SUPPORTED
+ mac_address:
+ type: string
+ description: Mac address
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.network.contrail.InterfaceData:
+ derived_from: tosca.datatypes.Root
+ description: Interface Data
+ properties:
+ static_routes:
+ type: list
+ description: An ordered list of static routes to be added to this interface
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.network.contrail.port.StaticRoute
+ virtual_network:
+ type: string
+ description: Virtual Network for this interface
+ required: true
+ status: SUPPORTED
+ allowed_address_pairs:
+ type: list
+ description: List of allowed address pair for this interface
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.network.contrail.AddressPair
+ ip_address:
+ type: string
+ description: IP for this interface
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.interface.Properties:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Interface Properties.
+ properties:
+ virtual_machine_interface_properties_service_interface_type:
+ type: string
+ description: Service Interface Type.
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.Root:
+ derived_from: tosca.datatypes.Root
+ description: |
+ The ECOMP root Data Type all other Data Types derive from
+ properties:
+ supplemental_data:
+ type: map
+ entry_schema:
+ description: |
+ A placeholder for missing properties that would be included in future ecomp model versions. fromat <key>:<value>
+ type: string
+ org.openecomp.datatypes.AssignmentRequirements:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ is_required:
+ description: |
+ "true" indicates that assignment is required
+ type: boolean
+ default: false
+ required: true
+ count:
+ description: number of assignments required
+ type: integer
+ required: false
+ org.openecomp.datatypes.network.SubnetAssignments:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ip_network_address_plan:
+ type: string
+ required: false
+ description: Reference to EIPAM, VLAN or other address plan ID used to assign subnets to this network
+ dhcp_enabled:
+ type: boolean
+ required: false
+ description: \"true\" indicates the network has 1 or more policies
+ ip_version:
+ type: integer
+ constraints:
+ - valid_values:
+ - 4
+ - 6
+ required: true
+ description: The IP version of the subnet
+ cidr_mask:
+ type: integer
+ required: true
+ description: The default subnet CIDR mask
+ min_subnets_count:
+ type: integer
+ default: 1
+ required: true
+ description: Quantity of subnets that must be initially assigned
+ org.openecomp.datatypes.network.IPv4SubnetAssignments:
+ derived_from: org.openecomp.datatypes.network.SubnetAssignments
+ properties:
+ use_ipv4:
+ type: boolean
+ required: true
+ description: Indicates IPv4 subnet assignments
+ org.openecomp.datatypes.network.IPv6SubnetAssignments:
+ derived_from: org.openecomp.datatypes.network.SubnetAssignments
+ properties:
+ use_ipv6:
+ type: boolean
+ required: true
+ description: Indicates IPv6 subnet assignments
+ org.openecomp.datatypes.network.NetworkAssignments:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ecomp_generated_network_assignment:
+ type: boolean
+ required: true
+ default: false
+ description: |
+ \"true\" indicates that the network assignments will be auto-generated by ECOMP \"false\" indicates operator-supplied Network assignments file upload is required (e.g. VID will present prompt to operator to upload operator-supplied Network assignments file).
+ is_shared_network:
+ type: boolean
+ required: true
+ description: \"true\" means this network is shared by multiple Openstack tenants
+ is_external_network:
+ type: boolean
+ required: true
+ default: false
+ description: |
+ \"true\" means this Contrail external network
+ ipv4_subnet_default_assignment:
+ type: org.openecomp.datatypes.network.IPv4SubnetAssignments
+ required: true
+ description: IPv4 defualt subnet assignments
+ ipv6_subnet_default_assignment:
+ type: org.openecomp.datatypes.network.IPv6SubnetAssignments
+ required: true
+ description: IPv6 defualt subnet assignments
+ related_networks:
+ type: list
+ required: false
+ description: Related Networks List.
+ entry_schema:
+ type: org.openecomp.datatypes.network.RelatedNetworksAssignments
+ is_trunked:
+ type: boolean
+ required: true
+ description: \"true\" indicates that network is trunked
+ default: false
+ org.openecomp.datatypes.network.ProviderNetwork:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ is_provider_network:
+ type: boolean
+ required: true
+ description: \"true\" indicates that this a Neutron provider type of network
+ physical_network_name:
+ type: string
+ required: false
+ constraints:
+ - valid_values:
+ - Physnet41
+ - Physnet42
+ - Physnet43
+ - Physnet44
+ - Physnet21
+ - Physnet22
+ - sriovnet1
+ - sriovnet2
+ - oam
+ description: |
+ Identifies the NUMA processor cluster to which this physical network interface belongs. NUMA instance correlates to the first digit of the Physical Network Name suffix (e.g. \"01\" = NUMA 0, \"11\" = NUMA 1)
+ numa:
+ type: string
+ required: false
+ constraints:
+ - valid_values:
+ - NUMA 0
+ - NUMA 1
+ description: |
+ PNIC instance within the NUMA processor cluster PNIC Instance correlates to the second digit of the Physical Network Name suffix (e.g. "01" = PNIC 1, "02" = "PNIC 2)
+ pnic_instance:
+ type: integer
+ required: false
+ description: PNIC instance within the NUMA processor cluster
+ org.openecomp.datatypes.network.NetworkFlows:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ is_network_policy:
+ type: boolean
+ required: false
+ default: false
+ description: \"true\" indicates the network has 1 or more policies
+ network_policy:
+ type: string
+ required: false
+ description: 'Identifies the specific Cloud network policy that must be applied
+ to this network (source: from Policy Manager).'
+ is_bound_to_vpn:
+ type: boolean
+ required: false
+ default: false
+ description: \"true\" indicates the network has 1 or more vpn bindings
+ vpn_binding:
+ type: string
+ required: false
+ description: 'Identifies the specific VPN Binding entry in A&AI that must
+ be applied when creating this network (source: A&AI)'
+ org.openecomp.datatypes.network.VlanRequirements:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ vlan_range_plan:
+ type: string
+ required: true
+ description: reference to a vlan range plan
+ vlan_type:
+ type: string
+ required: true
+ constraints:
+ - valid_values:
+ - c-tag
+ - s-tag
+ description: identifies the vlan type (e.g., c-tag)
+ vlan_count:
+ type: integer
+ required: true
+ description: identifies the number of vlan tags to assign to the CP from the plan
+ org.openecomp.datatypes.network.IpRequirements:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ip_version:
+ type: integer
+ required: true
+ constraints:
+ - valid_values:
+ - 4
+ - 6
+ ip_count:
+ description: identifies the number of ip address to assign to the CP from the plan
+ type: integer
+ required: false
+ floating_ip_count:
+ type: integer
+ required: false
+ subnet_role:
+ type: string
+ required: false
+ assingment_method:
+ type: string
+ required: true
+ constraints:
+ - valid_values:
+ - fixed
+ - dhcp
+ dhcp_enabled:
+ type: boolean
+ required: false
+ ip_count_required:
+ description: identifies the number of ip address to assign to the CP from the plan
+ type: org.openecomp.datatypes.AssignmentRequirements
+ required: false
+ floating_ip_count_required:
+ type: org.openecomp.datatypes.AssignmentRequirements
+ required: false
+ ip_address_plan_name:
+ type: string
+ required: false
+ vrf_name:
+ type: string
+ required: false
+ org.openecomp.datatypes.network.MacAssignments:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ mac_range_plan:
+ type: string
+ required: true
+ description: reference to a MAC address range plan
+ mac_count:
+ type: integer
+ required: true
+ description: identifies the number of MAC addresses to assign to the CP from the plan
+ org.openecomp.datatypes.EcompHoming:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ecomp_selected_instance_node_target:
+ type: boolean
+ required: true
+ default: false
+ description: |
+ \"true\" indicates that the target deployment node for this instance will be auto-selected by ECOMP \"false\" indicates operator-supplied instance target deployment node required (e.g. VID will present a prompt to operator and collect the operator-selected target node for the deployment of this Network instance).
+ homing_policy:
+ type: string
+ required: false
+ description: Referenc to a service level homing policy that ECOMP will use for instance deployment target node
+ instance_node_target:
+ type: string
+ required: false
+ description: Instance target deployment node
+ org.openecomp.datatypes.EcompNaming:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ecomp_generated_naming:
+ type: boolean
+ required: true
+ default: true
+ description: |
+ \"true\" indicates that the name for the instance will be auto-generated by ECOMP. \"false\" indicates operator-supplied name required (e.g. VID will present prompt to operator and collect the operator-supplied instance name).
+ naming_policy:
+ type: string
+ required: false
+ description: Referenc to naming policy that ECOMP will use when the name is auto-generated
+ org.openecomp.datatypes.network.MacRequirements:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ mac_range_plan:
+ description: reference to a MAC address range plan
+ type: string
+ required: false
+ mac_count:
+ description: identifies the number of MAC addresses to assign to the CP from the plan
+ type: integer
+ required: false
+ mac_count_required:
+ description: identifies the number of MAC addresses to assign to the CP from the plan
+ type: org.openecomp.datatypes.AssignmentRequirements
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPairIp:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Sub Interface Address Pair IP.
+ properties:
+ ip_prefix:
+ type: string
+ description: IP Prefix.
+ required: false
+ status: SUPPORTED
+ ip_prefix_len:
+ type: integer
+ description: IP Prefix Len.
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Sub Interface Mac Address.
+ properties:
+ mac_address:
+ type: list
+ description: Mac Addresses List.
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: string
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.Properties:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Sub Interface VLAN Properties.
+ properties:
+ sub_interface_vlan_tag:
+ type: string
+ description: Sub Interface VLAN Tag.
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPair:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Sub Interface Address Pair.
+ properties:
+ address_mode:
+ type: string
+ description: Address Mode.
+ required: false
+ status: SUPPORTED
+ ip:
+ type: org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPairIp
+ description: IP.
+ required: false
+ status: SUPPORTED
+ mac:
+ type: string
+ description: Mac.
+ required: false
+ status: SUPPORTED
+ org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPairs:
+ derived_from: tosca.datatypes.Root
+ description: Virtual Machine Sub Interface Address Pairs.
+ properties:
+ allowed_address_pair:
+ type: list
+ description: Addresses pair List.
+ required: false
+ status: SUPPORTED
+ entry_schema:
+ type: org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPair
+ org.openecomp.datatypes.Naming:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ ecomp_generated_naming:
+ description: |
+ "true" indicates that the name for the instance will be auto-generated by ECOMP. "false" indicates operator-supplied name required (e.g. VID will present prompt to operator and collect the operator-supplied instance name).
+ type: boolean
+ default: true
+ required: true
+ naming_policy:
+ description: Reference to naming policy that ECOMP will use when the name is auto-generated
+ type: string
+ required: false
+ instance_name:
+ description: indicates operator-supplied name required (e.g. VID will present prompt to operator and collect the operator-supplied instance name).
+ type: string
+ required: false
+ org.openecomp.datatypes.flavors.ComputeFlavor:
+ derived_from: tosca.datatypes.Root
+ properties:
+ num_cpus:
+ type: integer
+ disk_size:
+ type: scalar-unit.size
+ mem_size:
+ type: scalar-unit.size
+ org.openecomp.datatypes.flavors.LicenseFlavor:
+ derived_from: tosca.datatypes.Root
+ properties:
+ feature_group_uuid:
+ type: string
+ org.openecomp.datatypes.flavors.VendorInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ manufacturer_reference_number:
+ type: string
+ vendor_model:
+ type: string
+ org.openecomp.datatypes.flavors.DeploymentFlavor:
+ derived_from: tosca.datatypes.Root
+ properties:
+ sp_part_number:
+ type: string
+ vendor_info:
+ type: org.openecomp.datatypes.flavors.VendorInfo
+ compute_flavor:
+ type: org.openecomp.datatypes.flavors.ComputeFlavor
+ license_flavor:
+ type: org.openecomp.datatypes.flavors.LicenseFlavor
+ required: false
+ org.openecomp.datatypes.ImageInfo:
+ derived_from: tosca.datatypes.Root
+ properties:
+ software_version:
+ type: string
+ file_name:
+ type: string
+ file_hash:
+ type: string
+ description: checksum/signature
+ file_hash_type:
+ type: string
+ required: false
+ default: md5
+ org.openecomp.datatypes.network.RelatedNetworksAssignments:
+ derived_from: org.openecomp.datatypes.Root
+ properties:
+ related_network_role:
+ type: string
+ description: The network role of the related network, sharing provider network.
+ required: false
+ tosca.datatypes.nfv.VnfcAdditionalConfigurableProperties:
+ derived_from: tosca.datatypes.Root
+ description: VnfcAdditionalConfigurableProperties type is an empty base type for deriving data types for describing additional configurable properties for a given VNFC.
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfcConfigurableProperties:
+ derived_from: tosca.datatypes.Root
+ description: Defines the configurable properties of a VNFC
+ properties:
+ additional_vnfc_configurable_properties:
+ type: tosca.datatypes.nfv.VnfcAdditionalConfigurableProperties
+ description: Describes additional configuration for VNFC that can be modified using the ModifyVnfInfo operation
+ required: false
+ tosca.datatypes.nfv.RequestedAdditionalCapability:
+ derived_from: tosca.datatypes.Root
+ description: describes requested additional capability for a particular VDU
+ properties:
+ requested_additional_capability_name:
+ type: string
+ description: Identifies a requested additional capability for the VDU.
+ required: true
+ support_mandatory:
+ type: boolean
+ description: Indicates whether the requested additional capability is mandatory for successful operation.
+ required: true
+ min_requested_additional_capability_version:
+ type: string
+ description: Identifies the minimum version of the requested additional capability.
+ required: false
+ preferred_requested_additional_capability_version:
+ type: string
+ description: Identifies the preferred version of the requested additional capability.
+ required: false
+ target_performance_parameters:
+ type: map
+ description: Identifies specific attributes, dependent on the requested additional capability type.
+ required: true
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.VirtualMemory:
+ derived_from: tosca.datatypes.Root
+ description: supports the specification of requirements related to virtual memory of a virtual compute resource
+ properties:
+ virtual_mem_size:
+ type: scalar-unit.size
+ description: Amount of virtual memory.
+ required: true
+ virtual_mem_oversubscription_policy:
+ type: string
+ description: The memory core oversubscription policy in terms of virtual memory to physical memory on the platform.
+ required: false
+ vdu_mem_requirements:
+ type: map
+ description: The hardware platform specific VDU memory requirements. A map of strings that contains a set of key-value pairs that describes hardware platform specific VDU memory requirements.
+ required: false
+ entry_schema:
+ type: string
+ numa_enabled:
+ type: boolean
+ description: It specifies the memory allocation to be cognisant of the relevant process/core allocation.
+ required: false
+ default: false
+ tosca.datatypes.nfv.VirtualCpuPinning:
+ derived_from: tosca.datatypes.Root
+ description: Supports the specification of requirements related to the virtual CPU pinning configuration of a virtual compute resource
+ properties:
+ virtual_cpu_pinning_policy:
+ type: string
+ description: 'Indicates the policy for CPU pinning. The policy can take values
+ of "static" or "dynamic". In case of "dynamic" the allocation of virtual
+ CPU cores to logical CPU cores is decided by the VIM. (e.g.: SMT (Simultaneous
+ Multi-Threading) requirements). In case of "static" the allocation is requested
+ to be according to the virtual_cpu_pinning_rule.'
+ required: false
+ constraints:
+ - valid_values:
+ - static
+ - dynamic
+ virtual_cpu_pinning_rule:
+ type: list
+ description: Provides the list of rules for allocating virtual CPU cores to logical CPU cores/threads
+ required: false
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.VirtualCpu:
+ derived_from: tosca.datatypes.Root
+ description: Supports the specification of requirements related to virtual CPU(s) of a virtual compute resource
+ properties:
+ cpu_architecture:
+ type: string
+ description: CPU architecture type. Examples are x86, ARM
+ required: false
+ num_virtual_cpu:
+ type: integer
+ description: Number of virtual CPUs
+ required: true
+ constraints:
+ - greater_than: 0
+ virtual_cpu_clock:
+ type: scalar-unit.frequency
+ description: Minimum virtual CPU clock rate
+ required: false
+ virtual_cpu_oversubscription_policy:
+ type: string
+ description: CPU core oversubscription policy e.g. the relation of virtual CPU cores to physical CPU cores/threads.
+ required: false
+ vdu_cpu_requirements:
+ type: map
+ description: The hardware platform specific VDU CPU requirements. A map of strings that contains a set of key-value pairs describing VDU CPU specific hardware platform requirements.
+ required: false
+ entry_schema:
+ type: string
+ virtual_cpu_pinning:
+ type: tosca.datatypes.nfv.VirtualCpuPinning
+ description: The virtual CPU pinning configuration for the virtualised compute resource.
+ required: false
+ tosca.datatypes.nfv.LogicalNodeData:
+ derived_from: tosca.datatypes.Root
+ description: Describes compute, memory and I/O requirements associated with a particular VDU.
+ properties:
+ logical_node_requirements:
+ type: map
+ description: The logical node-level compute, memory and I/O requirements. A map of strings that contains a set of key-value pairs that describes hardware platform specific deployment requirements, including the number of CPU cores on this logical node, a memory configuration specific to a logical node or a requirement related to the association of an I/O device with the logical node.
+ required: false
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.VirtualNetworkInterfaceRequirements:
+ derived_from: tosca.datatypes.Root
+ description: Describes requirements on a virtual network interface
+ properties:
+ name:
+ type: string
+ description: Provides a human readable name for the requirement.
+ required: false
+ description:
+ type: string
+ description: Provides a human readable description of the requirement.
+ required: false
+ support_mandatory:
+ type: boolean
+ description: Indicates whether fulfilling the constraint is mandatory (TRUE) for successful operation or desirable (FALSE).
+ required: true
+ network_interface_requirements:
+ type: map
+ description: The network interface requirements. A map of strings that contain a set of key-value pairs that describes the hardware platform specific network interface deployment requirements.
+ required: true
+ entry_schema:
+ type: string
+ nic_io_requirements:
+ type: tosca.datatypes.nfv.LogicalNodeData
+ description: references (couples) the CP with any logical node I/O requirements (for network devices) that may have been created. Linking these attributes is necessary so that so that I/O requirements that need to be articulated at the logical node level can be associated with the network interface requirements associated with the CP.
+ required: false
+ tosca.datatypes.nfv.injectFile:
+ derived_from: tosca.datatypes.Root
+ properties:
+ source_path:
+ type: string
+ required: true
+ dest_path:
+ type: string
+ required: true
+ tosca.datatypes.nfv.L2AddressData:
+ derived_from: tosca.datatypes.Root
+ description: Describes the information on the MAC addresses to be assigned to a connection point.
+ properties:
+ mac_address_assignment:
+ type: boolean
+ description: Specifies if the address assignment is the responsibility of management and orchestration function or not. If it is set to True, it is the management and orchestration function responsibility
+ required: true
+ tosca.datatypes.nfv.L3AddressData:
+ derived_from: tosca.datatypes.Root
+ description: Provides information about Layer 3 level addressing scheme and parameters applicable to a CP
+ properties:
+ ip_address_assignment:
+ type: boolean
+ description: Specifies if the address assignment is the responsibility of management and orchestration function or not. If it is set to True, it is the management and orchestration function responsibility
+ required: true
+ floating_ip_activated:
+ type: boolean
+ description: Specifies if the floating IP scheme is activated on the Connection Point or not
+ required: true
+ ip_address_type:
+ type: string
+ description: Defines address type. The address type should be aligned with the address type supported by the layer_protocols properties of the parent VnfExtCp
+ required: false
+ constraints:
+ - valid_values:
+ - ipv4
+ - ipv6
+ number_of_ip_address:
+ type: integer
+ description: Minimum number of IP addresses to be assigned
+ required: false
+ constraints:
+ - greater_than: 0
+ fixed_ip_address:
+ type: list
+ entry_schema:
+ type: string
+ required: false
+ tosca.datatypes.nfv.AddressData:
+ derived_from: tosca.datatypes.Root
+ description: Describes information about the addressing scheme and parameters applicable to a CP
+ properties:
+ address_type:
+ type: string
+ description: Describes the type of the address to be assigned to a connection point. The content type shall be aligned with the address type supported by the layerProtocol property of the connection point
+ required: true
+ constraints:
+ - valid_values:
+ - mac_address
+ - ip_address
+ l2_address_data:
+ type: tosca.datatypes.nfv.L2AddressData
+ description: Provides the information on the MAC addresses to be assigned to a connection point.
+ required: false
+ l3_address_data:
+ type: tosca.datatypes.nfv.L3AddressData
+ description: Provides the information on the IP addresses to be assigned to a connection point
+ required: false
+ tosca.datatypes.nfv.ConnectivityType:
+ derived_from: tosca.datatypes.Root
+ description: describes additional connectivity information of a virtualLink
+ properties:
+ layer_protocols:
+ type: list
+ description: Identifies the protocol a virtualLink gives access to (ethernet, mpls, odu2, ipv4, ipv6, pseudo-wire).The top layer protocol of the virtualLink protocol stack shall always be provided. The lower layer protocols may be included when there are specific requirements on these layers.
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - ethernet
+ - mpls
+ - odu2
+ - ipv4
+ - ipv6
+ - pseudo-wire
+ flow_pattern:
+ type: string
+ description: Identifies the flow pattern of the connectivity
+ required: false
+ constraints:
+ - valid_values:
+ - line
+ - tree
+ - mesh
+ tosca.datatypes.nfv.VlFlavour:
+ derived_from: tosca.datatypes.Root
+ properties:
+ flavourId:
+ type: string
+ tosca.datatypes.nfv.ext.AddressPairs:
+ properties:
+ ip:
+ type: string
+ required: false
+ mac:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.FloatingIP:
+ properties:
+ external_network:
+ type: string
+ required: false
+ ip_address:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.LocationInfo:
+ properties:
+ availability_zone:
+ type: string
+ required: false
+ vimid:
+ type: integer
+ required: false
+ tenant:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.HostRouteInfo:
+ properties:
+ destination:
+ type: string
+ required: false
+ nexthop:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.InjectData:
+ properties:
+ file_name:
+ type: string
+ required: false
+ file_data:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.zte.WatchDog:
+ properties:
+ enable_delay:
+ type: integer
+ required: false
+ action:
+ type: string
+ required: false
+ tosca.datatypes.nfv.ext.LocalAffinityOrAntiAffinityRule:
+ properties:
+ scope:
+ type: string
+ required: false
+ affinity_antiaffinity:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VduProfile:
+ derived_from: tosca.datatypes.Root
+ description: describes additional instantiation data for a given Vdu.Compute used in a specific deployment flavour.
+ properties:
+ min_number_of_instances:
+ type: integer
+ description: Minimum number of instances of the VNFC based on this Vdu.Compute that is permitted to exist for a particular VNF deployment flavour.
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ max_number_of_instances:
+ type: integer
+ description: Maximum number of instances of the VNFC based on this Vdu.Compute that is permitted to exist for a particular VNF deployment flavour.
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ watchdog:
+ type: string
+ required: true
+ vmBootUpTimeOut:
+ type: integer
+ required: false
+ tosca.datatypes.nfv.LinkBitrateRequirements:
+ derived_from: tosca.datatypes.Root
+ description: describes the requirements in terms of bitrate for a virtual link
+ properties:
+ root:
+ type: integer
+ description: Specifies the throughput requirement in bits per second of the link (e.g. bitrate of E-Line, root bitrate of E-Tree, aggregate capacity of E-LAN).
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ leaf:
+ type: integer
+ description: Specifies the throughput requirement in bits per second of leaf connections to the link when applicable to the connectivity type (e.g. for E-Tree and E LAN branches).
+ required: false
+ constraints:
+ - greater_or_equal: 0
+ tosca.datatypes.nfv.Qos:
+ derived_from: tosca.datatypes.Root
+ description: describes QoS data for a given VL used in a VNF deployment flavour
+ properties:
+ latency:
+ type: scalar-unit.time
+ description: Specifies the maximum latency
+ required: true
+ constraints:
+ - greater_than: 0 s
+ packet_delay_variation:
+ type: scalar-unit.time
+ description: Specifies the maximum jitter
+ required: true
+ constraints:
+ - greater_or_equal: 0 s
+ packet_loss_ratio:
+ type: float
+ description: Specifies the maximum packet loss ratio
+ required: false
+ constraints:
+ - in_range:
+ - 0.0
+ - 1.0
+ tosca.datatypes.nfv.IpAllocationPool:
+ derived_from: tosca.datatypes.Root
+ description: Specifies a range of IP addresses
+ properties:
+ start_ip_address:
+ type: string
+ description: The IP address to be used as the first one in a pool of addresses derived from the cidr block full IP range
+ required: true
+ end_ip_address:
+ type: string
+ description: The IP address to be used as the last one in a pool of addresses derived from the cidr block full IP range
+ required: true
+ tosca.datatypes.nfv.L2ProtocolData:
+ derived_from: tosca.datatypes.Root
+ description: describes L2 protocol data for a given virtual link used in a specific VNF deployment flavour.
+ properties:
+ name:
+ type: string
+ description: Identifies the network name associated with this L2 protocol.
+ required: false
+ network_type:
+ type: string
+ description: Specifies the network type for this L2 protocol.The value may be overridden at run-time.
+ required: false
+ constraints:
+ - valid_values:
+ - flat
+ - vlan
+ - vxlan
+ - gre
+ vlan_transparent:
+ type: boolean
+ description: Specifies whether to support VLAN transparency for this L2 protocol or not.
+ required: false
+ default: false
+ mtu:
+ type: integer
+ description: Specifies the maximum transmission unit (MTU) value for this L2 protocol.
+ required: false
+ constraints:
+ - greater_than: 0
+ segmentation_id:
+ type: integer
+ required: false
+ physical_network:
+ type: string
+ required: false
+ tosca.datatypes.nfv.L3ProtocolData:
+ derived_from: tosca.datatypes.Root
+ description: describes L3 protocol data for a given virtual link used in a specific VNF deployment flavour.
+ properties:
+ name:
+ type: string
+ description: Identifies the network name associated with this L3 protocol.
+ required: false
+ ip_version:
+ type: string
+ description: Specifies IP version of this L3 protocol.The value of the ip_version property shall be consistent with the value of the layer_protocol in the connectivity_type property of the virtual link node.
+ required: true
+ constraints:
+ - valid_values:
+ - ipv4
+ - ipv6
+ cidr:
+ type: string
+ description: Specifies the CIDR (Classless Inter-Domain Routing) of this L3 protocol. The value may be overridden at run-time.
+ required: true
+ ip_allocation_pools:
+ type: list
+ description: Specifies the allocation pools with start and end IP addresses for this L3 protocol. The value may be overridden at run-time.
+ required: false
+ entry_schema:
+ type: tosca.datatypes.nfv.IpAllocationPool
+ gateway_ip:
+ type: string
+ description: Specifies the gateway IP address for this L3 protocol. The value may be overridden at run-time.
+ required: false
+ dhcp_enabled:
+ type: boolean
+ description: Indicates whether DHCP (Dynamic Host Configuration Protocol) is enabled or disabled for this L3 protocol. The value may be overridden at run-time.
+ required: false
+ ipv6_address_mode:
+ type: string
+ description: Specifies IPv6 address mode. May be present when the value of the ipVersion attribute is "ipv6" and shall be absent otherwise. The value may be overridden at run-time.
+ required: false
+ constraints:
+ - valid_values:
+ - slaac
+ - dhcpv6-stateful
+ - dhcpv6-stateless
+ tosca.datatypes.nfv.VirtualLinkProtocolData:
+ derived_from: tosca.datatypes.Root
+ description: describes one protocol layer and associated protocol data for a given virtual link used in a specific VNF deployment flavour
+ properties:
+ associated_layer_protocol:
+ type: string
+ description: Identifies one of the protocols a virtualLink gives access to (ethernet, mpls, odu2, ipv4, ipv6, pseudo-wire) as specified by the connectivity_type property.
+ required: true
+ constraints:
+ - valid_values:
+ - ethernet
+ - mpls
+ - odu2
+ - ipv4
+ - ipv6
+ - pseudo-wire
+ l2_protocol_data:
+ type: tosca.datatypes.nfv.L2ProtocolData
+ description: Specifies the L2 protocol data for a virtual link. Shall be present when the associatedLayerProtocol attribute indicates a L2 protocol and shall be absent otherwise.
+ required: false
+ l3_protocol_data:
+ type: tosca.datatypes.nfv.L3ProtocolData
+ description: Specifies the L3 protocol data for this virtual link. Shall be present when the associatedLayerProtocol attribute indicates a L3 protocol and shall be absent otherwise.
+ required: false
+ tosca.datatypes.nfv.VlProfile:
+ derived_from: tosca.datatypes.Root
+ description: Describes additional instantiation data for a given VL used in a specific VNF deployment flavour.
+ properties:
+ max_bitrate_requirements:
+ type: tosca.datatypes.nfv.LinkBitrateRequirements
+ description: Specifies the maximum bitrate requirements for a VL instantiated according to this profile.
+ required: true
+ min_bitrate_requirements:
+ type: tosca.datatypes.nfv.LinkBitrateRequirements
+ description: Specifies the minimum bitrate requirements for a VL instantiated according to this profile.
+ required: true
+ qos:
+ type: tosca.datatypes.nfv.Qos
+ description: Specifies the QoS requirements of a VL instantiated according to this profile.
+ required: false
+ virtual_link_protocol_data:
+ type: list
+ description: Specifies the protocol data for a virtual link.
+ required: false
+ entry_schema:
+ type: tosca.datatypes.nfv.VirtualLinkProtocolData
+ tosca.datatypes.nfv.VduLevel:
+ derived_from: tosca.datatypes.Root
+ description: Indicates for a given Vdu.Compute in a given level the number of instances to deploy
+ properties:
+ number_of_instances:
+ type: integer
+ description: Number of instances of VNFC based on this VDU to deploy for this level.
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ tosca.datatypes.nfv.ScaleInfo:
+ derived_from: tosca.datatypes.Root
+ description: Indicates for a given scaleAspect the corresponding scaleLevel
+ properties:
+ scale_level:
+ type: integer
+ description: The scale level for a particular aspect
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ tosca.datatypes.nfv.ScalingAspect:
+ derived_from: tosca.datatypes.Root
+ properties:
+ name:
+ type: string
+ required: true
+ description:
+ type: string
+ required: true
+ max_scale_level:
+ type: integer
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ step_deltas:
+ type: list
+ required: false
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.InstantiationLevel:
+ derived_from: tosca.datatypes.Root
+ description: Describes the scale level for each aspect that corresponds to a given level of resources to be instantiated within a deployment flavour in term of the number VNFC instances
+ properties:
+ description:
+ type: string
+ description: Human readable description of the level
+ required: true
+ scale_info:
+ type: map
+ description: Represents for each aspect the scale level that corresponds to this instantiation level. scale_info shall be present if the VNF supports scaling.
+ required: false
+ entry_schema:
+ type: tosca.datatypes.nfv.ScaleInfo
+ tosca.datatypes.nfv.VnfInstantiateOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the InstantiateVnf operation.
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfScaleOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: Represents information that affect the invocation of the ScaleVnf operation
+ properties:
+ scaling_by_more_than_one_step_supported:
+ type: boolean
+ description: Signals whether passing a value larger than one in the numScalingSteps parameter of the ScaleVnf operation is supported by this VNF.
+ required: false
+ default: false
+ tosca.datatypes.nfv.VnfScaleToLevelOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the ScaleVnfToLevel operation
+ properties:
+ arbitrary_target_levels_supported:
+ type: boolean
+ description: Signals whether scaling according to the parameter "scaleInfo" is supported by this VNF
+ required: true
+ tosca.datatypes.nfv.VnfHealOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the HealVnf operation
+ properties:
+ causes:
+ type: list
+ description: Supported "cause" parameter values
+ required: false
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.VnfTerminateOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the TerminateVnf
+ properties:
+ min_graceful_termination_timeout:
+ type: scalar-unit.time
+ description: Minimum timeout value for graceful termination of a VNF instance
+ required: true
+ max_recommended_graceful_termination_timeout:
+ type: scalar-unit.time
+ description: Maximum recommended timeout value that can be needed to gracefully terminate a VNF instance of a particular type under certain conditions, such as maximum load condition. This is provided by VNF provider as information for the operator facilitating the selection of optimal timeout value. This value is not used as constraint
+ required: false
+ tosca.datatypes.nfv.VnfOperateOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the OperateVnf operation
+ properties:
+ min_graceful_stop_timeout:
+ type: scalar-unit.time
+ description: Minimum timeout value for graceful stop of a VNF instance
+ required: true
+ max_recommended_graceful_stop_timeout:
+ type: scalar-unit.time
+ description: Maximum recommended timeout value that can be needed to gracefully stop a VNF instance of a particular type under certain conditions, such as maximum load condition. This is provided by VNF provider as information for the operator facilitating the selection of optimal timeout value. This value is not used as constraint
+ required: false
+ tosca.datatypes.nfv.VnfChangeFlavourOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the ChangeVnfFlavour operation
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfProfile:
+ derived_from: tosca.datatypes.Root
+ description: describes a profile for instantiating VNFs of a particular NS DF according to a specific VNFD and VNF DF.
+ properties:
+ instantiation_level:
+ type: string
+ description: Identifier of the instantiation level of the VNF DF to be used for instantiation. If not present, the default instantiation level as declared in the VNFD shall be used.
+ required: false
+ min_number_of_instances:
+ type: integer
+ description: Minimum number of instances of the VNF based on this VNFD that is permitted to exist for this VnfProfile.
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ max_number_of_instances:
+ type: integer
+ description: Maximum number of instances of the VNF based on this VNFD that is permitted to exist for this VnfProfile.
+ required: true
+ constraints:
+ - greater_or_equal: 0
+ tosca.datatypes.nfv.UriAuthority:
+ derived_from: tosca.datatypes.Root
+ description: information that corresponds to the authority component of a URI as specified in IETF RFC 3986 [8]
+ properties:
+ user_info:
+ type: string
+ description: user_info field of the authority component of a URI
+ required: false
+ host:
+ type: string
+ description: host field of the authority component of a URI
+ required: false
+ port:
+ type: string
+ description: port field of the authority component of a URI
+ required: false
+ tosca.datatypes.nfv.UriComponents:
+ derived_from: tosca.datatypes.Root
+ description: information used to build a URI that complies with IETF RFC 3986 [8].
+ properties:
+ scheme:
+ type: string
+ description: scheme component of a URI.
+ required: true
+ authority:
+ type: tosca.datatypes.nfv.UriAuthority
+ description: Authority component of a URI
+ required: false
+ path:
+ type: string
+ description: path component of a URI.
+ required: false
+ query:
+ type: string
+ description: query component of a URI.
+ required: false
+ fragment:
+ type: string
+ description: fragment component of a URI.
+ required: false
+ tosca.datatypes.nfv.InterfaceDetails:
+ derived_from: tosca.datatypes.Root
+ description: information used to access an interface exposed by a VNF
+ properties:
+ uri_components:
+ type: tosca.datatypes.nfv.UriComponents
+ description: Provides components to build a Uniform Ressource Identifier (URI) where to access the interface end point.
+ required: false
+ interface_specific_data:
+ type: map
+ description: Provides additional details that are specific to the type of interface considered.
+ required: false
+ entry_schema:
+ type: string
+ tosca.datatypes.nfv.VirtualLinkMonitoringParameter:
+ derived_from: tosca.datatypes.Root
+ description: Represents information on virtualised resource related performance metrics applicable to the VNF.
+ properties:
+ name:
+ type: string
+ description: Human readable name of the monitoring parameter
+ required: true
+ performance_metric:
+ type: string
+ description: Identifies a performance metric derived from those defined in ETSI GS NFV-IFA 027.The packetOutgoingVirtualLink and packetIncomingVirtualLink metrics shall be obtained by aggregation the PacketOutgoing and PacketIncoming measurements defined in clause 7.1 of GS NFV-IFA 027 of all virtual link ports attached to the virtual link to which the metrics apply.
+ required: true
+ constraints:
+ - valid_values:
+ - packet_outgoing_virtual_link
+ - packet_incoming_virtual_link
+ collection_period:
+ type: scalar-unit.time
+ description: Describes the recommended periodicity at which to collect the performance information.
+ required: false
+ constraints:
+ - greater_than: 0 s
+ tosca.datatypes.nfv.VnfcMonitoringParameter:
+ derived_from: tosca.datatypes.Root
+ description: Represents information on virtualised resource related performance metrics applicable to the VNF.
+ properties:
+ name:
+ type: string
+ description: Human readable name of the monitoring parameter
+ required: true
+ performance_metric:
+ type: string
+ description: Identifies the performance metric, according to ETSI GS NFV-IFA 027.
+ required: true
+ constraints:
+ - valid_values:
+ - v_cpu_usage_mean_vnf
+ - v_cpu_usage_peak_vnf
+ - v_memory_usage_mean_vnf
+ - v_memory_usage_peak_vnf
+ - v_disk_usage_mean_vnf
+ - v_disk_usage_peak_vnf
+ - byte_incoming_vnf_int_cp
+ - byte_outgoing_vnf_int_cp
+ - packet_incoming_vnf_int_cp
+ - packet_outgoing_vnf_int_cp
+ collection_period:
+ type: scalar-unit.time
+ description: Describes the recommended periodicity at which to collect the performance information.
+ required: false
+ constraints:
+ - greater_than: 0 s
+ tosca.datatypes.nfv.VnfChangeExtConnectivityOperationConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: represents information that affect the invocation of the ChangeExtVnfConnectivity operation
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfMonitoringParameter:
+ derived_from: tosca.datatypes.Root
+ description: Represents information on virtualised resource related performance metrics applicable to the VNF.
+ properties:
+ name:
+ type: string
+ description: Human readable name of the monitoring parameter
+ required: true
+ performance_metric:
+ type: string
+ description: Identifies the performance metric, according to ETSI GS NFV-IFA 027.
+ required: true
+ constraints:
+ - valid_values:
+ - v_cpu_usage_mean_vnf
+ - v_cpu_usage_peak_vnf
+ - v_memory_usage_mean_vnf
+ - v_memory_usage_peak_vnf
+ - v_disk_usage_mean_vnf
+ - v_disk_usage_peak_vnf
+ - byte_incoming_vnf_ext_cp
+ - byte_outgoing_vnf_ext_cp
+ - packet_incoming_vnf_ext_cp
+ - packet_outgoing_vnf_ext_cp
+ collection_period:
+ type: scalar-unit.time
+ description: Describes the recommended periodicity at which to collect the performance information.
+ required: false
+ constraints:
+ - greater_than: 0 s
+ tosca.datatypes.nfv.VnfLcmOperationsConfiguration:
+ derived_from: tosca.datatypes.Root
+ description: Represents information to configure lifecycle management operations
+ properties:
+ instantiate:
+ type: tosca.datatypes.nfv.VnfInstantiateOperationConfiguration
+ description: Configuration parameters for the InstantiateVnf operation
+ required: false
+ scale:
+ type: tosca.datatypes.nfv.VnfScaleOperationConfiguration
+ description: Configuration parameters for the ScaleVnf operation
+ required: false
+ scale_to_level:
+ type: tosca.datatypes.nfv.VnfScaleToLevelOperationConfiguration
+ description: Configuration parameters for the ScaleVnfToLevel operation
+ required: false
+ change_flavour:
+ type: tosca.datatypes.nfv.VnfChangeFlavourOperationConfiguration
+ description: Configuration parameters for the changeVnfFlavourOpConfig operation
+ required: false
+ heal:
+ type: tosca.datatypes.nfv.VnfHealOperationConfiguration
+ description: Configuration parameters for the HealVnf operation
+ required: false
+ terminate:
+ type: tosca.datatypes.nfv.VnfTerminateOperationConfiguration
+ description: Configuration parameters for the TerminateVnf operation
+ required: false
+ operate:
+ type: tosca.datatypes.nfv.VnfOperateOperationConfiguration
+ description: Configuration parameters for the OperateVnf operation
+ required: false
+ change_ext_connectivity:
+ type: tosca.datatypes.nfv.VnfChangeExtConnectivityOperationConfiguration
+ description: Configuration parameters for the changeExtVnfConnectivityOpConfig operation
+ required: false
+ tosca.datatypes.nfv.CpProtocolData:
+ derived_from: tosca.datatypes.Root
+ description: Describes and associates the protocol layer that a CP uses together with other protocol and connection point information
+ properties:
+ associated_layer_protocol:
+ type: string
+ required: true
+ description: One of the values of the property layer_protocols of the CP
+ constraints:
+ - valid_values:
+ - ethernet
+ - mpls
+ - odu2
+ - ipv4
+ - ipv6
+ - pseudo-wire
+ address_data:
+ type: list
+ description: Provides information on the addresses to be assigned to the CP
+ entry_schema:
+ type: tosca.datatypes.nfv.AddressData
+ required: false
+ tosca.datatypes.nfv.VnfAdditionalConfigurableProperties:
+ derived_from: tosca.datatypes.Root
+ description: is an empty base type for deriving data types for describing additional configurable properties for a given VNF
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfConfigurableProperties:
+ derived_from: tosca.datatypes.Root
+ description: indicates configuration properties for a given VNF (e.g. related to auto scaling and auto healing).
+ properties:
+ is_autoscale_enabled:
+ type: boolean
+ description: It permits to enable (TRUE)/disable (FALSE) the auto-scaling functionality. If the properties is not present for configuring, then VNF property is not supported
+ required: false
+ is_autoheal_enabled:
+ type: boolean
+ description: It permits to enable (TRUE)/disable (FALSE) the auto-healing functionality. If the properties is not present for configuring, then VNF property is not supported
+ required: false
+ additional_configurable_properties:
+ description: It provides VNF specific configurable properties that can be modified using the ModifyVnfInfo operation
+ required: false
+ type: tosca.datatypes.nfv.VnfAdditionalConfigurableProperties
+ tosca.datatypes.nfv.VnfInfoModifiableAttributesExtensions:
+ derived_from: tosca.datatypes.Root
+ description: is an empty base type for deriving data types for describing VNF-specific extension
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfInfoModifiableAttributesMetadata:
+ derived_from: tosca.datatypes.Root
+ description: is an empty base type for deriving data types for describing VNF-specific metadata
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VnfInfoModifiableAttributes:
+ derived_from: tosca.datatypes.Root
+ description: Describes VNF-specific extension and metadata for a given VNF
+ properties:
+ extensions:
+ type: tosca.datatypes.nfv.VnfInfoModifiableAttributesExtensions
+ description: \"Extension\" properties of VnfInfo that are writeable
+ required: false
+ metadata:
+ type: tosca.datatypes.nfv.VnfInfoModifiableAttributesMetadata
+ description: \"Metadata\" properties of VnfInfo that are writeable
+ required: false
+ tosca.datatypes.nfv.VirtualLinkBitrateLevel:
+ derived_from: tosca.datatypes.Root
+ description: Describes bitrate requirements applicable to the virtual link instantiated from a particicular VnfVirtualLink
+ properties:
+ description:
+ type: string
+ required: false
+ bitrate_requirements:
+ type: tosca.datatypes.nfv.LinkBitrateRequirements
+ description: Virtual link bitrate requirements for an instantiation level or bitrate delta for a scaling step
+ required: true
+ tosca.datatypes.nfv.VnfOperationAdditionalParameters:
+ derived_from: tosca.datatypes.Root
+ description: Is an empty base type for deriving data type for describing VNF-specific parameters to be passed when invoking lifecycle management operations
+ properties:
+ description:
+ type: string
+ required: false
+ tosca.datatypes.nfv.VirtualFileStorageData:
+ derived_from: tosca.datatypes.Root
+ description: VirtualFileStorageData describes file storage requirements associated with compute resources in a particular VDU
+ properties:
+ size_of_storage:
+ type: scalar-unit.size
+ description: Size of virtualized storage resource
+ required: true
+ file_system_protocol:
+ type: string
+ description: The shared file system protocol (e.g. NFS, CIFS)
+ required: true
+ tosca.datatypes.nfv.VirtualObjectStorageData:
+ derived_from: tosca.datatypes.Root
+ description: VirtualObjectStorageData describes object storage requirements associated with compute resources in a particular VDU
+ properties:
+ max_size_of_storage:
+ type: scalar-unit.size
+ description: Maximum size of virtualized storage resource
+ required: false
+ tosca.datatypes.nfv.VirtualBlockStorageData:
+ derived_from: tosca.datatypes.Root
+ description: VirtualBlockStorageData describes block storage requirements associated with compute resources in a particular VDU, either as a local disk or as virtual attached storage
+ properties:
+ size_of_storage:
+ type: scalar-unit.size
+ description: Size of virtualised storage resource
+ required: true
+ vdu_storage_requirements:
+ type: map
+ description: The hardware platform specific storage requirements. A map of strings that contains a set of key-value pairs that represents the hardware platform specific storage deployment requirements.
+ required: false
+ entry_schema:
+ type: string
+ rdma_enabled:
+ type: boolean
+ description: Indicates if the storage support RDMA
+ required: false
+ default: false
+ tosca.datatypes.nfv.SwImageData:
+ derived_from: tosca.datatypes.Root
+ description: describes information related to a software image artifact
+ properties:
+ name:
+ type: string
+ description: Name of this software image
+ required: true
+ version:
+ type: string
+ description: Version of this software image
+ required: true
+ checksum:
+ type: string
+ description: Checksum of the software image file
+ required: true
+ container_format:
+ type: string
+ description: The container format describes the container file format in which software image is provided
+ required: true
+ constraints:
+ - valid_values:
+ - aki
+ - ami
+ - ari
+ - bare
+ - docker
+ - ova
+ - ovf
+ disk_format:
+ type: string
+ description: The disk format of a software image is the format of the underlying disk image
+ required: true
+ constraints:
+ - valid_values:
+ - aki
+ - ami
+ - ari
+ - iso
+ - qcow2
+ - raw
+ - vdi
+ - vhd
+ - vhdx
+ - vmdk
+ min_disk:
+ type: scalar-unit.size
+ description: The minimal disk size requirement for this software image
+ required: true
+ min_ram:
+ type: scalar-unit.size
+ description: The minimal RAM requirement for this software image
+ required: false
+ size:
+ type: scalar-unit.size
+ description: The size of this software image
+ required: true
+ operating_system:
+ type: string
+ description: Identifies the operating system used in the software image
+ required: false
+ supported_virtualisation_environments:
+ type: list
+ description: Identifies the virtualisation environments (e.g. hypervisor) compatible with this software image
+ required: false
+ entry_schema:
+ type: string
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ required: true
+ type: string
+ eventName:
+ description: Event name to which thresholds need to be applied
+ required: true
+ type: string
+ policyName:
+ description: TCA Policy Scope Name
+ required: true
+ type: string
+ policyScope:
+ description: TCA Policy Scope
+ required: true
+ type: string
+ policyVersion:
+ description: TCA Policy Scope Version
+ required: true
+ type: string
+ thresholds:
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ required: true
+ type: list
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ constraints:
+ - equal: measurementsForVfScaling
+ default: measurementsForVfScaling
+ description: Domain name to which TCA needs to be applied
+ required: true
+ type: string
+ metricsPerEventName:
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ required: true
+ type: list
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ description: Closed Loop Control Name associated with the threshold
+ required: true
+ type: string
+ closedLoopEventStatus:
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ description: Closed Loop Event Status of the threshold
+ required: true
+ type: string
+ direction:
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ description: Direction of the threshold
+ required: true
+ type: string
+ fieldPath:
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ required: true
+ type: string
+ severity:
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ description: Threshold Event Severity
+ required: true
+ type: string
+ thresholdValue:
+ description: Threshold value for the field Path inside CEF message
+ required: true
+ type: integer
+ version:
+ description: Version number associated with the threshold
+ required: true
+ type: string
diff --git a/runtime/src/test/resources/example/sdc/service-Simsfoimap0112.csar b/runtime/src/test/resources/example/sdc/service-Simsfoimap0112.csar
new file mode 100644
index 000000000..8c16d31ee
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/service-Simsfoimap0112.csar
Binary files differ
diff --git a/runtime/src/test/resources/example/sdc/service-without-policy.csar b/runtime/src/test/resources/example/sdc/service-without-policy.csar
new file mode 100644
index 000000000..20c4eef65
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/service-without-policy.csar
Binary files differ
diff --git a/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_cds.csar b/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_cds.csar
new file mode 100644
index 000000000..ff337993a
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_cds.csar
Binary files differ
diff --git a/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_no_cds.csar b/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_no_cds.csar
new file mode 100644
index 000000000..3330dd1e8
--- /dev/null
+++ b/runtime/src/test/resources/example/sdc/service_Vloadbalancerms_no_cds.csar
Binary files differ
diff --git a/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.file b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.file
new file mode 100644
index 000000000..9e616dfea
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.file
@@ -0,0 +1,96 @@
+{
+ "blueprintName": "baseconfiguration",
+ "version": "1.0.0",
+ "workFlowData": {
+ "workFlowName": "resource-assignment",
+ "inputs": {
+ "resource-assignment-properties": {
+ "required": true,
+ "type": "dt-resource-assignment-properties"
+ }
+ },
+ "outputs": {
+ "response-property": {
+ "type": "string",
+ "value": "executed"
+ },
+ "template-properties": {
+ "type": "json",
+ "value": {
+ "get_attribute": [
+ "resource-assignment",
+ "assignment-params"
+ ]
+ }
+ }
+ }
+ },
+ "dataTypes": {
+ "dt-resource-assignment-properties": {
+ "description": "This is Dynamically generated data type for workflow activate",
+ "version": "1.0.0",
+ "metadata": null,
+ "attributes": null,
+ "properties": {
+ "request-id": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "service-instance-id": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "vnf-id": {
+ "required": true,
+ "type": "string"
+ },
+ "action-name": {
+ "required": true,
+ "type": "string"
+ },
+ "scope-type": {
+ "required": true,
+ "type": "string"
+ },
+ "hostname": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "request-info": {
+ "required": true,
+ "type": "dt-request-info-properties",
+ "input-param": true
+ },
+ "vnf_name": {
+ "required": true,
+ "type": "string"
+ }
+ },
+ "constraints": null,
+ "derived_from": "tosca.datatypes.Dynamic"
+ },
+ "dt-request-info-properties": {
+ "description": "This is Dynamically generated data type for workflow activate",
+ "version": "1.0.0",
+ "metadata": null,
+ "attributes": null,
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ },
+ "constraints": null,
+ "derived_from": "tosca.datatypes.Dynamic"
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.header b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.header
new file mode 100644
index 000000000..5464a754d
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflow-spec/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.file b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.file
new file mode 100644
index 000000000..58975d86a
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.file
@@ -0,0 +1,12 @@
+{
+ "blueprintName": "baseconfiguration",
+ "version": "1.0.0",
+ "workflows": [
+ "resource-assignment",
+ "activate",
+ "activate-restconf",
+ "activate-cli",
+ "assign-activate",
+ "imperative-test-wf"
+ ]
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.header b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/api/v1/blueprint-model/workflows/blueprint-name/baseconfiguration/version/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.file
new file mode 100644
index 000000000..91c3c87de
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.file
@@ -0,0 +1,197 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "topology_template": {
+ "policies": [
+ {
+ "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0": {
+ "type": "onap.policies.monitoring.tcagen2",
+ "type_version": "1.0.0",
+ "properties": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "policy-version": "1.0.0"
+ }
+ }
+ },
+ {
+ "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd": {
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "properties": {
+ "abatement": false,
+ "operations": [
+ {
+ "failure_retries": "final_failure_retries",
+ "id": "test1",
+ "failure_timeout": "final_failure_timeout",
+ "failure": "final_failure",
+ "operation": {
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": "{\"resource-assignment-properties\":{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}}"
+ },
+ "target": {
+ "entityIds": {
+ "resourceID": "Vloadbalancerms..vdns..module-3",
+ "modelInvariantId": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "modelVersionId": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "modelName": "Vloadbalancerms..vdns..module-3",
+ "modelVersion": "1",
+ "modelCustomizationId": "bafcdab0-801d-4d81-9ead-f464640a38b1"
+ },
+ "targetType": "VNF"
+ },
+ "actor": "SDNR",
+ "operation": "BandwidthOnDemand"
+ },
+ "failure_guard": "final_failure_guard",
+ "retries": 0,
+ "timeout": 0,
+ "failure_exception": "final_failure_exception",
+ "description": "test",
+ "success": "final_success"
+ }
+ ],
+ "trigger": "test1",
+ "timeout": 0,
+ "id": "LOOP_test"
+ },
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "policy-version": "1.0.0"
+ }
+ }
+ },
+ {
+ "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP": {
+ "type": "onap.policies.Naming",
+ "type_version": "1.0.0",
+ "properties": {
+ "naming-models": [
+ {
+ "naming-type": "VNF",
+ "naming-recipe": "AIC_CLOUD_REGION|DELIMITER|CONSTANT|DELIMITER|TIMESTAMP",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "AIC_CLOUD_REGION"
+ },
+ {
+ "property-name": "CONSTANT",
+ "property-value": "onap-nf"
+ },
+ {
+ "property-name": "TIMESTAMP"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VNFC",
+ "naming-recipe": "VNF_NAME|DELIMITER|NFC_NAMING_CODE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "ENTIRETY",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ },
+ {
+ "property-name": "NFC_NAMING_CODE"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VF-MODULE",
+ "naming-recipe": "VNF_NAME|DELIMITER|VF_MODULE_LABEL|DELIMITER|VF_MODULE_TYPE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ },
+ {
+ "property-name": "VF_MODULE_LABEL"
+ },
+ {
+ "property-name": "VF_MODULE_TYPE"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "PRECEEDING",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ }
+ ]
+ }
+ ],
+ "policy-instance-name": "ONAP_NF_NAMING_TIMESTAMP"
+ },
+ "name": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "policy-version": "1.0.0"
+ }
+ }
+ }
+ ]
+ },
+ "name": "ToscaServiceTemplateSimple",
+ "version": "1.0.0",
+ "metadata": {}
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policies/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.file
new file mode 100644
index 000000000..50fcf9135
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.file
@@ -0,0 +1,53 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.operational.common.Drools:
+ version: 1.0.0
+ description: Operational Policy for Control Loops using the Drools PDP
+ derived_from: onapy.policies.controlloop.Operational
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.controlloop.operational.common.Apex:
+ version: 1.0.0
+ description: Operational Policy for Control Loops using the APEX PDP
+ derived_from: onap.policies.controlloop.Operational
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.controlloop.guard.common.FrequencyLimiter:
+ version: 1.0.0
+ description: Supports limiting the frequency of actions being taken by a Actor.
+ derived_from: onap.policies.controlloop.Guard
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.controlloop.guard.common.Blacklist:
+ version: 1.0.0
+ description: Supports blacklist of VNF's from performing control loop actions on.
+ derived_from: onap.policies.controlloop.Guard
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.Naming:
+ version: 1.0.0
+ description: Supports blacklist of VNF's from performing control loop actions on.
+ derived_from: tosca.policies.Root
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.controlloop.guard.common.MinMax:
+ version: 1.0.0
+ description: Supports Min/Max number of VF Modules
+ derived_from: onap.policies.controlloop.Guard
+ properties:
+ # Omitted for brevity, see Section 1
+
+ onap.policies.controlloop.guard.common.MinMax:
+ version: 2.0.0
+ description: Supports Min/Max number of VF Modules
+ derived_from: onap.policies.controlloop.Guard
+ properties:
+ # Omitted for brevity, see Section 1
+
+data_types:
+ # Any bespoke data types referenced by policy type definitions[]
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.file
new file mode 100644
index 000000000..a00692971
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.file
@@ -0,0 +1,101 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.Naming:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ name: onap.policies.Naming
+ description: Virtual policy node for naming
+ properties:
+ policy-instance-name:
+ type: string
+ naming-models:
+ type: list
+ entry_schema:
+ type: policy.data.naming-model-entity
+data_types:
+ policy.data.naming-model-entity:
+ derived_from: tosca.datatypes.Root
+ properties:
+ nfRole:
+ type: string
+ required: false
+ metadata:
+ matchable: true
+ naming-type:
+ type: string
+ required: true
+ metadata:
+ matchable: true
+ naming-recipe:
+ type: string
+ required: true
+ name-operation:
+ type: string
+ required: false
+ naming-properties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.naming-property
+ policy.data.naming-property:
+ derived_from: tosca.datatypes.Root
+ properties:
+ property-name:
+ type: string
+ required: true
+ metadata:
+ matchable: true
+ property-value:
+ type: string
+ required: false
+ property-operation:
+ type: string
+ required: false
+ source-system:
+ type: string
+ required: false
+ source-endpoint:
+ type: string
+ required: false
+ increment-sequence:
+ type: policy.data.increment-sequence
+ required: false
+ policy.data.increment-sequence:
+ derived_from: tosca.datatypes.Root
+ properties:
+ scope:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - CLOUD_REGION_ID
+ - LOCATION_CLLI
+ - VNF
+ - VM
+ - VFMODULE
+ - PRECEEDING
+ - TRAILING
+ - ENTIRETY
+ sequence-type:
+ type: string
+ require: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - numeric
+ - alpha-numeric
+ start-value:
+ type: string
+ required: true
+ max:
+ type: string
+ required: false
+ increment:
+ type: string
+ required: true
+ length:
+ type: string
+ required: true \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.Naming/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.file
new file mode 100644
index 000000000..79e79f0fe
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.file
@@ -0,0 +1,38 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.guard.Common:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: |
+ This is the base Policy Type for Guard policies that guard the execution of Operational
+ Policies.
+ properties:
+ actor:
+ type: string
+ description: Specifies the Actor the guard applies to.
+ required: true
+ operation:
+ type: string
+ description: Specified the operation that the actor is performing the guard applies to.
+ required: true
+ timeRange:
+ type: tosca.datatypes.TimeInterval
+ description: |
+ An optional range of time during the day the guard policy is valid for.
+ required: false
+ id:
+ type: string
+ description: The Control Loop id this applies to.
+ required: false
+ onap.policies.controlloop.guard.common.Blacklist:
+ derived_from: onap.policies.controlloop.guard.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Supports blacklist of entity id's from performing control loop actions on.
+ properties:
+ blacklist:
+ type: list
+ description: List of entity id's
+ required: true
+ entry_schema:
+ type: string \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.Blacklist/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.file
new file mode 100644
index 000000000..163027e46
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.file
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.guard.Common:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: |
+ This is the base Policy Type for Guard policies that guard the execution of Operational
+ Policies.
+ properties:
+ actor:
+ type: string
+ description: Specifies the Actor the guard applies to.
+ required: true
+ operation:
+ type: string
+ description: Specified the operation that the actor is performing the guard applies to.
+ required: true
+ timeRange:
+ type: tosca.datatypes.TimeInterval
+ description: |
+ An optional range of time during the day the guard policy is valid for.
+ required: false
+ id:
+ type: string
+ description: The Control Loop id this applies to.
+ required: false
+ onap.policies.controlloop.guard.common.FrequencyLimiter:
+ derived_from: onap.policies.controlloop.guard.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Supports limiting the frequency of actions being taken by a Actor.
+ properties:
+ timeWindow:
+ type: integer
+ description: The time window to count the actions against.
+ required: true
+ timeUnits:
+ type: string
+ description: The units of time the window is counting.
+ constraints:
+ - valid_values: ["second", "minute", "hour", "day", "week", "month", "year"]
+ limit:
+ type: integer
+ description: The limit
+ required: true
+ constraints:
+ - greater_than: 0 \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.FrequencyLimiter/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.file
new file mode 100644
index 000000000..778efae9e
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.file
@@ -0,0 +1,80 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "policy_types": {
+ "onap.policies.controlloop.guard.Common": {
+ "properties": {
+ "id": {
+ "name": "id",
+ "type": "string",
+ "typeVersion": "0.0.0",
+ "description": "The Control Loop id this applies to.",
+ "required": false,
+ "constraints": [],
+ "metadata": {}
+ },
+ "actor": {
+ "name": "actor",
+ "type": "string",
+ "typeVersion": "0.0.0",
+ "description": "Specifies the Actor the guard applies to.",
+ "required": true,
+ "constraints": [],
+ "metadata": {}
+ },
+ "operation": {
+ "name": "operation",
+ "type": "string",
+ "typeVersion": "0.0.0",
+ "description": "Specified the operation that the actor is performing the guard applies to.",
+ "required": true,
+ "constraints": [],
+ "metadata": {}
+ },
+ "timeRange": {
+ "name": "timeRange",
+ "type": "tosca.datatypes.TimeInterval",
+ "typeVersion": "0.0.0",
+ "description": "An optional range of time during the day the guard policy is valid for.\n",
+ "required": false,
+ "constraints": [],
+ "metadata": {}
+ }
+ },
+ "name": "onap.policies.controlloop.guard.Common",
+ "version": "1.0.0",
+ "derived_from": "tosca.policies.Root",
+ "metadata": {},
+ "description": "This is the base Policy Type for Guard policies that guard the execution of Operational\nPolicies.\n"
+ },
+ "onap.policies.controlloop.guard.common.MinMax": {
+ "properties": {
+ "min": {
+ "name": "min",
+ "type": "integer",
+ "typeVersion": "0.0.0",
+ "description": "The minimum instances of this entity",
+ "required": true,
+ "constraints": [],
+ "metadata": {}
+ },
+ "max": {
+ "name": "max",
+ "type": "integer",
+ "typeVersion": "0.0.0",
+ "description": "The maximum instances of this entity",
+ "required": false,
+ "constraints": [],
+ "metadata": {}
+ }
+ },
+ "name": "onap.policies.controlloop.guard.common.MinMax",
+ "version": "1.0.0",
+ "derived_from": "onap.policies.controlloop.guard.Common",
+ "metadata": {},
+ "description": "Supports Min/Max number of entity for scaling operations"
+ }
+ },
+ "name": "ToscaServiceTemplateSimple",
+ "version": "1.0.0",
+ "metadata": {}
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.file
new file mode 100644
index 000000000..78bdde746
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.file
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.guard.Common:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: |
+ This is the base Policy Type for Guard policies that guard the execution of Operational
+ Policies.
+ properties:
+ actor:
+ type: string
+ description: Specifies the Actor the guard applies to.
+ required: true
+ operation:
+ type: string
+ description: Specified the operation that the actor is performing the guard applies to.
+ required: true
+ timeRange:
+ type: tosca.datatypes.TimeInterval
+ description: |
+ An optional range of time during the day the guard policy is valid for.
+ required: false
+ id:
+ type: string
+ description: The Control Loop id this applies to.
+ required: false
+ onap.policies.controlloop.guard.common.MinMax:
+ derived_from: onap.policies.controlloop.guard.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Supports Min/Max number of entity for scaling operations
+ properties:
+ min:
+ type: integer
+ required: true
+ description: The minimum instances of this entity
+ max:
+ type: integer
+ required: false
+ description: The maximum instances of this entity \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.header
new file mode 100644
index 000000000..5464a754d
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.guard.common.MinMax/versions/2.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.file
new file mode 100644
index 000000000..14ae7acd8
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.file
@@ -0,0 +1,360 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.operational.Common:
+ properties:
+ abatement:
+ name: abatement
+ type: boolean
+ typeVersion: 0.0.0
+ description: Whether an abatement event message will be expected for
+ the control loop from DCAE.
+ default: 'false'
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ operations:
+ name: operations
+ type: list
+ typeVersion: 0.0.0
+ description: List of operations to be performed when Control Loop
+ is triggered.
+ required: true
+ constraints: [
+ ]
+ entry_schema:
+ type: onap.datatype.controlloop.Operation
+ typeVersion: 0.0.0
+ constraints: [
+ ]
+ metadata: {
+ }
+ trigger:
+ name: trigger
+ type: string
+ typeVersion: 0.0.0
+ description: Initial operation to execute upon receiving an Onset
+ event message for the Control Loop.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ timeout:
+ name: timeout
+ type: integer
+ typeVersion: 0.0.0
+ description: |
+ Overall timeout for executing all the operations. This timeout should equal or exceed the total
+ timeout for each operation listed.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ id:
+ name: id
+ type: string
+ typeVersion: 0.0.0
+ description: The unique control loop id.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ name: onap.policies.controlloop.operational.Common
+ version: 1.0.0
+ derived_from: tosca.policies.Root
+ metadata: {
+ }
+ description: |
+ Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant
+ Policy Types. This does NOT support the legacy Policy YAML policy type.
+ onap.policies.controlloop.operational.common.Apex:
+ properties:
+ engineServiceParameters:
+ name: engineServiceParameters
+ type: string
+ typeVersion: 0.0.0
+ description: The engine parameters like name, instanceCount, policy
+ implementation, parameters etc.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ eventOutputParameters:
+ name: eventOutputParameters
+ type: string
+ typeVersion: 0.0.0
+ description: The event output parameters.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ javaProperties:
+ name: javaProperties
+ type: string
+ typeVersion: 0.0.0
+ description: Name/value pairs of properties to be set for APEX if
+ needed.
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ eventInputParameters:
+ name: eventInputParameters
+ type: string
+ typeVersion: 0.0.0
+ description: The event input parameters.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ name: onap.policies.controlloop.operational.common.Apex
+ version: 1.0.0
+ derived_from: onap.policies.controlloop.operational.Common
+ metadata: {
+ }
+ description: Operational policies for Apex PDP
+data_types:
+ onap.datatype.controlloop.Actor:
+ constraints: [
+ ]
+ properties:
+ payload:
+ name: payload
+ type: map
+ typeVersion: 0.0.0
+ description: Name/value pairs of payload information passed by Policy
+ to the actor
+ required: false
+ constraints: [
+ ]
+ entry_schema:
+ type: string
+ typeVersion: 0.0.0
+ constraints: [
+ ]
+ metadata:
+ clamp_possible_values: ClampExecution:CDS/payload
+ target:
+ name: target
+ type: onap.datatype.controlloop.Target
+ typeVersion: 0.0.0
+ description: The resource the operation should be performed on.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ actor:
+ name: actor
+ type: string
+ typeVersion: 0.0.0
+ description: The actor performing the operation.
+ required: true
+ constraints: [
+ ]
+ metadata:
+ clamp_possible_values: Dictionary:DefaultActors,ClampExecution:CDS/actor
+ operation:
+ name: operation
+ type: string
+ typeVersion: 0.0.0
+ description: The operation the actor is performing.
+ required: true
+ constraints: [
+ ]
+ metadata:
+ clamp_possible_values: Dictionary:DefaultOperations, ClampExecution:CDS/operation
+ name: onap.datatype.controlloop.Actor
+ version: 0.0.0
+ derived_from: tosca.datatypes.Root
+ metadata: {
+ }
+ description: An actor/operation/target definition
+ onap.datatype.controlloop.Operation:
+ constraints: [
+ ]
+ properties:
+ failure_retries:
+ name: failure_retries
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke when the current operation
+ has exceeded its max retries.
+ default: final_failure_retries
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ id:
+ name: id
+ type: string
+ typeVersion: 0.0.0
+ description: Unique identifier for the operation
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ failure_timeout:
+ name: failure_timeout
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke when the time out for
+ the operation occurs.
+ default: final_failure_timeout
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ failure:
+ name: failure
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke on Actor operation
+ failure.
+ default: final_failure
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ operation:
+ name: operation
+ type: onap.datatype.controlloop.Actor
+ typeVersion: 0.0.0
+ description: The definition of the operation to be performed.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ failure_guard:
+ name: failure_guard
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke when the current operation
+ is blocked due to guard policy enforcement.
+ default: final_failure_guard
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ retries:
+ name: retries
+ type: integer
+ typeVersion: 0.0.0
+ description: The number of retries the actor should attempt to perform
+ the operation.
+ default: '0'
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ timeout:
+ name: timeout
+ type: integer
+ typeVersion: 0.0.0
+ description: The amount of time for the actor to perform the operation.
+ required: true
+ constraints: [
+ ]
+ metadata: {
+ }
+ failure_exception:
+ name: failure_exception
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke when the current operation
+ causes an exception.
+ default: final_failure_exception
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ description:
+ name: description
+ type: string
+ typeVersion: 0.0.0
+ description: A user-friendly description of the intent for the operation
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ success:
+ name: success
+ type: string
+ typeVersion: 0.0.0
+ description: Points to the operation to invoke on success. A value
+ of "final_success" indicates and end to the operation.
+ default: final_success
+ required: false
+ constraints: [
+ ]
+ metadata: {
+ }
+ name: onap.datatype.controlloop.Operation
+ version: 0.0.0
+ derived_from: tosca.datatypes.Root
+ metadata: {
+ }
+ description: An operation supported by an actor
+ onap.datatype.controlloop.Target:
+ constraints: [
+ ]
+ properties:
+ entityIds:
+ name: entityIds
+ type: map
+ typeVersion: 0.0.0
+ description: |
+ Map of values that identify the resource. If none are provided, it is assumed that the
+ entity that generated the ONSET event will be the target.
+ required: false
+ constraints: [
+ ]
+ entry_schema:
+ type: string
+ typeVersion: 0.0.0
+ constraints: [
+ ]
+ metadata:
+ clamp_possible_values: ClampExecution:CSAR_RESOURCES
+ targetType:
+ name: targetType
+ type: string
+ typeVersion: 0.0.0
+ description: Category for the target type
+ required: true
+ constraints:
+ - valid_values:
+ - VNF
+ - VM
+ - VFMODULE
+ - PNF
+ metadata: {
+ }
+ name: onap.datatype.controlloop.Target
+ version: 0.0.0
+ derived_from: tosca.datatypes.Root
+ metadata: {
+ }
+ description: Definition for a entity in A&AI to perform a control loop operation
+ on
+name: ToscaServiceTemplateSimple
+version: 1.0.0
+metadata: {
+ }
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Apex/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.file
new file mode 100644
index 000000000..af7a61ef7
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.file
@@ -0,0 +1,150 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.operational.common.Drools:
+ derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Operational policies for Drools PDP
+ properties:
+ controllerName:
+ type: string
+ description: Drools controller properties
+ required: false
+ onap.policies.controlloop.operational.Common:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: |
+ Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant
+ Policy Types. This does NOT support the legacy Policy YAML policy type.
+ properties:
+ id:
+ type: string
+ description: The unique control loop id.
+ required: true
+ timeout:
+ type: integer
+ description: |
+ Overall timeout for executing all the operations. This timeout should equal or exceed the total
+ timeout for each operation listed.
+ required: true
+ abatement:
+ type: boolean
+ description: Whether an abatement event message will be expected for the control loop from DCAE.
+ required: true
+ default: false
+ trigger:
+ type: string
+ description: Initial operation to execute upon receiving an Onset event message for the Control Loop.
+ required: true
+ operations:
+ type: list
+ description: List of operations to be performed when Control Loop is triggered.
+ required: true
+ entry_schema:
+ type: onap.datatype.controlloop.Operation
+data_types:
+ onap.datatype.controlloop.Target:
+ derived_from: tosca.datatypes.Root
+ description: Definition for a entity in A&AI to perform a control loop operation on
+ properties:
+ targetType:
+ type: string
+ description: Category for the target type
+ required: true
+ constraints:
+ - valid_values: [VNF, VM, VFMODULE, PNF]
+ entityIds:
+ type: map
+ description: |
+ Map of values that identify the resource. If none are provided, it is assumed that the
+ entity that generated the ONSET event will be the target.
+ required: false
+ metadata:
+ clamp_possible_values: ClampExecution:CSAR_RESOURCES
+ entry_schema:
+ type: string
+
+ onap.datatype.controlloop.Actor:
+ derived_from: tosca.datatypes.Root
+ description: An actor/operation/target definition
+ properties:
+ actor:
+ type: string
+ description: The actor performing the operation.
+ required: true
+ metadata:
+ clamp_possible_values: Dictionary:DefaultActors,ClampExecution:CDS/actor
+ operation:
+ type: string
+ description: The operation the actor is performing.
+ required: true
+ metadata:
+ clamp_possible_values: Dictionary:DefaultOperations, ClampExecution:CDS/operations
+ target:
+ type: onap.datatype.controlloop.Target
+ description: The resource the operation should be performed on.
+ required: true
+ payload:
+ type: map
+ description: Name/value pairs of payload information passed by Policy to the actor
+ required: false
+ metadata:
+ clamp_possible_values: ClampExecution:CDS/payload
+ entry_schema:
+ type: string
+
+ onap.datatype.controlloop.Operation:
+ derived_from: tosca.datatypes.Root
+ description: An operation supported by an actor
+ properties:
+ id:
+ type: string
+ description: Unique identifier for the operation
+ required: true
+ description:
+ type: string
+ description: A user-friendly description of the intent for the operation
+ required: false
+ operation:
+ type: onap.datatype.controlloop.Actor
+ description: The definition of the operation to be performed.
+ required: true
+ timeout:
+ type: integer
+ description: The amount of time for the actor to perform the operation.
+ required: true
+ retries:
+ type: integer
+ description: The number of retries the actor should attempt to perform the operation.
+ required: true
+ default: 0
+ success:
+ type: string
+ description: Points to the operation to invoke on success. A value of "final_success" indicates and end to the operation.
+ required: false
+ default: final_success
+ failure:
+ type: string
+ description: Points to the operation to invoke on Actor operation failure.
+ required: false
+ default: final_failure
+ failure_timeout:
+ type: string
+ description: Points to the operation to invoke when the time out for the operation occurs.
+ required: false
+ default: final_failure_timeout
+ failure_retries:
+ type: string
+ description: Points to the operation to invoke when the current operation has exceeded its max retries.
+ required: false
+ default: final_failure_retries
+ failure_exception:
+ type: string
+ description: Points to the operation to invoke when the current operation causes an exception.
+ required: false
+ default: final_failure_exception
+ failure_guard:
+ type: string
+ description: Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.
+ required: false
+ default: final_failure_guard \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.controlloop.operational.common.Drools/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file
new file mode 100644
index 000000000..3c17c9004
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.file
@@ -0,0 +1,158 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: a base policy type for all policies that govern monitoring provisioning
+ onap.policies.monitoring.cdap.tca.hi.lo.app:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ properties:
+ tca_policy:
+ type: onap.datatypes.monitoring.tca_policy
+ description: TCA Policy JSON
+ required: true
+data_types:
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ type: string
+ required: true
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ eventName:
+ type: string
+ required: true
+ description: Event name to which thresholds need to be applied
+ policyName:
+ type: string
+ required: true
+ description: TCA Policy Scope Name
+ policyScope:
+ type: string
+ required: true
+ description: TCA Policy Scope
+ policyVersion:
+ type: string
+ required: true
+ description: TCA Policy Scope Version
+ thresholds:
+ type: list
+ required: true
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ type: string
+ required: true
+ description: Domain name to which TCA needs to be applied
+ default: measurementsForVfScaling
+ constraints:
+ - equal: measurementsForVfScaling
+ metricsPerEventName:
+ type: list
+ required: true
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ type: string
+ required: true
+ description: Closed Loop Control Name associated with the threshold
+ closedLoopEventStatus:
+ type: string
+ required: true
+ description: Closed Loop Event Status of the threshold
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ direction:
+ type: string
+ required: true
+ description: Direction of the threshold
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ fieldPath:
+ type: string
+ required: true
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ severity:
+ type: string
+ required: true
+ description: Threshold Event Severity
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ thresholdValue:
+ type: integer
+ required: true
+ description: Threshold value for the field Path inside CEF message
+ version:
+ type: string
+ required: true
+ description: Version number associated with the threshold \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.cdap.tca.hi.lo.app/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.file b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.file
new file mode 100644
index 000000000..367d2b5a4
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.file
@@ -0,0 +1,160 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ name: onap.policies.Monitoring
+ description: a base policy type for all policies that govern monitoring provisioning
+ onap.policies.monitoring.tcagen2:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ name: onap.policies.monitoring.tcagen2
+ properties:
+ tca.policy:
+ type: onap.datatypes.monitoring.tca_policy
+ description: TCA Policy JSON
+ required: true
+data_types:
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ type: string
+ required: true
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ eventName:
+ type: string
+ required: true
+ description: Event name to which thresholds need to be applied
+ policyName:
+ type: string
+ required: true
+ description: TCA Policy Scope Name
+ policyScope:
+ type: string
+ required: true
+ description: TCA Policy Scope
+ policyVersion:
+ type: string
+ required: true
+ description: TCA Policy Scope Version
+ thresholds:
+ type: list
+ required: true
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ type: string
+ required: true
+ description: Domain name to which TCA needs to be applied
+ default: measurementsForVfScaling
+ constraints:
+ - equal: measurementsForVfScaling
+ metricsPerEventName:
+ type: list
+ required: true
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ type: string
+ required: true
+ description: Closed Loop Control Name associated with the threshold
+ closedLoopEventStatus:
+ type: string
+ required: true
+ description: Closed Loop Event Status of the threshold
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ direction:
+ type: string
+ required: true
+ description: Direction of the threshold
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ fieldPath:
+ type: string
+ required: true
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ severity:
+ type: string
+ required: true
+ description: Threshold Event Severity
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ thresholdValue:
+ type: integer
+ required: true
+ description: Threshold value for the field Path inside CEF message
+ version:
+ type: string
+ required: true
+ description: Version number associated with the threshold \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.header b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/api/v1/policytypes/onap.policies.monitoring.tcagen2/versions/1.0.0/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.file b/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.file
new file mode 100644
index 000000000..467409f47
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.file
@@ -0,0 +1,104 @@
+{
+ "groups": [
+ {
+ "description": "This group should be used for managing all control loop related policies and pdps",
+ "name": "controlloop",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 1,
+ "pdpInstances": [],
+ "pdpType": "apex",
+ "policies": [
+ {
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0"
+ }
+ ],
+ "properties": {},
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.controlloop.Operational",
+ "version": "1.0.0"
+ },
+ {
+ "name": "onap.policies.controlloop.operational.common.*",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 1,
+ "pdpInstances": [],
+ "pdpType": "drools",
+ "policies": [
+ {
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0"
+ }
+ ],
+ "properties": {},
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.controlloop.operational.common.*",
+ "version": "1.0.0"
+ },
+ {
+ "name": "onap.policies.controlloop.Operational",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 1,
+ "pdpInstances": [],
+ "pdpType": "xacml",
+ "policies": [],
+ "properties": {},
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.controlloop.guard.common.*",
+ "version": "1.0.0"
+ }
+ ]
+ }
+ ],
+ "properties": {}
+ },
+ {
+ "description": "This group should be used for managing all monitoring related policies and pdps",
+ "name": "monitoring",
+ "pdpGroupState": "ACTIVE",
+ "pdpSubgroups": [
+ {
+ "currentInstanceCount": 0,
+ "desiredInstanceCount": 1,
+ "pdpInstances": [],
+ "pdpType": "xacml",
+ "policies": [
+ {
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0"
+ }
+ ],
+ "properties": {},
+ "supportedPolicyTypes": [
+ {
+ "name": "onap.policies.monitoring.*",
+ "version": "1.0.0"
+ },
+ {
+ "name": "onap.policies.Naming",
+ "version": "1.0.0"
+ }
+
+ ]
+ }
+ ],
+ "properties": {}
+ }
+ ]
+}
diff --git a/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.header b/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.header
new file mode 100644
index 000000000..b11784a21
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/example/policy/pap/v1/pdps/.header
@@ -0,0 +1 @@
+{"Transfer-Encoding": "chunked", "Server": "Jetty(9.3.21.v20170918)", "Content-Type": "application/json", "X-ECOMP-RequestID": "e2ddb3c8-994f-47df-b4dc-097d4fb55c08"} \ No newline at end of file
diff --git a/runtime/src/test/resources/http-cache/start_http_cache.sh b/runtime/src/test/resources/http-cache/start_http_cache.sh
new file mode 100755
index 000000000..1f84b56f5
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/start_http_cache.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2018 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+echo "Starting HTTP CACHE python script"
+for i in "$@"
+do
+case $i in
+ --python_proxyaddress=*)
+ python_proxyaddress="--proxyaddress ${i#*=}"
+ echo "- Using python_proxyaddress and set it to: $python_proxyaddress"
+ shift # past argument=value
+ ;;
+ --http_proxyaddress=*)
+ export http_proxy="${i#*=}"
+ export https_proxy="${i#*=}"
+ echo "- Defining http_proxy/https_proxy env variables to: $http_proxy"
+ shift # past argument=value
+ ;;
+ -?|--help|-help)
+ echo "Usage: $(basename $0) [--http_proxyaddress=<http://proxy_address:port>] [--python_proxyaddress=<python_simulator_address:port>]"
+ echo "--http_proxyaddress Set the http_proxy/https_proxy in the script before running python"
+ echo "--python_proxyaddress <python_simulator_address:port>, like localhost:8080 and will be set as --proxyaddress, this is the adress returned by DCAE simulator response"
+ exit 2
+ ;;
+esac
+done
+
+echo 'Installing requests packages for Python'
+pip install --no-cache-dir requests
+echo 'Executing the Http proxy in Cache mode only'
+python -u third_party_proxy.py --port 8080 --root /usr/src/http-cache-app/data-cache $python_proxyaddress
diff --git a/runtime/src/test/resources/http-cache/third_party_proxy.py b/runtime/src/test/resources/http-cache/third_party_proxy.py
new file mode 100644
index 000000000..7fe316852
--- /dev/null
+++ b/runtime/src/test/resources/http-cache/third_party_proxy.py
@@ -0,0 +1,497 @@
+#!/usr/bin/env python2
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2018 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+import json
+import requests
+import os
+import errno
+import sys
+import SimpleHTTPServer
+import SocketServer
+import argparse
+import tempfile
+import signal
+import uuid
+import shutil
+
+parser = argparse.ArgumentParser(description="3rd party Cache & Replay")
+parser.add_argument("--username", "-u", type=str, help="Set the username for contacting 3rd party - only used for GET")
+parser.add_argument("--password", "-p", type=str, help="Set the password for contacting 3rd party - only used for GET")
+parser.add_argument("--root", "-r", default=tempfile.mkdtemp(), type=str, help="Root folder for the proxy cache")
+parser.add_argument("--temp", "-t", default=tempfile.mkdtemp(), type=str, help="Temp folder for the generated content")
+parser.add_argument("--proxy" , type=str, help="Url of the Act as a proxy. If not set, this script only uses the cache and will return a 404 if files aren't found")
+parser.add_argument("--port", "-P", type=int, default="8081", help="Port on which the proxy should listen to")
+parser.add_argument("--verbose", "-v", type=bool, help="Print more information in case of error")
+parser.add_argument("--proxyaddress","-a", type=str, help="Address of this proxy, generally either third-party-proxy:8085 or localhost:8085 depending if started with docker-compose or not")
+options = parser.parse_args()
+
+
+PORT = options.port
+HOST = options.proxy
+AUTH = (options.username, options.password)
+HEADERS = {'X-ECOMP-InstanceID':'CLAMP'}
+CACHE_ROOT = str(options.root)
+TMP_ROOT = str(options.temp)
+PROXY_ADDRESS=str(options.proxyaddress)
+
+def signal_handler(signal_sent, frame):
+ global httpd
+ if signal_sent == signal.SIGINT:
+ print('Got Ctrl-C (SIGINT)')
+ httpd.socket.close()
+ httpd.shutdown()
+ httpd.server_close()
+
+class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ def print_headers(self):
+ for header,value in self.headers.items():
+ print("header: %s : %s" % (header, value))
+
+ def check_credentials(self):
+ pass
+
+ def _send_content(self, header_file, content_file):
+ self.send_response(200)
+ with open(header_file, 'rb') as f:
+ headers = json.load(f)
+ for key,value in headers.items():
+ if key in ('Transfer-Encoding',):
+ continue
+ self.send_header(key, value)
+ self.end_headers()
+ with open(content_file,'rb') as f:
+ fc = f.read()
+ self.wfile.write(fc)
+
+ def _write_cache(self,cached_file_folder, header_file, content_file, response):
+ os.makedirs(cached_file_folder, 0777)
+ with open(content_file, 'w') as f:
+ f.write(response.raw.read())
+ with open(header_file, 'w') as f:
+ json.dump(dict(response.raw.headers), f)
+ # Entry point of the code
+ def _get_cached_file_folder_name(self,folder):
+ cached_file_folder = '%s/%s' % (folder, self.path,)
+ print("Cached file name before escaping : %s" % cached_file_folder)
+ cached_file_folder = cached_file_folder.replace('<','&#60;').replace('>','&#62;').replace('?','&#63;').replace('*','&#42;').replace('\\','&#42;').replace(':','&#58;').replace('|','&#124;')
+ print("Cached file name after escaping (used for cache storage) : %s" % cached_file_folder)
+ return cached_file_folder
+
+ def _get_cached_content_file_name(self,cached_file_folder):
+ return "%s/.file" % (cached_file_folder,)
+
+ def _get_cached_header_file_name(self,cached_file_folder):
+ return "%s/.header" % (cached_file_folder,)
+
+ def _execute_content_generated_cases(self,http_type):
+ print("Testing special cases, cache files will be sent to :" +TMP_ROOT)
+ cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ _file_available = os.path.exists(cached_file_content)
+
+ if self.path.startswith("/dcae-service-types?asdcResourceId=") and http_type == "GET":
+ if not _file_available:
+ print "self.path start with /dcae-service-types?asdcResourceId=, generating response json..."
+ uuidGenerated = str(uuid.uuid4())
+ typeId = "typeId-" + uuidGenerated
+ typeName = "typeName-" + uuidGenerated
+ print "typeId generated: " + typeName + " and typeName: "+ typeId
+ jsonGenerated = "{\"totalCount\":1, \"items\":[{\"typeId\":\"" + typeId + "\", \"typeName\":\"" + typeName +"\"}]}"
+ print "jsonGenerated: " + jsonGenerated
+
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/dcae-operationstatus/install") and http_type == "GET":
+ if not _file_available:
+ print "self.path start with /dcae-operationstatus/install, generating response json..."
+ jsonGenerated = "{\"operationType\": \"install\", \"status\": \"succeeded\"}"
+ print "jsonGenerated: " + jsonGenerated
+
+ try:
+ os.makedirs(cached_file_folder, 0777)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ print(cached_file_folder+" already exists")
+
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/dcae-operationstatus/uninstall") and http_type == "GET":
+ if not _file_available:
+ print "self.path start with /dcae-operationstatus/uninstall, generating response json..."
+ jsonGenerated = "{\"operationType\": \"uninstall\", \"status\": \"succeeded\"}"
+ print "jsonGenerated: " + jsonGenerated
+
+ try:
+ os.makedirs(cached_file_folder, 0777)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ print(cached_file_folder+" already exists")
+
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/sdc/v1/catalog/services/") and http_type == "POST":
+ if not _file_available:
+ print "self.path start with /sdc/v1/catalog/services/, generating response json..."
+ jsondata = json.loads(self.data_string)
+ jsonGenerated = "{\"artifactName\":\"" + jsondata['artifactName'] + "\",\"artifactType\":\"" + jsondata['artifactType'] + "\",\"artifactURL\":\"" + self.path + "\",\"artifactDescription\":\"" + jsondata['description'] + "\",\"artifactChecksum\":\"ZjJlMjVmMWE2M2M1OTM2MDZlODlmNTVmZmYzNjViYzM=\",\"artifactUUID\":\"" + str(uuid.uuid4()) + "\",\"artifactVersion\":\"1\"}"
+ print "jsonGenerated: " + jsonGenerated
+
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/dcae-deployments/") and http_type == "PUT":
+ print "self.path start with /dcae-deployments/ DEPLOY, generating response json..."
+ #jsondata = json.loads(self.data_string)
+ jsonGenerated = "{\"operationType\":\"install\",\"status\":\"processing\",\"links\":{\"status\":\"http:\/\/" + PROXY_ADDRESS + "\/dcae-operationstatus/install?test=test\"}}"
+ print "jsonGenerated: " + jsonGenerated
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/dcae-deployments/") and http_type == "DELETE":
+ print "self.path start with /dcae-deployments/ UNDEPLOY, generating response json..."
+ #jsondata = json.loads(self.data_string)
+ jsonGenerated = "{\"operationType\":\"uninstall\",\"status\":\"processing\",\"links\":{\"status\":\"http:\/\/" + PROXY_ADDRESS + "\/dcae-operationstatus/uninstall?test=test\"}}"
+ print "jsonGenerated: " + jsonGenerated
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(jsonGenerated)
+ return True
+ elif (self.path.startswith("/pdp/api/") and (http_type == "PUT" or http_type == "DELETE")) or (self.path.startswith("/pdp/api/policyEngineImport") and http_type == "POST"):
+ print "self.path start with /pdp/api/, copying body to response ..."
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(self.data_string)
+ return True
+ elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "POST":
+ print "self.path start with POST new policy API /pdp/api/, copying body to response ..."
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(self.data_string)
+ return True
+ elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "DELETE":
+ print "self.path start with DELETE new policy API /policy/api/v1/policytypes/ ..."
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(self.data_string)
+ return True
+ elif self.path.startswith("/policy/pap/v1/pdps/policies") and http_type == "POST":
+ print "self.path start with POST new policy API /policy/pap/v1/pdps/ ..."
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w+') as f:
+ f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
+ with open(cached_file_content, 'w+') as f:
+ f.write(self.data_string)
+ return True
+ elif (self.path.startswith("/policy/pap/v1/policies/deployed/")) and http_type == "GET":
+ print "self.path start with /policy/api/v1/policytypes/, generating response json..."
+ jsonGenerated = "{\"policyTypeId\": \"onap.policies.controlloop.operational\",\"policyTypeVersion\": \"1.0.0\",\"policyId\": \"OPERATIONAL_z711F_v1_0_ResourceInstanceName1_tca\"}"
+ print "jsonGenerated: " + jsonGenerated
+ if not os.path.exists(cached_file_folder):
+ os.makedirs(cached_file_folder, 0777)
+
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(jsonGenerated)
+ return True
+ elif self.path.startswith("/dcae-service-types") and http_type == "GET":
+ if not _file_available:
+ self.path = "/dcae-service-types"
+ cached_file_folder = '%s/%s' % (TMP_ROOT, self.path)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ print "self.path start with /dcae-service-types, generating response json..."
+ response = "{\"links\": {\"previousLink\": {\"title\": \"string\",\"rel\": \"string\",\"uri\": \"string\",\"uriBuilder\": {},\"rels\": [\"string\"],\"params\": {\"additionalProp1\": \"string\",\"additionalProp2\": \"string\",\"additionalProp3\": \"string\"},\"type\": \"string\"},\"nextLink\": {\"title\": \"string\",\"rel\": \"string\",\"uri\": \"string\",\"uriBuilder\": {},\"rels\": [\"string\"],\"params\": {\"additionalProp1\": \"string\",\"additionalProp2\": \"string\",\"additionalProp3\": \"string\"},\"type\": \"string\"}},\"totalCount\": 1,\"items\": [{\"owner\": \"testOwner\",\"application\": \"testApplication\",\"component\": \"testComponent\",\"typeName\": \"testTypeName\",\"typeVersion\": 0,\"blueprintTemplate\": \"testBlueprintTemplate\",\"serviceIds\": [\"serviceId1\", \"serviceId2\"],\"vnfTypes\": [\"vnfType1\", \"vnfType2\"],\"serviceLocations\": [\"serviceLocation1\", \"serviceLocation2\"],\"asdcServiceId\": \"testAsdcServiceId\",\"asdcResourceId\": \"0\",\"asdcServiceURL\": \"testAsdcServiceURL\",\"typeId\": \"testtypeId\",\"selfLink\": {\"title\": \"selfLinkTitle\",\"rel\": \"selfLinkRel\",\"uri\": \"selfLinkUri\",\"uriBuilder\": {},\"rels\": [\"string\"],\"params\": {\"additionalProp1\": \"string\",\"additionalProp2\": \"string\",\"additionalProp3\": \"string\"},\"type\": \"string\"},\"created\": \"2020-01-22T09:38:15.436Z\",\"deactivated\": \"2020-01-22T09:38:15.437Z\"},{\"owner\": \"testOwner2\",\"application\": \"testApplication1\",\"component\": \"testComponent2\",\"typeName\": \"testTypeName2\",\"typeVersion\": 0,\"blueprintTemplate\": \"testBlueprintTemplate2\",\"serviceIds\": [\"serviceId3\", \"serviceId4\"],\"vnfTypes\": [\"vnfType13\", \"vnfType4\"],\"serviceLocations\": [\"serviceLocation3\", \"serviceLocation4\"],\"asdcServiceId\": \"testAsdcServiceId\",\"asdcResourceId\": \"1\",\"asdcServiceURL\": \"testAsdcServiceURL2\",\"typeId\": \"testtypeId2\",\"selfLink\": {\"title\": \"selfLinkTitle\",\"rel\": \"selfLinkRel\",\"uri\": \"selfLinkUri\",\"uriBuilder\": {},\"rels\": [\"string\"],\"params\": {\"additionalProp1\": \"string\",\"additionalProp2\": \"string\",\"additionalProp3\": \"string\"},\"type\": \"string\"},\"created\": \"2020-01-22T09:38:15.436Z\",\"deactivated\": \"2020-01-22T09:38:15.437Z\"}]}"
+ print "jsonGenerated: " + response
+
+ os.makedirs(cached_file_folder, 0777)
+ with open(cached_file_header, 'w') as f:
+ f.write("{\"Content-Length\": \"" + str(len(response)) + "\", \"Content-Type\": \"application/json\"}")
+ with open(cached_file_content, 'w') as f:
+ f.write(response)
+ return True
+ else:
+ return False
+
+
+ def do_GET(self):
+ cached_file_folder = ""
+ cached_file_content =""
+ cached_file_header=""
+ print("\n\n\nGot a GET request for %s " % self.path)
+
+ self.print_headers()
+ self.check_credentials()
+ # Verify if it's a special case
+ is_special = self._execute_content_generated_cases("GET")
+ if is_special:
+ cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ else:
+ cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+
+ _file_available = os.path.exists(cached_file_content)
+
+ if not _file_available:
+ print("Request for data currently not present in cache: %s" % (cached_file_folder,))
+
+ if not HOST:
+ self.send_response(404)
+ self.end_headers()
+ self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
+ print("HOST value is: %s " % (options.proxy))
+ return "404 Not found, no remote HOST specified on the emulator !!!"
+
+ url = '%s%s' % (HOST, self.path)
+ response = requests.get(url, auth=AUTH, headers=HEADERS, stream=True)
+
+ if response.status_code == 200:
+ self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
+ else:
+ print('Error when requesting file :')
+ print('Requested url : %s' % (url,))
+ print('Status code : %s' % (response.status_code,))
+ print('Content : %s' % (response.content,))
+ self.send_response(response.status_code)
+ self.end_headers()
+ self.wfile.write('404 Not found, nothing found on the remote server !!!')
+ return response.content
+ else:
+ print("Request for data currently present in cache: %s" % (cached_file_folder,))
+ print("HOST value is: %s " % (HOST))
+
+ self._send_content(cached_file_header, cached_file_content)
+
+ if self.path.startswith("/dcae-service-types?asdcResourceId="):
+ print "DCAE case deleting folder created " + cached_file_folder
+ shutil.rmtree(cached_file_folder, ignore_errors=False, onerror=None)
+ elif self.path.startswith("/dcae-service-types"):
+ print "DCAE case deleting folder created " + cached_file_folder
+ shutil.rmtree(cached_file_folder, ignore_errors=False, onerror=None)
+ else:
+ print "NOT in DCAE case deleting folder created " + cached_file_folder
+
+ def do_POST(self):
+ cached_file_folder = ""
+ cached_file_content =""
+ cached_file_header=""
+ print("\n\n\nGot a POST for %s" % self.path)
+ self.check_credentials()
+ self.data_string = self.rfile.read(int(self.headers['Content-Length']))
+ print("data-string:\n %s" % self.data_string)
+ print("self.headers:\n %s" % self.headers)
+
+ is_special = self._execute_content_generated_cases("POST")
+ if is_special:
+ cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ else:
+ cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+
+ _file_available = os.path.exists(cached_file_content)
+
+ if not _file_available:
+
+ if not HOST:
+ self.send_response(404)
+ self.end_headers()
+ self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
+ return "404 Not found, no remote HOST specified on the emulator !!!"
+
+ print("Request for data currently not present in cache: %s" % (cached_file_folder,))
+
+ url = '%s%s' % (HOST, self.path)
+ print("url: %s" % (url,))
+ response = requests.post(url, data=self.data_string, headers=self.headers, stream=True)
+
+ if response.status_code == 200:
+ self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
+ else:
+ print('Error when requesting file :')
+ print('Requested url : %s' % (url,))
+ print('Status code : %s' % (response.status_code,))
+ print('Content : %s' % (response.content,))
+ self.send_response(response.status_code)
+ self.end_headers()
+ self.wfile.write('404 Not found, nothing found on the remote server !!!')
+ return response.content
+ else:
+ print("Request for data present in cache: %s" % (cached_file_folder,))
+
+ self._send_content(cached_file_header, cached_file_content)
+
+ def do_PUT(self):
+ cached_file_folder = ""
+ cached_file_content =""
+ cached_file_header=""
+ print("\n\n\nGot a PUT for %s " % self.path)
+ self.check_credentials()
+ self.data_string = self.rfile.read(int(self.headers['Content-Length']))
+ print("data-string:\n %s" % self.data_string)
+ print("self.headers:\n %s" % self.headers)
+
+ is_special = self._execute_content_generated_cases("PUT")
+ if is_special:
+ cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ else:
+ cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+
+ _file_available = os.path.exists(cached_file_content)
+
+ if not _file_available:
+ if not HOST:
+ self.send_response(404)
+ self.end_headers()
+ self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
+ return "404 Not found, no remote HOST specified on the emulator !!!"
+
+ print("Request for data currently not present in cache: %s" % (cached_file_folder,))
+
+ url = '%s%s' % (HOST, self.path)
+ print("url: %s" % (url,))
+ response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
+
+ if response.status_code == 200:
+ self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
+ else:
+ print('Error when requesting file :')
+ print('Requested url : %s' % (url,))
+ print('Status code : %s' % (response.status_code,))
+ print('Content : %s' % (response.content,))
+ self.send_response(response.status_code)
+ self.end_headers()
+ self.wfile.write('404 Not found, nothing found on the remote server !!!')
+ return response.content
+ else:
+ print("Request for data present in cache: %s" % (cached_file_folder,))
+
+ self._send_content(cached_file_header, cached_file_content)
+
+
+ def do_DELETE(self):
+ cached_file_folder = ""
+ cached_file_content =""
+ cached_file_header=""
+ print("\n\n\nGot a DELETE for %s " % self.path)
+ self.check_credentials()
+ if self.headers.get('Content-Length') is not None:
+ self.data_string = self.rfile.read(int(self.headers['Content-Length']))
+ else:
+ self.data_string = "empty generated"
+ print("self.headers:\n %s" % self.headers)
+
+ is_special = self._execute_content_generated_cases("DELETE")
+ if is_special:
+ cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+ else:
+ cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
+ cached_file_content = self._get_cached_content_file_name(cached_file_folder)
+ cached_file_header = self._get_cached_header_file_name(cached_file_folder)
+
+ _file_available = os.path.exists(cached_file_content)
+
+ if not _file_available:
+ if not HOST:
+ self.send_response(404)
+ self.end_headers()
+ self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
+ return "404 Not found, no remote HOST specified on the emulator !!!"
+
+ print("Request for data currently not present in cache: %s" % (cached_file_folder,))
+
+ url = '%s%s' % (HOST, self.path)
+ print("url: %s" % (url,))
+ response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
+
+ if response.status_code == 200:
+ self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
+ else:
+ print('Error when requesting file :')
+ print('Requested url : %s' % (url,))
+ print('Status code : %s' % (response.status_code,))
+ print('Content : %s' % (response.content,))
+ self.send_response(response.status_code)
+ self.end_headers()
+ self.wfile.write('404 Not found, nothing found on the remote server !!!')
+ return response.content
+ else:
+ print("Request for data present in cache: %s" % (cached_file_folder,))
+
+ self._send_content(cached_file_header, cached_file_content)
+
+
+
+# Main code that start the HTTP server
+httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
+httpd.allow_reuse_address = True
+print "Listening on port "+ str(PORT) + "(Press Ctrl+C/Ctrl+Z to stop HTTPD Caching script)"
+print "Caching folder " + CACHE_ROOT + ", Tmp folder for generated files " + TMP_ROOT
+signal.signal(signal.SIGINT, signal_handler)
+httpd.serve_forever() \ No newline at end of file
diff --git a/runtime/src/test/resources/https/https-test.properties b/runtime/src/test/resources/https/https-test.properties
new file mode 100644
index 000000000..14079a78e
--- /dev/null
+++ b/runtime/src/test/resources/https/https-test.properties
@@ -0,0 +1,135 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+### Set the port for HTTP or HTTPS protocol (Controlled by Spring framework, only one at a time).
+### (See below for the parameter 'server.http.port' if you want to have both enabled)
+### To have only HTTP, keep the lines server.ssl.* commented
+### To have only HTTPS enabled, uncomment the server.ssl.* lines and specify a right keystore location
+server.port=${clamp.it.tests.https}
+### Settings for HTTPS (this automatically enables the HTTPS on the port 'server.port')
+server.ssl.key-store=classpath:clds/aaf/org.onap.clamp.p12
+server.ssl.key-store-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-store-type=PKCS12
+server.ssl.key-alias=clamptest
+
+# The key file used to decode the key store and trust store password
+# If not defined, the key store and trust store password will not be decrypted
+clamp.config.keyFile=classpath:clds/aaf/org.onap.clamp.keyfile
+clamp.config.caCerts=classpath:clds/aaf/ssl/ca-certs.pem
+
+## Config part for Client certificates
+server.ssl.client-auth=want
+server.ssl.trust-store=classpath:clds/aaf/truststoreONAPall.jks
+server.ssl.trust-store-password=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
+
+### In order to be user friendly when HTTPS is enabled,
+### you can add another HTTP port that will be automatically redirected to HTTPS
+### by enabling this parameter (server.http.port) and set it to another port (80 or 8080, 8090, etc ...)
+server.http-to-https-redirection.port=${clamp.it.tests.http-redirected}
+
+### HTTP Example:
+###--------------
+### server.port=8080
+
+### HTTPS Example:
+### --------------
+### server.port=8443
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+
+### HTTP (Redirected to HTTPS) and HTTPS Example:
+### --------------------------------------------
+### server.port=8443 <-- The HTTPS port
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+### server.http-to-https-redirection.port=8090 <-- The HTTP port
+
+server.servlet.context-path=/
+#Modified engine-rest applicationpath
+spring.profiles.active=clamp-default, clamp-aaf-authentication,clamp-ssl-config
+
+
+#clds datasource connection details
+spring.datasource.driverClassName=org.mariadb.jdbc.Driver
+spring.datasource.url=jdbc:mariadb:sequential://localhost:${docker.mariadb.port.host}/cldsdb4?autoReconnect=true&retriesAllDown=2147483647&failoverLoopRetries=2147483647
+spring.datasource.username=clds
+spring.datasource.password=sidnnd83K
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.validationQueryTimeout=20000
+spring.datasource.validationInterval=30000
+spring.datasource.testWhileIdle = true
+spring.datasource.minIdle = 0
+spring.datasource.initialSize=0
+# Automatically test whether a connection provided is good or not
+spring.datasource.testOnBorrow=true
+spring.datasource.ignoreExceptionOnPreLoad=true
+
+camel.springboot.consumer-template-cache-size=1000
+camel.springboot.producer-template-cache-size=1000
+# JMX enabled to have Camel Swagger runtime working
+camel.springboot.jmx-enabled=true
+camel.defaultthreadpool.poolsize=10
+camel.defaultthreadpool.maxpoolsize=20
+camel.defaultthreadpool.maxqueuesize=1000
+camel.defaultthreadpool.keepaliveTime=60
+camel.defaultthreadpool.rejectpolicy=CallerRuns
+camel.springboot.xml-routes=classpath:/clds/camel/routes/*.xml
+camel.springboot.xml-rests=classpath:/clds/camel/rest/*.xml
+camel.springboot.backlog-tracing=true
+camel.springboot.tracing=true
+camel.springboot.message-history=true
+
+#For EELF logback file
+#com.att.eelf.logging.path=
+com.att.eelf.logging.file=logback-default.xml
+#The log folder that will be used in logback.xml file
+clamp.config.log.path=log
+
+clamp.config.httpclient.socketTimeout=20000
+clamp.config.httpclient.connectTimeout=10000
+
+#Define user permission related parameters, the permission type can be changed but MUST be redefined in clds-users.properties in that case !
+clamp.config.security.permission.type.cl=org.onap.clamp.clds.cl
+clamp.config.security.permission.type.cl.manage=org.onap.clamp.clds.cl.manage
+clamp.config.security.permission.type.cl.event=org.onap.clamp.clds.cl.event
+clamp.config.security.permission.type.filter.vf=org.onap.clamp.clds.filter.vf
+clamp.config.security.permission.type.template=org.onap.clamp.clds.template
+clamp.config.security.permission.type.tosca=org.onap.clamp.clds.tosca
+clamp.config.security.permission.type.policies=org.onap.clamp.clds.policies
+#This one indicates the type of instances (dev|prod|perf...), this must be set accordingly in clds-users.properties
+clamp.config.security.permission.instance=dev
+clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal, org.onap.aaf.cadi.principal.CachedBasicPrincipal
+
+#AAF related parameters
+clamp.config.cadi.cadiLoglevel=DEBUG
+clamp.config.cadi.cadiLatitude=10
+clamp.config.cadi.cadiLongitude=10
+clamp.config.cadi.aafLocateUrl=https://aaf-locate:8095
+clamp.config.cadi.oauthTokenUrl= https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.token:2.1/token
+clamp.config.cadi.oauthIntrospectUrll=https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.introspect:2.1/introspect
+clamp.config.cadi.aafEnv=DEV
+clamp.config.cadi.aafUrl=https://AAF_LOCATE_URL/onap.org.osaaf.aaf.service:2.1
+clamp.config.cadi.cadiX509Issuers=CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US \ No newline at end of file
diff --git a/runtime/src/test/resources/https/keystore-test.jks b/runtime/src/test/resources/https/keystore-test.jks
new file mode 100644
index 000000000..04ad3b114
--- /dev/null
+++ b/runtime/src/test/resources/https/keystore-test.jks
Binary files differ
diff --git a/runtime/src/test/resources/logback.xml b/runtime/src/test/resources/logback.xml
new file mode 100644
index 000000000..97a8982a9
--- /dev/null
+++ b/runtime/src/test/resources/logback.xml
@@ -0,0 +1,95 @@
+<!-- Empty Configuration to prevent creating log files by Units Tests (e.g LoggingUtilsTest) ! -->
+<configuration>
+ <jmxConfigurator />
+ <!-- Example evaluator filter applied against console appender -->
+ <property
+ name="p_tim"
+ value="%d{&quot;yyyy-MM-dd'T'HH:mm:ss.SSSXXX&quot;, UTC}" />
+ <property
+ name="p_lvl"
+ value="%level" />
+ <property
+ name="p_log"
+ value="%logger" />
+ <property
+ name="p_mdc"
+ value="%replace(%replace(%mdc){'\t','\\\\t'}){'\n', '\\\\n'}" />
+ <property
+ name="p_msg"
+ value="%replace(%replace(%msg){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_exc"
+ value="%replace(%replace(%rootException){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_mak"
+ value="%replace(%replace(%marker){'\t', '\\\\t'}){'\n','\\\\n'}" />
+ <property
+ name="p_thr"
+ value="%thread" />
+ <property
+ name="defaultPattern"
+ value="%nopexception${p_tim}\t${p_thr}\t${p_lvl}\t${p_log}\t${p_mdc}\t${p_msg}\t${p_exc}\t${p_mak}\t%n" />
+ <property
+ name="debugPattern"
+ value="%nopexception${p_tim}|${p_lvl}|${p_mdc}|${p_exc}|%msg%n" />
+
+ <!-- Example evaluator filter applied against console appender -->
+ <appender
+ name="STDOUT"
+ class="ch.qos.logback.core.ConsoleAppender">
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>INFO</level>
+ </filter>
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+ <logger
+ name="org.onap.aaf"
+ level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </logger>
+ <logger
+ name="org.apache"
+ level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </logger>
+ <!-- Spring related loggers -->
+ <logger
+ name="org.springframework"
+ level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <!-- CLDS related loggers -->
+ <logger
+ name="org.onap.policy.clamp"
+ level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <!-- CLDS related loggers -->
+ <logger
+ name="com.att.eelf.error"
+ level="OFF">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <logger
+ name="ch.qos.logback.classic"
+ level="INFO" >
+ <appender-ref ref="STDOUT" />
+ </logger>
+ <logger
+ name="ch.qos.logback.core"
+ level="INFO" >
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <!-- logback jms appenders & loggers definition ends here -->
+
+ <root level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
diff --git a/runtime/src/test/resources/robotframework/Dockerfile b/runtime/src/test/resources/robotframework/Dockerfile
new file mode 100644
index 000000000..e93b7b9d1
--- /dev/null
+++ b/runtime/src/test/resources/robotframework/Dockerfile
@@ -0,0 +1,6 @@
+FROM ppodgorsek/robot-framework:3.8.0
+
+USER root
+COPY requirements.txt .
+RUN pip3 install --no-cache-dir -r requirements.txt
+
diff --git a/runtime/src/test/resources/robotframework/requirements.txt b/runtime/src/test/resources/robotframework/requirements.txt
new file mode 100644
index 000000000..2ae8f4500
--- /dev/null
+++ b/runtime/src/test/resources/robotframework/requirements.txt
@@ -0,0 +1,6 @@
+certifi
+chardet
+idna
+requests
+urllib3
+robotframework-extendedrequestslibrary
diff --git a/runtime/src/test/resources/robotframework/robotframework-test.properties b/runtime/src/test/resources/robotframework/robotframework-test.properties
new file mode 100644
index 000000000..fed074198
--- /dev/null
+++ b/runtime/src/test/resources/robotframework/robotframework-test.properties
@@ -0,0 +1,180 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP POLICY-CLAMP
+# ================================================================================
+# Copyright (C) 2017-2018, 2021 AT&T Intellectual Property. 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============================================
+# ===================================================================
+#
+###
+
+### Set the port for HTTP or HTTPS protocol (Controlled by Spring framework, only one at a time).
+### (See below for the parameter 'server.http.port' if you want to have both enabled)
+### To have only HTTP, keep the lines server.ssl.* commented
+### To have only HTTPS enabled, uncomment the server.ssl.* lines and specify a right keystore location
+server.port=${clamp.it.tests.robotframework.http}
+### Settings for HTTPS (this automatically enables the HTTPS on the port 'server.port')
+#server.ssl.key-store=file:/tmp/mykey.jks
+#server.ssl.key-store-password=pass
+#server.ssl.key-password=pass
+
+clamp.config.keyFile=classpath:clds/aaf/org.onap.clamp.keyfile
+
+### In order to be user friendly when HTTPS is enabled,
+### you can add another HTTP port that will be automatically redirected to HTTPS
+### by enabling this parameter (server.http.port) and set it to another port (80 or 8080, 8090, etc ...)
+#server.http-to-https-redirection.port=8090
+
+### HTTP Example:
+###--------------
+### server.port=8080
+
+### HTTPS Example:
+### --------------
+### server.port=8443
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+
+### HTTP (Redirected to HTTPS) and HTTPS Example:
+### --------------------------------------------
+### server.port=8443 <-- The HTTPS port
+### server.ssl.key-store=file:/tmp/mykey.jks
+### server.ssl.key-store-password=mypass
+### server.ssl.key-password=mypass
+### server.http-to-https-redirection.port=8090 <-- The HTTP port
+
+server.servlet.context-path=/
+#Modified engine-rest applicationpath
+spring.profiles.active=clamp-default,clamp-default-user
+spring.http.converters.preferred-json-mapper=gson
+
+#The max number of active threads in this pool
+server.tomcat.max-threads=200
+#The minimum number of threads always kept alive
+server.tomcat.min-Spare-Threads=25
+#The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads
+server.tomcat.max-idle-time=60000
+
+#Servlet context parameters
+server.context_parameters.p-name=value #context parameter with p-name as key and value as value.
+
+camel.springboot.consumer-template-cache-size=1000
+camel.springboot.producer-template-cache-size=1000
+# JMX enabled to have Camel Swagger runtime working
+camel.springboot.jmx-enabled=true
+camel.defaultthreadpool.poolsize=10
+camel.defaultthreadpool.maxpoolsize=20
+camel.defaultthreadpool.maxqueuesize=1000
+camel.defaultthreadpool.keepaliveTime=60
+camel.defaultthreadpool.rejectpolicy=CallerRuns
+camel.springboot.xml-routes=classpath:/clds/camel/routes/*.xml
+camel.springboot.xml-rests=classpath:/clds/camel/rest/*.xml
+camel.springboot.backlog-tracing=true
+camel.springboot.tracing=true
+camel.springboot.message-history=true
+
+#clds datasource connection details
+spring.datasource.driverClassName=org.mariadb.jdbc.Driver
+spring.datasource.url=jdbc:mariadb:sequential://localhost:3306,localhost:${docker.mariadb.port.host}/cldsdb4?autoReconnect=true&connectTimeout=10000&socketTimeout=10000&retriesAllDown=3
+spring.datasource.username=clds
+spring.datasource.password=sidnnd83K
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.validationQueryTimeout=20000
+spring.datasource.validationInterval=30000
+spring.datasource.testWhileIdle = true
+spring.datasource.minIdle = 0
+spring.datasource.initialSize=0
+# Automatically test whether a connection provided is good or not
+spring.datasource.testOnBorrow=true
+spring.datasource.ignoreExceptionOnPreLoad=true
+
+spring.jpa.properties.javax.persistence.schema-generation.database.action=none
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+# disable Hibernate DDL generation because the schema will be generated from a sql script
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+spring.jpa.properties.hibernate.ddl-auto=validate
+spring.jpa.properties.hibernate.hbm2ddl.delimiter=;
+spring.jpa.properties.hibernate.format_sql=true
+spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
+
+# Whether to enable logging of SQL statements.
+#spring.jpa.show-sql=true
+
+#Async Executor default Parameters
+async.core.pool.size=10
+async.max.pool.size=20
+async.queue.capacity=500
+
+#For EELF logback file
+#com.att.eelf.logging.path=
+clamp.config.logback.filename=logback-default.xml
+#The log folder that will be used in logback.xml file
+clamp.config.log.path=log
+clamp.config.files.systemProperties=classpath:/system.properties
+clamp.config.files.cldsUsers=classpath:/clds/clds-users.json
+clamp.config.files.globalProperties=classpath:/clds/templates/globalProperties.json
+clamp.config.files.sdcController=classpath:/clds/sdc-controllers-config.json
+
+clamp.config.httpclient.socketTimeout=20000
+clamp.config.httpclient.connectTimeout=10000
+
+#
+# Configuration Settings for Policy Engine Components
+clamp.config.policy.api.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.policy.api.userName=healthcheck
+clamp.config.policy.api.password=zb!XztG34
+clamp.config.policy.pap.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.policy.pap.userName=healthcheck
+clamp.config.policy.pap.password=zb!XztG34
+
+# Sdc service properties
+#
+clamp.config.sdc.csarFolder = ${project.build.directory}/sdc-tests
+
+#DCAE Inventory Url Properties
+clamp.config.dcae.inventory.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.dcae.intentory.retry.interval=100
+clamp.config.dcae.intentory.retry.limit=1
+
+#DCAE Deployment Url Properties
+clamp.config.dcae.deployment.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.dcae.deployment.userName=test
+clamp.config.dcae.deployment.password=test
+
+#Define user permission related parameters, the permission type can be changed but MUST be redefined in clds-users.properties in that case !
+clamp.config.security.permission.type.cl=org.onap.clamp.clds.cl
+clamp.config.security.permission.type.cl.manage=org.onap.clamp.clds.cl.manage
+clamp.config.security.permission.type.cl.event=org.onap.clamp.clds.cl.event
+clamp.config.security.permission.type.filter.vf=org.onap.clamp.clds.filter.vf
+clamp.config.security.permission.type.template=org.onap.clamp.clds.template
+clamp.config.security.permission.type.tosca=org.onap.clamp.clds.tosca
+clamp.config.security.permission.type.policies=org.onap.clamp.clds.policies
+#This one indicates the type of instances (dev|prod|perf...), this must be set accordingly in clds-users.properties
+clamp.config.security.permission.instance=dev
+clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal, org.onap.aaf.cadi.principal.CachedBasicPrincipal
+
+# Configuration settings for CDS
+clamp.config.cds.url=http://localhost:${docker.http-cache.port.host}
+clamp.config.cds.userName=ccsdkapps
+clamp.config.cds.password=ccsdkapps
+
+## Tosca converter
+clamp.config.tosca.converter.json.schema.templates=classpath:/clds/tosca-converter/templates.json
+clamp.config.tosca.converter.default.datatypes=classpath:/clds/tosca-converter/default-tosca-types.yaml
+clamp.config.tosca.converter.dictionary.support.enabled=true \ No newline at end of file
diff --git a/runtime/src/test/resources/robotframework/tests/01_healthcheck.robot b/runtime/src/test/resources/robotframework/tests/01_healthcheck.robot
new file mode 100644
index 000000000..f19266781
--- /dev/null
+++ b/runtime/src/test/resources/robotframework/tests/01_healthcheck.robot
@@ -0,0 +1,19 @@
+*** Settings ***
+Library Collections
+Library RequestsLibrary
+Library OperatingSystem
+Library json
+Library OperatingSystem
+*** Variables ***
+${login} admin
+${passw} password
+*** Keywords ***
+Create the sessions
+*** Test Cases ***
+Get Requests health check ok
+ ${port} = Get Environment Variable CLAMP_PORT
+ ${auth}= Create List ${login} ${passw}
+ Create Session clamp http://localhost:${port} auth=${auth} disable_warnings=1
+ Set Global Variable ${clamp_session} clamp
+ ${resp}= Get Request ${clamp_session} /restservices/clds/v1/healthcheck
+ Should Be Equal As Strings ${resp.status_code} 200 \ No newline at end of file
diff --git a/runtime/src/test/resources/robotframework/tests/02_policy_queries.robot b/runtime/src/test/resources/robotframework/tests/02_policy_queries.robot
new file mode 100644
index 000000000..713a39f52
--- /dev/null
+++ b/runtime/src/test/resources/robotframework/tests/02_policy_queries.robot
@@ -0,0 +1,21 @@
+*** Settings ***
+Library Collections
+Library RequestsLibrary
+Library OperatingSystem
+Library json
+Library OperatingSystem
+*** Variables ***
+${login} admin
+${passw} password
+${reponse_pdp_group} pdpGroupInfo
+*** Keywords ***
+Create the sessions
+*** Test Cases ***
+Get Requests policies list ok
+ ${port} = Get Environment Variable CLAMP_PORT
+ ${auth} = Create List ${login} ${passw}
+ Create Session clamp http://localhost:${port} auth=${auth} disable_warnings=1
+ Set Global Variable ${clamp_session} clamp
+ ${response_query}= Get Request ${clamp_session} /restservices/clds/v2/policies
+ Should Be Equal As Strings ${response_query.status_code} 200
+ Should Contain ${response_query.text} ${reponse_pdp_group} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/micro-service-policy-payload.json b/runtime/src/test/resources/tosca/micro-service-policy-payload.json
new file mode 100644
index 000000000..2533a5410
--- /dev/null
+++ b/runtime/src/test/resources/tosca/micro-service-policy-payload.json
@@ -0,0 +1,42 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_0_0",
+ "topology_template": {
+ "policies": [
+ {
+ "testPolicy": {
+ "type": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "type_version": "1.0.0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "testPolicy"
+ },
+ "properties": {
+ "tca_policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyVersion": "1.0.0",
+ "thresholds": [
+ {
+ "severity": "CRITICAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "thresholdValue": 1,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "test",
+ "version": "1.0.0",
+ "direction": "LESS"
+ }
+ ],
+ "policyName": "test",
+ "controlLoopSchemaType": "VM",
+ "policyScope": "test",
+ "eventName": "test"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/micro-service-policy-properties.json b/runtime/src/test/resources/tosca/micro-service-policy-properties.json
new file mode 100644
index 000000000..04fe0cc7f
--- /dev/null
+++ b/runtime/src/test/resources/tosca/micro-service-policy-properties.json
@@ -0,0 +1,25 @@
+{
+ "tca_policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyVersion": "1.0.0",
+ "thresholds": [
+ {
+ "severity": "CRITICAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "thresholdValue": 1,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "test",
+ "version": "1.0.0",
+ "direction": "LESS"
+ }
+ ],
+ "policyName": "test",
+ "controlLoopSchemaType": "VM",
+ "policyScope": "test",
+ "eventName": "test"
+ }
+ ]
+ }
+}
diff --git a/runtime/src/test/resources/tosca/model-properties-cds.json b/runtime/src/test/resources/tosca/model-properties-cds.json
new file mode 100644
index 000000000..fea658431
--- /dev/null
+++ b/runtime/src/test/resources/tosca/model-properties-cds.json
@@ -0,0 +1,154 @@
+{
+ "serviceDetails": {
+ "serviceType": "",
+ "namingPolicy": "",
+ "environmentContext": "General_Revenue-Bearing",
+ "serviceEcompNaming": "true",
+ "serviceRole": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "30ec5b59-4799-48d8-ac5f-1058a6b0e48f",
+ "ecompGeneratedNaming": "true",
+ "category": "Network L4+",
+ "type": "Service",
+ "UUID": "63cac700-ab9a-4115-a74f-7eac85e3fce0",
+ "instantiationType": "A-la-carte"
+ },
+ "resourceDetails": {
+ "CP": {},
+ "VL": {},
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552",
+ "controllerProperties": {
+ "sdnc_model_name": "baseconfiguration",
+ "sdnc_model_version": "1.0.0",
+ "workflows": {
+ "resource-assignment": {
+ "inputs": {
+ "template-prefix": {
+ "required": true,
+ "type": "list",
+ "entry_schema": {
+ "type": "string"
+ }
+ },
+ "template-prefix-with-complex-type": {
+ "type": "list",
+ "properties": {
+ "prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ }
+ },
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "private1-prefix-id": {
+ "description": "",
+ "required": false,
+ "type": "string",
+ "status": "",
+ "constraints": [
+ {}
+ ],
+ "entry_schema": {
+ "type": ""
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "CR": {},
+ "VFC": {},
+ "PNF": {},
+ "Service": {},
+ "CVFC": {},
+ "Service Proxy": {},
+ "Configuration": {},
+ "AllottedResource": {},
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vdns..module-3": {
+ "vfModuleModelInvariantUUID": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vdns..module-3",
+ "vfModuleModelUUID": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "vfModuleModelCustomizationUUID": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vdns",
+ "max_vf_module_instances": 50,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..base_template..module-0": {
+ "vfModuleModelInvariantUUID": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..base_template..module-0",
+ "vfModuleModelUUID": "63734409-f745-4e4d-a38b-131638a0edce",
+ "vfModuleModelCustomizationUUID": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "min_vf_module_instances": 1,
+ "vf_module_label": "base_template",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Base",
+ "isBase": true,
+ "initial_count": 1,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vlb..module-2": {
+ "vfModuleModelInvariantUUID": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vlb..module-2",
+ "vfModuleModelUUID": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "vfModuleModelCustomizationUUID": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vlb",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/model-properties-operational-policy.json b/runtime/src/test/resources/tosca/model-properties-operational-policy.json
new file mode 100644
index 000000000..2a6568528
--- /dev/null
+++ b/runtime/src/test/resources/tosca/model-properties-operational-policy.json
@@ -0,0 +1,353 @@
+{
+ "serviceDetails": {
+ "serviceType": "",
+ "namingPolicy": "",
+ "environmentContext": "General_Revenue-Bearing",
+ "serviceEcompNaming": "true",
+ "serviceRole": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "30ec5b59-4799-48d8-ac5f-1058a6b0e48f",
+ "ecompGeneratedNaming": "true",
+ "category": "Network L4+",
+ "type": "Service",
+ "UUID": "63cac700-ab9a-4115-a74f-7eac85e3fce0",
+ "instantiationType": "A-la-carte"
+ },
+ "resourceDetails": {
+ "CP": {
+ },
+ "VL": {
+ },
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552",
+ "controllerProperties": {
+ "sdnc_model_name": "baseconfiguration",
+ "sdnc_model_version": "1.0.0",
+ "workflows": {
+ "resource-assignment": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate": {
+ "inputs": {
+ "activate-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-restconf": {
+ "inputs": {
+ "activate-restconf-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-cli": {
+ "inputs": {
+ "activate-cli-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "assign-activate": {
+ "inputs": {
+ "assign-activate-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "imperative-test-wf": {
+ "inputs": {
+ "imperative-test-wf-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "CR": {
+ },
+ "VFC": {
+ },
+ "PNF": {
+ },
+ "Service": {
+ },
+ "CVFC": {
+ },
+ "Service Proxy": {
+ },
+ "Configuration": {
+ },
+ "AllottedResource": {
+ },
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vdns..module-3": {
+ "vfModuleModelInvariantUUID": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vdns..module-3",
+ "vfModuleModelUUID": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "vfModuleModelCustomizationUUID": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vdns",
+ "max_vf_module_instances": 50,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..base_template..module-0": {
+ "vfModuleModelInvariantUUID": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..base_template..module-0",
+ "vfModuleModelUUID": "63734409-f745-4e4d-a38b-131638a0edce",
+ "vfModuleModelCustomizationUUID": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "min_vf_module_instances": 1,
+ "vf_module_label": "base_template",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Base",
+ "isBase": true,
+ "initial_count": 1,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vlb..module-2": {
+ "vfModuleModelInvariantUUID": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vlb..module-2",
+ "vfModuleModelUUID": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "vfModuleModelCustomizationUUID": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vlb",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/model-properties.json b/runtime/src/test/resources/tosca/model-properties.json
new file mode 100644
index 000000000..1c0fe24b4
--- /dev/null
+++ b/runtime/src/test/resources/tosca/model-properties.json
@@ -0,0 +1,353 @@
+{
+ "serviceDetails": {
+ "serviceType": "",
+ "namingPolicy": "",
+ "environmentContext": "General_Revenue-Bearing",
+ "serviceEcompNaming": "true",
+ "serviceRole": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "30ec5b59-4799-48d8-ac5f-1058a6b0e48f",
+ "ecompGeneratedNaming": "true",
+ "category": "Network L4+",
+ "type": "Service",
+ "UUID": "63cac700-ab9a-4115-a74f-7eac85e3fce0",
+ "instantiationType": "A-la-carte"
+ },
+ "resourceDetails": {
+ "CP": {
+ },
+ "VL": {
+ },
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552",
+ "controllerProperties": {
+ "sdnc_model_name": "baseconfiguration",
+ "sdnc_model_version": "1.0.0",
+ "workflows": {
+ "resource-assignment": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-restconf": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-cli": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "assign-activate": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "imperative-test-wf": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "CR": {
+ },
+ "VFC": {
+ },
+ "PNF": {
+ },
+ "Service": {
+ },
+ "CVFC": {
+ },
+ "Service Proxy": {
+ },
+ "Configuration": {
+ },
+ "AllottedResource": {
+ },
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vdns..module-3": {
+ "vfModuleModelInvariantUUID": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vdns..module-3",
+ "vfModuleModelUUID": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "vfModuleModelCustomizationUUID": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vdns",
+ "max_vf_module_instances": 50,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..base_template..module-0": {
+ "vfModuleModelInvariantUUID": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..base_template..module-0",
+ "vfModuleModelUUID": "63734409-f745-4e4d-a38b-131638a0edce",
+ "vfModuleModelCustomizationUUID": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "min_vf_module_instances": 1,
+ "vf_module_label": "base_template",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Base",
+ "isBase": true,
+ "initial_count": 1,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vlb..module-2": {
+ "vfModuleModelInvariantUUID": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vlb..module-2",
+ "vfModuleModelUUID": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "vfModuleModelCustomizationUUID": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vlb",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/new-converter/constraints.yaml b/runtime/src/test/resources/tosca/new-converter/constraints.yaml
new file mode 100644
index 000000000..b711f35c8
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/constraints.yaml
@@ -0,0 +1,60 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.controlloop.operational.common.Drools:
+ derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Operational policies for Drools PDP
+ properties:
+ controllerName:
+ type: String
+ description: Drools controller properties
+ required: true
+data_types:
+ onap.datatype.controlloop.Operation:
+ derived_from: tosca.datatypes.Root
+ description: An operation supported by an actor
+ properties:
+ id:
+ type: String
+ description: Unique identifier for the operation
+ required: true
+ constraints:
+ - length: 8
+ description:
+ type: Array
+ description: A user-friendly description of the intent for the operation
+ required: false
+ constraints:
+ - min_length: 5
+ - max_length: 7
+ test:
+ type: Integer
+ description: |
+ Overall timeout for executing all the operations. This timeout should equal or exceed the total
+ timeout for each operation listed.
+ required: true
+ constraints:
+ - greater_than: 7
+ - greater_or_equal: 1
+ - less_than: 7
+ - less_or_equal: 1
+ timeout:
+ type: Integer
+ description: The amount of time for the actor to perform the operation.
+ required: true
+ constraints:
+ - valid_values: [3,4,5.5,6,10]
+ retries:
+ type: Integer
+ description: The number of retries the actor should attempt to perform the operation.
+ required: true
+ default: 0
+ constraints:
+ - equal: 5
+ success:
+ type: String
+ description: Points to the operation to invoke on success. A value of "final_success" indicates and end to the operation.
+ required: false
+ constraints:
+ - valid_values: [VALID,TERMINATED]
diff --git a/runtime/src/test/resources/tosca/new-converter/sampleOperationalPolicies.yaml b/runtime/src/test/resources/tosca/new-converter/sampleOperationalPolicies.yaml
new file mode 100644
index 000000000..1da17190e
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/sampleOperationalPolicies.yaml
@@ -0,0 +1,160 @@
+
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.controlloop.operational.Common:
+ derived_from: tosca.policies.Root
+ version: 1.0.0
+ description: Operational Policy for Control Loop execution
+ properties:
+ id:
+ type: String
+ description: The unique control loop id.
+ required: true
+ timeout:
+ type: Integer
+ description: |
+ Overall timeout for executing all the operations. This timeout should equal or exceed the total
+ timeout for each operation listed.
+ required: true
+ abatement:
+ type: Boolean
+ description: Whether an abatement event message will be expected for the control loop from DCAE.
+ required: true
+ default: false
+ trigger:
+ type: String
+ description: Initial operation to execute upon receiving an Onset event message for the Control Loop.
+ required: true
+ operations:
+ type: List
+ description: List of operations to be performed when Control Loop is triggered.
+ required: true
+ entry_schema:
+ type: onap.datatype.controlloop.Operation
+ onap.policies.controlloop.operational.common.Drools:
+ derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Operational policies for Drools PDP
+ properties:
+ controllerName:
+ type: String
+ description: Drools controller properties
+ required: false
+data_types:
+ # TBD if this is needed
+ onap.datatype.controlloop.operation.Failure:
+ derived_from: tosca.datatypes.Root
+ description: Captures information of an operational failure performed for control loop
+ properties:
+ messages:
+ type: String
+ description: error message
+ required: true
+ category:
+ type: String
+ description: |
+ The category the error occurred in. Whether this is a general error from the actor, or the operation
+ timed out, retries were exhausted in trying to execute the operation, a guard policy prevented the
+ operation from occuring, or an exception in the system caused the failure.
+ constraints:
+ - valid_values: [error, timeout, retries, guard, exception]
+ onap.datatype.controlloop.Target:
+ derived_from: tosca.datatypes.Root
+ description: Definition for a entity in A&AI to perform a control loop operation on
+ properties:
+ targetType:
+ type: String
+ description: Category for the target type
+ required: true
+ constraints:
+ - valid_values: [VNF, VM, VFMODULE, PNF]
+ entityIds:
+ type: Map
+ description: |
+ Map of values that identify the resource. If none are provided, it is assumed that the
+ entity that generated the ONSET event will be the target.
+ required: false
+ entry_schema:
+ type: String
+ onap.datatype.controlloop.Actor:
+ derived_from: tosca.datatypes.Root
+ description: An actor/operation/target definition
+ properties:
+ actor:
+ type: String
+ description: The actor performing the operation.
+ required: true
+ operation:
+ type: String
+ description: The operation the actor is performing.
+ required: true
+ target:
+ type: String
+ description: The resource the operation should be performed on.
+ required: true
+ metadata:
+ clamp_possible_values: <string:see clamp project for syntax>
+ payload:
+ type: Map
+ description: Name/value pairs of payload information passed by Policy to the actor
+ required: false
+ entry_schema:
+ type: String
+ onap.datatype.controlloop.Operation:
+ derived_from: tosca.datatypes.Root
+ description: An operation supported by an actor
+ properties:
+ id:
+ type: String
+ description: Unique identifier for the operation
+ required: true
+ description:
+ type: String
+ description: A user-friendly description of the intent for the operation
+ required: false
+ operation:
+ type: onap.datatype.controlloop.Actor
+ description: The definition of the operation to be performed.
+ required: true
+ metadata:
+ clamp_possible_values: <string:see clamp project for syntax>
+ timeout:
+ type: Integer
+ description: The amount of time for the actor to perform the operation.
+ required: true
+ retries:
+ type: Integer
+ description: The number of retries the actor should attempt to perform the operation.
+ required: true
+ default: 0
+ success:
+ type: String
+ description: Points to the operation to invoke on success. A value of "final_success" indicates and end to the operation.
+ required: false
+ default: final_success
+ failure:
+ type: String
+ description: Points to the operation to invoke on Actor operation failure.
+ required: false
+ default: final_failure
+ failure_timeout:
+ type: String
+ description: Points to the operation to invoke when the time out for the operation occurs.
+ required: false
+ default: final_failure_timeout
+ failure_retries:
+ type: String
+ description: Points to the operation to invoke when the current operation has exceeded its max retries.
+ required: false
+ default: final_failure_retries
+ failure_exception:
+ type: String
+ description: Points to the operation to invoke when the current operation causes an exception.
+ required: false
+ default: final_failure_exception
+ failure_guard:
+ type: String
+ description: Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.
+ required: false
+ default: final_failure_guard
diff --git a/runtime/src/test/resources/tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml b/runtime/src/test/resources/tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml
new file mode 100644
index 000000000..780acadc2
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/sampleOperationalPoliciesEXTENTED.yaml
@@ -0,0 +1,174 @@
+
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.controlloop.operational.Common:
+ derived_from: onap.datatype.controlloop.operation.Failure
+ version: 1.0.0
+ description: Operational Policy for Control Loop execution
+ properties:
+ id:
+ type: String
+ description: The unique control loop id.
+ required: true
+ timeout:
+ type: Integer
+ description: |
+ Overall timeout for executing all the operations. This timeout should equal or exceed the total
+ timeout for each operation listed.
+ required: true
+ constraints:
+ - valid_values: [1, 2, 5]
+ - equal: 5
+ - greater_than: 7
+ - greater_or_equal: 1
+ - less_than: 7
+ - less_or_equal: 1
+ abatement:
+ type: Boolean
+ description: Whether an abatement event message will be expected for the control loop from DCAE.
+ required: true
+ default: false
+ trigger:
+ type: String
+ description: Initial operation to execute upon receiving an Onset event message for the Control Loop.
+ required: true
+ operations:
+ type: List
+ description: List of operations to be performed when Control Loop is triggered.
+ required: true
+ entry_schema:
+ type: onap.datatype.controlloop.Operation
+ onap.policies.controlloop.operational.common.Drools:
+ derived_from: onap.policies.controlloop.operational.Common
+ type_version: 1.0.0
+ version: 1.0.0
+ description: Operational policies for Drools PDP
+ properties:
+ controllerName:
+ type: String
+ description: Drools controller properties
+ required: true
+data_types:
+ # TBD if this is needed
+ onap.datatype.controlloop.operation.Failure:
+ derived_from: onap.datatype.controlloop.Target
+ description: Captures information of an operational failure performed for control loop
+ properties:
+ messages:
+ type: String
+ description: error message
+ required: true
+ category:
+ type: String
+ description: |
+ The category the error occurred in. Whether this is a general error from the actor, or the operation
+ timed out, retries were exhausted in trying to execute the operation, a guard policy prevented the
+ operation from occuring, or an exception in the system caused the failure.
+ constraints:
+ - valid_values: [error, timeout, retries, guard, exception]
+ onap.datatype.controlloop.Target:
+ derived_from: tosca.datatypes.Root
+ description: Definition for a entity in A&AI to perform a control loop operation on
+ properties:
+ targetType:
+ type: String
+ description: Category for the target type
+ required: true
+ constraints:
+ - valid_values: [VNF, VM, VFMODULE, PNF]
+ entityIds:
+ type: Map
+ description: |
+ Map of values that identify the resource. If none are provided, it is assumed that the
+ entity that generated the ONSET event will be the target.
+ required: false
+ entry_schema:
+ type: String
+ onap.datatype.controlloop.Actor:
+ derived_from: tosca.datatypes.Root
+ description: An actor/operation/target definition
+ properties:
+ actor:
+ type: String
+ description: The actor performing the operation.
+ required: true
+ default: [1,"String",5.5,true]
+ operation:
+ type: String
+ description: The operation the actor is performing.
+ required: true
+ target:
+ type: String
+ description: The resource the operation should be performed on.
+ required: true
+ metadata:
+ clamp_possible_values: <string:see clamp project for syntax>
+ payload:
+ type: Map
+ description: Name/value pairs of payload information passed by Policy to the actor
+ required: false
+ entry_schema:
+ type: String
+ onap.datatype.controlloop.Operation:
+ derived_from: tosca.datatypes.Root
+ description: An operation supported by an actor
+ properties:
+ id:
+ type: String
+ description: Unique identifier for the operation
+ required: true
+ description:
+ type: Array
+ description: A user-friendly description of the intent for the operation
+ required: false
+ constraints:
+ - min_length: 5
+ - max_length: 7
+ - length: 1
+ operation:
+ type: onap.datatype.controlloop.Actor
+ description: The definition of the operation to be performed.
+ required: true
+ metadata:
+ clamp_possible_values: <string:see clamp project for syntax>
+ timeout:
+ type: Integer
+ description: The amount of time for the actor to perform the operation.
+ required: true
+ constraints:
+ - valid_values: [3, 4, 5.5, 6, 10]
+ retries:
+ type: Integer
+ description: The number of retries the actor should attempt to perform the operation.
+ required: true
+ default: 0
+ success:
+ type: String
+ description: Points to the operation to invoke on success. A value of "final_success" indicates and end to the operation.
+ required: false
+ default: final_success
+ failure:
+ type: String
+ description: Points to the operation to invoke on Actor operation failure.
+ required: false
+ default: final_failure
+ failure_timeout:
+ type: String
+ description: Points to the operation to invoke when the time out for the operation occurs.
+ required: false
+ default: final_failure_timeout
+ failure_retries:
+ type: String
+ description: Points to the operation to invoke when the current operation has exceeded its max retries.
+ required: false
+ default: final_failure_retries
+ failure_exception:
+ type: String
+ description: Points to the operation to invoke when the current operation causes an exception.
+ required: false
+ default: final_failure_exception
+ failure_guard:
+ type: String
+ description: Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.
+ required: false
+ default: final_failure_guard
diff --git a/runtime/src/test/resources/tosca/new-converter/tca-with-metadata.json b/runtime/src/test/resources/tosca/new-converter/tca-with-metadata.json
new file mode 100644
index 000000000..3a700c8ee
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/tca-with-metadata.json
@@ -0,0 +1,224 @@
+{
+ "title": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "type": "object",
+ "required": [],
+ "properties": {
+ "tca_policy": {
+ "type": "object",
+ "description": "TCA Policy JSON",
+ "properties": {
+ "onap.datatypes.monitoring.tca_policy": {
+ "title": "onap.datatypes.monitoring.tca_policy",
+ "type": "object",
+ "required": [
+ "domain",
+ "metricsPerEventName"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string",
+ "description": "Domain name to which TCA needs to be applied",
+ "default": "measurementsForVfScaling",
+ "const": "measurementsForVfScaling"
+ },
+ "metricsPerEventName": {
+ "type": "array",
+ "description": "Contains eventName and threshold details that need to be applied to given eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.metricsPerEventName",
+ "type": "object",
+ "required": [
+ "controlLoopSchemaType",
+ "eventName",
+ "policyName",
+ "policyScope",
+ "policyVersion",
+ "thresholds",
+ "context",
+ "signature"
+ ],
+ "properties": {
+ "controlLoopSchemaType": {
+ "type": "string",
+ "description": "Specifies Control Loop Schema Type for the event Name e.g. VNF, VM",
+ "enum": [
+ "VM",
+ "VNF"
+ ]
+ },
+ "eventName": {
+ "type": "string",
+ "description": "Event name to which thresholds need to be applied"
+ },
+ "policyName": {
+ "type": "string",
+ "description": "TCA Policy Scope Name"
+ },
+ "policyScope": {
+ "type": "string",
+ "description": "TCA Policy Scope"
+ },
+ "policyVersion": {
+ "type": "string",
+ "description": "TCA Policy Scope Version"
+ },
+ "thresholds": {
+ "type": "array",
+ "description": "Thresholds associated with eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.thresholds",
+ "type": "object",
+ "required": [
+ "closedLoopControlName",
+ "closedLoopEventStatus",
+ "direction",
+ "fieldPath",
+ "severity",
+ "thresholdValue",
+ "version"
+ ],
+ "properties": {
+ "closedLoopControlName": {
+ "type": "string",
+ "description": "Closed Loop Control Name associated with the threshold"
+ },
+ "closedLoopEventStatus": {
+ "type": "string",
+ "description": "Closed Loop Event Status of the threshold",
+ "enum": [
+ "ONSET",
+ "ABATED"
+ ]
+ },
+ "direction": {
+ "type": "string",
+ "description": "Direction of the threshold",
+ "enum": [
+ "LESS",
+ "LESS_OR_EQUAL",
+ "GREATER",
+ "GREATER_OR_EQUAL",
+ "EQUAL"
+ ]
+ },
+ "fieldPath": {
+ "type": "string",
+ "description": "Json field Path as per CEF message which needs to be analyzed for TCA",
+ "enum": [
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage",
+ "$.event.measurementsForVfScalingFields.meanRequestLatency",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed",
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value"
+ ]
+ },
+ "severity": {
+ "type": "string",
+ "description": "Threshold Event Severity",
+ "enum": [
+ "CRITICAL",
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "NORMAL"
+ ]
+ },
+ "thresholdValue": {
+ "type": "integer",
+ "description": "Threshold value for the field Path inside CEF message"
+ },
+ "version": {
+ "type": "string",
+ "description": "Version number associated with the threshold"
+ }
+ }
+ },
+ "format": "tabs-top"
+ },
+ "context": {
+ "type": "string",
+ "description": "TCA Policy Dummy Context",
+ "enum": [
+ "PROD"
+ ],
+ "options": {
+ "enum_titles": [
+ "PROD"
+ ]
+ }
+ },
+ "signature": {
+ "title": "onap.datatypes.monitoring.Dummy_Signature",
+ "type": "object",
+ "required": [
+ "filter_clause"
+ ],
+ "properties": {
+ "filter_clause": {
+ "type": "qbldr",
+ "description": "Filter Clause",
+ "minLength": 1,
+ "qschema": {
+ "filters": [
+ {
+ "type": "string",
+ "minLength": 1,
+ "id": "alarmCondition",
+ "label": "alarmCondition",
+ "operators": [
+ "equals"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/new-converter/tosca_apex_with_metadata.json b/runtime/src/test/resources/tosca/new-converter/tosca_apex_with_metadata.json
new file mode 100644
index 000000000..4519d5c9f
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/tosca_apex_with_metadata.json
@@ -0,0 +1,577 @@
+{
+ "title": "onap.policies.controlloop.operational.common.Apex",
+ "type": "object",
+ "description": "Operational policies for Apex PDP",
+ "required": [
+ "abatement",
+ "operations",
+ "trigger",
+ "timeout",
+ "id",
+ "engineServiceParameters",
+ "eventOutputParameters",
+ "eventInputParameters"
+ ],
+ "properties": {
+ "abatement": {
+ "type": "boolean",
+ "description": "Whether an abatement event message will be expected for the control loop from DCAE.",
+ "default": "false"
+ },
+ "operations": {
+ "type": "array",
+ "description": "List of operations to be performed when Control Loop is triggered.",
+ "items": {
+ "title": "onap.datatype.controlloop.Operation",
+ "type": "object",
+ "description": "An operation supported by an actor",
+ "required": [
+ "id",
+ "operation",
+ "retries",
+ "timeout"
+ ],
+ "properties": {
+ "failure_retries": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation has exceeded its max retries.",
+ "default": "final_failure_retries"
+ },
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for the operation"
+ },
+ "failure_timeout": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the time out for the operation occurs.",
+ "default": "final_failure_timeout"
+ },
+ "failure": {
+ "type": "string",
+ "description": "Points to the operation to invoke on Actor operation failure.",
+ "default": "final_failure"
+ },
+ "operation": {
+ "title": "onap.datatype.controlloop.Actor",
+ "type": "object",
+ "description": "An actor/operation/target definition",
+ "required": [
+ "target",
+ "actor",
+ "operation"
+ ],
+ "properties": {
+ "payload": {
+ "type": "object",
+ "description": "Name/value pairs of payload information passed by Policy to the actor",
+ "anyOf": [
+ {
+ "title": "User defined",
+ "properties": {}
+ },
+ {
+ "title": "resource-assignment",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ },
+ {
+ "title": "activate",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ },
+ {
+ "title": "activate-restconf",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ },
+ {
+ "title": "activate-cli",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ },
+ {
+ "title": "assign-activate",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ },
+ {
+ "title": "imperative-test-wf",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": true
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": true
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async",
+ "readOnly": false
+ },
+ "data": {
+ "title": "data",
+ "type": "string",
+ "format": "textarea",
+ "default": "{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}"
+ }
+ }
+ }
+ ]
+ },
+ "target": {
+ "title": "onap.datatype.controlloop.Target",
+ "type": "object",
+ "description": "Definition for a entity in A&AI to perform a control loop operation on",
+ "required": [
+ "targetType"
+ ],
+ "properties": {
+ "entityIds": {
+ "type": "object",
+ "description": "Map of values that identify the resource. If none are provided, it is assumed that the\nentity that generated the ONSET event will be the target.\n",
+ "anyOf": [
+ {
+ "title": "User defined",
+ "properties": {}
+ },
+ {
+ "title": "VNF-vLoadBalancerMS 0",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vpkg..module-1",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vdns..module-3",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..base_template..module-0",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "63734409-f745-4e4d-a38b-131638a0edce",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vlb..module-2",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "readOnly": "True"
+ }
+ }
+ }
+ ]
+ },
+ "targetType": {
+ "type": "string",
+ "description": "Category for the target type",
+ "enum": [
+ "VNF",
+ "VM",
+ "VFMODULE",
+ "PNF"
+ ]
+ }
+ }
+ },
+ "actor": {
+ "type": "string",
+ "description": "The actor performing the operation.",
+ "enum": [
+ "SDNR",
+ "SDNC",
+ "VFC",
+ "SO",
+ "APPC",
+ "CDS"
+ ],
+ "options": {
+ "enum_titles": [
+ "SDNR",
+ "SDNC",
+ "VFC",
+ "SO",
+ "APPC"
+ ]
+ }
+ },
+ "operation": {
+ "type": "string",
+ "description": "The operation the actor is performing.",
+ "enum": [
+ "BandwidthOnDemand",
+ "VF Module Delete",
+ "Reroute",
+ "VF Module Create",
+ "ModifyConfig",
+ "Rebuild",
+ "Restart",
+ "Migrate",
+ "Health-Check",
+ "resource-assignment",
+ "activate",
+ "activate-restconf",
+ "activate-cli",
+ "assign-activate",
+ "imperative-test-wf"
+ ],
+ "options": {
+ "enum_titles": [
+ "BandwidthOnDemand (SDNC operation)",
+ "VF Module Delete (SO operation)",
+ "Reroute (SDNC operation)",
+ "VF Module Create (SO operation)",
+ "ModifyConfig (APPC/VFC operation)",
+ "Rebuild (APPC operation)",
+ "Restart (APPC operation)",
+ "Migrate (APPC operation)",
+ "Health-Check (APPC operation)",
+ "resource-assignment (CDS operation)",
+ "activate (CDS operation)",
+ "activate-restconf (CDS operation)",
+ "activate-cli (CDS operation)",
+ "assign-activate (CDS operation)",
+ "imperative-test-wf (CDS operation)"
+ ]
+ }
+ }
+ }
+ },
+ "failure_guard": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.",
+ "default": "final_failure_guard"
+ },
+ "retries": {
+ "type": "integer",
+ "description": "The number of retries the actor should attempt to perform the operation.",
+ "default": "0"
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "The amount of time for the actor to perform the operation."
+ },
+ "failure_exception": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation causes an exception.",
+ "default": "final_failure_exception"
+ },
+ "description": {
+ "type": "string",
+ "description": "A user-friendly description of the intent for the operation"
+ },
+ "success": {
+ "type": "string",
+ "description": "Points to the operation to invoke on success. A value of \"final_success\" indicates and end to the operation.",
+ "default": "final_success"
+ }
+ }
+ },
+ "format": "tabs-top"
+ },
+ "trigger": {
+ "type": "string",
+ "description": "Initial operation to execute upon receiving an Onset event message for the Control Loop."
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "Overall timeout for executing all the operations. This timeout should equal or exceed the total\ntimeout for each operation listed.\n"
+ },
+ "id": {
+ "type": "string",
+ "description": "The unique control loop id."
+ },
+ "engineServiceParameters": {
+ "type": "string",
+ "description": "The engine parameters like name, instanceCount, policy implementation, parameters etc."
+ },
+ "eventOutputParameters": {
+ "type": "string",
+ "description": "The event output parameters."
+ },
+ "javaProperties": {
+ "type": "string",
+ "description": "Name/value pairs of properties to be set for APEX if needed."
+ },
+ "eventInputParameters": {
+ "type": "string",
+ "description": "The event input parameters."
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/new-converter/tosca_metadata_clamp_possible_values.yaml b/runtime/src/test/resources/tosca/new-converter/tosca_metadata_clamp_possible_values.yaml
new file mode 100644
index 000000000..7fe9d5398
--- /dev/null
+++ b/runtime/src/test/resources/tosca/new-converter/tosca_metadata_clamp_possible_values.yaml
@@ -0,0 +1,184 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ description: a base policy type for all policies that governs monitoring provisioning
+ onap.policies.monitoring.cdap.tca.hi.lo.app:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ properties:
+ tca_policy:
+ type: map
+ description: TCA Policy JSON
+ entry_schema:
+ type: onap.datatypes.monitoring.tca_policy
+ metadata:
+ policy_model_type: onap.policies.monitoring.cdap.tca.hi.lo.app
+ acronym: tca
+
+data_types:
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ type: string
+ required: true
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ eventName:
+ type: string
+ required: true
+ description: Event name to which thresholds need to be applied
+ policyName:
+ type: string
+ required: true
+ description: TCA Policy Scope Name
+ policyScope:
+ type: string
+ required: true
+ description: TCA Policy Scope
+ policyVersion:
+ type: string
+ required: true
+ description: TCA Policy Scope Version
+ thresholds:
+ type: list
+ required: true
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ context:
+ type: string
+ required: true
+ description: TCA Policy Dummy Context
+ metadata:
+ clamp_possible_values: Dictionary:Context
+
+ signature:
+ type: onap.datatypes.monitoring.Dummy_Signature
+ description: Signature
+ required: true
+
+ onap.datatypes.monitoring.Dummy_Signature:
+ derived_from: tosca.datatypes.Root
+ properties:
+ filter_clause:
+ type: string
+ description: Filter Clause
+ required: true
+ metadata:
+ clamp_possible_values: Dictionary:EventDictionary#Operators
+
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ type: string
+ required: true
+ description: Domain name to which TCA needs to be applied
+ default: measurementsForVfScaling
+ constraints:
+ - equal: measurementsForVfScaling
+ metricsPerEventName:
+ type: list
+ required: true
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ type: string
+ required: true
+ description: Closed Loop Control Name associated with the threshold
+ closedLoopEventStatus:
+ type: string
+ required: true
+ description: Closed Loop Event Status of the threshold
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ direction:
+ type: string
+ required: true
+ description: Direction of the threshold
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ fieldPath:
+ type: string
+ required: true
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ severity:
+ type: string
+ required: true
+ description: Threshold Event Severity
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ thresholdValue:
+ type: integer
+ required: true
+ description: Threshold value for the field Path inside CEF message
+ version:
+ type: string
+ required: true
+ description: Version number associated with the threshold
diff --git a/runtime/src/test/resources/tosca/operational-policy-cds-payload-with-list.json b/runtime/src/test/resources/tosca/operational-policy-cds-payload-with-list.json
new file mode 100644
index 000000000..9a9308e3b
--- /dev/null
+++ b/runtime/src/test/resources/tosca/operational-policy-cds-payload-with-list.json
@@ -0,0 +1,590 @@
+{
+ "type": "object",
+ "title": "Configuration",
+ "required": [
+ "operational_policy"
+ ],
+ "properties": {
+ "operational_policy": {
+ "type": "object",
+ "title": "Related Parameters",
+ "required": [
+ "controlLoop",
+ "policies"
+ ],
+ "properties": {
+ "controlLoop": {
+ "type": "object",
+ "title": "Control Loop details",
+ "required": [
+ "timeout",
+ "abatement",
+ "trigger_policy",
+ "controlLoopName"
+ ],
+ "properties": {
+ "timeout": {
+ "type": "string",
+ "title": "Overall Time Limit",
+ "default": "0",
+ "format": "number"
+ },
+ "abatement": {
+ "type": "string",
+ "title": "Abatement",
+ "enum": [
+ "True",
+ "False"
+ ]
+ },
+ "trigger_policy": {
+ "type": "string",
+ "title": "Policy Decision Entry"
+ },
+ "controlLoopName": {
+ "type": "string",
+ "title": "Control loop name",
+ "readOnly": "True"
+ }
+ }
+ },
+ "policies": {
+ "uniqueItems": "true",
+ "id": "policies_array",
+ "type": "array",
+ "title": "Policy Decision Tree",
+ "format": "tabs-top",
+ "items": {
+ "title": "Policy Decision",
+ "type": "object",
+ "id": "policy_item",
+ "headerTemplate": "{{self.id}} - {{self.recipe}}",
+ "format": "categories",
+ "basicCategoryTitle": "recipe",
+ "required": [
+ "id",
+ "retry",
+ "timeout",
+ "actor",
+ "success",
+ "failure",
+ "failure_timeout",
+ "failure_retries",
+ "failure_exception",
+ "failure_guard",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "default": "Policy 1",
+ "title": "Policy ID",
+ "type": "string"
+ },
+ "retry": {
+ "default": "0",
+ "title": "Number of Retry",
+ "type": "string",
+ "format": "number"
+ },
+ "timeout": {
+ "default": "0",
+ "title": "Timeout",
+ "type": "string",
+ "format": "number"
+ },
+ "actor": {
+ "type": "object",
+ "title": "Actor",
+ "anyOf": [
+ {
+ "title": "APPC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "APPC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SO",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SO",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VF Module Create",
+ "VF Module Delete"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SDNC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SDNC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Reroute",
+ "BandwidthOnDemand"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "VFC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "VFC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "CDS",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "CDS",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "object",
+ "anyOf": [
+ {
+ "title": "user-defined",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "user-defined",
+ "format": "textarea"
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "default": "",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "resource-assignment",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "resource-assignment",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "template-prefix": {
+ "title": "template-prefix",
+ "type": "array"
+ },
+ "template-prefix-with-complex-type": {
+ "title": "template-prefix-with-complex-type",
+ "type": "array",
+ "items": {
+ "properties": {
+ "prefix-id": {
+ "title": "prefix-id",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "private1-prefix-id": {
+ "title": "private1-prefix-id",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "success": {
+ "default": "final_success",
+ "title": "When Success",
+ "type": "string"
+ },
+ "failure": {
+ "default": "final_failure",
+ "title": "When Failure",
+ "type": "string"
+ },
+ "failure_timeout": {
+ "default": "final_failure_timeout",
+ "title": "When Failure Timeout",
+ "type": "string"
+ },
+ "failure_retries": {
+ "default": "final_failure_retries",
+ "title": "When Failure Retries",
+ "type": "string"
+ },
+ "failure_exception": {
+ "default": "final_failure_exception",
+ "title": "When Failure Exception",
+ "type": "string"
+ },
+ "failure_guard": {
+ "default": "final_failure_guard",
+ "title": "When Failure Guard",
+ "type": "string"
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "resourceID"
+ ],
+ "anyOf": [
+ {
+ "title": "User Defined",
+ "additionalProperties": "True",
+ "properties": {
+ "type": {
+ "title": "Target type",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VNF",
+ "VFMODULE",
+ "VM"
+ ]
+ },
+ "resourceID": {
+ "title": "Target type",
+ "type": "string",
+ "default": ""
+ }
+ }
+ },
+ {
+ "title": "User defined",
+ "properties": {}
+ },
+ {
+ "title": "VNF-vLoadBalancerMS 0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VNF",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vpkg..module-1",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vdns..module-3",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..base_template..module-0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "63734409-f745-4e4d-a38b-131638a0edce",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vlb..module-2",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "readOnly": "True"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/operational-policy-json-schema.json b/runtime/src/test/resources/tosca/operational-policy-json-schema.json
new file mode 100644
index 000000000..dc6c32fa7
--- /dev/null
+++ b/runtime/src/test/resources/tosca/operational-policy-json-schema.json
@@ -0,0 +1,936 @@
+{
+ "type": "object",
+ "title": "Configuration",
+ "required": [
+ "operational_policy"
+ ],
+ "properties": {
+ "operational_policy": {
+ "type": "object",
+ "title": "Related Parameters",
+ "required": [
+ "controlLoop",
+ "policies"
+ ],
+ "properties": {
+ "controlLoop": {
+ "type": "object",
+ "title": "Control Loop details",
+ "required": [
+ "timeout",
+ "abatement",
+ "trigger_policy",
+ "controlLoopName"
+ ],
+ "properties": {
+ "timeout": {
+ "type": "string",
+ "title": "Overall Time Limit",
+ "default": "0",
+ "format": "number"
+ },
+ "abatement": {
+ "type": "string",
+ "title": "Abatement",
+ "enum": [
+ "True",
+ "False"
+ ]
+ },
+ "trigger_policy": {
+ "type": "string",
+ "title": "Policy Decision Entry"
+ },
+ "controlLoopName": {
+ "type": "string",
+ "title": "Control loop name",
+ "readOnly": "True"
+ }
+ }
+ },
+ "policies": {
+ "uniqueItems": "true",
+ "id": "policies_array",
+ "type": "array",
+ "title": "Policy Decision Tree",
+ "format": "tabs-top",
+ "items": {
+ "title": "Policy Decision",
+ "type": "object",
+ "id": "policy_item",
+ "headerTemplate": "{{self.id}} - {{self.recipe}}",
+ "format": "categories",
+ "basicCategoryTitle": "recipe",
+ "required": [
+ "id",
+ "retry",
+ "timeout",
+ "actor",
+ "success",
+ "failure",
+ "failure_timeout",
+ "failure_retries",
+ "failure_exception",
+ "failure_guard",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "default": "Policy 1",
+ "title": "Policy ID",
+ "type": "string"
+ },
+ "retry": {
+ "default": "0",
+ "title": "Number of Retry",
+ "type": "string",
+ "format": "number"
+ },
+ "timeout": {
+ "default": "0",
+ "title": "Timeout",
+ "type": "string",
+ "format": "number"
+ },
+ "actor": {
+ "type": "object",
+ "title": "Actor",
+ "anyOf": [
+ {
+ "title": "APPC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "APPC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Restart",
+ "Rebuild",
+ "Migrate",
+ "Health-Check",
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SO",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SO",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VF Module Create",
+ "VF Module Delete"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "SDNC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "SDNC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "Reroute",
+ "BandwidthOnDemand"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "VFC",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "VFC",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "ModifyConfig"
+ ]
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "CDS",
+ "type": "object",
+ "properties": {
+ "actor": {
+ "title": "actor",
+ "type": "string",
+ "default": "CDS",
+ "options": {
+ "hidden": true
+ }
+ },
+ "recipe": {
+ "title": "recipe",
+ "type": "object",
+ "anyOf": [
+ {
+ "title": "user-defined",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "user-defined",
+ "format": "textarea"
+ },
+ "payload": {
+ "title": "Payload (YAML)",
+ "type": "string",
+ "default": "",
+ "format": "textarea"
+ }
+ }
+ },
+ {
+ "title": "resource-assignment",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "resource-assignment",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "activate",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "activate",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "activate-restconf",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "activate-restconf",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "activate-cli",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "activate-cli",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "assign-activate",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "assign-activate",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "title": "imperative-test-wf",
+ "type": "object",
+ "properties": {
+ "recipe": {
+ "title": "recipe",
+ "type": "string",
+ "default": "imperative-test-wf",
+ "options": {
+ "hidden": true
+ }
+ },
+ "payload": {
+ "title": "Payload",
+ "type": "object",
+ "properties": {
+ "artifact_name": {
+ "title": "artifact name",
+ "type": "string",
+ "default": "baseconfiguration",
+ "readOnly": "True"
+ },
+ "artifact_version": {
+ "title": "artifact version",
+ "type": "string",
+ "default": "1.0.0",
+ "readOnly": "True"
+ },
+ "mode": {
+ "title": "mode",
+ "type": "string",
+ "default": "async"
+ },
+ "data": {
+ "title": "data",
+ "properties": {
+ "request-id": {
+ "title": "request-id",
+ "type": "string"
+ },
+ "service-instance-id": {
+ "title": "service-instance-id",
+ "type": "string"
+ },
+ "hostname": {
+ "title": "hostname",
+ "type": "string"
+ },
+ "request-info": {
+ "title": "request-info",
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "title": "prop1",
+ "type": "string"
+ },
+ "prop2": {
+ "title": "prop2",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "success": {
+ "default": "final_success",
+ "title": "When Success",
+ "type": "string"
+ },
+ "failure": {
+ "default": "final_failure",
+ "title": "When Failure",
+ "type": "string"
+ },
+ "failure_timeout": {
+ "default": "final_failure_timeout",
+ "title": "When Failure Timeout",
+ "type": "string"
+ },
+ "failure_retries": {
+ "default": "final_failure_retries",
+ "title": "When Failure Retries",
+ "type": "string"
+ },
+ "failure_exception": {
+ "default": "final_failure_exception",
+ "title": "When Failure Exception",
+ "type": "string"
+ },
+ "failure_guard": {
+ "default": "final_failure_guard",
+ "title": "When Failure Guard",
+ "type": "string"
+ },
+ "target": {
+ "type": "object",
+ "required": [
+ "type",
+ "resourceID"
+ ],
+ "anyOf": [
+ {
+ "title": "User Defined",
+ "additionalProperties": "True",
+ "properties": {
+ "type": {
+ "title": "Target type",
+ "type": "string",
+ "default": "",
+ "enum": [
+ "VNF",
+ "VFMODULE",
+ "VM"
+ ]
+ },
+ "resourceID": {
+ "title": "Target type",
+ "type": "string",
+ "default": ""
+ }
+ }
+ },
+ {
+ "title": "User defined",
+ "properties": {}
+ },
+ {
+ "title": "VNF-vLoadBalancerMS 0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VNF",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vpkg..module-1",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vpkg..module-1",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vdns..module-3",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vdns..module-3",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..base_template..module-0",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "63734409-f745-4e4d-a38b-131638a0edce",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..base_template..module-0",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Vloadbalancerms..vlb..module-2",
+ "properties": {
+ "type": {
+ "title": "Type",
+ "type": "string",
+ "default": "VFMODULE",
+ "readOnly": "True"
+ },
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Vloadbalancerms..vlb..module-2",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "readOnly": "True"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/operational-policy-no-guard-properties.json b/runtime/src/test/resources/tosca/operational-policy-no-guard-properties.json
new file mode 100644
index 000000000..fdb1906a4
--- /dev/null
+++ b/runtime/src/test/resources/tosca/operational-policy-no-guard-properties.json
@@ -0,0 +1,35 @@
+{
+ "operational_policy": {
+ "controlLoop": {
+ "trigger_policy": "new",
+ "timeout": "0",
+ "abatement": "on",
+ "controlLoopName": "LOOP_iYTIP_v1_0_ResourceInstanceName1_tca"
+ },
+ "policies": [
+ {
+ "id": "new",
+ "recipe": "Restart",
+ "retry": "10",
+ "timeout": "10",
+ "actor": "SO",
+ "payload": "",
+ "success": "",
+ "failure": "",
+ "failure_timeout": "",
+ "failure_retries": "",
+ "failure_exception": "",
+ "failure_guard": "",
+ "target": {
+ "type": "VM",
+ "resourceID": "",
+ "modelInvariantId": "",
+ "modelVersionId": "",
+ "modelName": "",
+ "modelVersion": "",
+ "modelCustomizationId": ""
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/operational-policy-properties.json b/runtime/src/test/resources/tosca/operational-policy-properties.json
new file mode 100644
index 000000000..a38334b55
--- /dev/null
+++ b/runtime/src/test/resources/tosca/operational-policy-properties.json
@@ -0,0 +1,132 @@
+{
+ "operational_policy": {
+ "controlLoop": {
+ "timeout": "0",
+ "abatement": "True",
+ "trigger_policy": "policy1",
+ "controlLoopName": "LOOP_ASJOy_v1_0_ResourceInstanceName1_tca"
+ },
+ "policies": [
+ {
+ "actor": {
+ "actor": "APPC",
+ "recipe": "Restart",
+ "payload": "requestParameters: '{\"usePreload\":true,\"userParams\":[]}'\r\nconfigurationParameters: '[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[10].value\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[15].value\",\"enabled\":\"$.vf-module-topology.vf-module-parameters.param[22].value\"}]'"
+ },
+ "id": "policy1",
+ "retry": "0",
+ "timeout": "0",
+ "success": "final_success",
+ "failure": "policy2",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VNF",
+ "resourceID": "vLoadBalancerMS"
+ }
+ },
+ {
+ "actor": {
+ "actor": "SO",
+ "recipe": "VF Module Create",
+ "payload": ""
+ },
+ "id": "policy2",
+ "retry": "0",
+ "timeout": "0",
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VFMODULE",
+ "resourceID": "Vloadbalancerms..vpkg..module-1",
+ "modelInvariantId": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "modelVersionId": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "modelName": "Vloadbalancerms..vpkg..module-1",
+ "modelVersion": "1",
+ "modelCustomizationId": "1bffdc31-a37d-4dee-b65c-dde623a76e52"
+ }
+ },
+ {
+ "actor": {
+ "actor": "CDS",
+ "recipe": {
+ "recipe": "resource-assignment",
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": {
+ "resource-assignment-properties": {
+ "request-id": "request-id",
+ "service-instance-id": "service-instance-id",
+ "vnf-id": "vnf-id",
+ "action-name": "action-name",
+ "scope-type": "scope-type",
+ "hostname": "hostname",
+ "vnf_name": "vnf_name"
+ }
+ }
+ }
+ }
+ },
+ "id": "policy3",
+ "retry": "0",
+ "timeout": "0",
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VFMODULE",
+ "resourceID": "Vloadbalancerms..vpkg..module-1",
+ "modelInvariantId": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "modelVersionId": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "modelName": "Vloadbalancerms..vpkg..module-1",
+ "modelVersion": "1",
+ "modelCustomizationId": "1bffdc31-a37d-4dee-b65c-dde623a76e52"
+ }
+ },
+ {
+ "actor": {
+ "actor": "CDS",
+ "recipe": {
+ "recipe": "modify-config",
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": {
+ }
+ }
+ }
+ },
+ "id": "policy4",
+ "retry": "0",
+ "timeout": "0",
+ "success": "final_success",
+ "failure": "final_failure",
+ "failure_timeout": "final_failure_timeout",
+ "failure_retries": "final_failure_retries",
+ "failure_exception": "final_failure_exception",
+ "failure_guard": "final_failure_guard",
+ "target": {
+ "type": "VFMODULE",
+ "resourceID": "Vloadbalancerms..vpkg..module-1",
+ "modelInvariantId": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "modelVersionId": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "modelName": "Vloadbalancerms..vpkg..module-1",
+ "modelVersion": "1",
+ "modelCustomizationId": "1bffdc31-a37d-4dee-b65c-dde623a76e52"
+ }
+ }
+ ]
+ }
+}
diff --git a/runtime/src/test/resources/tosca/resource-details-cds.json b/runtime/src/test/resources/tosca/resource-details-cds.json
new file mode 100644
index 000000000..d972d0cb9
--- /dev/null
+++ b/runtime/src/test/resources/tosca/resource-details-cds.json
@@ -0,0 +1,336 @@
+{
+ "CP": {
+ },
+ "VL": {
+ },
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552",
+ "controllerProperties": {
+ "sdnc_model_name": "baseconfiguration",
+ "sdnc_model_version": "1.0.0",
+ "workflows": {
+ "resource-assignment": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate": {
+ "inputs": {
+ "activate-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-restconf": {
+ "inputs": {
+ "activate-restconf-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-cli": {
+ "inputs": {
+ "activate-cli-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "assign-activate": {
+ "inputs": {
+ "assign-activate-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "imperative-test-wf": {
+ "inputs": {
+ "imperative-test-wf-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "CR": {
+ },
+ "VFC": {
+ },
+ "PNF": {
+ },
+ "Service": {
+ },
+ "CVFC": {
+ },
+ "Service Proxy": {
+ },
+ "Configuration": {
+ },
+ "AllottedResource": {
+ },
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vdns..module-3": {
+ "vfModuleModelInvariantUUID": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vdns..module-3",
+ "vfModuleModelUUID": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "vfModuleModelCustomizationUUID": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vdns",
+ "max_vf_module_instances": 50,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..base_template..module-0": {
+ "vfModuleModelInvariantUUID": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..base_template..module-0",
+ "vfModuleModelUUID": "63734409-f745-4e4d-a38b-131638a0edce",
+ "vfModuleModelCustomizationUUID": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "min_vf_module_instances": 1,
+ "vf_module_label": "base_template",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Base",
+ "isBase": true,
+ "initial_count": 1,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vlb..module-2": {
+ "vfModuleModelInvariantUUID": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vlb..module-2",
+ "vfModuleModelUUID": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "vfModuleModelCustomizationUUID": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vlb",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/resource-details.json b/runtime/src/test/resources/tosca/resource-details.json
new file mode 100644
index 000000000..b55adbf52
--- /dev/null
+++ b/runtime/src/test/resources/tosca/resource-details.json
@@ -0,0 +1,336 @@
+{
+ "CP": {
+ },
+ "VL": {
+ },
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552",
+ "controllerProperties": {
+ "sdnc_model_name": "baseconfiguration",
+ "sdnc_model_version": "1.0.0",
+ "workflows": {
+ "resource-assignment": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-restconf": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "activate-cli": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "assign-activate": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "imperative-test-wf": {
+ "inputs": {
+ "resource-assignment-properties": {
+ "type": "object",
+ "properties": {
+ "request-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "service-instance-id": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "hostname": {
+ "type": "string",
+ "required": true,
+ "input-param": true
+ },
+ "request-info": {
+ "type": "object",
+ "properties": {
+ "prop1": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ },
+ "prop2": {
+ "required": true,
+ "type": "string",
+ "input-param": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "CR": {
+ },
+ "VFC": {
+ },
+ "PNF": {
+ },
+ "Service": {
+ },
+ "CVFC": {
+ },
+ "Service Proxy": {
+ },
+ "Configuration": {
+ },
+ "AllottedResource": {
+ },
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vdns..module-3": {
+ "vfModuleModelInvariantUUID": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vdns..module-3",
+ "vfModuleModelUUID": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "vfModuleModelCustomizationUUID": "bafcdab0-801d-4d81-9ead-f464640a38b1",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vdns",
+ "max_vf_module_instances": 50,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ },
+ "Vloadbalancerms..base_template..module-0": {
+ "vfModuleModelInvariantUUID": "921f7c96-ebdd-42e6-81b9-1cfc0c9796f3",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..base_template..module-0",
+ "vfModuleModelUUID": "63734409-f745-4e4d-a38b-131638a0edce",
+ "vfModuleModelCustomizationUUID": "86baddea-c730-4fb8-9410-cd2e17fd7f27",
+ "min_vf_module_instances": 1,
+ "vf_module_label": "base_template",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Base",
+ "isBase": true,
+ "initial_count": 1,
+ "volume_group": false
+ },
+ "Vloadbalancerms..vlb..module-2": {
+ "vfModuleModelInvariantUUID": "a772a1f4-0064-412c-833d-4749b15828dd",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vlb..module-2",
+ "vfModuleModelUUID": "0f5c3f6a-650a-4303-abb6-fff3e573a07a",
+ "vfModuleModelCustomizationUUID": "96a78aad-4ffb-4ef0-9c4f-deb03bf1d806",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vlb",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/service-details.json b/runtime/src/test/resources/tosca/service-details.json
new file mode 100644
index 000000000..f41eec107
--- /dev/null
+++ b/runtime/src/test/resources/tosca/service-details.json
@@ -0,0 +1,15 @@
+{
+ "serviceType": "",
+ "namingPolicy": "",
+ "environmentContext": "General_Revenue-Bearing",
+ "serviceEcompNaming": "true",
+ "serviceRole": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "30ec5b59-4799-48d8-ac5f-1058a6b0e48f",
+ "ecompGeneratedNaming": "true",
+ "category": "Network L4+",
+ "type": "Service",
+ "UUID": "63cac700-ab9a-4115-a74f-7eac85e3fce0",
+ "instantiationType": "A-la-carte"
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/tca_hi_lo.json b/runtime/src/test/resources/tosca/tca_hi_lo.json
new file mode 100644
index 000000000..cb3ed893f
--- /dev/null
+++ b/runtime/src/test/resources/tosca/tca_hi_lo.json
@@ -0,0 +1,179 @@
+{
+ "title": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "type": "object",
+ "required": [
+ "tca_policy"
+ ],
+ "properties": {
+ "tca_policy": {
+ "title": "onap.datatypes.monitoring.tca_policy",
+ "type": "object",
+ "required": [
+ "domain",
+ "metricsPerEventName"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string",
+ "description": "Domain name to which TCA needs to be applied",
+ "default": "measurementsForVfScaling",
+ "const": "measurementsForVfScaling"
+ },
+ "metricsPerEventName": {
+ "type": "array",
+ "description": "Contains eventName and threshold details that need to be applied to given eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.metricsPerEventName",
+ "type": "object",
+ "required": [
+ "controlLoopSchemaType",
+ "eventName",
+ "policyName",
+ "policyScope",
+ "policyVersion",
+ "thresholds"
+ ],
+ "properties": {
+ "controlLoopSchemaType": {
+ "type": "string",
+ "description": "Specifies Control Loop Schema Type for the event Name e.g. VNF, VM",
+ "enum": [
+ "VM",
+ "VNF"
+ ]
+ },
+ "eventName": {
+ "type": "string",
+ "description": "Event name to which thresholds need to be applied"
+ },
+ "policyName": {
+ "type": "string",
+ "description": "TCA Policy Scope Name"
+ },
+ "policyScope": {
+ "type": "string",
+ "description": "TCA Policy Scope"
+ },
+ "policyVersion": {
+ "type": "string",
+ "description": "TCA Policy Scope Version"
+ },
+ "thresholds": {
+ "type": "array",
+ "description": "Thresholds associated with eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.thresholds",
+ "type": "object",
+ "required": [
+ "closedLoopControlName",
+ "closedLoopEventStatus",
+ "direction",
+ "fieldPath",
+ "severity",
+ "thresholdValue",
+ "version"
+ ],
+ "properties": {
+ "closedLoopControlName": {
+ "type": "string",
+ "description": "Closed Loop Control Name associated with the threshold"
+ },
+ "closedLoopEventStatus": {
+ "type": "string",
+ "description": "Closed Loop Event Status of the threshold",
+ "enum": [
+ "ONSET",
+ "ABATED"
+ ]
+ },
+ "direction": {
+ "type": "string",
+ "description": "Direction of the threshold",
+ "enum": [
+ "LESS",
+ "LESS_OR_EQUAL",
+ "GREATER",
+ "GREATER_OR_EQUAL",
+ "EQUAL"
+ ]
+ },
+ "fieldPath": {
+ "type": "string",
+ "description": "Json field Path as per CEF message which needs to be analyzed for TCA",
+ "enum": [
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage",
+ "$.event.measurementsForVfScalingFields.meanRequestLatency",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed",
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value"
+ ]
+ },
+ "severity": {
+ "type": "string",
+ "description": "Threshold Event Severity",
+ "enum": [
+ "CRITICAL",
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "NORMAL"
+ ]
+ },
+ "thresholdValue": {
+ "type": "integer",
+ "description": "Threshold value for the field Path inside CEF message"
+ },
+ "version": {
+ "type": "string",
+ "description": "Version number associated with the threshold"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/tosca_example.yaml b/runtime/src/test/resources/tosca/tosca_example.yaml
new file mode 100644
index 000000000..b0119f887
--- /dev/null
+++ b/runtime/src/test/resources/tosca/tosca_example.yaml
@@ -0,0 +1,158 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ description: a base policy type for all policies that governs monitoring provisioning
+ onap.policies.monitoring.cdap.tca.hi.lo.app:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ properties:
+ tca_policy:
+ type: map
+ description: TCA Policy JSON
+ entry_schema:
+ type: onap.datatypes.monitoring.tca_policy
+data_types:
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ type: string
+ required: true
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ eventName:
+ type: string
+ required: true
+ description: Event name to which thresholds need to be applied
+ policyName:
+ type: string
+ required: true
+ description: TCA Policy Scope Name
+ policyScope:
+ type: string
+ required: true
+ description: TCA Policy Scope
+ policyVersion:
+ type: string
+ required: true
+ description: TCA Policy Scope Version
+ thresholds:
+ type: list
+ required: true
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ type: string
+ required: true
+ description: Domain name to which TCA needs to be applied
+ default: measurementsForVfScaling
+ constraints:
+ - equal: measurementsForVfScaling
+ metricsPerEventName:
+ type: list
+ required: true
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ type: string
+ required: true
+ description: Closed Loop Control Name associated with the threshold
+ closedLoopEventStatus:
+ type: string
+ required: true
+ description: Closed Loop Event Status of the threshold
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ direction:
+ type: string
+ required: true
+ description: Direction of the threshold
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ fieldPath:
+ type: string
+ required: true
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ severity:
+ type: string
+ required: true
+ description: Threshold Event Severity
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ thresholdValue:
+ type: integer
+ required: true
+ description: Threshold value for the field Path inside CEF message
+ version:
+ type: string
+ required: true
+ description: Version number associated with the threshold
diff --git a/runtime/src/test/resources/tosca/tosca_with_date_time_json_schema.json b/runtime/src/test/resources/tosca/tosca_with_date_time_json_schema.json
new file mode 100644
index 000000000..e15942cc5
--- /dev/null
+++ b/runtime/src/test/resources/tosca/tosca_with_date_time_json_schema.json
@@ -0,0 +1,240 @@
+{
+ "schema":{
+ "uniqueItems":"true",
+ "format":"tabs",
+ "type":"array",
+ "title":"TCA Policy JSON",
+ "items":{
+ "type":"object",
+ "title":"TCA Policy JSON",
+ "required":[
+ "domain",
+ "metricsPerEventName"
+ ],
+ "properties":{
+ "domain":{
+ "propertyOrder":1001,
+ "default":"measurementsForVfScaling",
+ "title":"Domain name to which TCA needs to be applied",
+ "type":"string"
+ },
+ "metricsPerEventName":{
+ "propertyOrder":1002,
+ "uniqueItems":"true",
+ "format":"tabs-top",
+ "title":"Contains eventName and threshold details that need to be applied to given eventName",
+ "type":"array",
+ "items":{
+ "type":"object",
+ "required":[
+ "controlLoopSchemaType",
+ "eventName",
+ "policyName",
+ "policyScope",
+ "policyVersion",
+ "thresholds",
+ "context",
+ "signature"
+ ],
+ "properties":{
+ "policyVersion":{
+ "propertyOrder":1007,
+ "title":"TCA Policy Scope Version",
+ "type":"string"
+ },
+ "thresholds":{
+ "propertyOrder":1008,
+ "uniqueItems":"true",
+ "format":"tabs-top",
+ "title":"Thresholds associated with eventName",
+ "type":"array",
+ "items":{
+ "type":"object",
+ "required":[
+ "closedLoopControlName",
+ "closedLoopEventStatus",
+ "direction",
+ "fieldPath",
+ "severity",
+ "thresholdValue",
+ "version"
+ ],
+ "properties":{
+ "severity":{
+ "propertyOrder":1013,
+ "title":"Threshold Event Severity",
+ "type":"string",
+ "enum":[
+ "CRITICAL",
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "NORMAL"
+ ]
+ },
+ "fieldPath":{
+ "propertyOrder":1012,
+ "title":"Json field Path as per CEF message which needs to be analyzed for TCA",
+ "type":"string",
+ "enum":[
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage",
+ "$.event.measurementsForVfScalingFields.meanRequestLatency",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed",
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value"
+ ]
+ },
+ "thresholdValue":{
+ "propertyOrder":1014,
+ "title":"Threshold value for the field Path inside CEF message",
+ "type":"integer"
+ },
+ "closedLoopEventStatus":{
+ "propertyOrder":1010,
+ "title":"Closed Loop Event Status of the threshold",
+ "type":"string",
+ "enum":[
+ "ONSET",
+ "ABATED"
+ ]
+ },
+ "closedLoopControlName":{
+ "propertyOrder":1009,
+ "title":"Closed Loop Control Name associated with the threshold",
+ "type":"string"
+ },
+ "version":{
+ "propertyOrder":1015,
+ "title":"Version number associated with the threshold",
+ "type":"string"
+ },
+ "direction":{
+ "propertyOrder":1011,
+ "title":"Direction of the threshold",
+ "type":"string",
+ "enum":[
+ "LESS",
+ "LESS_OR_EQUAL",
+ "GREATER",
+ "GREATER_OR_EQUAL",
+ "EQUAL"
+ ]
+ }
+ }
+ }
+ },
+ "policyName":{
+ "propertyOrder":1005,
+ "title":"TCA Policy Scope Name",
+ "type":"string"
+ },
+ "signature":{
+ "propertyOrder":1017,
+ "title":"Signature",
+ "required":[
+ "filter_clause"
+ ],
+ "properties":{
+ "filter_clause":{
+ "propertyOrder":30002,
+ "qschema":{
+ "filters":[
+ {
+ "plugin":"datetimepicker",
+ "operators":[
+ "equals"
+ ],
+ "minLength":1,
+ "id":"timeEpoch",
+ "label":"timeEpoch",
+ "type":"datetime",
+ "input_event":"dp.change",
+ "validation":{
+ "format":"YYYY/MM/DD HH:mm:ss"
+ }
+ }
+ ]
+ },
+ "minLength":1,
+ "title":"Filter Clause",
+ "type":"qbldr"
+ }
+ }
+ },
+ "controlLoopSchemaType":{
+ "propertyOrder":1003,
+ "title":"Specifies Control Loop Schema Type for the event Name e.g. VNF, VM",
+ "type":"string",
+ "enum":[
+ "VM",
+ "VNF"
+ ]
+ },
+ "policyScope":{
+ "propertyOrder":1006,
+ "title":"TCA Policy Scope",
+ "type":"string"
+ },
+ "context":{
+ "propertyOrder":1016,
+ "options":{
+ "enum_titles":[
+ "PROD"
+ ]
+ },
+ "title":"TCA Policy Dummy Context",
+ "type":"string",
+ "enum":[
+ "PROD"
+ ]
+ },
+ "eventName":{
+ "propertyOrder":1004,
+ "title":"Event name to which thresholds need to be applied",
+ "type":"string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/runtime/src/test/resources/tosca/tosca_with_metadata.yaml b/runtime/src/test/resources/tosca/tosca_with_metadata.yaml
new file mode 100644
index 000000000..5967d1569
--- /dev/null
+++ b/runtime/src/test/resources/tosca/tosca_with_metadata.yaml
@@ -0,0 +1,162 @@
+tosca_definitions_version: tosca_simple_yaml_1_0_0
+policy_types:
+ onap.policies.Monitoring:
+ derived_from: tosca.policies.Root
+ description: a base policy type for all policies that governs monitoring provisioning
+ onap.policies.monitoring.cdap.tca.hi.lo.app:
+ derived_from: onap.policies.Monitoring
+ version: 1.0.0
+ properties:
+ tca_policy:
+ type: map
+ description: TCA Policy JSON
+ entry_schema:
+ type: onap.datatypes.monitoring.tca_policy
+ metadata:
+ policy_model_type: onap.policies.monitoring.cdap.tca.hi.lo.app
+ acronym: tca
+
+data_types:
+ onap.datatypes.monitoring.metricsPerEventName:
+ derived_from: tosca.datatypes.Root
+ properties:
+ controlLoopSchemaType:
+ type: string
+ required: true
+ description: Specifies Control Loop Schema Type for the event Name e.g. VNF, VM
+ constraints:
+ - valid_values:
+ - VM
+ - VNF
+ eventName:
+ type: string
+ required: true
+ description: Event name to which thresholds need to be applied
+ policyName:
+ type: string
+ required: true
+ description: TCA Policy Scope Name
+ policyScope:
+ type: string
+ required: true
+ description: TCA Policy Scope
+ policyVersion:
+ type: string
+ required: true
+ description: TCA Policy Scope Version
+ thresholds:
+ type: list
+ required: true
+ description: Thresholds associated with eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.thresholds
+ onap.datatypes.monitoring.tca_policy:
+ derived_from: tosca.datatypes.Root
+ properties:
+ domain:
+ type: string
+ required: true
+ description: Domain name to which TCA needs to be applied
+ default: measurementsForVfScaling
+ constraints:
+ - equal: measurementsForVfScaling
+ metricsPerEventName:
+ type: list
+ required: true
+ description: Contains eventName and threshold details that need to be applied to given eventName
+ entry_schema:
+ type: onap.datatypes.monitoring.metricsPerEventName
+ onap.datatypes.monitoring.thresholds:
+ derived_from: tosca.datatypes.Root
+ properties:
+ closedLoopControlName:
+ type: string
+ required: true
+ description: Closed Loop Control Name associated with the threshold
+ closedLoopEventStatus:
+ type: string
+ required: true
+ description: Closed Loop Event Status of the threshold
+ constraints:
+ - valid_values:
+ - ONSET
+ - ABATED
+ direction:
+ type: string
+ required: true
+ description: Direction of the threshold
+ constraints:
+ - valid_values:
+ - LESS
+ - LESS_OR_EQUAL
+ - GREATER
+ - GREATER_OR_EQUAL
+ - EQUAL
+ fieldPath:
+ type: string
+ required: true
+ description: Json field Path as per CEF message which needs to be analyzed for TCA
+ constraints:
+ - valid_values:
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait
+ - $.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage
+ - $.event.measurementsForVfScalingFields.meanRequestLatency
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree
+ - $.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed
+ - $.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value
+ severity:
+ type: string
+ required: true
+ description: Threshold Event Severity
+ constraints:
+ - valid_values:
+ - CRITICAL
+ - MAJOR
+ - MINOR
+ - WARNING
+ - NORMAL
+ thresholdValue:
+ type: integer
+ required: true
+ description: Threshold value for the field Path inside CEF message
+ version:
+ type: string
+ required: true
+ description: Version number associated with the threshold
diff --git a/runtime/ui-react-lib/libExportExclusions.dat b/runtime/ui-react-lib/libExportExclusions.dat
new file mode 100644
index 000000000..7194fc2ad
--- /dev/null
+++ b/runtime/ui-react-lib/libExportExclusions.dat
@@ -0,0 +1,4 @@
+./src/theme/globalStyle.js
+./src/index.js
+./src/setupTests.js
+./src/OnapClamp.js
diff --git a/runtime/ui-react-lib/libIndex.js b/runtime/ui-react-lib/libIndex.js
new file mode 100755
index 000000000..75d1bc9df
--- /dev/null
+++ b/runtime/ui-react-lib/libIndex.js
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export { default as CsvToJson } from './src/utils/CsvToJson';
+export { default as CreateLoopModal } from './src/components/dialogs/Loop/CreateLoopModal';
+export { default as DeployLoopModal } from './src/components/dialogs/Loop/DeployLoopModal';
+export { default as LoopActionService } from './src/api/LoopActionService';
+export { default as LoopCache } from './src/api/LoopCache';
+export { default as LoopLogs } from './src/components/loop_viewer/logs/LoopLogs';
+export { default as LoopPropertiesModal } from './src/components/dialogs/Loop/LoopPropertiesModal';
+export { default as LoopService } from './src/api/LoopService';
+export { default as PolicyService } from './src/api/PolicyService';
+export { default as LoopStatus } from './src/components/loop_viewer/status/LoopStatus';
+export { default as LoopUI } from './src/LoopUI';
+export { default as ManageDictionaries } from './src/components/dialogs/ManageDictionaries/ManageDictionaries';
+export { default as MenuBar } from './src/components/menu/MenuBar';
+export { default as ModifyLoopModal } from './src/components/dialogs/Loop/ModifyLoopModal';
+export { default as NotFound } from './src/NotFound';
+export { default as OnapConstants } from './src/utils/OnapConstants';
+export { default as OnapUtils } from './src/utils/OnapUtils';
+export { default as OpenLoopModal } from './src/components/dialogs/Loop/OpenLoopModal';
+export { default as PerformActions } from './src/components/dialogs/PerformActions';
+export { default as PolicyModal } from './src/components/dialogs/Policy/PolicyModal';
+export { default as ToscaViewer } from './src/components/dialogs/Policy/ToscaViewer';
+export { default as PolicyEditor } from './src/components/dialogs/Policy/PolicyEditor';
+export { default as PolicyToscaService } from './src/api/PolicyToscaService';
+export { default as RefreshStatus } from './src/components/dialogs/RefreshStatus';
+export { default as SvgGenerator } from './src/components/loop_viewer/svg/SvgGenerator';
+export { default as TemplateService } from './src/api/TemplateService';
+export { default as UserInfoModal } from './src/components/dialogs/UserInfoModal';
+export { default as UserService } from './src/api/UserService';
+export { default as ViewLoopTemplatesModal } from './src/components/dialogs/Tosca/ViewLoopTemplatesModal';
+export { default as ViewAllPolicies } from './src/components/dialogs/Policy/ViewAllPolicies';
+export { default as PolicyDeploymentEditor } from './src/components/dialogs/Policy/PolicyDeploymentEditor';
+export { default as PoliciesTreeViewer } from './src/components/dialogs/Policy/PoliciesTreeViewer';
+export { default as PolicyToscaFileSelector } from './src/components/dialogs/Policy/PolicyToscaFileSelector'; \ No newline at end of file
diff --git a/runtime/ui-react-lib/package.json b/runtime/ui-react-lib/package.json
new file mode 100755
index 000000000..b1efe2f8e
--- /dev/null
+++ b/runtime/ui-react-lib/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "onap-policy-clamp-ui-lib",
+ "version": "${project.version}",
+ "description": "ONAP Policy Clamp UI Library",
+ "author": "ONAP Policy Team",
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "registry": "${npm.publish.url}"
+ },
+ "main": "dist/index.js",
+ "module": "dist/esindex.js",
+ "scripts": {
+ "build": "rollup -c"
+ },
+ "files": [
+ "dist"
+ ],
+ "peerDependencies": {
+ "@json-editor/json-editor": "1.4.0-beta.0",
+ "@material-ui/core": "4.6.0",
+ "@material-ui/icons": "4.5.1",
+ "bootstrap-css-only": "4.3.1",
+ "material-table": "1.53.0",
+ "react": "16.9.0",
+ "react-bootstrap": "1.0.0-beta.14",
+ "react-dom": "16.9.0",
+ "react-router-dom": "5.0.1",
+ "react-scripts": "3.1.1",
+ "react-select": "3.0.8",
+ "rollup": "^1.29.1",
+ "styled-components": "4.3.2"
+ },
+ "devDependencies": {
+ "@babel/cli": "7.7.5",
+ "@babel/core": "7.7.5",
+ "@babel/helper-plugin-utils": "7.0.0",
+ "@babel/plugin-external-helpers": "^7.7.4",
+ "@babel/plugin-proposal-class-properties": "7.5.5",
+ "@babel/plugin-transform-runtime": "7.7.6",
+ "@babel/preset-env": "7.5.5",
+ "@babel/preset-react": "7.0.0",
+ "rollup": "1.29.1",
+ "@rollup/plugin-commonjs": "^11.0.1",
+ "@rollup/plugin-image": "2.0.0",
+ "@rollup/plugin-node-resolve": "7.0.0",
+ "@rollup/plugin-replace": "2.2.1",
+ "@rollup/plugin-url": "4.0.0",
+ "@svgr/rollup": "5.1.0",
+ "babel-plugin-external-helpers": "6.22.0",
+ "rollup-plugin-babel": "4.3.3",
+ "rollup-plugin-peer-deps-external": "2.2.0",
+ "rollup-plugin-postcss": "2.0.3"
+ }
+}
diff --git a/runtime/ui-react-lib/rollup.config.js b/runtime/ui-react-lib/rollup.config.js
new file mode 100755
index 000000000..c671779c0
--- /dev/null
+++ b/runtime/ui-react-lib/rollup.config.js
@@ -0,0 +1,48 @@
+import babel from 'rollup-plugin-babel'
+import commonjs from '@rollup/plugin-commonjs'
+import postcss from 'rollup-plugin-postcss'
+import resolve from '@rollup/plugin-node-resolve'
+import external from 'rollup-plugin-peer-deps-external'
+import img from '@rollup/plugin-image'
+
+import pkg from './package.json'
+
+export default {
+ input: './libIndex.js',
+ output: [
+ {
+ file: pkg.main,
+ format: 'cjs',
+ sourcemap: true
+ },
+ {
+ file: pkg.module,
+ format: 'es',
+ sourcemap: true
+ }
+ ],
+ plugins: [
+ img(),
+ external(),
+ postcss({
+ modules: true
+ }),
+ babel({
+ exclude: 'node_modules/**',
+ presets: [
+
+ "@babel/preset-env", {},
+ "@babel/preset-react", {}
+ ],
+ plugins: [
+ [
+ "@babel/plugin-proposal-class-properties",
+ {
+ "loose": true
+ }
+ ]
+ ]
+ }),
+ resolve({ preferBuiltins: true, mainFields: ['browser'] })
+ ]
+}
diff --git a/runtime/ui-react/package.json b/runtime/ui-react/package.json
new file mode 100644
index 000000000..fd3dc0ad3
--- /dev/null
+++ b/runtime/ui-react/package.json
@@ -0,0 +1,100 @@
+{
+ "name": "onap-policy-clamp-ui",
+ "version": "${project.version}",
+ "description": "ONAP Policy Clamp UI",
+ "author": "ONAP Policy Team",
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "registry": "${npm.publish.url}"
+ },
+ "main": "index.js",
+ "proxy": "https://localhost:8443",
+ "scripts": {
+ "start": "HTTPS=true react-scripts start",
+ "build": "react-scripts build",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "test:coverage": "jest --coverage",
+ "eject": "react-scripts eject"
+ },
+ "files": [
+ "src/*.js",
+ "src/*.png",
+ "src/api",
+ "src/components",
+ "src/theme"
+ ],
+ "dependencies": {
+ "@json-editor/json-editor": "2.5.2",
+ "@fortawesome/fontawesome-free": "5.15.2",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
+ "react-scripts": "4.0.3",
+ "react-bootstrap": "1.5.2",
+ "bootstrap-css-only": "4.3.1",
+ "styled-components": "5.2.1",
+ "react-router-dom": "5.2.0",
+ "@material-ui/core": "4.11.3",
+ "@material-ui/icons": "4.11.2",
+ "@material-ui/pickers": "3.3.10",
+ "@material-ui/lab": "4.0.0-alpha.57",
+ "material-table": "1.68.1",
+ "react-select": "4.2.1"
+ },
+ "devDependencies": {
+ "jest": "26.6.0",
+ "babel-jest": "26.6.0",
+ "@babel/preset-env": "7.13.10",
+ "@babel/preset-react": "7.12.13",
+ "@babel/plugin-proposal-class-properties": "7.13.0",
+ "enzyme": "3.11.0",
+ "@wojtekmaj/enzyme-adapter-react-17": "0.6.1",
+ "enzyme-to-json": "3.6.1",
+ "jest-fetch-mock": "3.0.3",
+ "jest-canvas-mock": "2.3.1"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ],
+ "jest": {
+ "verbose": true,
+ "coverageDirectory": "${project.build.directory}/${ui.react.src}/coverage",
+ "collectCoverageFrom": [
+ "**/*.{js,jsx}"
+ ],
+ "rootDir": "${project.build.directory}/${ui.react.src}",
+ "coverageReporters": [
+ "lcov"
+ ],
+ "moduleNameMapper": {
+ "\\.(css|png)$": "identity-obj-proxy"
+ },
+ "setupFiles": [
+ "./src/setupTests.js",
+ "jest-canvas-mock"
+ ],
+ "snapshotSerializers": [
+ "enzyme-to-json/serializer"
+ ]
+ },
+ "babel": {
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-react"
+ ],
+ "plugins": [
+ [
+ "@babel/plugin-proposal-class-properties",
+ {
+ "loose": true
+ }
+ ],
+ [
+ "@babel/plugin-transform-runtime"
+ ]
+ ]
+ }
+}
diff --git a/runtime/ui-react/public/index.html b/runtime/ui-react/public/index.html
new file mode 100644
index 000000000..bab3e7ab6
--- /dev/null
+++ b/runtime/ui-react/public/index.html
@@ -0,0 +1,40 @@
+<!--
+ ============LICENSE_START=======================================================
+ ONAP CLAMP
+ ================================================================================
+ Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ ===================================================================
+
+ -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport"
+ content="width=device-width, initial-scale=1, shrink-to-fit=no">
+<meta name="theme-color" content="#000000">
+<link rel="manifest" href="manifest.json">
+<link rel="shortcut icon" href="onap.ico">
+
+<title>Clamp Designer UI</title>
+</head>
+<body>
+ <noscript>You need to enable JavaScript to run this app.</noscript>
+ <div id="root"></div>
+</body>
+</html>
diff --git a/runtime/ui-react/public/manifest.json b/runtime/ui-react/public/manifest.json
new file mode 100644
index 000000000..8210c4ee5
--- /dev/null
+++ b/runtime/ui-react/public/manifest.json
@@ -0,0 +1,15 @@
+{
+ "short_name": "Clamp Designer UI",
+ "name": "Clamp Designer UI",
+ "icons": [
+ {
+ "src": "onap.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": "./index.html",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/runtime/ui-react/public/onap.ico b/runtime/ui-react/public/onap.ico
new file mode 100644
index 000000000..85e168ae2
--- /dev/null
+++ b/runtime/ui-react/public/onap.ico
Binary files differ
diff --git a/runtime/ui-react/src/LoopUI.js b/runtime/ui-react/src/LoopUI.js
new file mode 100644
index 000000000..8dc3bdb03
--- /dev/null
+++ b/runtime/ui-react/src/LoopUI.js
@@ -0,0 +1,419 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react';
+import styled from 'styled-components';
+import MenuBar from './components/menu/MenuBar';
+import Navbar from 'react-bootstrap/Navbar';
+import logo from './logo.png';
+import { GlobalClampStyle } from './theme/globalStyle.js';
+import OnapConstants from './utils/OnapConstants';
+
+import SvgGenerator from './components/loop_viewer/svg/SvgGenerator';
+import LoopLogs from './components/loop_viewer/logs/LoopLogs';
+import LoopStatus from './components/loop_viewer/status/LoopStatus';
+import UserService from './api/UserService';
+import LoopCache from './api/LoopCache';
+import LoopActionService from './api/LoopActionService';
+
+import { Route } from 'react-router-dom'
+import CreateLoopModal from './components/dialogs/Loop/CreateLoopModal';
+import OpenLoopModal from './components/dialogs/Loop/OpenLoopModal';
+import ModifyLoopModal from './components/dialogs/Loop/ModifyLoopModal';
+import PolicyModal from './components/dialogs/Policy/PolicyModal';
+import ViewAllPolicies from './components/dialogs/Policy/ViewAllPolicies';
+import LoopPropertiesModal from './components/dialogs/Loop/LoopPropertiesModal';
+import UserInfoModal from './components/dialogs/UserInfoModal';
+import LoopService from './api/LoopService';
+import ViewLoopTemplatesModal from './components/dialogs/Tosca/ViewLoopTemplatesModal';
+import ManageDictionaries from './components/dialogs/ManageDictionaries/ManageDictionaries';
+import PerformAction from './components/dialogs/PerformActions';
+import RefreshStatus from './components/dialogs/RefreshStatus';
+import DeployLoopModal from './components/dialogs/Loop/DeployLoopModal';
+import Alert from 'react-bootstrap/Alert';
+import Spinner from 'react-bootstrap/Spinner';
+
+import { Link } from 'react-router-dom';
+
+const StyledMainDiv = styled.div`
+ background-color: ${props => props.theme.backgroundColor};
+`
+
+const StyledSpinnerDiv = styled.div`
+ justify-content: center !important;
+ display: flex !important;
+`;
+
+const ProjectNameStyled = styled.a`
+ vertical-align: middle;
+ padding-left: 30px;
+ font-size: 36px;
+ font-weight: bold;
+`
+
+const StyledRouterLink = styled(Link)`
+ color: ${props => props.theme.menuFontColor};
+ background-color: ${props => props.theme.backgroundColor};
+`
+
+const StyledLoginInfo = styled.a`
+ color: ${props => props.theme.menuFontColor};
+ background-color: ${props => props.theme.backgroundColor};
+`
+
+const LoopViewDivStyled = styled.div`
+ height: 100%;
+ overflow: hidden;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+ color: ${props => props.theme.loopViewerFontColor};
+ background-color: ${props => props.theme.loopViewerBackgroundColor};
+ border: 1px solid transparent;
+ border-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
+`
+
+const LoopViewHeaderDivStyled = styled.div`
+ background-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
+ padding: 10px 10px;
+ color: ${props => props.theme.loopViewerHeaderFontColor};
+`
+
+const LoopViewBodyDivStyled = styled.div`
+ background-color: ${props => (props.theme.loopViewerBackgroundColor)};
+ padding: 10px 10px;
+ color: ${props => (props.theme.loopViewerHeaderFontColor)};
+ height: 95%;
+`
+
+export default class LoopUI extends React.Component {
+
+ state = {
+ userName: null,
+ loopName: OnapConstants.defaultLoopName,
+ loopCache: new LoopCache({}),
+ showSucAlert: false,
+ showFailAlert: false,
+ busyLoadingCount: 0
+ };
+
+ constructor() {
+ super();
+ this.getUser = this.getUser.bind(this);
+ this.updateLoopCache = this.updateLoopCache.bind(this);
+ this.loadLoop = this.loadLoop.bind(this);
+ this.closeLoop = this.closeLoop.bind(this);
+ this.showSucAlert = this.showSucAlert.bind(this);
+ this.showFailAlert = this.showFailAlert.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.setBusyLoading = this.setBusyLoading.bind(this);
+ this.clearBusyLoading = this.clearBusyLoading.bind(this);
+ this.isBusyLoading = this.isBusyLoading.bind(this);
+ this.renderGlobalStyle = this.renderGlobalStyle.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ }
+
+ componentWillMount() {
+ this.getUser();
+ }
+
+ getUser() {
+ UserService.login().then(user => {
+ this.setState({ userName: user })
+ });
+ }
+
+ renderMenuNavBar() {
+ return (
+ <MenuBar loopName={this.state.loopName}/>
+ );
+ }
+
+ renderUserLoggedNavBar() {
+ return (
+ <Navbar.Text>
+ <StyledLoginInfo>Signed in as: </StyledLoginInfo>
+ <StyledRouterLink to="/userInfo">{this.state.userName}</StyledRouterLink>
+ </Navbar.Text>
+ );
+ }
+
+ renderLogoNavBar() {
+ return (
+ <Navbar.Brand>
+ <img height="50px" width="234px" src={logo} alt="" />
+ <ProjectNameStyled>CLAMP</ProjectNameStyled>
+ </Navbar.Brand>
+ );
+ }
+
+ renderAlertBar() {
+ return (
+ <div>
+ <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
+ {this.state.showMessage}
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ {this.state.showMessage}
+ </Alert>
+ </div>
+ );
+ }
+
+ renderNavBar() {
+ return (
+ <Navbar >
+ {this.renderLogoNavBar()}
+ <Navbar.Toggle aria-controls="responsive-navbar-nav" />
+ {this.renderMenuNavBar()}
+ {this.renderUserLoggedNavBar()}
+ </Navbar>
+ );
+ }
+
+ renderLoopViewHeader() {
+ return (
+ <LoopViewHeaderDivStyled>
+ Loop Viewer - {this.state.loopName} - ({this.state.loopCache.getTemplateName()})
+ </LoopViewHeaderDivStyled>
+ );
+ }
+
+ renderSvg() {
+ return (
+ <SvgGenerator loopCache={this.state.loopCache} clickable={true} generatedFrom={SvgGenerator.GENERATED_FROM_INSTANCE} isBusyLoading={this.isBusyLoading}/>
+ )
+ }
+ renderLoopViewBody() {
+ return (
+ <LoopViewBodyDivStyled>
+ {this.renderSvg()}
+ <LoopStatus loopCache={this.state.loopCache}/>
+ <LoopLogs loopCache={this.state.loopCache} />
+ </LoopViewBodyDivStyled>
+ );
+ }
+
+ getLoopCache() {
+ return this.state.loopCache;
+
+ }
+
+ renderLoopViewer() {
+ return (
+ <LoopViewDivStyled>
+ {this.renderLoopViewHeader()}
+ {this.renderLoopViewBody()}
+ </LoopViewDivStyled>
+ );
+ }
+
+ updateLoopCache(loopJson) {
+
+ // If call with an empty object for loopJson, this is a reset to empty
+ // from someplace like PerformActions for the case where we are "deleting"
+ // a Control Loop model. Set the loopName to the default.
+
+ if (loopJson === null) {
+ this.setState({ loopName: OnapConstants.defaultLoopName });
+ this.setState({ loopCache: new LoopCache({}) });
+ } else {
+ this.setState({ loopCache: new LoopCache(loopJson) });
+ this.setState({ loopName: this.state.loopCache.getLoopName() });
+ }
+ console.info(this.state.loopName+" loop loaded successfully");
+ }
+
+ showSucAlert(message) {
+ this.setState ({ showSucAlert: true, showMessage:message });
+ }
+
+ showFailAlert(message) {
+ this.setState ({ showFailAlert: true, showMessage:message });
+ }
+
+ disableAlert() {
+ this.setState ({ showSucAlert: false, showFailAlert: false });
+ }
+
+ loadLoop(loopName) {
+ this.setBusyLoading();
+ LoopService.getLoop(loopName).then(loop => {
+ console.debug("Updating loopCache");
+ LoopActionService.refreshStatus(loopName).then(data => {
+ this.updateLoopCache(data);
+ this.clearBusyLoading();
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ this.updateLoopCache(loop);
+ this.clearBusyLoading();
+ this.props.history.push('/');
+ });
+ });
+ }
+
+ setBusyLoading() {
+ this.setState((state,props) => ({ busyLoadingCount: ++state.busyLoadingCount }));
+ }
+
+ clearBusyLoading() {
+ this.setState((state,props) => ({ busyLoadingCount: --state.busyLoadingCount }));
+ }
+
+ isBusyLoading() {
+ if (this.state.busyLoadingCount === 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ closeLoop() {
+ this.setState({ loopCache: new LoopCache({}), loopName: OnapConstants.defaultLoopName });
+ this.props.history.push('/');
+ }
+
+ renderRoutes() {
+ return(
+ <React.Fragment>
+ <Route path="/viewLoopTemplatesModal" render={(routeProps) => (<ViewLoopTemplatesModal {...routeProps} />)} />
+ <Route path="/manageDictionaries" render={(routeProps) => (<ManageDictionaries {...routeProps} />)} />
+ <Route path="/viewAllPolicies" render={(routeProps) => (<ViewAllPolicies {...routeProps} />)} />
+ <Route path="/policyModal/:policyInstanceType/:policyName" render={(routeProps) => (<PolicyModal {...routeProps}
+ loopCache={this.getLoopCache()}
+ loadLoopFunction={this.loadLoop}/>)}
+ />
+ <Route path="/createLoop" render={(routeProps) => (<CreateLoopModal {...routeProps}
+ loadLoopFunction={this.loadLoop} />)}
+ />
+ <Route path="/openLoop" render={(routeProps) => (<OpenLoopModal {...routeProps}
+ loadLoopFunction={this.loadLoop} />)}
+ />
+ <Route path="/loopProperties" render={(routeProps) => (<LoopPropertiesModal {...routeProps}
+ loopCache={this.getLoopCache()}
+ loadLoopFunction={this.loadLoop}/>)}
+ />
+ <Route path="/modifyLoop" render={(routeProps) => (<ModifyLoopModal {...routeProps}
+ loopCache={this.getLoopCache()}
+ loadLoopFunction={this.loadLoop}/>)}
+ />
+
+ <Route path="/userInfo" render={(routeProps) => (<UserInfoModal {...routeProps} />)} />
+ <Route path="/closeLoop" render={this.closeLoop} />
+
+ <Route path="/submit" render={(routeProps) => (<PerformAction {...routeProps}
+ loopAction="submit"
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}
+ setBusyLoading={this.setBusyLoading}
+ clearBusyLoading={this.clearBusyLoading}/>)}
+ />
+ <Route path="/stop" render={(routeProps) => (<PerformAction {...routeProps}
+ loopAction="stop"
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}
+ setBusyLoading={this.setBusyLoading}
+ clearBusyLoading={this.clearBusyLoading}/>)}
+ />
+ <Route path="/restart" render={(routeProps) => (<PerformAction {...routeProps}
+ loopAction="restart"
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}
+ setBusyLoading={this.setBusyLoading}
+ clearBusyLoading={this.clearBusyLoading}/>)}
+ />
+ <Route path="/delete" render={(routeProps) => (<PerformAction {...routeProps}
+ loopAction="delete"
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}
+ setBusyLoading={this.setBusyLoading}
+ clearBusyLoading={this.clearBusyLoading}/>)}
+ />
+ <Route path="/undeploy" render={(routeProps) => (<PerformAction {...routeProps}
+ loopAction="undeploy"
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}
+ setBusyLoading={this.setBusyLoading}
+ clearBusyLoading={this.clearBusyLoading}/>)}
+ />
+ <Route path="/deploy" render={(routeProps) => (<DeployLoopModal {...routeProps}
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}/>)}
+ />
+ <Route path="/refreshStatus" render={(routeProps) => (<RefreshStatus {...routeProps}
+ loopCache={this.getLoopCache()}
+ updateLoopFunction={this.updateLoopCache}
+ showSucAlert={this.showSucAlert}
+ showFailAlert={this.showFailAlert}/>)}
+ />
+ </React.Fragment>
+ );
+ }
+
+ renderGlobalStyle() {
+ return (
+ <GlobalClampStyle />
+ );
+ };
+
+
+ renderSpinner() {
+ if (this.isBusyLoading()) {
+ return (
+ <StyledSpinnerDiv>
+ <Spinner animation="border" role="status">
+ <span className="sr-only">Loading...</span>
+ </Spinner>
+ </StyledSpinnerDiv>
+ );
+ } else {
+ return (<div></div>);
+ }
+ }
+
+ render() {
+ return (
+ <StyledMainDiv id="main_div">
+ {this.renderGlobalStyle()}
+ {this.renderRoutes()}
+ {this.renderSpinner()}
+ {this.renderAlertBar()}
+ {this.renderNavBar()}
+ {this.renderLoopViewer()}
+ </StyledMainDiv>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/LoopUI.test.js b/runtime/ui-react/src/LoopUI.test.js
new file mode 100644
index 000000000..bfd6376e3
--- /dev/null
+++ b/runtime/ui-react/src/LoopUI.test.js
@@ -0,0 +1,171 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import LoopUI from './LoopUI';
+import OnapConstants from './utils/OnapConstants';
+
+import LoopCache from './api/LoopCache';
+import LoopActionService from './api/LoopActionService';
+import LoopService from './api/LoopService';
+
+describe('Verify LoopUI', () => {
+ beforeEach(() => {
+ fetch.resetMocks();
+ fetch.mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ text: () => "testUser"
+
+ });
+ });
+ })
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "components": {
+ "POLICY": {
+ "componentState": {
+ "stateName": "UNKNOWN",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ }
+ });
+
+ it('Test the render method', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+
+ const component = shallow(<LoopUI />)
+ component.setState({
+ loopName: "testLoopName",
+ showSucAlert: false,
+ showFailAlert: false
+ });
+ await flushPromises();
+ expect(component).toMatchSnapshot();
+ });
+
+ test('Test closeLoop method', () => {
+ const historyMock = { push: jest.fn() };
+ const component = shallow(<LoopUI history={historyMock}/>)
+ const instance = component.instance();
+ instance.closeLoop();
+
+ expect(component.state('loopName')).toEqual(OnapConstants.defaultLoopName);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ })
+
+ test('Test loadLoop method refresh suc', async () => {
+ const historyMock = { push: jest.fn() };
+ LoopService.getLoop = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ text: () => {}
+ });
+ });
+
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.resolve({name: "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca"});
+ });
+
+ const flushPromises = () => new Promise(setImmediate);
+ const component = shallow(<LoopUI history={historyMock}/>)
+ const instance = component.instance();
+ instance.loadLoop("LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca");
+
+ await flushPromises();
+
+ const resLoopCache = instance.getLoopCache();
+
+ expect(resLoopCache.getComponentStates()).toBeUndefined();
+ expect(component.state('loopName')).toEqual("LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca");
+ })
+
+ test('Test loadLoop method refresh fail', async () => {
+ const historyMock = { push: jest.fn() };
+ LoopService.getLoop = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ name: "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "components": {
+ "POLICY": {
+ "componentState": {
+ "stateName": "UNKNOWN",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ }});
+ });
+
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.reject({error: "whatever"});
+ });
+
+ const flushPromises = () => new Promise(setImmediate);
+ const component = shallow(<LoopUI history={historyMock}/>)
+ const instance = component.instance();
+ instance.loadLoop("LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca");
+
+ await flushPromises();
+
+ const resLoopCache = instance.getLoopCache();
+
+ expect(resLoopCache).toEqual(loopCache);
+ expect(component.state('loopName')).toEqual("LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca");
+ })
+
+ test('Test alert methods', () => {
+ const component = shallow(<LoopUI />)
+ expect(component.state('showSucAlert')).toEqual(false);
+
+ const instance = component.instance();
+ instance.showSucAlert("testAlert");
+ expect(component.state('showSucAlert')).toEqual(true);
+ expect(component.state('showFailAlert')).toEqual(false);
+ expect(component.state('showMessage')).toEqual("testAlert");
+
+ instance.disableAlert();
+
+ expect(component.state('showSucAlert')).toEqual(false);
+ expect(component.state('showFailAlert')).toEqual(false);
+
+ instance.showFailAlert("testAlert2");
+ expect(component.state('showSucAlert')).toEqual(false);
+ expect(component.state('showFailAlert')).toEqual(true);
+ expect(component.state('showMessage')).toEqual("testAlert2");
+ })
+});
diff --git a/runtime/ui-react/src/NotFound.js b/runtime/ui-react/src/NotFound.js
new file mode 100644
index 000000000..d4b53fd71
--- /dev/null
+++ b/runtime/ui-react/src/NotFound.js
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react'
+
+
+export default class NotFound extends React.Component {
+ render () {
+ return (
+ <div id='main'>
+ <div class="divRow"><b>Page Not Found!</b></div>
+ <div class="divRow">Please cick <a href="/">here</a> to go back to the main page.</div>
+ </div>
+
+ );
+ }
+}
diff --git a/runtime/ui-react/src/NotFound.test.js b/runtime/ui-react/src/NotFound.test.js
new file mode 100644
index 000000000..3a5fc107d
--- /dev/null
+++ b/runtime/ui-react/src/NotFound.test.js
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import NotFound from './NotFound';
+
+describe('Verify OnapClamp', () => {
+
+ it('Test the render method', () => {
+
+ const component = shallow(<NotFound />)
+
+ expect(component).toMatchSnapshot();
+ });
+
+});
diff --git a/runtime/ui-react/src/OnapClamp.js b/runtime/ui-react/src/OnapClamp.js
new file mode 100644
index 000000000..506f6e09d
--- /dev/null
+++ b/runtime/ui-react/src/OnapClamp.js
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react';
+import LoopUI from './LoopUI'
+import { ThemeProvider } from 'styled-components';
+import { DefaultClampTheme } from './theme/globalStyle.js';
+
+export default class OnapClamp extends LoopUI {
+
+ render() {
+ console.info("Onap Clamp UI starting");
+ return (
+ <ThemeProvider theme={DefaultClampTheme}>
+ {super.render()}
+ </ThemeProvider>);
+ }
+}
+
diff --git a/runtime/ui-react/src/OnapClamp.test.js b/runtime/ui-react/src/OnapClamp.test.js
new file mode 100644
index 000000000..c3336a9ab
--- /dev/null
+++ b/runtime/ui-react/src/OnapClamp.test.js
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import OnapClamp from './OnapClamp';
+
+describe('Verify OnapClamp', () => {
+
+ it('Test the render method', () => {
+
+ const component = shallow(<OnapClamp />)
+
+ expect(component).toMatchSnapshot();
+ });
+
+});
diff --git a/runtime/ui-react/src/__snapshots__/LoopUI.test.js.snap b/runtime/ui-react/src/__snapshots__/LoopUI.test.js.snap
new file mode 100644
index 000000000..322c93155
--- /dev/null
+++ b/runtime/ui-react/src/__snapshots__/LoopUI.test.js.snap
@@ -0,0 +1,188 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify LoopUI Test the render method 1`] = `
+<styled.div
+ id="main_div"
+>
+ <Memo(l) />
+ <Route
+ path="/viewLoopTemplatesModal"
+ render={[Function]}
+ />
+ <Route
+ path="/manageDictionaries"
+ render={[Function]}
+ />
+ <Route
+ path="/viewAllPolicies"
+ render={[Function]}
+ />
+ <Route
+ path="/policyModal/:policyInstanceType/:policyName"
+ render={[Function]}
+ />
+ <Route
+ path="/createLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/openLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/loopProperties"
+ render={[Function]}
+ />
+ <Route
+ path="/modifyLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/userInfo"
+ render={[Function]}
+ />
+ <Route
+ path="/closeLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/submit"
+ render={[Function]}
+ />
+ <Route
+ path="/stop"
+ render={[Function]}
+ />
+ <Route
+ path="/restart"
+ render={[Function]}
+ />
+ <Route
+ path="/delete"
+ render={[Function]}
+ />
+ <Route
+ path="/undeploy"
+ render={[Function]}
+ />
+ <Route
+ path="/deploy"
+ render={[Function]}
+ />
+ <Route
+ path="/refreshStatus"
+ render={[Function]}
+ />
+ <div />
+ <div>
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="success"
+ />
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="danger"
+ />
+ </div>
+ <Navbar
+ collapseOnSelect={false}
+ expand={true}
+ variant="light"
+ >
+ <NavbarBrand>
+ <img
+ alt=""
+ height="50px"
+ src={null}
+ width="234px"
+ />
+ <styled.a>
+ CLAMP
+ </styled.a>
+ </NavbarBrand>
+ <NavbarToggle
+ aria-controls="responsive-navbar-nav"
+ label="Toggle navigation"
+ />
+ <MenuBar
+ loopName="testLoopName"
+ />
+ <NavbarText>
+ <styled.a>
+ Signed in as:
+ </styled.a>
+ <Styled(Link)
+ to="/userInfo"
+ >
+ testUser
+ </Styled(Link)>
+ </NavbarText>
+ </Navbar>
+ <styled.div>
+ <styled.div>
+ Loop Viewer -
+ testLoopName
+ - (
+ )
+ </styled.div>
+ <styled.div>
+ <withRouter(SvgGenerator)
+ clickable={true}
+ generatedFrom="INSTANCE"
+ isBusyLoading={[Function]}
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ <LoopStatus
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ <LoopLogs
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ </styled.div>
+ </styled.div>
+</styled.div>
+`;
diff --git a/runtime/ui-react/src/__snapshots__/NotFound.test.js.snap b/runtime/ui-react/src/__snapshots__/NotFound.test.js.snap
new file mode 100644
index 000000000..86bcfd1c4
--- /dev/null
+++ b/runtime/ui-react/src/__snapshots__/NotFound.test.js.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify OnapClamp Test the render method 1`] = `
+<div
+ id="main"
+>
+ <div
+ class="divRow"
+ >
+ <b>
+ Page Not Found!
+ </b>
+ </div>
+ <div
+ class="divRow"
+ >
+ Please cick
+ <a
+ href="/"
+ >
+ here
+ </a>
+ to go back to the main page.
+ </div>
+</div>
+`;
diff --git a/runtime/ui-react/src/__snapshots__/OnapClamp.test.js.snap b/runtime/ui-react/src/__snapshots__/OnapClamp.test.js.snap
new file mode 100644
index 000000000..353bc1173
--- /dev/null
+++ b/runtime/ui-react/src/__snapshots__/OnapClamp.test.js.snap
@@ -0,0 +1,216 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify OnapClamp Test the render method 1`] = `
+<Component
+ theme={
+ Object {
+ "backgroundColor": "#eeeeee",
+ "fontDanger": "#eb238e",
+ "fontDark": "#888888",
+ "fontFamily": "Arial, Sans-serif",
+ "fontHighlight": "#ffff00",
+ "fontLight": "#ffffff",
+ "fontNormal": "black",
+ "fontSize": "16px",
+ "fontWarning": "#eb238e",
+ "loopLogsHeaderBackgroundColor": "white",
+ "loopLogsHeaderFontColor": "black",
+ "loopViewerBackgroundColor": "white",
+ "loopViewerFontColor": "yellow",
+ "loopViewerHeaderBackgroundColor": "#337ab7",
+ "loopViewerHeaderFontColor": "white",
+ "menuBackgroundColor": "white",
+ "menuFontColor": "black",
+ "menuHighlightedBackgroundColor": "#337ab7",
+ "menuHighlightedFontColor": "white",
+ "policyEditorBackgroundColor": "white",
+ "policyEditorFontSize": "13px",
+ "toscaTextareaBackgroundColor": "white",
+ "toscaTextareaFontSize": "13px",
+ }
+ }
+>
+ <styled.div
+ id="main_div"
+ >
+ <Memo(l) />
+ <Route
+ path="/viewLoopTemplatesModal"
+ render={[Function]}
+ />
+ <Route
+ path="/manageDictionaries"
+ render={[Function]}
+ />
+ <Route
+ path="/viewAllPolicies"
+ render={[Function]}
+ />
+ <Route
+ path="/policyModal/:policyInstanceType/:policyName"
+ render={[Function]}
+ />
+ <Route
+ path="/createLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/openLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/loopProperties"
+ render={[Function]}
+ />
+ <Route
+ path="/modifyLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/userInfo"
+ render={[Function]}
+ />
+ <Route
+ path="/closeLoop"
+ render={[Function]}
+ />
+ <Route
+ path="/submit"
+ render={[Function]}
+ />
+ <Route
+ path="/stop"
+ render={[Function]}
+ />
+ <Route
+ path="/restart"
+ render={[Function]}
+ />
+ <Route
+ path="/delete"
+ render={[Function]}
+ />
+ <Route
+ path="/undeploy"
+ render={[Function]}
+ />
+ <Route
+ path="/deploy"
+ render={[Function]}
+ />
+ <Route
+ path="/refreshStatus"
+ render={[Function]}
+ />
+ <div />
+ <div>
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="success"
+ />
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="danger"
+ />
+ </div>
+ <Navbar
+ collapseOnSelect={false}
+ expand={true}
+ variant="light"
+ >
+ <NavbarBrand>
+ <img
+ alt=""
+ height="50px"
+ src={null}
+ width="234px"
+ />
+ <styled.a>
+ CLAMP
+ </styled.a>
+ </NavbarBrand>
+ <NavbarToggle
+ aria-controls="responsive-navbar-nav"
+ label="Toggle navigation"
+ />
+ <MenuBar
+ loopName="Empty (NO loop loaded yet)"
+ />
+ <NavbarText>
+ <styled.a>
+ Signed in as:
+ </styled.a>
+ <Styled(Link)
+ to="/userInfo"
+ />
+ </NavbarText>
+ </Navbar>
+ <styled.div>
+ <styled.div>
+ Loop Viewer -
+ Empty (NO loop loaded yet)
+ - (
+ )
+ </styled.div>
+ <styled.div>
+ <withRouter(SvgGenerator)
+ clickable={true}
+ generatedFrom="INSTANCE"
+ isBusyLoading={[Function]}
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ <LoopStatus
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ <LoopLogs
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ </styled.div>
+ </styled.div>
+ </styled.div>
+</Component>
+`;
diff --git a/runtime/ui-react/src/api/LoopActionService.js b/runtime/ui-react/src/api/LoopActionService.js
new file mode 100644
index 000000000..bff812a2f
--- /dev/null
+++ b/runtime/ui-react/src/api/LoopActionService.js
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class LoopActionService{
+
+ static performAction(cl_name, uiAction) {
+ console.info("LoopActionService perform action: " + uiAction + " closedloopName=" + cl_name);
+ const svcAction = uiAction.toLowerCase();
+ return fetch(window.location.pathname + "restservices/clds/v2/loop/" + svcAction + "/" + cl_name, {
+ method: 'PUT',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ if (response.ok) {
+ return response.json();
+ } else {
+ return Promise.reject("Perform action failed with code:" + response.status);
+ }
+ })
+ .then(function (data) {
+ console.info("Action Successful: " + uiAction);
+ return data;
+ })
+ .catch(function(error) {
+ console.info("Action Failure: " + uiAction);
+ return Promise.reject(error);
+ });
+ }
+
+
+ static refreshStatus(cl_name) {
+ console.info("Refresh the status for closedloopName=" + cl_name);
+
+ return fetch(window.location.pathname + "restservices/clds/v2/loop/getstatus/" + cl_name, {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ if (response.ok) {
+ return response.json();
+ } else {
+ return Promise.reject("Refresh status failed with code:" + response.status);
+ }
+ })
+ .then(function (data) {
+ console.info ("Refresh status Successful");
+ return data;
+ })
+ .catch(function(error) {
+ console.info ("Refresh status failed:", error);
+ return Promise.reject(error);
+ });
+ }
+}
diff --git a/runtime/ui-react/src/api/LoopCache.js b/runtime/ui-react/src/api/LoopCache.js
new file mode 100644
index 000000000..3e19b4fc7
--- /dev/null
+++ b/runtime/ui-react/src/api/LoopCache.js
@@ -0,0 +1,252 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class LoopCache {
+ loopJsonCache;
+
+ constructor(loopJson) {
+ this.loopJsonCache=loopJson;
+ }
+
+ updateMicroServiceProperties(name, newMsProperties) {
+ for (var policy in this.loopJsonCache["microServicePolicies"]) {
+ if (this.loopJsonCache["microServicePolicies"][policy]["name"] === name) {
+ this.loopJsonCache["microServicePolicies"][policy]["configurationsJson"] = newMsProperties;
+ }
+ }
+ }
+
+ updateMicroServicePdpGroup(name, pdpGroup, pdpSubgroup) {
+ for (var policy in this.loopJsonCache["microServicePolicies"]) {
+ if (this.loopJsonCache["microServicePolicies"][policy]["name"] === name) {
+ this.loopJsonCache["microServicePolicies"][policy]["pdpGroup"] = pdpGroup;
+ this.loopJsonCache["microServicePolicies"][policy]["pdpSubgroup"] = pdpSubgroup;
+ }
+ }
+ }
+
+ updateGlobalProperties(newGlobalProperties) {
+ this.loopJsonCache["globalPropertiesJson"] = newGlobalProperties;
+ }
+
+ updateOperationalPolicyProperties(name, newOpProperties) {
+ for (var policy in this.loopJsonCache["operationalPolicies"]) {
+ if (this.loopJsonCache["operationalPolicies"][policy]["name"] === name) {
+ this.loopJsonCache["operationalPolicies"][policy]["configurationsJson"] = newOpProperties;
+ }
+ }
+ }
+
+ updateOperationalPolicyPdpGroup(name, pdpGroup, pdpSubgroup) {
+ for (var policy in this.loopJsonCache["operationalPolicies"]) {
+ if (this.loopJsonCache["operationalPolicies"][policy]["name"] === name) {
+ this.loopJsonCache["operationalPolicies"][policy]["pdpGroup"] = pdpGroup;
+ this.loopJsonCache["operationalPolicies"][policy]["pdpSubgroup"] = pdpSubgroup;
+ }
+ }
+ }
+
+ getLoopName() {
+ return this.loopJsonCache["name"];
+ }
+
+ getOperationalPolicyJsonSchema() {
+ return this.loopJsonCache["operationalPolicies"]["0"]["jsonRepresentation"];
+ }
+
+ getOperationalPolicies() {
+ return this.loopJsonCache["operationalPolicies"];
+ }
+
+ getOperationalPoliciesNoJsonSchema() {
+ var operationalPolicies = JSON.parse(JSON.stringify(this.loopJsonCache["operationalPolicies"]));
+ delete operationalPolicies[0]["jsonRepresentation"];
+ return operationalPolicies;
+ }
+
+ getGlobalProperties() {
+ return this.loopJsonCache["globalPropertiesJson"];
+ }
+
+ getDcaeDeploymentProperties() {
+ return this.loopJsonCache["globalPropertiesJson"]["dcaeDeployParameters"];
+ }
+
+ getMicroServicePolicies() {
+ return this.loopJsonCache["microServicePolicies"];
+ }
+
+ getOperationalPolicyForName(name) {
+ var opProperties=this.getOperationalPolicies();
+ for (var policy in opProperties) {
+ if (opProperties[policy]["name"] === name) {
+ return opProperties[policy];
+ }
+ }
+ return null;
+ }
+
+ getOperationalPolicyPropertiesForName(name) {
+ var opConfig = this.getOperationalPolicyForName(name);
+ if (opConfig !== null) {
+ return opConfig["configurationsJson"];
+ }
+ return null;
+ }
+
+ getOperationalPolicyJsonRepresentationForName(name) {
+ var opConfig = this.getOperationalPolicyForName(name);
+ if (opConfig !== null) {
+ return opConfig["jsonRepresentation"];
+ }
+ return null;
+ }
+
+ getOperationalPolicySupportedPdpGroup(name) {
+ var opConfig=this.getOperationalPolicyForName(name);
+ if (opConfig !== null) {
+ if (opConfig["policyModel"]["policyPdpGroup"] !== undefined && opConfig["policyModel"]["policyPdpGroup"]["supportedPdpGroups"] !== undefined) {
+ return opConfig["policyModel"]["policyPdpGroup"]["supportedPdpGroups"];
+ }
+ }
+ return [];
+ }
+
+ getOperationalPolicyPdpGroup(name) {
+ var opConfig=this.getOperationalPolicyForName(name);
+ if (opConfig !== null) {
+ return opConfig["pdpGroup"];
+ }
+ return null;
+ }
+
+ getOperationalPolicyPdpSubgroup(name) {
+ var opConfig=this.getOperationalPolicyForName(name);
+ if (opConfig !== null) {
+ return opConfig["pdpSubgroup"];
+ }
+ return null;
+ }
+
+ getMicroServiceSupportedPdpGroup(name) {
+ var microService=this.getMicroServiceForName(name);
+ if (microService !== null) {
+ if (microService["policyModel"]["policyPdpGroup"] !== undefined && microService["policyModel"]["policyPdpGroup"]["supportedPdpGroups"] !== undefined) {
+ return microService["policyModel"]["policyPdpGroup"]["supportedPdpGroups"];
+ }
+ }
+ return [];
+ }
+
+ getMicroServicePdpGroup(name) {
+ var microService=this.getMicroServiceForName(name);
+ if (microService !== null) {
+ return microService["pdpGroup"];
+ }
+ return null;
+ }
+
+ getMicroServicePdpSubgroup(name) {
+ var microService=this.getMicroServiceForName(name);
+ if (microService !== null) {
+ return microService["pdpSubgroup"];
+ }
+ return null;
+ }
+
+ getMicroServiceForName(name) {
+ var msProperties=this.getMicroServicePolicies();
+ for (var policy in msProperties) {
+ if (msProperties[policy]["name"] === name) {
+ return msProperties[policy];
+ }
+ }
+ return null;
+ }
+
+ getMicroServicePropertiesForName(name) {
+ var msConfig = this.getMicroServiceForName(name);
+ if (msConfig !== null) {
+ return msConfig["configurationsJson"];
+ }
+ return null;
+ }
+
+ getMicroServiceJsonRepresentationForName(name) {
+ var msConfig = this.getMicroServiceForName(name);
+ if (msConfig !== null) {
+ return msConfig["jsonRepresentation"];
+ }
+ return null;
+ }
+
+ getResourceDetailsVfProperty() {
+ return this.loopJsonCache["modelService"]["resourceDetails"]["VF"];
+ }
+
+ getResourceDetailsVfModuleProperty() {
+ return this.loopJsonCache["modelService"]["resourceDetails"]["VFModule"];
+ }
+
+ getLoopLogsArray() {
+ return this.loopJsonCache.loopLogs;
+ }
+
+ getComputedState() {
+ return this.loopJsonCache.lastComputedState;
+ }
+
+ getComponentStates() {
+ return this.loopJsonCache.components;
+ }
+
+ getTemplateName() {
+ if (this.getLoopTemplate() !== undefined) {
+ return this.getLoopTemplate().name;
+ }
+ return null;
+ }
+
+ getLoopTemplate() {
+ return this.loopJsonCache["loopTemplate"];
+ }
+
+ isOpenLoopTemplate() {
+ var loopTemplate = this.getLoopTemplate();
+ if(loopTemplate != null && loopTemplate["allowedLoopType"] === "OPEN") {
+ return true;
+ }
+ return false;
+ }
+
+ getAllLoopElementModels() {
+ var loopTemplate = this.getLoopTemplate();
+ var loopElementModels = [];
+ if(loopTemplate != null) {
+ for (var element of loopTemplate['loopElementModelsUsed']) {
+ loopElementModels.push(element['loopElementModel'])
+ }
+ }
+ return loopElementModels;
+ }
+}
diff --git a/runtime/ui-react/src/api/LoopCache.test.js b/runtime/ui-react/src/api/LoopCache.test.js
new file mode 100644
index 000000000..76f819c69
--- /dev/null
+++ b/runtime/ui-react/src/api/LoopCache.test.js
@@ -0,0 +1,305 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import LoopCache from '../api/LoopCache';
+
+const json = require('./LoopCacheMockFile.json');
+
+describe('Verify LoopCache functions', () => {
+ const loopCache = new LoopCache(json);
+ it('getLoopName', () => {
+ expect(loopCache.getLoopName()).toBe("LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca");
+ });
+
+ it('getOperationalPolicies', () => {
+ const opPolicy = [{
+ "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "configurationsJson": {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ },
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ "jsonRepresentation": {
+ "schema": {}
+ }
+ }];
+ expect(loopCache.getOperationalPolicies()).toStrictEqual(opPolicy);
+ });
+
+ it('getOperationalPoliciesNoJsonSchema', () => {
+ const opPolicy = [{
+ "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "configurationsJson": {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ },
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ }];
+ expect(loopCache.getOperationalPoliciesNoJsonSchema()).toStrictEqual(opPolicy);
+ });
+
+ it('getOperationalPolicyJsonSchema', () => {
+ const jsonSchema = {
+ "schema": {}
+ };
+
+ expect(loopCache.getOperationalPolicyJsonSchema()).toStrictEqual(jsonSchema);
+ });
+ it('getGlobalProperties', () => {
+ const globelProp = {
+ "dcaeDeployParameters": {
+ "location_id": "",
+ "service_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ };
+ expect(loopCache.getGlobalProperties()).toStrictEqual(globelProp);
+ });
+
+ it('getDcaeDeploymentProperties', () => {
+ const deploymentProp = {
+ "location_id": "",
+ "service_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ };
+ expect(loopCache.getDcaeDeploymentProperties()).toStrictEqual(deploymentProp);
+ });
+
+ it('getMicroServiceForName', () => {
+ const msJson = {
+ "name": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "modelType": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "configurationsJson": {"domain": "measurementsForVfScaling"},
+ "shared": false,
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ "policyModel": {"policyPdpGroup": {"supportedPdpGroups": "supportedPdpGroupsTest"}},
+ "jsonRepresentation": {"schema": {}}
+ };
+ expect(loopCache.getMicroServiceForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(msJson);
+ expect(loopCache.getMicroServiceForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca_2")).toBeNull();
+ });
+
+ it('getMicroServicePropertiesForName', () => {
+ const msProp = {"domain": "measurementsForVfScaling"};
+ expect(loopCache.getMicroServicePropertiesForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(msProp);
+ expect(loopCache.getMicroServicePropertiesForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca_2")).toBeNull();
+ });
+
+ it('getMicroServiceJsonRepresentationForName', () => {
+ const msJsonRepresentation = {"schema": {}};
+ expect(loopCache.getMicroServiceJsonRepresentationForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(msJsonRepresentation);
+ });
+
+ it('getResourceDetailsVfProperty', () => {
+ const resourceVF = {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552"
+ }
+ };
+ expect(loopCache.getResourceDetailsVfProperty()).toStrictEqual(resourceVF);
+ });
+
+ it('getResourceDetailsVfModuleProperty', () => {
+ const vfModule = {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ };
+ expect(loopCache.getResourceDetailsVfModuleProperty()).toStrictEqual(vfModule);
+ });
+
+ it('getLoopLogsArray', () => {
+ const logs = [
+ {
+ "id": 1,
+ "logType": "INFO",
+ "logComponent": "CLAMP",
+ "message": "Operational policies UPDATED",
+ "logInstant": "2019-07-08T09:44:37Z"
+ }
+ ];
+ expect(loopCache.getLoopLogsArray()).toStrictEqual(logs);
+ });
+
+ it('getComponentStates', () => {
+ const component = {
+ "POLICY": {
+ "componentState": {
+ "stateName": "NOT_SENT",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ };
+ expect(loopCache.getComponentStates()).toStrictEqual(component);
+ });
+
+ it('getOperationalPolicyForName', () => {
+ const opPolicy = {
+ "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "configurationsJson": {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ },
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ "jsonRepresentation": {
+ "schema": {}
+ }
+ };
+ expect(loopCache.getOperationalPolicyForName("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(opPolicy);
+ expect(loopCache.getOperationalPolicyForName("Not_Exist")).toBeNull();
+ });
+
+ it('getOperationalPolicyPropertiesForName', () => {
+ const opPolicyJson = {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }};
+ expect(loopCache.getOperationalPolicyPropertiesForName("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(opPolicyJson);
+ expect(loopCache.getOperationalPolicyPropertiesForName("Not_Exist")).toBeNull();
+ });
+
+ it('getOperationalPolicyJsonRepresentationForName', () => {
+ const opPolicySchema = {
+ "schema": {}
+ };
+ expect(loopCache.getOperationalPolicyJsonRepresentationForName("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(opPolicySchema);
+ expect(loopCache.getOperationalPolicyJsonRepresentationForName("Not_Exist")).toBeNull();
+ });
+
+ it('getOperationalPolicySupportedPdpGroup', () => {
+ expect(loopCache.getOperationalPolicySupportedPdpGroup("Not_Exist")).toStrictEqual([]);
+ });
+
+ it('getOperationalPolicyPdpGroup', () => {
+ expect(loopCache.getOperationalPolicyPdpGroup("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpGroupTest");
+ expect(loopCache.getOperationalPolicyPdpGroup("Not_Exist")).toBeNull();
+ });
+
+ it('getOperationalPolicyPdpSubgroup', () => {
+ expect(loopCache.getOperationalPolicyPdpSubgroup("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpSubgroupTest");
+ expect(loopCache.getOperationalPolicyPdpSubgroup("Not_Exist")).toBeNull();
+ });
+
+ it('getMicroServiceSupportedPdpGroup', () => {
+ expect(loopCache.getMicroServiceSupportedPdpGroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("supportedPdpGroupsTest");
+ expect(loopCache.getMicroServiceSupportedPdpGroup("Not_Exist")).toStrictEqual([]);
+ });
+
+ it('getMicroServicePdpGroup', () => {
+ expect(loopCache.getMicroServicePdpGroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpGroupTest");
+ expect(loopCache.getMicroServicePdpGroup("Not_Exist")).toBeNull();
+ });
+
+ it('getMicroServicePdpSubgroup', () => {
+ expect(loopCache.getMicroServicePdpSubgroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpSubgroupTest");
+ expect(loopCache.getMicroServicePdpSubgroup("Not_Exist")).toBeNull();
+ });
+
+ it('getMicroServiceJsonRepresentationForName', () => {
+ const msPolicySchema = {
+ "schema": {}
+ };
+ expect(loopCache.getMicroServiceJsonRepresentationForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(msPolicySchema);
+ expect(loopCache.getMicroServiceJsonRepresentationForName("Not_Exist")).toBeNull();
+ });
+
+ it('getTemplateName', () => {
+ expect(loopCache.getTemplateName()).toStrictEqual("loopTemplateTest");
+ });
+
+ it('updateGlobalProperties', () => {
+ const newGlobalProps = {
+ "dcaeDeployParameters": {
+ "location_id": "newLocation",
+ "service_id": "newServiceId",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca_2"
+ }
+ };
+ loopCache.updateGlobalProperties(newGlobalProps);
+ expect(loopCache.getGlobalProperties()).toStrictEqual(newGlobalProps);
+ });
+
+ it('updateOperationalPolicyProperties', () => {
+ const newOpPolicy = {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ };
+ loopCache.updateOperationalPolicyProperties("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",newOpPolicy);
+ expect(loopCache.getOperationalPolicyPropertiesForName("OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(newOpPolicy);
+ });
+
+ it('updateMicroServiceProperties', () => {
+ const newMsPolicyProperties = {"domain": "measurementsForVfScalingNew"};
+ loopCache.updateMicroServiceProperties("TCA_h2NMX_v1_0_ResourceInstanceName1_tca", newMsPolicyProperties);
+ expect(loopCache.getMicroServicePropertiesForName("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual(newMsPolicyProperties);
+ });
+
+ it('updateMicroServicePdpGroup', () => {
+ const newMsPolicyProperties = {"domain": "measurementsForVfScalingNew"};
+ loopCache.updateMicroServicePdpGroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca", "pdpGroupTest1", "pdpSubgroupTest1");
+ expect(loopCache.getMicroServicePdpGroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpGroupTest1");
+ expect(loopCache.getMicroServicePdpGroup("Not_Exist")).toBeNull();
+ expect(loopCache.getMicroServicePdpSubgroup("TCA_h2NMX_v1_0_ResourceInstanceName1_tca")).toStrictEqual("pdpSubgroupTest1");
+ expect(loopCache.getMicroServicePdpSubgroup("Not_Exist")).toBeNull();
+ });
+ });
diff --git a/runtime/ui-react/src/api/LoopCacheMockFile.json b/runtime/ui-react/src/api/LoopCacheMockFile.json
new file mode 100644
index 000000000..cb9ed87b0
--- /dev/null
+++ b/runtime/ui-react/src/api/LoopCacheMockFile.json
@@ -0,0 +1,125 @@
+{
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "dcaeBlueprintId": "typeId-3a942643-a8f7-4e54-b2c1-eea8daba2b17",
+ "globalPropertiesJson": {
+ "dcaeDeployParameters": {
+ "location_id": "",
+ "service_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ },
+ "loopTemplate": {"name": "loopTemplateTest"},
+ "modelService": {
+ "serviceDetails": {
+ "serviceType": "",
+ "namingPolicy": "",
+ "environmentContext": "General_Revenue-Bearing",
+ "serviceEcompNaming": "true",
+ "serviceRole": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "30ec5b59-4799-48d8-ac5f-1058a6b0e48f",
+ "ecompGeneratedNaming": "true",
+ "category": "Network L4+",
+ "type": "Service",
+ "UUID": "63cac700-ab9a-4115-a74f-7eac85e3fce0",
+ "instantiationType": "A-la-carte"
+ },
+ "resourceDetails": {
+ "CP": {},
+ "VL": {},
+ "VF": {
+ "vLoadBalancerMS 0": {
+ "resourceVendor": "Test",
+ "resourceVendorModelNumber": "",
+ "name": "vLoadBalancerMS",
+ "description": "vLBMS",
+ "invariantUUID": "1a31b9f2-e50d-43b7-89b3-a040250cf506",
+ "subcategory": "Load Balancer",
+ "category": "Application L4+",
+ "type": "VF",
+ "UUID": "b4c4f3d7-929e-4b6d-a1cd-57e952ddc3e6",
+ "version": "1.0",
+ "resourceVendorRelease": "1.0",
+ "customizationUUID": "465246dc-7748-45f4-a013-308d92922552"
+ }
+ },
+ "CR": {},
+ "VFC": {},
+ "PNF": {},
+ "Service": {},
+ "CVFC": {},
+ "Service Proxy": {},
+ "Configuration": {},
+ "AllottedResource": {},
+ "VFModule": {
+ "Vloadbalancerms..vpkg..module-1": {
+ "vfModuleModelInvariantUUID": "ca052563-eb92-4b5b-ad41-9111768ce043",
+ "vfModuleModelVersion": "1",
+ "vfModuleModelName": "Vloadbalancerms..vpkg..module-1",
+ "vfModuleModelUUID": "1e725ccc-b823-4f67-82b9-4f4367070dbc",
+ "vfModuleModelCustomizationUUID": "1bffdc31-a37d-4dee-b65c-dde623a76e52",
+ "min_vf_module_instances": 0,
+ "vf_module_label": "vpkg",
+ "max_vf_module_instances": 1,
+ "vf_module_type": "Expansion",
+ "isBase": false,
+ "initial_count": 0,
+ "volume_group": false
+ }
+ }
+ }
+ },
+ "lastComputedState": "DESIGN",
+ "components": {
+ "POLICY": {
+ "componentState": {
+ "stateName": "NOT_SENT",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ },
+ "operationalPolicies": [
+ {
+ "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "configurationsJson": {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ },
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ "jsonRepresentation": {
+ "schema": {}
+ }
+ }
+ ],
+ "microServicePolicies": [
+ {
+ "name": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "modelType": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "configurationsJson": {"domain": "measurementsForVfScaling"},
+ "shared": false,
+ "pdpGroup": "pdpGroupTest",
+ "pdpSubgroup": "pdpSubgroupTest",
+ "policyModel": {"policyPdpGroup": {"supportedPdpGroups": "supportedPdpGroupsTest"}},
+ "jsonRepresentation": {"schema": {}}
+ }
+ ],
+ "loopLogs": [
+ {
+ "id": 1,
+ "logType": "INFO",
+ "logComponent": "CLAMP",
+ "message": "Operational policies UPDATED",
+ "logInstant": "2019-07-08T09:44:37Z"
+ }
+ ]
+}
diff --git a/runtime/ui-react/src/api/LoopService.js b/runtime/ui-react/src/api/LoopService.js
new file mode 100644
index 000000000..96bb8a0a7
--- /dev/null
+++ b/runtime/ui-react/src/api/LoopService.js
@@ -0,0 +1,244 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class LoopService {
+ static getLoopNames() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/getAllNames', { method: 'GET', credentials: 'same-origin' })
+ .then(function (response) {
+ console.debug("GetLoopNames response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("GetLoopNames query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("GetLoopNames error received", error);
+ return {};
+ });
+ }
+
+ static createLoop(loopName, templateName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/create/' + loopName + '?templateName=' + templateName, {
+ method: 'POST',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("CreateLoop response received: ", response.status);
+ return response.json();
+ })
+ .catch(function (error) {
+ console.error("CreateLoop error received", error);
+ return "";
+ });
+ }
+
+ static getLoop(loopName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/' + loopName, {
+ method: 'GET',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("GetLoop response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("GetLoop query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("GetLoop error received", error);
+ return {};
+ });
+ }
+
+ static setMicroServiceProperties(loopName, jsonData) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/updateMicroservicePolicy/' + loopName, {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(jsonData)
+ })
+ .then(function (response) {
+ console.debug("updateMicroservicePolicy response received: ", response.status);
+ if (response.ok) {
+ return response.text();
+ } else {
+ console.error("updateMicroservicePolicy query failed");
+ return "";
+ }
+ })
+ .catch(function (error) {
+ console.error("updateMicroservicePolicy error received", error);
+ return "";
+ });
+ }
+
+ static setOperationalPolicyProperties(loopName, jsonData) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/updateOperationalPolicies/' + loopName, {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(jsonData)
+ })
+ .then(function (response) {
+ console.debug("updateOperationalPolicies response received: ", response.status);
+ if (response.ok) {
+ return response.text();
+ } else {
+ console.error("updateOperationalPolicies query failed");
+ return "";
+ }
+ })
+ .catch(function (error) {
+ console.error("updateOperationalPolicies error received", error);
+ return "";
+ });
+ }
+
+ static updateGlobalProperties(loopName, jsonData) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/updateGlobalProperties/' + loopName, {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(jsonData)
+ })
+ .then(function (response) {
+ console.debug("updateGlobalProperties response received: ", response.status);
+ if (response.ok) {
+ return response.text();
+ } else {
+ console.error("updateGlobalProperties query failed");
+ return "";
+ }
+ })
+ .catch(function (error) {
+ console.error("updateGlobalProperties error received", error);
+ return "";
+ });
+ }
+
+ static refreshOperationalPolicyJson(loopName,operationalPolicyName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/refreshOperationalPolicyJsonSchema/' + loopName + '/' + operationalPolicyName, {
+ method: 'PUT',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("Refresh Operational Policy Json Schema response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("Refresh Operational Policy Json Schema query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("Refresh Operational Policy Json Schema error received", error);
+ return {};
+ });
+ }
+
+ static refreshMicroServicePolicyJson(loopName,microServicePolicyName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/refreshMicroServicePolicyJsonSchema/' + loopName + '/' + microServicePolicyName, {
+ method: 'PUT',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("Refresh Operational Policy Json Schema response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("Refresh Operational Policy Json Schema query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("Refresh Operational Policy Json Schema error received", error);
+ return {};
+ });
+ }
+
+ static addOperationalPolicyType(loopName, policyType, policyVersion) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/addOperationaPolicy/' + loopName + '/policyModel/' + policyType +'/' + policyVersion , {
+ method: 'PUT',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("Add Operational Policy response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ return response.text();
+ }
+ })
+ .catch(function (error) {
+ console.error("Add Operational Policy query failed");
+ throw new Error(error);
+ })
+ }
+
+ static removeOperationalPolicyType(loopName, policyType, policyVersion, policyName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/removeOperationaPolicy/' + loopName + '/policyModel/' + policyType +'/' + policyVersion + '/' + policyName , {
+ method: 'PUT',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("Remove Operational Policy response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("Remove Operational Policy query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("Remove Operational Policy error received", error);
+ return {};
+ });
+ }
+}
diff --git a/runtime/ui-react/src/api/PoliciesListCacheMockFile.json b/runtime/ui-react/src/api/PoliciesListCacheMockFile.json
new file mode 100644
index 000000000..5c6bd5b6b
--- /dev/null
+++ b/runtime/ui-react/src/api/PoliciesListCacheMockFile.json
@@ -0,0 +1,215 @@
+{
+ "policies": [
+ {
+ "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0": {
+ "type": "onap.policies.monitoring.tcagen2",
+ "type_version": "1.0.0",
+ "properties": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "name": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "MICROSERVICE_vLoadBalancerMS_v1_0_tcagen2_1_0_0_AV0",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": {
+ "pdpGroup": "pdpGroup2",
+ "pdpSubGroup": "subGroup2"
+ },
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd": {
+ "type": "onap.policies.controlloop.operational.common.Drools",
+ "type_version": "1.0.0",
+ "properties": {
+ "abatement": false,
+ "operations": [
+ {
+ "failure_retries": "final_failure_retries",
+ "id": "test1",
+ "failure_timeout": "final_failure_timeout",
+ "failure": "final_failure",
+ "operation": {
+ "payload": {
+ "artifact_name": "baseconfiguration",
+ "artifact_version": "1.0.0",
+ "mode": "async",
+ "data": "{\"resource-assignment-properties\":{\"request-id\":\"\",\"service-instance-id\":\"\",\"hostname\":\"\",\"request-info\":{\"prop1\":\"\",\"prop2\":\"\"}}}"
+ },
+ "target": {
+ "entityIds": {
+ "resourceID": "Vloadbalancerms..vdns..module-3",
+ "modelInvariantId": "4c10ba9b-f88f-415e-9de3-5d33336047fa",
+ "modelVersionId": "4fa73b49-8a6c-493e-816b-eb401567b720",
+ "modelName": "Vloadbalancerms..vdns..module-3",
+ "modelVersion": "1",
+ "modelCustomizationId": "bafcdab0-801d-4d81-9ead-f464640a38b1"
+ },
+ "targetType": "VNF"
+ },
+ "actor": "SDNR",
+ "operation": "BandwidthOnDemand"
+ },
+ "failure_guard": "final_failure_guard",
+ "retries": 0,
+ "timeout": 0,
+ "failure_exception": "final_failure_exception",
+ "description": "test",
+ "success": "final_success"
+ }
+ ],
+ "trigger": "test1",
+ "timeout": 0,
+ "id": "LOOP_test"
+ },
+ "name": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "OPERATIONAL_vLoadBalancerMS_v1_0_Drools_1_0_0_7xd",
+ "policy-version": "1.0.0"
+ },
+ "pdpGroupInfo": {
+ "pdpGroup": "pdpGroup2",
+ "pdpSubGroup": "subGroup3"
+ },
+ "supportedPdpGroups": [
+ {
+ "pdpGroup2": [
+ "subGroup2",
+ "subGroup3"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP": {
+ "type": "onap.policies.Naming",
+ "type_version": "1.0.0",
+ "properties": {
+ "naming-models": [
+ {
+ "naming-type": "VNF",
+ "naming-recipe": "AIC_CLOUD_REGION|DELIMITER|CONSTANT|DELIMITER|TIMESTAMP",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "AIC_CLOUD_REGION"
+ },
+ {
+ "property-name": "CONSTANT",
+ "property-value": "onap-nf"
+ },
+ {
+ "property-name": "TIMESTAMP"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VNFC",
+ "naming-recipe": "VNF_NAME|DELIMITER|NFC_NAMING_CODE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "ENTIRETY",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ },
+ {
+ "property-name": "NFC_NAMING_CODE"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ }
+ ]
+ },
+ {
+ "naming-type": "VF-MODULE",
+ "naming-recipe": "VNF_NAME|DELIMITER|VF_MODULE_LABEL|DELIMITER|VF_MODULE_TYPE|DELIMITER|SEQUENCE",
+ "name-operation": "to_lower_case()",
+ "naming-properties": [
+ {
+ "property-name": "VNF_NAME"
+ },
+ {
+ "property-value": "-",
+ "property-name": "DELIMITER"
+ },
+ {
+ "property-name": "VF_MODULE_LABEL"
+ },
+ {
+ "property-name": "VF_MODULE_TYPE"
+ },
+ {
+ "property-name": "SEQUENCE",
+ "increment-sequence": {
+ "max": "zzz",
+ "scope": "PRECEEDING",
+ "start-value": "1",
+ "length": "3",
+ "increment": "1",
+ "sequence-type": "alpha-numeric"
+ }
+ }
+ ]
+ }
+ ],
+ "policy-instance-name": "ONAP_NF_NAMING_TIMESTAMP"
+ },
+ "name": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "version": "1.0.0",
+ "metadata": {
+ "policy-id": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+ "policy-version": "1.0.0"
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/runtime/ui-react/src/api/PolicyService.js b/runtime/ui-react/src/api/PolicyService.js
new file mode 100644
index 000000000..f2886b30a
--- /dev/null
+++ b/runtime/ui-react/src/api/PolicyService.js
@@ -0,0 +1,148 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class PolicyService {
+ static getPoliciesList() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies', {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function(response) {
+ console.debug("getPoliciesList response received: ", response.status);
+ if (response.ok) {
+ console.info("getPoliciesList query successful");
+ return response.json();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function(error) {
+ console.error("getPoliciesList error occurred ", error);
+ alert("getPoliciesList error occurred " + error);
+ return undefined;
+ });
+ }
+ static createNewPolicy(policyModelType, policyModelVersion, policyName, policyVersion, policyJson) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/' + policyModelType + '/'
+ + policyModelVersion + '/' + policyName + '/' + policyVersion, {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(policyJson)
+ })
+ .then(function (response) {
+ console.debug("createNewPolicy response received: ", response.status);
+ if (response.ok) {
+ console.info("createNewPolicy query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("createNewPolicy error occurred ", error);
+ alert ("createNewPolicy error occurred " + error);
+ return undefined;
+ });
+ }
+ static deletePolicy(policyModelType, policyModelVersion, policyName, policyVersion) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/' + policyModelType + '/'
+ + policyModelVersion + '/' + policyName + '/' + policyVersion, {
+ method: 'DELETE',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("deletePolicy response received: ", response.status);
+ if (response.ok) {
+ console.info("deletePolicy query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("deletePolicy error occurred ", error);
+ alert ("deletePolicy error occurred " + error);
+ return undefined;
+ });
+ }
+ static updatePdpDeployment(pdpOperationsList) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/pdpDeployment', {
+ method: 'PUT',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(pdpOperationsList)
+ })
+ .then(function (response) {
+ console.debug("updatePdpDeployment response received: ", response.status);
+ if (response.ok) {
+ console.info("updatePdpDeployment query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("updatePdpDeployment error occurred ", error);
+ alert ("updatePdpDeployment error occurred " + error);
+ return undefined;
+ });
+ }
+ static sendNewPolicyModel(newPolicyModel) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/policytype', {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "plain/text"
+ },
+ body: newPolicyModel
+ })
+ .then(function (response) {
+ console.debug("sendNewPolicyModel response received: ", response.status);
+ if (response.ok) {
+ console.info("sendNewPolicyModel query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("sendNewPolicyModel error occurred ", error);
+ alert ("sendNewPolicyModel error occurred " + error);
+ return undefined;
+ });
+ }
+}
diff --git a/runtime/ui-react/src/api/PolicyToscaService.js b/runtime/ui-react/src/api/PolicyToscaService.js
new file mode 100644
index 000000000..e2a1f45e4
--- /dev/null
+++ b/runtime/ui-react/src/api/PolicyToscaService.js
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class PolicyToscaService {
+ static getToscaPolicyModels() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels', { method: 'GET', credentials: 'same-origin' })
+ .then(function (response) {
+ console.debug("getToscaPolicyModels response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getToscaPolicyModels query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getToscaPolicyModels error received", error);
+ return {};
+ });
+ }
+
+ static getToscaPolicyModelYaml(policyModelType, policyModelVersion) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels/yaml/' + policyModelType + "/" + policyModelVersion, {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("getToscaPolicyModelYaml response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getToscaPolicyModelYaml query failed");
+ return "";
+ }
+ })
+ .catch(function (error) {
+ console.error("getToscaPolicyModelYaml error received", error);
+ return "";
+ });
+ }
+
+ static getToscaPolicyModel(policyModelType, policyModelVersion) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels/' + policyModelType + "/" + policyModelVersion, {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("getToscaPolicyModel response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getToscaPolicyModel query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getToscaPolicyModel error received", error);
+ return {};
+ });
+ }
+}
diff --git a/runtime/ui-react/src/api/TemplateService.js b/runtime/ui-react/src/api/TemplateService.js
new file mode 100644
index 000000000..08436f2b8
--- /dev/null
+++ b/runtime/ui-react/src/api/TemplateService.js
@@ -0,0 +1,197 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class TemplateService {
+
+ static getLoopNames() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/loop/getAllNames', { method: 'GET', credentials: 'same-origin' })
+ .then(function (response) {
+ console.debug("getLoopNames response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getLoopNames query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getLoopNames error received", error);
+ return {};
+ });
+ }
+
+ static getAllLoopTemplates() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/templates', { method: 'GET', credentials: 'same-origin', })
+ .then(function (response) {
+ console.debug("getAllLoopTemplates response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getAllLoopTemplates query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getAllLoopTemplates error received", error);
+ return {};
+ });
+ }
+
+ static getDictionary() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/', { method: 'GET', credentials: 'same-origin', })
+ .then(function (response) {
+ console.debug("getDictionary response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getDictionary query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getDictionary error received", error);
+ return {};
+ });
+ }
+
+ static getDictionaryElements(dictionaryName) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/' + dictionaryName, {
+ method: 'GET',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ credentials: 'same-origin',
+ })
+ .then(function (response) {
+ console.debug("getDictionaryElements response received: ", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ console.error("getDictionaryElements query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("getDictionaryElements error received", error);
+ return {};
+ });
+ }
+
+ static insDictionary(jsonData) {
+ console.log("dictionaryName is", jsonData.name)
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/', {
+ method: 'PUT',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(jsonData)
+ })
+ .then(function (response) {
+ console.debug("insDictionary response received: ", response.status);
+ if (response.ok) {
+ return response.status;
+ } else {
+ var errorMessage = response.status;
+ console.error("insDictionary query failed", response.status);
+ return errorMessage;
+ }
+ })
+ .catch(function (error) {
+ console.error("insDictionary error received", error);
+ return "";
+ });
+ }
+
+ static insDictionaryElements(jsonData) {
+ console.log("dictionaryName is", jsonData.name)
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/' + jsonData.name, {
+ method: 'PUT',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(jsonData)
+ })
+ .then(function (response) {
+ console.debug("insDictionary response received: ", response.status);
+ if (response.ok) {
+ return response.status;
+ } else {
+ var errorMessage = response.status;
+ console.error("insDictionary query failed", response.status);
+ return errorMessage;
+ }
+ })
+ .catch(function (error) {
+ console.error("insDictionary error received", error);
+ return "";
+ });
+ }
+
+ static deleteDictionary(dictionaryName) {
+ console.log("inside templaemenu service", dictionaryName)
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/' + dictionaryName, {
+ method: 'DELETE',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ credentials: 'same-origin',
+ })
+ .then(function (response) {
+ console.debug("deleteDictionary response received: ", response.status);
+ if (response.ok) {
+ return response.status;
+ } else {
+ console.error("deleteDictionary query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("deleteDictionary error received", error);
+ return {};
+ });
+ }
+
+ static deleteDictionaryElements(dictionaryData) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/dictionary/' + dictionaryData.name + '/elements/' + dictionaryData.shortName , {
+ method: 'DELETE',
+ headers: {
+ "Content-Type": "application/json",
+ },
+ credentials: 'same-origin',
+ })
+ .then(function (response) {
+ console.debug("deleteDictionary response received: ", response.status);
+ if (response.ok) {
+ return response.status;
+ } else {
+ console.error("deleteDictionary query failed");
+ return {};
+ }
+ })
+ .catch(function (error) {
+ console.error("deleteDictionary error received", error);
+ return {};
+ });
+ }
+ }
diff --git a/runtime/ui-react/src/api/UserService.js b/runtime/ui-react/src/api/UserService.js
new file mode 100644
index 000000000..5fb4aa6b4
--- /dev/null
+++ b/runtime/ui-react/src/api/UserService.js
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class UserService {
+ static notLoggedUserName='Anonymous';
+ static login() {
+ return fetch(window.location.pathname + 'restservices/clds/v1/user/getUser', {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("getUser response received, status code:", response.status);
+ if (response.ok) {
+ return response.text();
+ } else {
+ console.error("getUser response is nok");
+ return UserService.notLoggedUserName;
+ }
+ })
+ .then(function (data) {
+ console.info ("User connected:",data)
+ return data;
+ })
+ .catch(function(error) {
+ console.warn("getUser error received, user set to: ",UserService.notLoggedUserName);
+ console.error("getUser error:",error);
+ return UserService.notLoggedUserName;
+ });
+ }
+
+ static getUserInfo() {
+ return fetch(window.location.pathname + 'restservices/clds/v2/clampInformation', {
+ method: 'GET',
+ credentials: 'same-origin'
+ })
+ .then(function (response) {
+ console.debug("getUserInfo response received, status code:", response.status);
+ if (response.ok) {
+ return response.json();
+ } else {
+ return {}
+ }
+ })
+ .then(function (data) {
+ console.info ("User info received:",data)
+ return data;
+ })
+ .catch(function(error) {
+ console.warn("getUserInfo error received, user set to: ",UserService.notLoggedUserName);
+ console.error("getUserInfo error:",error);
+ return {};
+ });
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.js b/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.js
new file mode 100644
index 000000000..5663360a0
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.js
@@ -0,0 +1,190 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Select from 'react-select';
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import styled from 'styled-components';
+import LoopService from '../../../api/LoopService';
+import TemplateService from '../../../api/TemplateService';
+import LoopCache from '../../../api/LoopCache';
+import SvgGenerator from '../../loop_viewer/svg/SvgGenerator';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+const ErrMsgStyled = styled.div`
+ color: red;
+`
+
+export default class CreateLoopModal extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.getAllLoopTemplates = this.getAllLoopTemplates.bind(this);
+ this.handleCreate = this.handleCreate.bind(this);
+ this.handleModelName = this.handleModelName.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleDropDownListChange = this.handleDropDownListChange.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ this.state = {
+ show: true,
+ chosenTemplateName: '',
+ modelInputErrMsg: '',
+ modelName: '',
+ templateNames: [],
+ fakeLoopCacheWithTemplate: new LoopCache({})
+ };
+ }
+
+ async componentDidMount() {
+ await this.getAllLoopTemplates();
+ await this.getModelNames();
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ handleDropDownListChange(e) {
+ if (typeof e.value !== "undefined") {
+ this.setState({
+ fakeLoopCacheWithTemplate:
+ new LoopCache({
+ "loopTemplate":e.templateObject,
+ "name": "fakeLoop"
+ }),
+ chosenTemplateName: e.value
+ })
+ } else {
+ this.setState({ fakeLoopCacheWithTemplate: new LoopCache({}) })
+ }
+ }
+
+ getAllLoopTemplates() {
+ TemplateService.getAllLoopTemplates().then(templatesData => {
+ const templateOptions = templatesData.map((templateData) => { return { label: templateData.name, value: templateData.name, templateObject: templateData } });
+ this.setState({
+ templateNames: templateOptions })
+ });
+ }
+
+ getModelNames() {
+ TemplateService.getLoopNames().then(loopNames => {
+ if (!loopNames) {
+ loopNames = [];
+ }
+ // Remove LOOP_ prefix
+ let trimmedLoopNames = loopNames.map(str => str.replace('LOOP_', ''));
+ this.setState({ modelNames: trimmedLoopNames });
+ });
+ }
+
+ handleCreate() {
+ if (!this.state.modelName) {
+ alert("A model name is required");
+ return;
+ }
+ console.debug("Create Model " + this.state.modelName + ", Template " + this.state.chosenTemplateName + " is chosen");
+ this.setState({ show: false });
+ LoopService.createLoop("LOOP_" + this.state.modelName, this.state.chosenTemplateName).then(text => {
+ console.debug("CreateLoop response received: ", text);
+ try {
+ this.props.history.push('/');
+ this.props.loadLoopFunction("LOOP_" + this.state.modelName);
+ } catch(err) {
+ alert(text);
+ this.props.history.push('/');
+ }
+ })
+ .catch(error => {
+ console.debug("Create Loop failed");
+ });
+ }
+
+ handleModelName(event) {
+ if (this.state.modelNames.includes(event.target.value)) {
+ this.setState({
+ modelInputErrMsg: 'A model named "' + event.target.value + '" already exists. Please pick another name.',
+ modelName: event.target.value
+ });
+ return;
+ } else {
+ this.setState({
+ modelInputErrMsg: '',
+ modelName: event.target.value
+ });
+ }
+ }
+
+ renderSvg() {
+ return (
+ <SvgGenerator loopCache={this.state.fakeLoopCacheWithTemplate} clickable={false} generatedFrom={SvgGenerator.GENERATED_FROM_TEMPLATE}/>
+ );
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Create Model</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Form.Label column sm="2">Template Name:</Form.Label>
+ <Col sm="10">
+ <Select onChange={this.handleDropDownListChange} options={this.state.templateNames} />
+ </Col>
+ </Form.Group>
+ <Form.Group as={Row} style={{alignItems: 'center'}} controlId="formSvgPreview">
+ <Form.Label column sm="2">Model Preview:</Form.Label>
+ <Col sm="10">
+ {this.renderSvg()}
+ </Col>
+ </Form.Group>
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Form.Label column sm="2">Model Name:</Form.Label>
+ <input sm="5" type="text" style={{width: '50%', marginLeft: '1em' }}
+ value={this.state.modelName}
+ onChange={this.handleModelName}
+ />
+ <span sm="5"/>
+ </Form.Group>
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Form.Label column sm="2"> </Form.Label>
+ <ErrMsgStyled>{this.state.modelInputErrMsg}</ErrMsgStyled>
+ </Form.Group>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" type="submit" onClick={this.handleCreate}>Create</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js b/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js
new file mode 100644
index 000000000..8ef53b412
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js
@@ -0,0 +1,143 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import CreateLoopModal from './CreateLoopModal';
+import LoopService from '../../../api/LoopService';
+import TemplateService from '../../../api/TemplateService';
+
+let errorMessage = '';
+window.alert = jest.fn().mockImplementation((mesg) => { errorMessage = mesg ; return });
+
+
+describe('Verify CreateLoopModal', () => {
+
+ it('Test the render method', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ TemplateService.getAllLoopTemplates = jest.fn().mockImplementation(() => {
+ return Promise.resolve([{"name":"template1"},{"name":"template2"}]);
+ });
+ TemplateService.getLoopNames = jest.fn().mockImplementation(() => {
+ return Promise.resolve([]);
+ });
+
+ const component = shallow(<CreateLoopModal/>);
+ expect(component).toMatchSnapshot();
+ await flushPromises();
+ component.update();
+ expect(component.state('templateNames')).toStrictEqual([{"label": "template1", "value": "template1", "templateObject": {"name": "template1"}}, {"label": "template2", "value": "template2","templateObject": {"name": "template2"}}]);
+ });
+
+ it('handleDropdownListChange event', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+
+ const component = shallow(<CreateLoopModal/>);
+ component.find('StateManager').simulate('change', {value: 'template1', templateObject: {"name":"template1"} });
+ await flushPromises();
+ component.update();
+ expect(component.state('chosenTemplateName')).toEqual("template1");
+ expect(component.state('fakeLoopCacheWithTemplate').getLoopTemplate()['name']).toEqual("template1");
+ expect(component.state('fakeLoopCacheWithTemplate').getLoopName()).toEqual("fakeLoop");
+
+ component.find('StateManager').simulate('change',{value: 'template2', templateObject: {"name":"template2"} });
+ await flushPromises();
+ component.update();
+ expect(component.state('chosenTemplateName')).toEqual("template2");
+ expect(component.state('fakeLoopCacheWithTemplate').getLoopTemplate()['name']).toEqual("template2");
+ expect(component.state('fakeLoopCacheWithTemplate').getLoopName()).toEqual("fakeLoop");
+ });
+
+ it('handleModelName event', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ TemplateService.getAllLoopTemplates = jest.fn().mockImplementation(() => {
+ return Promise.resolve([{"name":"template1"},{"name":"template2"}]);
+ });
+ TemplateService.getLoopNames = jest.fn().mockImplementation(() => {
+ return Promise.resolve([]);
+ });
+ const event = {target: {value : "model1"} };
+ const component = shallow(<CreateLoopModal/>);
+ await flushPromises();
+ component.find('input').simulate('change', event);
+ component.update();
+ expect(component.state('modelName')).toEqual("model1");
+ });
+
+ it('Test handleClose', () => {
+ const historyMock = { push: jest.fn() };
+ const handleClose = jest.spyOn(CreateLoopModal.prototype,'handleClose');
+ const component = shallow(<CreateLoopModal history={historyMock} />)
+
+ component.find('[variant="secondary"]').prop('onClick')();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+
+ handleClose.mockClear();
+ });
+
+ it('Test handleCreate Fail', () => {
+ const handleCreate = jest.spyOn(CreateLoopModal.prototype,'handleCreate');
+ const component = shallow(<CreateLoopModal/>)
+
+ component.find('[variant="primary"]').prop('onClick')();
+
+ expect(handleCreate).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(true);
+
+ handleCreate.mockClear();
+ });
+
+ it('Test handleCreate Suc', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const loadLoopFunction = jest.fn();
+
+ LoopService.createLoop = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+
+ const handleCreate = jest.spyOn(CreateLoopModal.prototype,'handleCreate');
+ const component = shallow(<CreateLoopModal history={historyMock} loadLoopFunction={loadLoopFunction}/>)
+ component.setState({
+ modelName: "modelNameTest",
+ chosenTemplateName: "template1"
+ });
+
+ component.find('[variant="primary"]').prop('onClick')();
+ await flushPromises();
+ component.update();
+
+ expect(handleCreate).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+
+ handleCreate.mockClear();
+ });
+
+});
diff --git a/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.js b/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.js
new file mode 100644
index 000000000..803cfa9cb
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.js
@@ -0,0 +1,173 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../../api/LoopActionService';
+import LoopService from '../../../api/LoopService';
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Tabs from 'react-bootstrap/Tabs';
+import Tab from 'react-bootstrap/Tab';
+import styled from 'styled-components';
+import Spinner from 'react-bootstrap/Spinner'
+
+const StyledSpinnerDiv = styled.div`
+ justify-content: center !important;
+ display: flex !important;
+`;
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+const FormStyled = styled(Form.Group)`
+ padding: .25rem 1.5rem;
+`
+export default class DeployLoopModal extends React.Component {
+
+
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.handleSave = this.handleSave.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.refreshStatus = this.refreshStatus.bind(this);
+ this.renderDeployParam = this.renderDeployParam.bind(this);
+ this.renderSpinner = this.renderSpinner.bind(this);
+
+ const propertiesJson = JSON.parse(JSON.stringify(this.props.loopCache.getGlobalProperties()));
+ this.state = {
+ loopCache: this.props.loopCache,
+ temporaryPropertiesJson: propertiesJson,
+ show: true,
+ key: this.getInitialKeyValue(propertiesJson)
+ };
+ }
+ getInitialKeyValue(temporaryPropertiesJson) {
+ const deployJsonList = temporaryPropertiesJson["dcaeDeployParameters"];
+ return Object.keys(deployJsonList).find((obj) => Object.keys(deployJsonList).indexOf(obj) === 0);
+ }
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName(),
+ show: true
+ });
+ }
+
+ handleClose(){
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ renderSpinner() {
+ if (this.state.deploying) {
+ return (
+ <StyledSpinnerDiv>
+ <Spinner animation="border" role="status">
+ <span className="sr-only">Loading...</span>
+ </Spinner>
+ </StyledSpinnerDiv>
+ );
+ } else {
+ return (<div></div>);
+ }
+ }
+
+ handleSave() {
+ const loopName = this.props.loopCache.getLoopName();
+ // save the global propserties
+ this.setState({ deploying: true });
+ LoopService.updateGlobalProperties(loopName, this.state.temporaryPropertiesJson).then(resp => {
+ LoopActionService.performAction(loopName, "deploy").then(pars => {
+ this.props.showSucAlert("Action deploy successfully performed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ })
+ .catch(error => {
+ this.props.showFailAlert("Action deploy failed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ });
+ });
+ }
+
+ refreshStatus(loopName) {
+ LoopActionService.refreshStatus(loopName).then(data => {
+ this.props.updateLoopFunction(data);
+ this.setState({ show: false, deploying: false });
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ this.props.showFailAlert("Refresh status failed");
+ this.setState({ show: false, deploying: false });
+ this.props.history.push('/');
+ });
+ }
+ handleChange(event) {
+ let deploymentParam = this.state.temporaryPropertiesJson["dcaeDeployParameters"];
+ deploymentParam[this.state.key][event.target.name] = event.target.value;
+
+ this.setState({temporaryPropertiesJson:{dcaeDeployParameters: deploymentParam}});
+ }
+ renderDeployParamTabs() {
+ if (typeof (this.state.temporaryPropertiesJson) === "undefined") {
+ return "";
+ }
+
+ const deployJsonList = this.state.temporaryPropertiesJson["dcaeDeployParameters"];
+ var indents = [];
+ Object.keys(deployJsonList).forEach(item =>
+ indents.push(<Tab key={item} eventKey={item} title={item}>
+ {this.renderDeployParam(deployJsonList[item])}
+ </Tab>)
+ );
+ return indents;
+ }
+ renderDeployParam(deployJson) {
+ var indents = [];
+ Object.keys(deployJson).forEach(item =>
+ indents.push(<FormStyled key={item}>
+ <Form.Label>{item}</Form.Label>
+ <Form.Control type="text" name={item} onChange={this.handleChange} defaultValue={deployJson[item]}></Form.Control>
+ </FormStyled>));
+ return indents;
+ }
+ render() {
+ return (
+ <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Deployment parameters</Modal.Title>
+ </Modal.Header>
+ <Tabs id="controlled-tab-example" activeKey={this.state.key} onSelect={key => this.setState({ key })}>
+ {this.renderDeployParamTabs()}
+ </Tabs>
+ {this.renderSpinner()}
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" type="submit" onClick={this.handleSave}>Deploy</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.test.js b/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.test.js
new file mode 100644
index 000000000..84dbfd1f6
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/DeployLoopModal.test.js
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import DeployLoopModal from './DeployLoopModal';
+import LoopCache from '../../../api/LoopCache';
+import LoopActionService from '../../../api/LoopActionService';
+import LoopService from '../../../api/LoopService';
+
+describe('Verify DeployLoopModal', () => {
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "globalPropertiesJson": {
+ "dcaeDeployParameters": {
+ "testMs": {
+ "location_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ }
+ }
+ });
+
+ it('Test the render method', () => {
+ const component = shallow(
+ <DeployLoopModal loopCache={loopCache}/>
+ )
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Test handleClose', () => {
+ const historyMock = { push: jest.fn() };
+ const handleClose = jest.spyOn(DeployLoopModal.prototype,'handleClose');
+ const component = shallow(<DeployLoopModal history={historyMock} loopCache={loopCache}/>)
+
+ component.find('[variant="secondary"]').prop('onClick')();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test handleSave successful', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const updateLoopFunction = jest.fn();
+ const showSucAlert = jest.fn();
+ const showFailAlert = jest.fn();
+ const handleSave = jest.spyOn(DeployLoopModal.prototype,'handleSave');
+ LoopService.updateGlobalProperties = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ text: () => "OK"
+ });
+ });
+ LoopActionService.performAction = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+
+ const component = shallow(<DeployLoopModal history={historyMock}
+ loopCache={loopCache} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} />)
+
+ component.find('[variant="primary"]').prop('onClick')();
+ await flushPromises();
+ component.update();
+
+ expect(handleSave).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ handleSave.mockClear();
+ });
+
+ it('Onchange event', () => {
+ const event = { target: { name: "location_id", value: "testLocation"} };
+ const component = shallow(<DeployLoopModal loopCache={loopCache}/>);
+
+ component.find('[name="location_id"]').simulate('change', event);
+ component.update();
+ expect(component.state('temporaryPropertiesJson').dcaeDeployParameters.testMs.location_id).toEqual("testLocation");
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.js b/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.js
new file mode 100644
index 000000000..acd0acade
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.js
@@ -0,0 +1,118 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import styled from 'styled-components';
+import LoopService from '../../../api/LoopService';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+export default class LoopPropertiesModal extends React.Component {
+
+ state = {
+ show: true,
+ loopCache: this.props.loopCache,
+ temporaryPropertiesJson: JSON.parse(JSON.stringify(this.props.loopCache.getGlobalProperties()))
+ };
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.handleClose = this.handleClose.bind(this);
+ this.handleSave = this.handleSave.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+
+ this.renderDcaeParameters = this.renderDcaeParameters.bind(this);
+ this.renderAllParameters = this.renderAllParameters.bind(this);
+ this.getDcaeParameters = this.getDcaeParameters.bind(this);
+ this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
+ }
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopCache: newProps.loopCache,
+ temporaryPropertiesJson: JSON.parse(JSON.stringify(newProps.loopCache.getGlobalProperties()))
+ });
+ }
+
+ handleClose() {
+ this.props.history.push('/');
+ }
+
+ handleSave(event) {
+ LoopService.updateGlobalProperties(this.state.loopCache.getLoopName(), this.state.temporaryPropertiesJson).then(resp => {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ });
+ }
+
+ handleChange(event) {
+ this.setState({temporaryPropertiesJson:{[event.target.name]: JSON.parse(event.target.value)}});
+ }
+
+ renderAllParameters() {
+ return (<Modal.Body>
+ <Form>
+ {this.renderDcaeParameters()}
+ </Form>
+ </Modal.Body>
+ );
+ }
+
+ getDcaeParameters() {
+ if (typeof (this.state.temporaryPropertiesJson) !== "undefined") {
+ return JSON.stringify(this.state.temporaryPropertiesJson["dcaeDeployParameters"]);
+ } else {
+ return "";
+ }
+
+ }
+
+ renderDcaeParameters() {
+ return (
+ <Form.Group >
+ <Form.Label>Deploy Parameters</Form.Label>
+ <Form.Control as="textarea" rows="3" name="dcaeDeployParameters" onChange={this.handleChange} defaultValue={this.getDcaeParameters()}></Form.Control>
+ </Form.Group>
+ );
+ }
+
+ render() {
+ return (
+ <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Model Properties</Modal.Title>
+ </Modal.Header>
+ {this.renderAllParameters()}
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" type="submit" disabled={this.readOnly} onClick={this.handleSave}>Save Changes</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.test.js b/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.test.js
new file mode 100644
index 000000000..5bbefe228
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/LoopPropertiesModal.test.js
@@ -0,0 +1,108 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import LoopPropertiesModal from './LoopPropertiesModal';
+import LoopCache from '../../../api/LoopCache';
+import LoopService from '../../../api/LoopService';
+
+describe('Verify LoopPropertiesModal', () => {
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "globalPropertiesJson": {
+ "dcaeDeployParameters": {
+ "location_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ }
+ });
+
+ it('Test the render method', () => {
+ const component = shallow(
+ <LoopPropertiesModal loopCache={loopCache}/>
+ )
+ component.setState({ show: true,
+ temporaryPropertiesJson: {
+ "dcaeDeployParameters": {
+ "location_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ }
+ });
+
+ expect(component.state('temporaryPropertiesJson')).toEqual({
+ "dcaeDeployParameters": {
+ "location_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"}
+ });
+ expect(component.state('show')).toEqual(true);
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Test handleClose', () => {
+ const historyMock = { push: jest.fn() };
+ const handleClose = jest.spyOn(LoopPropertiesModal.prototype,'handleClose');
+ const component = shallow(<LoopPropertiesModal history={historyMock} loopCache={loopCache}/>)
+
+ component.find('[variant="secondary"]').prop('onClick')();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test handleSave successful', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const loadLoopFunction = jest.fn();
+ const handleSave = jest.spyOn(LoopPropertiesModal.prototype,'handleSave');
+ LoopService.updateGlobalProperties = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ text: () => "OK"
+ });
+ });
+
+ const component = shallow(<LoopPropertiesModal history={historyMock}
+ loopCache={loopCache} loadLoopFunction={loadLoopFunction} />)
+
+ component.find('[variant="primary"]').prop('onClick')();
+ await flushPromises();
+ component.update();
+
+ expect(handleSave).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Onchange event', () => {
+ const event = {target:{name:"dcaeDeployParameters", value:"{\"location_id\": \"testLocation\",\"policy_id\": \"TCA_h2NMX_v1_0_ResourceInstanceName1_tca\"}"}};
+ const component = shallow(<LoopPropertiesModal loopCache={loopCache}/>);
+
+ component.find('FormControl').simulate('change', event);
+ component.update();
+
+ expect(component.state('temporaryPropertiesJson').dcaeDeployParameters.location_id).toEqual("testLocation");
+ });
+});
diff --git a/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js b/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js
new file mode 100644
index 000000000..f6c0d2ede
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js
@@ -0,0 +1,247 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react'
+import MaterialTable from "material-table";
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+import ArrowUpward from '@material-ui/icons/ArrowUpward';
+import ChevronLeft from '@material-ui/icons/ChevronLeft';
+import ChevronRight from '@material-ui/icons/ChevronRight';
+import Clear from '@material-ui/icons/Clear';
+import FirstPage from '@material-ui/icons/FirstPage';
+import LastPage from '@material-ui/icons/LastPage';
+import Search from '@material-ui/icons/Search';
+import LoopService from '../../../api/LoopService';
+import Tabs from 'react-bootstrap/Tabs';
+import Tab from 'react-bootstrap/Tab';
+import Alert from 'react-bootstrap/Alert';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+const TextModal = styled.textarea`
+ margin-top: 20px;
+ white-space:pre;
+ background-color: ${props => props.theme.toscaTextareaBackgroundColor};
+ text-align: justify;
+ font-size: ${props => props.theme.toscaTextareaFontSize};
+ width: 100%;
+ height: 300px;
+`
+const cellStyle = { border: '1px solid black' };
+const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
+const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
+export default class ModifyLoopModal extends React.Component {
+
+ state = {
+ show: true,
+ loopCache: this.props.loopCache,
+ content: 'Please select Tosca model to view the details',
+ selectedRowData: {},
+ toscaPolicyModelsData: [],
+ selectedPolicyModelsData: [],
+ key: 'add',
+ showFailAlert: false,
+ toscaColumns: [
+ { title: "#", field: "index", render: rowData => rowData.tableData.id + 1,
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Policy Model Type", field: "policyModelType",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Policy Acronym", field: "policyAcronym",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Policy Name", field: "policyName",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Version", field: "version",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Uploaded By", field: "updatedBy",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Uploaded Date", field: "updatedDate", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Created Date", field: "createdDate", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ }
+ ],
+ tableIcons: {
+ FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
+ LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
+ NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
+ ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
+ SortArrow: forwardRef((props, ref) => <ArrowUpward {...props} ref={ref} />)
+ }
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.initializeToscaPolicyModelsInfo = this.initializeToscaPolicyModelsInfo.bind(this);
+ this.handleYamlContent = this.handleYamlContent.bind(this);
+ this.getToscaPolicyModelYaml = this.getToscaPolicyModelYaml.bind(this);
+ this.handleAdd = this.handleAdd.bind(this);
+ this.handleRemove = this.handleRemove.bind(this);
+ this.initializeToscaPolicyModelsInfo();
+ }
+
+ initializeToscaPolicyModelsInfo() {
+ var operationalPolicies = this.state.loopCache.getOperationalPolicies();
+ var selectedPolicyModels = [];
+ for (var policy in operationalPolicies) {
+ var newRow = operationalPolicies[policy]["policyModel"];
+ newRow["policyName"] = operationalPolicies[policy].name;
+ selectedPolicyModels.push(newRow);
+ }
+
+ PolicyToscaService.getToscaPolicyModels().then(allToscaModels => {
+ this.setState({ toscaPolicyModelsData: allToscaModels,
+ selectedPolicyModelsData: selectedPolicyModels});
+ });
+ }
+
+ getToscaPolicyModelYaml(policyModelType, policyModelVersion) {
+ if (typeof policyModelType !== "undefined") {
+ PolicyToscaService.getToscaPolicyModelYaml(policyModelType, policyModelVersion).then(toscaYaml => {
+ if (toscaYaml.length !== 0) {
+ this.setState({content: toscaYaml})
+ } else {
+ this.setState({ content: 'No Tosca model Yaml available' })
+ }
+ });
+ } else {
+ this.setState({ content: 'Please select Tosca model to view the details' })
+ }
+ }
+
+ handleYamlContent(event) {
+ this.setState({ content: event.target.value });
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ renderAlert() {
+ return (
+ <div>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ {this.state.showMessage}
+ </Alert>
+ </div>
+ );
+ }
+
+ handleAdd() {
+ LoopService.addOperationalPolicyType(this.state.loopCache.getLoopName(),this.state.selectedRowData.policyModelType,this.state.selectedRowData.version)
+ .then(pars => {
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ this.handleClose();
+ })
+ .catch(error => {
+ this.setState({ showFailAlert: true, showMessage: "Adding failed with error: " + error.message});
+ });
+ }
+
+ handleRemove() {
+ LoopService.removeOperationalPolicyType(this.state.loopCache.getLoopName(),this.state.selectedRowData.policyModelType,this.state.selectedRowData.version,this.state.selectedRowData.policyName);
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ this.handleClose();
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Modify Loop Operational Policies</Modal.Title>
+ </Modal.Header>
+ <Tabs id="controlled-tab-example" activeKey={this.state.key} onSelect={key => this.setState({ key, selectedRowData: {} })}>
+ <Tab eventKey="add" title="Add Operational Policies">
+ <Modal.Body>
+ <MaterialTable
+ title={"View Tosca Policy Models"}
+ data={this.state.toscaPolicyModelsData}
+ columns={this.state.toscaColumns}
+ icons={this.state.tableIcons}
+ onRowClick={(event, rowData) => {this.getToscaPolicyModelYaml(rowData.policyModelType, rowData.version);this.setState({selectedRowData: rowData})}}
+ options={{
+ headerStyle: rowHeaderStyle,
+ rowStyle: rowData => ({
+ backgroundColor: (this.state.selectedRowData !== {} && this.state.selectedRowData.tableData !== undefined
+ && this.state.selectedRowData.tableData.id === rowData.tableData.id) ? '#EEE' : '#FFF'
+ })
+ }}
+ />
+ <div>
+ <TextModal value={this.state.content} onChange={this.handleYamlContent}/>
+ </div>
+ </Modal.Body>
+ {this.renderAlert()}
+ </Tab>
+ <Tab eventKey="remove" title="Remove Operational Policies">
+ <Modal.Body>
+ <MaterialTable
+ title={"Tosca Policy Models already added"}
+ data={this.state.selectedPolicyModelsData}
+ columns={this.state.toscaColumns}
+ icons={this.state.tableIcons}
+ onRowClick={(event, rowData) => {this.setState({selectedRowData: rowData})}}
+ options={{
+ headerStyle: rowHeaderStyle,
+ rowStyle: rowData => ({
+ backgroundColor: (this.state.selectedRowData !== {} && this.state.selectedRowData.tableData !== undefined
+ && this.state.selectedRowData.tableData.id === rowData.tableData.id) ? '#EEE' : '#FFF'
+ })
+ }}
+ />
+ </Modal.Body>
+ </Tab>
+ </Tabs>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" disabled={(this.state.key === "remove")} type="submit" onClick={this.handleAdd}>Add</Button>
+ <Button variant="primary" disabled={(this.state.key === "add")} type="submit" onClick={this.handleRemove}>Remove</Button>
+ </Modal.Footer>
+
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.test.js b/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.test.js
new file mode 100644
index 000000000..055ad0e68
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/ModifyLoopModal.test.js
@@ -0,0 +1,109 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { mount } from 'enzyme';
+import ModifyLoopModal from './ModifyLoopModal';
+import LoopCache from '../../../api/LoopCache';
+import LoopService from '../../../api/LoopService';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+
+describe('Verify ModifyLoopModal', () => {
+ beforeEach(() => {
+ PolicyToscaService.getToscaPolicyModels = jest.fn().mockImplementation(() => {
+ return Promise.resolve([{
+ "policyModelType":"test",
+ "policyAcronym":"test",
+ "version":"1.0.0",
+ "updatedBy":"",
+ "updatedDate":""
+ }]);
+ });
+ PolicyToscaService.getToscaPolicyModelYaml = jest.fn().mockImplementation(() => {
+ return Promise.resolve("OK");
+ });
+ })
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "microServicePolicies": [{
+ "name": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "modelType": "onap.policies.monitoring.cdap.tca.hi.lo.app",
+ "properties": {"domain": "measurementsForVfScaling"},
+ "shared": false,
+ "jsonRepresentation": {"schema": {}}
+ }],
+ "globalPropertiesJson": {
+ "dcaeDeployParameters": {
+ "testMs": {
+ "location_id": "",
+ "policy_id": "TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ }
+ }
+ }
+ });
+ const historyMock = { push: jest.fn() };
+ const flushPromises = () => new Promise(setImmediate);
+
+ it('Test handleClose', () => {
+ const handleClose = jest.spyOn(ModifyLoopModal.prototype,'handleClose');
+ const component = mount(<ModifyLoopModal history={historyMock} loopCache={loopCache}/>)
+
+ component.find('[variant="secondary"]').get(0).props.onClick();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test getToscaPolicyModelYaml', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const component = mount(<ModifyLoopModal history={historyMock} loopCache={loopCache}/>)
+ component.setState({
+ "selectedRowData": {"tableData":{"id":0}}
+ });
+ const instance = component.instance();
+
+ instance.getToscaPolicyModelYaml("","1.0.0");
+ expect(component.state('content')).toEqual("Please select Tosca model to view the details");
+
+ instance.getToscaPolicyModelYaml("test","1.0.0");
+ await flushPromises();
+ expect(component.state('content')).toEqual("OK");
+
+ PolicyToscaService.getToscaPolicyModelYaml = jest.fn().mockImplementation(() => {
+ return Promise.resolve("");
+ });
+ instance.getToscaPolicyModelYaml("test","1.0.0");
+ await flushPromises();
+ expect(component.state('content')).toEqual("No Tosca model Yaml available");
+ });
+
+ it('Test handleYamlContent', async () => {
+ const component = mount(<ModifyLoopModal loopCache={loopCache}/>)
+ const instance = component.instance();
+
+ const event = {"target":{"value":"testValue"}}
+ instance.handleYamlContent(event);
+ expect(component.state('content')).toEqual("testValue");
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.js b/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.js
new file mode 100644
index 000000000..b45df6502
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.js
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Select from 'react-select';
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import FormCheck from 'react-bootstrap/FormCheck'
+import styled from 'styled-components';
+import LoopService from '../../../api/LoopService';
+import SvgGenerator from '../../loop_viewer/svg/SvgGenerator';
+import LoopCache from '../../../api/LoopCache';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+const CheckBoxStyled = styled(FormCheck.Input)`
+ margin-left:3rem;
+`
+
+export default class OpenLoopModal extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+
+ this.getLoopNames = this.getLoopNames.bind(this);
+ this.handleOpen = this.handleOpen.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleDropDownListChange = this.handleDropDownListChange.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ this.showReadOnly = props.showReadOnly !== undefined ? props.showReadOnly : true;
+ this.state = {
+ show: true,
+ chosenLoopName: '',
+ loopNames: [],
+ loopCacheOpened: new LoopCache({})
+ };
+ }
+
+ componentWillMount() {
+ this.getLoopNames();
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ handleDropDownListChange(e) {
+ LoopService.getLoop(e.value).then(loop => {
+ this.setState({
+ chosenLoopName: e.value,
+ loopCacheOpened: new LoopCache(loop)
+ });
+ });
+ }
+
+ getLoopNames() {
+ LoopService.getLoopNames().then(loopNames => {
+ if (Object.entries(loopNames).length !== 0) {
+ const loopOptions = loopNames.filter(loopName => loopName!=='undefined').map((loopName) => { return { label: loopName, value: loopName } });
+ this.setState({ loopNames: loopOptions })
+ }
+ });
+ }
+
+ handleOpen() {
+ console.info("Loop " + this.state.chosenLoopName + " is chosen");
+ this.handleClose();
+ this.props.loadLoopFunction(this.state.chosenLoopName);
+ }
+
+ renderSvg() {
+ return(
+ <SvgGenerator loopCache={this.state.loopCacheOpened} clickable={false} generatedFrom={SvgGenerator.GENERATED_FROM_INSTANCE}/>
+ );
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Open Model</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Form.Label column sm="2">Model Name:</Form.Label>
+ <Col sm="10">
+ <Select onChange={this.handleDropDownListChange}
+ options={this.state.loopNames} />
+ </Col>
+ </Form.Group>
+ <Form.Group as={Row} style={{alignItems: 'center'}} controlId="formSvgPreview">
+ <Form.Label column sm="2">Model Preview:</Form.Label>
+ <Col sm="10">
+ {this.renderSvg()}
+ </Col>
+ </Form.Group>
+ {this.showReadOnly === true ?
+ <Form.Group as={Row} controlId="formBasicCheckbox">
+ <Form.Check>
+ <FormCheck.Label>Read Only Mode:</FormCheck.Label>
+ <CheckBoxStyled style={{marginLeft: '3.5em'}} type="checkbox" />
+ </Form.Check>
+ </Form.Group>
+ : null}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ <Button variant="primary" type="submit" onClick={this.handleOpen}>Open</Button>
+ </Modal.Footer>
+ </ModalStyled>
+
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.test.js b/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.test.js
new file mode 100644
index 000000000..1865869df
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/OpenLoopModal.test.js
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import OpenLoopModal from './OpenLoopModal';
+import LoopService from '../../../api/LoopService';
+
+describe('Verify OpenLoopModal', () => {
+
+ beforeEach(() => {
+ fetch.resetMocks();
+ fetch.mockResponse(JSON.stringify([
+ "LOOP_gmtAS_v1_0_ResourceInstanceName1_tca",
+ "LOOP_gmtAS_v1_0_ResourceInstanceName1_tca_3",
+ "LOOP_gmtAS_v1_0_ResourceInstanceName2_tca_2"
+ ]));
+ });
+
+ it('Test the render method', () => {
+
+ const component = shallow(<OpenLoopModal/>);
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Onchange event', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ LoopService.getLoop = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+ const event = {value: 'LOOP_gmtAS_v1_0_ResourceInstanceName1_tca_3'};
+ const component = shallow(<OpenLoopModal/>);
+ component.find('StateManager').simulate('change', event);
+ await flushPromises();
+ component.update();
+ expect(component.state('chosenLoopName')).toEqual("LOOP_gmtAS_v1_0_ResourceInstanceName1_tca_3");
+ });
+
+
+ it('Test handleClose', () => {
+ const historyMock = { push: jest.fn() };
+ const handleClose = jest.spyOn(OpenLoopModal.prototype,'handleClose');
+ const component = shallow(<OpenLoopModal history={historyMock} />)
+
+ component.find('[variant="secondary"]').prop('onClick')();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+
+ handleClose.mockClear();
+ });
+
+ it('Test handleSubmit', () => {
+ const historyMock = { push: jest.fn() };
+ const loadLoopFunction = jest.fn();
+ const handleOpen = jest.spyOn(OpenLoopModal.prototype,'handleOpen');
+ const component = shallow(<OpenLoopModal history={historyMock} loadLoopFunction={loadLoopFunction}/>)
+
+ component.find('[variant="primary"]').prop('onClick')();
+
+ expect(handleOpen).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+
+ handleOpen.mockClear();
+ });
+
+});
diff --git a/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/CreateLoopModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/CreateLoopModal.test.js.snap
new file mode 100644
index 000000000..1ba9dbaf1
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/CreateLoopModal.test.js.snap
@@ -0,0 +1,167 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify CreateLoopModal Test the render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="xl"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Create Model
+ </ModalTitle>
+ </ModalHeader>
+ <ModalBody>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formPlaintextEmail"
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Template Name:
+ </FormLabel>
+ <Col
+ sm="10"
+ >
+ <StateManager
+ defaultInputValue=""
+ defaultMenuIsOpen={false}
+ defaultValue={null}
+ onChange={[Function]}
+ options={Array []}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formSvgPreview"
+ style={
+ Object {
+ "alignItems": "center",
+ }
+ }
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Model Preview:
+ </FormLabel>
+ <Col
+ sm="10"
+ >
+ <withRouter(SvgGenerator)
+ clickable={false}
+ generatedFrom="TEMPLATE"
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formPlaintextEmail"
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Model Name:
+ </FormLabel>
+ <input
+ onChange={[Function]}
+ sm="5"
+ style={
+ Object {
+ "marginLeft": "1em",
+ "width": "50%",
+ }
+ }
+ type="text"
+ value=""
+ />
+ <span
+ sm="5"
+ />
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formPlaintextEmail"
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+
+ </FormLabel>
+ <styled.div />
+ </FormGroup>
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Cancel
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="submit"
+ variant="primary"
+ >
+ Create
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap
new file mode 100644
index 000000000..33f8faa77
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap
@@ -0,0 +1,88 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify DeployLoopModal Test the render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="lg"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Deployment parameters
+ </ModalTitle>
+ </ModalHeader>
+ <Tabs
+ activeKey="testMs"
+ id="controlled-tab-example"
+ mountOnEnter={false}
+ onSelect={[Function]}
+ unmountOnExit={false}
+ variant="tabs"
+ >
+ <Tab
+ eventKey="testMs"
+ key="testMs"
+ title="testMs"
+ >
+ <Styled(FormGroup)
+ key="location_id"
+ >
+ <FormLabel
+ column={false}
+ srOnly={false}
+ >
+ location_id
+ </FormLabel>
+ <FormControl
+ defaultValue=""
+ name="location_id"
+ onChange={[Function]}
+ type="text"
+ />
+ </Styled(FormGroup)>
+ <Styled(FormGroup)
+ key="policy_id"
+ >
+ <FormLabel
+ column={false}
+ srOnly={false}
+ >
+ policy_id
+ </FormLabel>
+ <FormControl
+ defaultValue="TCA_h2NMX_v1_0_ResourceInstanceName1_tca"
+ name="policy_id"
+ onChange={[Function]}
+ type="text"
+ />
+ </Styled(FormGroup)>
+ </Tab>
+ </Tabs>
+ <div />
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Cancel
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="submit"
+ variant="primary"
+ >
+ Deploy
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/LoopPropertiesModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/LoopPropertiesModal.test.js.snap
new file mode 100644
index 000000000..3baaa5798
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/LoopPropertiesModal.test.js.snap
@@ -0,0 +1,61 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify LoopPropertiesModal Test the render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="lg"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Model Properties
+ </ModalTitle>
+ </ModalHeader>
+ <ModalBody>
+ <Form
+ inline={false}
+ >
+ <FormGroup>
+ <FormLabel
+ column={false}
+ srOnly={false}
+ >
+ Deploy Parameters
+ </FormLabel>
+ <FormControl
+ as="textarea"
+ defaultValue="{\\"location_id\\":\\"\\",\\"policy_id\\":\\"TCA_h2NMX_v1_0_ResourceInstanceName1_tca\\"}"
+ name="dcaeDeployParameters"
+ onChange={[Function]}
+ rows="3"
+ />
+ </FormGroup>
+ </Form>
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Cancel
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="submit"
+ variant="primary"
+ >
+ Save Changes
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/OpenLoopModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/OpenLoopModal.test.js.snap
new file mode 100644
index 000000000..581fd0ec0
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Loop/__snapshots__/OpenLoopModal.test.js.snap
@@ -0,0 +1,137 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify OpenLoopModal Test the render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="xl"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Open Model
+ </ModalTitle>
+ </ModalHeader>
+ <ModalBody>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formPlaintextEmail"
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Model Name:
+ </FormLabel>
+ <Col
+ sm="10"
+ >
+ <StateManager
+ defaultInputValue=""
+ defaultMenuIsOpen={false}
+ defaultValue={null}
+ onChange={[Function]}
+ options={Array []}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formSvgPreview"
+ style={
+ Object {
+ "alignItems": "center",
+ }
+ }
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Model Preview:
+ </FormLabel>
+ <Col
+ sm="10"
+ >
+ <withRouter(SvgGenerator)
+ clickable={false}
+ generatedFrom="INSTANCE"
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formBasicCheckbox"
+ >
+ <FormCheck>
+ <FormCheckLabel>
+ Read Only Mode:
+ </FormCheckLabel>
+ <Styled(FormCheckInput)
+ style={
+ Object {
+ "marginLeft": "3.5em",
+ }
+ }
+ type="checkbox"
+ />
+ </FormCheck>
+ </FormGroup>
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Cancel
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="submit"
+ variant="primary"
+ >
+ Open
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js b/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
new file mode 100644
index 000000000..90bbc887c
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
@@ -0,0 +1,631 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+
+import React, { forwardRef } from 'react';
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import styled from 'styled-components';
+import TemplateMenuService from '../../../api/TemplateService';
+import CsvToJson from '../../../utils/CsvToJson';
+import MaterialTable, {MTableToolbar} from "material-table";
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+import AddBox from '@material-ui/icons/AddBox';
+import ArrowUpward from '@material-ui/icons/ArrowUpward';
+import Check from '@material-ui/icons/Check';
+import ChevronLeft from '@material-ui/icons/ChevronLeft';
+import VerticalAlignTopIcon from '@material-ui/icons/VerticalAlignTop';
+import VerticalAlignBottomIcon from '@material-ui/icons/VerticalAlignBottom';
+import ChevronRight from '@material-ui/icons/ChevronRight';
+import Clear from '@material-ui/icons/Clear';
+import DeleteOutline from '@material-ui/icons/DeleteOutline';
+import Edit from '@material-ui/icons/Edit';
+import FilterList from '@material-ui/icons/FilterList';
+import FirstPage from '@material-ui/icons/FirstPage';
+import LastPage from '@material-ui/icons/LastPage';
+import Remove from '@material-ui/icons/Remove';
+import Search from '@material-ui/icons/Search';
+import ViewColumn from '@material-ui/icons/ViewColumn';
+
+
+const ModalStyled = styled(Modal)`
+ @media (min-width: 1200px) {
+ .modal-xl {
+ max-width: 96%;
+ }
+ }
+ background-color: transparent;
+`
+
+const MTableToolbarStyled = styled(MTableToolbar)`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+`
+const ColPullLeftStyled = styled(Col)`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ margin-left: -40px;
+`
+
+const cellStyle = { border: '1px solid black' };
+const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
+const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
+let dictList = [];
+let subDictFlag = false;
+
+function SelectSubDictType(props) {
+ const {onChange} = props;
+ const selectedValues = (e) => {
+ let options = e.target.options;
+ let SelectedDictTypes = '';
+ for (let dictType = 0, values = options.length; dictType < values; dictType++) {
+ if (options[dictType].selected) {
+ SelectedDictTypes = SelectedDictTypes.concat(options[dictType].value);
+ SelectedDictTypes = SelectedDictTypes.concat('|');
+ }
+ }
+ SelectedDictTypes = SelectedDictTypes.slice(0,-1);
+ onChange(SelectedDictTypes);
+ }
+ // When the subDictFlag is true, we need to disable selection of element "type"
+ return(
+ <div>
+ <select disabled={subDictFlag} multiple={true} onChange={selectedValues}>
+ <option value="string">string</option>
+ <option value="number">number</option>
+ <option value="datetime">datetime</option>
+ <option value="map">map</option>
+ <option value="json">json</option>
+ </select>
+ </div>
+ );
+}
+
+function SubDict(props) {
+ const {onChange} = props;
+ const subDicts = [];
+ subDicts.push('none');
+ if (dictList !== undefined && dictList.length > 0) {
+ let item;
+ for(item in dictList) {
+ if(dictList[item].secondLevelDictionary === 1) {
+ subDicts.push(dictList[item].name);
+ }
+ }
+ }
+ let optionItems = [];
+ for (let i=0; i<subDicts.length; ++i) {
+ if (i === 0) {
+ optionItems.push(<option selected key={subDicts[i]}>{subDicts[i]}</option>);
+ } else {
+ optionItems.push(<option key={subDicts[i]}>{subDicts[i]}</option>);
+ }
+ }
+
+ function selectedValue (e) {
+ onChange(e.target.value);
+ }
+ // When the subDictFlag is true, we need to disable selection of
+ // the sub-dictionary flag
+ return(
+ <select disabled={subDictFlag} onChange={selectedValue} >
+ {optionItems}
+ </select>
+ );
+}
+
+export default class ManageDictionaries extends React.Component {
+ constructor(props, context) {
+ super(props, context);
+ this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
+ this.addDictionaryRow = this.addDictionaryRow.bind(this);
+ this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
+ this.clickHandler = this.clickHandler.bind(this);
+ this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
+ this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
+ this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
+ this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
+ this.getDictionaries = this.getDictionaries.bind(this);
+ this.getDictionaryElements = this.getDictionaryElements.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleDictionaryRowClick = this.handleDictionaryRowClick.bind(this);
+ this.importCsvData = this.importCsvData.bind(this);
+ this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
+ this.updateDictionaryElementsRequest = this.updateDictionaryElementsRequest.bind(this);
+ this.updateDictionaryRow = this.updateDictionaryRow.bind(this);
+ this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
+ this.state = {
+ show: true,
+ currentSelectedDictionary: null,
+ exportFilename: '',
+ content: null,
+ dictionaryElements: [],
+ tableIcons: {
+ Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
+ Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
+ DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
+ Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
+ Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Export: forwardRef((props, ref) => <VerticalAlignBottomIcon {...props} ref={ref} />),
+ Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
+ FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
+ LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
+ NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
+ ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
+ SortArrow: forwardRef((props, ref) => <ArrowUpward {...props} ref={ref} />),
+ ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
+ ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
+ },
+ dictColumns: [
+ {
+ title: "Dictionary Name", field: "name",editable: 'onAdd',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Sub Dictionary ?", field: "secondLevelDictionary", lookup: {0: 'No', 1: 'Yes'},
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Dictionary Type", field: "subDictionaryType",lookup: {string: 'string', number: 'number'},
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Updated By", field: "updatedBy", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Last Updated Date", field: "updatedDate", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ }
+ ],
+ dictElementColumns: [
+ {
+ title: "Element Short Name", field: "shortName",editable: 'onAdd',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Element Name", field: "name",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Element Description", field: "description",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Element Type", field: "type",
+ editComponent: props => (
+ <div>
+ <SelectSubDictType value={props.value} onChange={props.onChange} />
+ </div>
+ ),
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Sub-Dictionary", field: "subDictionary",
+ editComponent: props => (
+ <div>
+ <SubDict value={props.value} onChange={props.onChange} />
+ </div>
+ ),
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Updated By", field: "updatedBy", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Updated Date", field: "updatedDate", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ }
+ ]
+ }
+ }
+
+ componentDidMount() {
+ this.getDictionaries();
+ }
+
+ getDictionaries() {
+ TemplateMenuService.getDictionary().then(arrayOfdictionaries => {
+ this.setState({ dictionaries: arrayOfdictionaries, currentSelectedDictionary: null })
+ // global variable setting used functional components in this file
+ dictList = arrayOfdictionaries;
+ }).catch(() => {
+ console.error('Failed to retrieve dictionaries');
+ this.setState({ dictionaries: [], currentSelectedDictionary: null })
+ });
+ }
+
+ getDictionaryElements(dictionaryName) {
+ TemplateMenuService.getDictionaryElements(dictionaryName).then(dictionaryElements => {
+ this.setState({ dictionaryElements: dictionaryElements.dictionaryElements} );
+ this.setState({ currentSelectDictionary: dictionaryName });
+ }).catch(() => console.error('Failed to retrieve dictionary elements'))
+ }
+
+ clickHandler(rowData) {
+ this.getDictionaries();
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ addReplaceDictionaryRequest(dictionaryEntry) {
+ TemplateMenuService.insDictionary(dictionaryEntry)
+ .then(resp => {
+ this.getDictionaries();
+ })
+ .catch(() => console.error('Failed to insert new dictionary elements'));
+ }
+
+ updateDictionaryElementsRequest(dictElements) {
+ let reqData = { "name": this.state.currentSelectedDictionary, 'dictionaryElements': dictElements };
+ TemplateMenuService.insDictionaryElements(reqData)
+ .then(resp => { this.getDictionaryElements(this.state.currentSelectedDictionary) })
+ .catch(() => console.error('Failed to update dictionary elements'));
+ }
+
+ deleteDictionaryRequest(dictionaryName) {
+ TemplateMenuService.deleteDictionary(dictionaryName)
+ .then(resp => {
+ this.getDictionaries();
+ })
+ .catch(() => console.error('Failed to delete dictionary'));
+ }
+
+ deleteDictionaryElementRequest(dictionaryName, elemenetShortName) {
+ TemplateMenuService.deleteDictionaryElements({ 'name': dictionaryName, 'shortName': elemenetShortName })
+ .then(resp => {
+ this.getDictionaryElements(dictionaryName);
+ })
+ .catch(() => console.error('Failed to delete dictionary elements'));
+ }
+
+ fileSelectedHandler = (event) => {
+
+ if (event.target.files[0].type === 'text/csv' || event.target.files[0].type === 'application/vnd.ms-excel') {
+ if (event.target.files && event.target.files[0]) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ let errorMessages = this.importCsvData(reader.result);
+ if (errorMessages !== '') {
+ alert(errorMessages);
+ }
+ }
+ reader.readAsText(event.target.files[0]);
+ }
+ } else {
+ alert('Please upload .csv extention files only.');
+ }
+ }
+
+ importCsvData(rawCsvData) {
+
+ const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
+ const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary' ];
+ const validTypes = ['string','number','datetime','json','map'];
+
+ let mandatory;
+
+ if (subDictFlag) {
+ mandatory = [ true, true, true, false, false ];
+ } else {
+ mandatory = [ true, true, true, true, false ];
+ }
+
+ let result = CsvToJson(rawCsvData, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
+
+ let errorMessages = result.errorMessages;
+ let jsonObjArray = result.jsonObjArray;
+
+ let validTypesErrorMesg = '';
+
+ for (let i=0; i < validTypes.length; ++i) {
+ if (i === 0) {
+ validTypesErrorMesg = validTypes[i];
+ } else {
+ validTypesErrorMesg += ',' + validTypes[i];
+ }
+ }
+
+ if (errorMessages !== '') {
+ return errorMessages;
+ }
+
+ // Perform further checks on data that is now in JSON form
+ let subDictionaries = [];
+
+ // NOTE: dictList is a global variable maintained faithfully
+ // by the getDictionaries() method outside this import
+ // functionality.
+ let item;
+ for (item in dictList) {
+ if (dictList[item].secondLevelDictionary === 1) {
+ subDictionaries.push(dictList[item].name);
+ }
+ };
+
+ // Check for valid Sub-Dictionary and Element Type values
+ subDictionaries = subDictionaries.toString();
+ let row = 2;
+ let dictElem;
+ for (dictElem of jsonObjArray) {
+ let itemKey;
+ for (itemKey in dictElem){
+ let value = dictElem[itemKey].trim();
+ let keyIndex = jsonKeyNames.indexOf(itemKey);
+ if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
+ errorMessages += '\n' + userHeaderNames[keyIndex] +
+ ' at row #' + row +
+ ' can only contain alphanumeric characters and periods, hyphens or underscores';
+ }
+ if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
+ errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
+ errorMessages += '\nValid types are: ' + validTypesErrorMesg;
+ }
+ if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
+ errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
+ }
+ }
+ ++row;
+ }
+ if (errorMessages === '') {
+ // We made it through all the checks. Send it to back end
+ this.updateDictionaryElementsRequest(jsonObjArray);
+ }
+
+ return errorMessages;
+ }
+
+ addDictionaryRow(newData) {
+ let validData = true;
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
+ validData = false;
+ alert('Please enter alphanumeric input. Only allowed special characters are:(period, hyphen, underscore)');
+ reject();
+ }
+ for (let i = 0; i < this.state.dictionaries.length; i++) {
+ if (this.state.dictionaries[i].name === newData.name) {
+ validData = false;
+ alert(newData.name + ' dictionary name already exists')
+ reject();
+ }
+ }
+ if (validData) {
+ this.addReplaceDictionaryRequest(newData);
+ }
+ resolve();
+ }, 1000);
+ });
+ }
+
+
+ updateDictionaryRow(newData, oldData) {
+ let validData = true;
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
+ validData = false;
+ alert('Please enter alphanumberic input. Only allowed special characters are:(period, hyphen, underscore)');
+ reject();
+ }
+ if (validData) {
+ this.addReplaceDictionaryRequest(newData);
+ }
+ resolve();
+ }, 1000);
+ });
+ }
+
+ deleteDictionaryRow(oldData) {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ this.deleteDictionaryRequest(oldData.name);
+ resolve();
+ }, 1000);
+ });
+ }
+
+ addDictionaryElementRow(newData) {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ let dictionaryElements = this.state.dictionaryElements;
+ let errorMessages = '';
+ for (let i = 0; i < this.state.dictionaryElements.length; i++) {
+ if (this.state.dictionaryElements[i].shortName === newData.shortName) {
+ alert('Short Name "' + newData.shortName + '" already exists');
+ reject("");
+ }
+ }
+ // MaterialTable returns no property at all if the user has not touched a
+ // new column, so we want to add the property with an emptry string
+ // for several cases if that is the case to simplify other checks.
+ if (newData.description === undefined) {
+ newData.description = "";
+ }
+ if (newData.subDictionary === undefined) {
+ newData.subDictionary = null;
+ }
+ if (newData.type === undefined) {
+ newData.type = "";
+ }
+ if (!newData.shortName && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
+ errorMessages += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
+ }
+ if (!newData.shortName){
+ errorMessages += '\nShort Name must be specified';
+ }
+ if (!newData.name){
+ errorMessages += '\nElement Name must be specified';
+ }
+ if (!newData.type && !subDictFlag){
+ errorMessages += '\nElement Type must be specified';
+ }
+ if (errorMessages === '') {
+ dictionaryElements.push(newData);
+ this.updateDictionaryElementsRequest([newData]);
+ resolve();
+ } else {
+ alert(errorMessages);
+ reject("");
+ }
+ }, 1000);
+ });
+ }
+
+ updateDictionaryElementRow(newData, oldData) {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ let dictionaryElements = this.state.dictionaryElements;
+ let validData = true;
+ if (!newData.type) {
+ validData = false;
+ alert('Element Type cannot be null');
+ reject();
+ }
+ if (validData) {
+ const index = dictionaryElements.indexOf(oldData);
+ dictionaryElements[index] = newData;
+ this.updateDictionaryElementsRequest([newData]);
+ }
+ resolve();
+ }, 1000);
+ });
+ }
+
+
+ deleteDictionaryElementRow(oldData) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ this.deleteDictionaryElementRequest(this.state.currentSelectedDictionary, oldData.shortName);
+ resolve();
+ }, 1000);
+ });
+ }
+
+ handleDictionaryRowClick(event, rowData) {
+ subDictFlag = rowData.secondLevelDictionary === 1 ? true : false;
+ this.setState({
+ currentSelectedDictionary : rowData.name,
+ exportFilename: rowData.name
+ })
+ this.getDictionaryElements(rowData.name);
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Manage Dictionaries</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ {this.state.currentSelectedDictionary === null ?
+ <MaterialTable
+ title={"Dictionary List"}
+ data={this.state.dictionaries}
+ columns={this.state.dictColumns}
+ icons={this.state.tableIcons}
+ onRowClick={this.handleDictionaryRowClick}
+ options={{
+ headerStyle: rowHeaderStyle,
+ }}
+ editable={!this.readOnly ?
+ {
+ onRowAdd: this.addDictionaryRow,
+ onRowUpdate: this.updateDictionaryRow,
+ onRowDelete: this.deleteDictionaryRow
+ } : undefined }
+ /> : null
+ }
+ {this.state.currentSelectedDictionary !== null ?
+ <MaterialTable
+ title={'Dictionary Elements List for ' + (subDictFlag ? 'Sub-Dictionary "' : '"') + this.state.currentSelectedDictionary + '"'}
+ data={this.state.dictionaryElements}
+ columns={this.state.dictElementColumns}
+ icons={this.state.tableIcons}
+ options={{
+ exportAllData: true,
+ exportButton: true,
+ exportFileName: this.state.exportFilename,
+ headerStyle:{backgroundColor:'white', fontSize: '15pt', text: 'bold', border: '1px solid black'}
+ }}
+ components={{
+ Toolbar: props => (
+ <Row>
+ <Col sm="11">
+ <MTableToolbarStyled {...props} />
+ </Col>
+ <ColPullLeftStyled sm="1">
+ <Tooltip title="Import" placement = "bottom">
+ <IconButton aria-label="import" disabled={this.readOnly} onClick={() => this.fileUpload.click()}>
+ <VerticalAlignTopIcon />
+ </IconButton>
+ </Tooltip>
+ <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
+ style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
+ </ColPullLeftStyled>
+ </Row>
+ )
+ }}
+ editable={!this.readOnly ?
+ {
+ onRowAdd: this.addDictionaryElementRow,
+ onRowUpdate: this.updateDictionaryElementRow,
+ onRowDelete: this.deleteDictionaryElementRow
+ } : undefined
+ }
+ /> : null
+ }
+ {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js b/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js
new file mode 100644
index 000000000..a4c1335d8
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js
@@ -0,0 +1,462 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import { mount } from 'enzyme';
+import { render } from 'enzyme';
+import ManageDictionaries from './ManageDictionaries';
+import TemplateMenuService from '../../../api/TemplateService'
+
+const TestDictionaryElements = {
+ name: "test",
+ secondLevelDictionary: 0,
+ subDictionaryType: "",
+ dictionaryElements: [
+ {
+ shortName: "alertType",
+ name: "Alert Type",
+ description: "Type of Alert",
+ type: "string",
+ subDictionary: "",
+ createdDate: "2020-06-12T13:58:51.443931Z",
+ updatedDate: "2020-06-13T16:27:57.084870Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+ ]
+};
+
+const TestDictionaries =
+[
+ {
+ name: "test",
+ secondLevelDictionary: 0,
+ subDictionaryType: "string",
+ dictionaryElements: [ TestDictionaryElements ],
+ createdDate: "2020-06-14T21:00:33.231166Z",
+ updatedDate: "2020-06-14T21:00:33.231166Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ },
+ {
+ name: "testSub1",
+ secondLevelDictionary: 1,
+ subDictionaryType: "string",
+ dictionaryElements: [
+ {
+ shortName: "subElem",
+ name: "Sub Element",
+ description: "Sub Element Description",
+ type: "string",
+ createdDate: "2020-06-14T21:04:44.402287Z",
+ updatedDate: "2020-06-14T21:04:44.402287Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+ ],
+ createdDate: "2020-06-14T21:01:16.390250Z",
+ updatedDate: "2020-06-14T21:01:16.390250Z",
+ updatedBy: "admin",
+ createdBy: "admin"
+ }
+];
+
+
+const historyMock = { push: jest.fn() };
+
+let errorMessage = '';
+
+window.alert = jest.fn().mockImplementation((mesg) => { errorMessage = mesg ; return });
+
+TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve(TestDictionaries);
+});
+
+TemplateMenuService.insDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+});
+
+TemplateMenuService.deleteDictionary = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+TemplateMenuService.getDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve(TestDictionaryElements);
+});
+
+TemplateMenuService.deleteDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve("200");
+});
+
+
+describe('Verify ManageDictionaries', () => {
+
+ beforeEach(() => {
+ fetch.resetMocks();
+ });
+
+ it('Test API Successful', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "name": "vtest",
+ "secondLevelDictionary": 1,
+ "subDictionaryType": "string",
+ "updatedBy": "test",
+ "updatedDate": "05-07-2019 19:09:42"
+ });
+ }
+ });
+ });
+ const component = shallow(<ManageDictionaries />);
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Test API Exception', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: false,
+ status: 500,
+ json: () => {
+ return Promise.resolve({
+ "name": "vtest",
+ "secondLevelDictionary": 1,
+ "subDictionaryType": "string",
+ "updatedBy": "test",
+ "updatedDate": "05-07-2019 19:09:42"
+ });
+ }
+ });
+ });
+ const component = shallow(<ManageDictionaries />);
+ });
+
+ it('Test Table icons', () => {
+
+ const component = mount(<ManageDictionaries />);
+ expect(component.find('[className="MuiSelect-icon MuiTablePagination-selectIcon"]')).toBeTruthy();
+ });
+
+ test('Test add/replace and delete dictionary requests', async () => {
+
+ const component = shallow(<ManageDictionaries history={historyMock}/>)
+ const instance = component.instance();
+
+ const flushPromises = () => new Promise(setImmediate);
+
+ instance.addReplaceDictionaryRequest({name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string"});
+ instance.deleteDictionaryRequest("test");
+
+ await flushPromises();
+
+ expect(component.state('currentSelectedDictionary')).toEqual(null);
+ expect(component.state('dictionaries')).toEqual(TestDictionaries);
+ });
+
+ test('Test update dictionary row', async () => {
+
+ const component = shallow(<ManageDictionaries history={historyMock}/>)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await expect(instance.updateDictionaryRow(rowData, rowData)).resolves.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test add dictionary row', async () => {
+
+ const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await instance.addDictionaryRow(rowData);
+ expect(addReplaceRequest).toHaveBeenCalledWith(rowData);
+
+ }, 2000);
+
+ test('Test add dictionary row with errors name already exists', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test add dictionary row with errors illegal chars in name', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+ test('Test update dictionary row with errors illegal chars in name', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.updateDictionaryRow(rowData)).rejects.toEqual(undefined);
+ });
+
+
+ test('Test add dictionary row with errors (illegal chars)', async () => {
+
+ const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ let rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+ await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+ }, 2000);
+
+
+ test('Test delete dictionary row', async () => {
+
+ const deleteRequest = jest.spyOn(ManageDictionaries.prototype,'deleteDictionaryRequest');
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ await instance.deleteDictionaryRow(rowData);
+ expect(deleteRequest).toHaveBeenCalledWith("newdict");
+
+ }, 2000);
+
+ test('Test handle select dictionary row click', async () => {
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+ instance.handleDictionaryRowClick("event", rowData);
+ expect(component.state('currentSelectedDictionary')).toEqual("newdict");
+ }, 2000);
+
+ test('Test dictionary element row add, update, delete', async () => {
+
+ const rowData = {
+ createdBy: "admin",
+ createdDate: "2020-06-15T13:59:20.467381Z",
+ description: "Description",
+ name: "Some Elem",
+ shortName: "someElem",
+ type: "string",
+ updatedBy: "admin",
+ updatedDate: "2020-06-15T13:59:20.467381Z"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ const badRowData = {
+ description: "Description",
+ name: "Some Elem",
+ shortName: "someElem",
+ type: "string"
+ };
+
+ await instance.clickHandler();
+ await instance.getDictionaryElements("test");
+
+ await expect(instance.addDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+ await expect(instance.updateDictionaryElementRow(rowData, rowData)).resolves.toEqual(undefined);
+ await expect(instance.deleteDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+ });
+
+ test('Test dictionary element row add with errors', async () => {
+
+ const badRowData = {
+ description: "",
+ name: "",
+ shortName: "some#Elem",
+ type: ""
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+ test('Test dictionary element update with error illegal name', async () => {
+
+ const badRowData = {
+ description: "",
+ name: "test@@",
+ shortName: "some#Elem",
+ type: ""
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ await expect(instance.updateDictionaryElementRow(badRowData)).rejects.toEqual(undefined);
+ });
+
+ test('Test dictionary element addition with duplicate name error', async () => {
+
+ const badRowData = {
+ description: "description",
+ name: "Alert Type",
+ shortName: "alertType",
+ type: "string"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ component.setState({ currentSelectedDictionary: 'test' });
+
+ await instance.getDictionaryElements();
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+ test('Test dictionary element addition with empty name error', async () => {
+
+ const badRowData = {
+ description: "description",
+ name: "Alert Type",
+ shortName: "",
+ type: "string"
+ };
+
+ const component = shallow(<ManageDictionaries/>)
+ const instance = component.instance();
+
+ component.setState({ currentSelectedDictionary: 'test' });
+
+ await instance.getDictionaryElements();
+ await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+ });
+
+
+ it('Test Import CSV Sunny Day', async () => {
+
+ TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+ });
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"alertType","Alert Type","Alert Type Description","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = [
+ {
+ description: "Alert Type Description",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ];
+
+ const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+
+ await expect(instance.importCsvData(rawCsvData)).toEqual('');
+ expect(updateDictionaryElementsRequest).toHaveBeenCalledWith(expectedResult);
+ });
+
+ it('Test Import CSV Mandatory Field Check Errors', () => {
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"","","","","","",""';
+
+ // The empty values for all the fields in row 1 of the rawCsvData will trigger a bunch of errors.
+ // Getting Enzyme to properly match them with embedded newlines turned out to be impossible
+ // and maybe not desirable anyway; so our test for "success" here is simply that the
+ // routine returns a non-empty error string.
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+ expect(instance.importCsvData(rawCsvData)).not.toEqual('');
+ });
+
+ it('Test Import CSV Errors in Row Data', async () => {
+
+ TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+ return Promise.resolve({ ok: true, status: 200 });
+ });
+
+ let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsvData += '"alert@Type","Alert Type","Alert Type Description","strin","subby","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = [
+ {
+ description: "Alert Type Description",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ];
+
+ const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+ const component = shallow(<ManageDictionaries />)
+ const instance = component.instance();
+
+ await expect(instance.importCsvData(rawCsvData)).not.toEqual('');
+ });
+
+
+ it('Test handleClose', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "name": "vtest",
+ "secondLevelDictionary": 1,
+ "subDictionaryType": "string",
+ "updatedBy": "test",
+ "updatedDate": "05-07-2019 19:09:42"
+ });
+ }
+ });
+ });
+ const handleClose = jest.spyOn(ManageDictionaries.prototype,'handleClose');
+ const component = shallow(<ManageDictionaries history={historyMock} />)
+ component.find('[variant="secondary"]').prop('onClick')();
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ handleClose.mockClear();
+ });
+});
diff --git a/runtime/ui-react/src/components/dialogs/ManageDictionaries/__snapshots__/ManageDictionaries.test.js.snap b/runtime/ui-react/src/components/dialogs/ManageDictionaries/__snapshots__/ManageDictionaries.test.js.snap
new file mode 100644
index 000000000..6b583632f
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/ManageDictionaries/__snapshots__/ManageDictionaries.test.js.snap
@@ -0,0 +1,196 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify ManageDictionaries Test API Successful 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="xl"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Manage Dictionaries
+ </ModalTitle>
+ </ModalHeader>
+ <ModalBody>
+ <WithStyles(Component)
+ columns={
+ Array [
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "editable": "onAdd",
+ "field": "name",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Dictionary Name",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "secondLevelDictionary",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "lookup": Object {
+ "0": "No",
+ "1": "Yes",
+ },
+ "title": "Sub Dictionary ?",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "subDictionaryType",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "lookup": Object {
+ "number": "number",
+ "string": "string",
+ },
+ "title": "Dictionary Type",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "editable": "never",
+ "field": "updatedBy",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Updated By",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "editable": "never",
+ "field": "updatedDate",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Last Updated Date",
+ },
+ ]
+ }
+ editable={
+ Object {
+ "onRowAdd": [Function],
+ "onRowDelete": [Function],
+ "onRowUpdate": [Function],
+ }
+ }
+ icons={
+ Object {
+ "Add": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Check": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Clear": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Delete": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "DetailPanel": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Edit": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Export": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Filter": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "FirstPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "LastPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "NextPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "PreviousPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "ResetSearch": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Search": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "SortArrow": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "ThirdStateCheck": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "ViewColumn": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ }
+ }
+ onRowClick={[Function]}
+ options={
+ Object {
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "1px solid black",
+ "fontSize": "15pt",
+ "text": "bold",
+ },
+ }
+ }
+ title="Dictionary List"
+ />
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Close
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/PerformActions.js b/runtime/ui-react/src/components/dialogs/PerformActions.js
new file mode 100644
index 000000000..f6001e21f
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/PerformActions.js
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../api/LoopActionService';
+
+
+export default class PerformActions extends React.Component {
+ state = {
+ loopName: this.props.loopCache.getLoopName(),
+ loopAction: this.props.loopAction
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.refreshStatus = this.refreshStatus.bind(this);
+ }
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName(),
+ loopAction: newProps.loopAction
+ });
+ }
+
+ componentDidMount() {
+ const action = this.state.loopAction;
+ const loopName = this.state.loopName;
+
+ if (action === 'delete') {
+ if (window.confirm('You are about to remove Control Loop Model "' + loopName +
+ '". Select OK to continue with deletion or Cancel to keep the model.') === false) {
+ return;
+ }
+ }
+
+ this.props.setBusyLoading(); // Alert top level to start block user clicks
+
+ LoopActionService.performAction(loopName, action)
+ .then(pars => {
+ this.props.showSucAlert("Action " + action + " successfully performed");
+ if (action === 'delete') {
+ this.props.updateLoopFunction(null);
+ this.props.history.push('/');
+ } else {
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ }
+ })
+ .catch(error => {
+ this.props.showFailAlert("Action " + action + " failed");
+ // refresh status and update loop logs
+ this.refreshStatus(loopName);
+ })
+ .finally(() => this.props.clearBusyLoading());
+ }
+
+ refreshStatus(loopName) {
+
+ this.props.setBusyLoading();
+
+ LoopActionService.refreshStatus(loopName)
+ .then(data => {
+ this.props.updateLoopFunction(data);
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ this.props.history.push('/');
+ })
+ .finally(() => this.props.clearBusyLoading());
+ }
+
+ render() {
+ return null;
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/PerformActions.test.js b/runtime/ui-react/src/components/dialogs/PerformActions.test.js
new file mode 100644
index 000000000..c91c2f675
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/PerformActions.test.js
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import PerformActions from './PerformActions';
+import LoopCache from '../../api/LoopCache';
+import LoopActionService from '../../api/LoopActionService';
+
+describe('Verify PerformActions', () => {
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca"
+ });
+
+ it('Test the render method action failed', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const updateLoopFunction = jest.fn();
+ const showSucAlert = jest.fn();
+ const showFailAlert = jest.fn();
+ const setBusyLoading = jest.fn();
+ const clearBusyLoading = jest.fn();
+
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+ const component = shallow(<PerformActions loopCache={loopCache}
+ loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} setBusyLoading={setBusyLoading} clearBusyLoading={clearBusyLoading}/>)
+ await flushPromises();
+ component.update();
+
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test the render method action successful', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const updateLoopFunction = jest.fn();
+ const showSucAlert = jest.fn();
+ const showFailAlert = jest.fn();
+ const setBusyLoading = jest.fn();
+ const clearBusyLoading = jest.fn();
+
+ LoopActionService.performAction = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+ const component = shallow(<PerformActions loopCache={loopCache}
+ loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} setBusyLoading={setBusyLoading} clearBusyLoading={clearBusyLoading}/>)
+ await flushPromises();
+ component.update();
+
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+});
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js b/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js
new file mode 100644
index 000000000..9c2f102b4
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js
@@ -0,0 +1,109 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react'
+import TreeView from '@material-ui/lab/TreeView';
+import TreeItem from '@material-ui/lab/TreeItem';
+import FolderIcon from '@material-ui/icons/Folder';
+import FolderOpenIcon from '@material-ui/icons/FolderOpen';
+import DescriptionIcon from '@material-ui/icons/Description';
+
+
+export default class PoliciesTreeViewer extends React.Component {
+
+ separator = ".";
+
+ nodesList = new Map();
+
+ constructor(props, context) {
+ super(props, context);
+ this.createPoliciesTree = this.createPoliciesTree.bind(this);
+ this.handleTreeItemClick = this.handleTreeItemClick.bind(this);
+ this.buildNameWithParent = this.buildNameWithParent.bind(this);
+
+ }
+
+ state = {
+ policiesTreeData: this.createPoliciesTree(this.props.policiesData),
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.policiesData !== this.props.policiesData) {
+ this.setState({policiesTreeData: this.createPoliciesTree(this.props.policiesData)})
+ }
+ }
+
+ createPoliciesTree(policiesArray) {
+ // put my policies array in a Json
+ let nodeId = 1;
+ let root = {id:nodeId, policyCount:0, name:"ROOT", children:[], parent: undefined};
+ this.nodesList.set(nodeId++, root);
+
+ policiesArray.forEach(policy => {
+ let currentTreeNode = root;
+ policy[this.props.valueForTreeCreation].split(this.separator).forEach((policyNamePart, index, policyNamePartsArray) => {
+ let node = currentTreeNode["children"].find(element => element.name === policyNamePart);
+ if (typeof(node) === "undefined") {
+ node = {id:nodeId, policyCount:0, children:[], name:policyNamePart, parent:currentTreeNode};
+ this.nodesList.set(nodeId++, node);
+ currentTreeNode["children"].push(node);
+ }
+ if ((index+1) === policyNamePartsArray.length) {
+ ++currentTreeNode["policyCount"];
+ }
+ currentTreeNode = node;
+ })
+ })
+ return root;
+ }
+
+ buildNameWithParent(node) {
+ let nameToBuild = node.name;
+ if (node.parent !== undefined) {
+ nameToBuild = this.buildNameWithParent(node.parent) + this.separator + node.name;
+ }
+ return nameToBuild;
+ }
+
+ handleTreeItemClick(event, value) {
+ let fullName = this.buildNameWithParent(this.nodesList.get(value[0])).substring(5);
+ this.props.policiesFilterFunction(fullName);
+ }
+
+ renderTreeItems(nodes) {
+ return (<TreeItem key={nodes.id} nodeId={nodes.id} label={nodes.name + "("+ nodes.policyCount + ")"} onNodeSelect={this.handleTreeItemClick}>
+ {
+ Array.isArray(nodes.children) ? nodes.children.map((node) => this.renderTreeItems(node)) : null
+ }
+ </TreeItem>);
+ };
+
+ render() {
+ return (
+ <TreeView defaultExpanded={['root']} defaultCollapseIcon={<FolderOpenIcon />}
+ defaultExpandIcon={<FolderIcon />} defaultEndIcon={<DescriptionIcon />} onNodeSelect={this.handleTreeItemClick} multiSelect>
+ {this.renderTreeItems(this.state.policiesTreeData)}
+ </TreeView>
+ );
+ }
+} \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js
new file mode 100644
index 000000000..57d61600a
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import Button from 'react-bootstrap/Button';
+import Alert from 'react-bootstrap/Alert';
+import PolicyService from '../../../api/PolicyService';
+import FormGroup from '@material-ui/core/FormGroup';
+import Checkbox from '@material-ui/core/Checkbox';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
+const PanelDiv = styled.div`
+ text-align: justify;
+ font-size: ${props => props.theme.policyEditorFontSize};
+ background-color: ${props => props.theme.loopViewerBackgroundColor};
+`
+
+export default class PolicyDeploymentEditor extends React.Component {
+
+ state = {
+ policyData: this.props.policyData,
+ showSuccessAlert: false,
+ showFailAlert: false,
+ checkboxesState: this.createPdpStructure(this.props.policyData),
+ checkboxesInitialState: this.createPdpStructure(this.props.policyData),
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleUpdatePdpDeployment = this.handleUpdatePdpDeployment.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.renderPdpDeploymentCheckboxes = this.renderPdpDeploymentCheckboxes.bind(this);
+ this.createPdpStructure = this.createPdpStructure.bind(this);
+ this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
+ this.createPdpGroupOperations = this.createPdpGroupOperations.bind(this);
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+
+ }
+
+ disableAlert() {
+ this.setState ({ showSuccessAlert: false, showFailAlert: false });
+ }
+
+ createPdpGroupOperations(initialStates, newStates) {
+ let commandsArray = [];
+ initialStates.forEach(initElem => {
+ let newStateFound = newStates.find(newElement => newElement.name === initElem.name);
+ if (initElem.value !== newStateFound.value) {
+ let newPdpGroupsArray = newStateFound.name.split("/");
+ let operation = "POST/";
+ if (initElem.value) {
+ operation = "DELETE/";
+ }
+ commandsArray.push(operation + newPdpGroupsArray[0] + "/"+newPdpGroupsArray[1] + "/"
+ +this.state.policyData.name + "/" + this.state.policyData.version);
+ }
+ });
+ return commandsArray.length > 0 ? {"PdpActions":commandsArray} : undefined;
+ }
+
+ handleUpdatePdpDeployment() {
+ let operationsList = this.createPdpGroupOperations(this.state.checkboxesInitialState,
+ this.state.checkboxesState);
+ if (typeof(operationsList) !== "undefined") {
+ PolicyService.updatePdpDeployment(operationsList).then(respPdpDeploymentUpdate => {
+ if (typeof(respPdpDeploymentUpdate) === "undefined") {
+ //it indicates a failure
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Pdp Deployment update Failure'
+ });
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Pdp Deployment Update successful'
+ });
+ this.props.policiesTableUpdateFunction();
+ }
+ })
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Pdp Deployment: Nothing to change'
+ });
+ }
+ }
+
+ createPdpStructure(policyData) {
+ // Create map with data for all group/subgroup where the policy is deployed
+ let infoPdpMap = new Map();
+ if (typeof policyData.pdpGroupInfo !== "undefined") {
+ policyData["pdpGroupInfo"].forEach(pdpGroupElem => {
+ let pdpGroupName = Object.keys(pdpGroupElem)[0];
+ pdpGroupElem[pdpGroupName]["pdpSubgroups"].forEach(pdpSubGroupElem => {
+ infoPdpMap.set(pdpGroupName + "/" + pdpSubGroupElem["pdpType"], true);
+ });
+ });
+ }
+ // Create the possible values for pdpgroup/subgroup and tick the ones where policy is deployed
+ let pdpStates = [];
+ if (typeof policyData.supportedPdpGroups !== "undefined") {
+ for (const pdpGroup of policyData["supportedPdpGroups"]) {
+ let pdpGroupName = Object.keys(pdpGroup)[0];
+ for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
+ let fullName = pdpGroupName + "/" + pdpSubGroup;
+ pdpStates.push({name: fullName,
+ value: infoPdpMap.get(fullName) !== undefined});
+ }
+ }
+ }
+ return pdpStates;
+ }
+
+ handleCheckboxChange(event) {
+ const checkboxesArray = this.state.checkboxesState;
+ checkboxesArray.find(element => element.name === event.target.name).value = event.target.checked;
+ this.setState({checkboxesState:checkboxesArray});
+ }
+
+ renderPdpDeploymentCheckboxes() {
+ return this.state.checkboxesState.map(item => {
+ return <FormControlLabel control={<Checkbox checked={item.value} onChange={this.handleCheckboxChange}
+ name={item.name} />} label={item.name} />;
+ });
+ }
+
+ render() {
+ return (
+ <PanelDiv>
+ <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Button variant="secondary" title="Update the policy to the specified PDP Groups/Subgroups"
+ onClick={this.handleUpdatePdpDeployment}>Update PDP</Button>
+ <FormGroup>{this.renderPdpDeploymentCheckboxes()}</FormGroup>
+ </PanelDiv>
+ );
+ }
+ } \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js
new file mode 100644
index 000000000..be77f14e9
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js
@@ -0,0 +1,192 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import PolicyToscaService from '../../../api/PolicyToscaService';
+import { JSONEditor } from '@json-editor/json-editor/dist/nonmin/jsoneditor.js';
+import "@fortawesome/fontawesome-free/css/all.css"
+import styled from 'styled-components';
+import Button from 'react-bootstrap/Button';
+import TextField from '@material-ui/core/TextField';
+import Alert from 'react-bootstrap/Alert';
+import PolicyService from '../../../api/PolicyService';
+import OnapUtils from '../../../utils/OnapUtils';
+
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
+const JsonEditorDiv = styled.div`
+ margin-top: 20px;
+ background-color: ${props => props.theme.loopViewerBackgroundColor};
+ text-align: justify;
+ font-size: ${props => props.theme.policyEditorFontSize};
+ border: 1px solid #C0C0C0;
+`
+const PanelDiv = styled.div`
+ text-align: justify;
+ font-size: ${props => props.theme.policyEditorFontSize};
+ background-color: ${props => props.theme.loopViewerBackgroundColor};
+`
+
+export default class PolicyEditor extends React.Component {
+
+ state = {
+ policyModelType: this.props.policyModelType,
+ policyModelTypeVersion: this.props.policyModelTypeVersion,
+ policyName: (typeof this.props.policyName !== "undefined") ? this.props.policyName : "org.onap.policy.new",
+ policyVersion: (typeof this.props.policyVersion !== "undefined") ? this.props.policyVersion : "0.0.1",
+ policyProperties: this.props.policyProperties,
+ showSuccessAlert: false,
+ showFailAlert: false,
+ jsonEditor: null,
+ jsonEditorDivId: this.props.policyModelType + "_" + this.props.policyModelTypeVersion + "_" + this.props.policyName + "_" + this.props.policyVersion,
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this.createJsonEditor = this.createJsonEditor.bind(this);
+ this.getToscaModelForPolicy = this.getToscaModelForPolicy.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.handleCreateNewVersion = this.handleCreateNewVersion.bind(this);
+ this.handleChangePolicyName = this.handleChangePolicyName.bind(this);
+ this.handleChangePolicyVersion = this.handleChangePolicyVersion.bind(this);
+ }
+
+ disableAlert() {
+ this.setState ({ showSuccessAlert: false, showFailAlert: false });
+ }
+
+ customValidation(editorData) {
+ // method for sub-classes to override with customized validation
+ return [];
+ }
+
+ handleCreateNewVersion() {
+ var editorData = this.state.jsonEditor.getValue();
+ var errors = this.state.jsonEditor.validate();
+ errors = errors.concat(this.customValidation(editorData));
+
+ if (errors.length !== 0) {
+ console.error("Errors detected during policy data validation ", errors);
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
+ });
+ return;
+ } else {
+ console.info("NO validation errors found in policy data");
+ PolicyService.createNewPolicy(this.state.policyModelType, this.state.policyModelTypeVersion,
+ this.state.policyName, this.state.policyVersion, editorData).then(respPolicyCreation => {
+ if (typeof(respPolicyCreation) === "undefined") {
+ //it indicates a failure
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Policy Creation Failure'
+ });
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Policy '+ this.state.policyName + '/' + this.state.policyVersion + ' created successfully'
+ });
+ this.props.policiesTableUpdateFunction();
+ }
+ })
+ }
+ }
+
+ getToscaModelForPolicy() {
+ PolicyToscaService.getToscaPolicyModel(this.state.policyModelType, this.state.policyModelTypeVersion).then(respJsonPolicyTosca => {
+ if (respJsonPolicyTosca !== {}) {
+ this.setState({
+ jsonSchemaPolicyTosca: respJsonPolicyTosca,
+ jsonEditor: this.createJsonEditor(respJsonPolicyTosca, this.state.policyProperties),
+ })
+ }
+ });
+ }
+
+ componentDidMount() {
+ this.getToscaModelForPolicy();
+ }
+
+ createJsonEditor(toscaModel, editorData) {
+ return new JSONEditor(document.getElementById(this.state.jsonEditorDivId),
+ {
+ schema: toscaModel,
+ startval: editorData,
+ theme: 'bootstrap4',
+ iconlib: 'fontawesome5',
+ object_layout: 'grid',
+ disable_properties: false,
+ disable_edit_json: false,
+ disable_array_reorder: true,
+ disable_array_delete_last_row: true,
+ disable_array_delete_all_rows: false,
+ array_controls_top: true,
+ keep_oneof_values: false,
+ collapsed: true,
+ show_errors: 'always',
+ display_required_only: false,
+ show_opt_in: false,
+ prompt_before_delete: true,
+ required_by_default: false
+ })
+ }
+
+ handleChangePolicyName(event) {
+ this.setState({
+ policyName: event.target.value,
+ });
+ }
+
+ handleChangePolicyVersion(event) {
+ this.setState({
+ policyVersion: event.target.value,
+ });
+ }
+
+ render() {
+ return (
+ <PanelDiv>
+ <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <TextField required id="policyName" label="Required" defaultValue={this.state.policyName}
+ onChange={this.handleChangePolicyName} variant="outlined" size="small"/>
+ <TextField required id="policyVersion" label="Required" defaultValue={this.state.policyVersion}
+ onChange={this.handleChangePolicyVersion} size="small" variant="outlined"/>
+ <Button variant="secondary" title="Create a new policy version from the defined parameters"
+ onClick={this.handleCreateNewVersion}>Create New Version</Button>
+ <JsonEditorDiv id={this.state.jsonEditorDivId} title="Policy Properties"/>
+ </PanelDiv>
+ );
+ }
+} \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js
new file mode 100644
index 000000000..0b734430a
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import PolicyEditor from './PolicyEditor';
+import { shallow, mount } from 'enzyme';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+
+describe('Verify PolicyEditor', () => {
+ const fs = require('fs');
+
+ let toscaJson = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.json', {encoding:'utf8', flag:'r'})
+
+ const policyProperties = {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ };
+
+
+ it('Test the render method',async () => {
+ PolicyToscaService.getToscaPolicyModel = jest.fn().mockImplementation(() => {
+ return Promise.resolve(toscaJson);
+ });
+
+ const component = mount(<PolicyEditor policyModelType="onap.policies.monitoring.tcagen2" policyModelTypeVersion="1.0.0"
+ policyName="org.onap.new" policyVersion="1.0.0" policyProperties={policyProperties}
+ policiesTableUpdateFunction={() => {}} />);
+ await PolicyToscaService.getToscaPolicyModel();
+ expect(component).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js
new file mode 100644
index 000000000..4a883fffa
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js
@@ -0,0 +1,345 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Button from 'react-bootstrap/Button';
+import Form from 'react-bootstrap/Form';
+import Col from 'react-bootstrap/Col';
+import Row from 'react-bootstrap/Row';
+import Select from 'react-select';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import LoopService from '../../../api/LoopService';
+import LoopCache from '../../../api/LoopCache';
+import { JSONEditor } from '@json-editor/json-editor/dist/jsoneditor.js';
+import "@fortawesome/fontawesome-free/css/all.css"
+import Alert from 'react-bootstrap/Alert';
+import OnapConstant from '../../../utils/OnapConstants';
+import OnapUtils from '../../../utils/OnapUtils';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
+export default class PolicyModal extends React.Component {
+
+ state = {
+ show: true,
+ loopCache: this.props.loopCache,
+ jsonEditor: null,
+ policyName: this.props.match.params.policyName,
+ // This is to indicate whether it's an operational or config policy (in terms of loop instance)
+ policyInstanceType: this.props.match.params.policyInstanceType,
+ pdpGroup: null,
+ pdpGroupList: [],
+ pdpSubgroupList: [],
+ chosenPdpGroup: '',
+ chosenPdpSubgroup: '',
+ showSucAlert: false,
+ showFailAlert: false
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleSave = this.handleSave.bind(this);
+ this.renderJsonEditor = this.renderJsonEditor.bind(this);
+ this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
+ this.handlePdpSubgroupChange = this.handlePdpSubgroupChange.bind(this);
+ this.createJsonEditor = this.createJsonEditor.bind(this);
+ this.handleRefresh = this.handleRefresh.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this);
+ this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this);
+ this.renderModalTitle = this.renderModalTitle.bind(this);
+ this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
+ }
+
+ handleSave() {
+ var editorData = this.state.jsonEditor.getValue();
+ var errors = this.state.jsonEditor.validate();
+ errors = errors.concat(this.customValidation(editorData, this.state.loopCache.getTemplateName()));
+
+ if (errors.length !== 0) {
+ console.error("Errors detected during policy data validation ", errors);
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
+ });
+ return;
+ }
+ else {
+ console.info("NO validation errors found in policy data");
+ if (this.state.policyInstanceType === OnapConstant.microServiceType) {
+ this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData);
+ this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
+ LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ });
+ } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
+ this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData);
+ this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
+ LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ this.props.loadLoopFunction(this.state.loopCache.getLoopName());
+ });
+ }
+ }
+ }
+
+ customValidation(editorData, templateName) {
+ // method for sub-classes to override with customized validation
+ return [];
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/');
+ }
+
+ componentDidMount() {
+ this.renderJsonEditor();
+ }
+
+ componentDidUpdate() {
+ if (this.state.showSucAlert === true || this.state.showFailAlert === true) {
+ let modalElement = document.getElementById("policyModal")
+ if (modalElement) {
+ modalElement.scrollTo(0, 0);
+ }
+ }
+ }
+
+ createJsonEditor(toscaModel, editorData) {
+ return new JSONEditor(document.getElementById("editor"),
+ { schema: toscaModel,
+ startval: editorData,
+ theme: 'bootstrap4',
+ iconlib: 'fontawesome5',
+ object_layout: 'grid',
+ disable_properties: false,
+ disable_edit_json: false,
+ disable_array_reorder: true,
+ disable_array_delete_last_row: true,
+ disable_array_delete_all_rows: false,
+ array_controls_top: true,
+ keep_oneof_values: false,
+ collapsed:true,
+ show_errors: 'always',
+ display_required_only: false,
+ show_opt_in: false,
+ prompt_before_delete: true,
+ required_by_default: false
+ })
+ }
+
+ renderJsonEditor() {
+ console.debug("Rendering PolicyModal ", this.state.policyName);
+ var toscaModel = {};
+ var editorData = {};
+ var pdpGroupValues = {};
+ var chosenPdpGroupValue, chosenPdpSubgroupValue;
+ if (this.state.policyInstanceType === OnapConstant.microServiceType) {
+ toscaModel = this.state.loopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
+ editorData = this.state.loopCache.getMicroServicePropertiesForName(this.state.policyName);
+ pdpGroupValues = this.state.loopCache.getMicroServiceSupportedPdpGroup(this.state.policyName);
+ chosenPdpGroupValue = this.state.loopCache.getMicroServicePdpGroup(this.state.policyName);
+ chosenPdpSubgroupValue = this.state.loopCache.getMicroServicePdpSubgroup(this.state.policyName);
+ } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
+ toscaModel = this.state.loopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
+ editorData = this.state.loopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
+ pdpGroupValues = this.state.loopCache.getOperationalPolicySupportedPdpGroup(this.state.policyName);
+ chosenPdpGroupValue = this.state.loopCache.getOperationalPolicyPdpGroup(this.state.policyName);
+ chosenPdpSubgroupValue = this.state.loopCache.getOperationalPolicyPdpSubgroup(this.state.policyName);
+ }
+
+ if (toscaModel == null) {
+ return;
+ }
+
+ var pdpSubgroupValues = [];
+ if (typeof(chosenPdpGroupValue) !== "undefined") {
+ var selectedPdpGroup = pdpGroupValues.filter(entry => (Object.keys(entry)[0] === chosenPdpGroupValue));
+ pdpSubgroupValues = selectedPdpGroup[0][chosenPdpGroupValue].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
+ }
+ this.setState({
+ jsonEditor: this.createJsonEditor(toscaModel,editorData),
+ pdpGroup: pdpGroupValues,
+ pdpGroupList: pdpGroupValues.map(entry => {
+ return { label: Object.keys(entry)[0], value: Object.keys(entry)[0] };
+ }),
+ pdpSubgroupList: pdpSubgroupValues,
+ chosenPdpGroup: chosenPdpGroupValue,
+ chosenPdpSubgroup: chosenPdpSubgroupValue
+ })
+ }
+
+ handlePdpGroupChange(e) {
+ var selectedPdpGroup = this.state.pdpGroup.filter(entry => (Object.keys(entry)[0] === e.value));
+ const pdpSubgroupValues = selectedPdpGroup[0][e.value].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
+ if (this.state.chosenPdpGroup !== e.value) {
+ this.setState({
+ chosenPdpGroup: e.value,
+ chosenPdpSubgroup: '',
+ pdpSubgroupList: pdpSubgroupValues
+ });
+ }
+ }
+
+ handlePdpSubgroupChange(e) {
+ this.setState({ chosenPdpSubgroup: e.value });
+ }
+
+ handleRefresh() {
+ var newLoopCache, toscaModel, editorData;
+ if (this.state.policyInstanceType === OnapConstant.microServiceType) {
+ LoopService.refreshMicroServicePolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
+ newLoopCache = new LoopCache(data);
+ toscaModel = newLoopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
+ editorData = newLoopCache.getMicroServicePropertiesForName(this.state.policyName);
+ document.getElementById("editor").innerHTML = "";
+ this.setState({
+ loopCache: newLoopCache,
+ jsonEditor: this.createJsonEditor(toscaModel,editorData),
+ showSucAlert: true,
+ showMessage: "Successfully refreshed"
+ });
+ })
+ .catch(error => {
+ console.error("Error while refreshing the Operational Policy Json Representation");
+ this.setState({
+ showFailAlert: true,
+ showMessage: "Refreshing of UI failed"
+ });
+ });
+ } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
+ LoopService.refreshOperationalPolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
+ var newLoopCache = new LoopCache(data);
+ toscaModel = newLoopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
+ editorData = newLoopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
+ document.getElementById("editor").innerHTML = "";
+ this.setState({
+ loopCache: newLoopCache,
+ jsonEditor: this.createJsonEditor(toscaModel,editorData),
+ showSucAlert: true,
+ showMessage: "Successfully refreshed"
+ });
+ })
+ .catch(error => {
+ console.error("Error while refreshing the Operational Policy Json Representation");
+ this.setState({
+ showFailAlert: true,
+ showMessage: "Refreshing of UI failed"
+ });
+ });
+ }
+ }
+
+ disableAlert() {
+ this.setState ({ showSucAlert: false, showFailAlert: false });
+ }
+
+ renderPdpGroupDropDown() {
+ if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
+ return (
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Form.Label column sm="2">Pdp Group Info</Form.Label>
+ <Col sm="3">
+ <Select value={{ label: this.state.chosenPdpGroup, value: this.state.chosenPdpGroup }} onChange={this.handlePdpGroupChange} options={this.state.pdpGroupList} />
+ </Col>
+ <Col sm="3">
+ <Select value={{ label: this.state.chosenPdpSubgroup, value: this.state.chosenPdpSubgroup }} onChange={this.handlePdpSubgroupChange} options={this.state.pdpSubgroupList} />
+ </Col>
+ </Form.Group>
+ );
+ }
+ }
+
+ renderOpenLoopMessage() {
+ if(this.state.policyInstanceType === OnapConstant.operationalPolicyType && this.state.loopCache.isOpenLoopTemplate()) {
+ return (
+ "Operational Policy cannot be configured as only Open Loop is supported for this Template!"
+ );
+ }
+ }
+
+ renderModalTitle() {
+ return (
+ <Modal.Title>Edit the policy</Modal.Title>
+ );
+ }
+
+ renderButton() {
+ var allElement = [(<Button key="close" variant="secondary" onClick={this.handleClose}>
+ Close
+ </Button>)];
+ if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
+ allElement.push((
+ <Button key="save" variant="primary" disabled={this.readOnly} onClick={this.handleSave}>
+ Save Changes
+ </Button>
+ ));
+ allElement.push((
+ <Button key="refresh" variant="primary" disabled={this.readOnly} onClick={this.handleRefresh}>
+ Refresh
+ </Button>
+ ));
+ }
+ return allElement;
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" backdrop="static" keyboard={false} show={this.state.show} onHide={this.handleClose}>
+ <Modal.Header closeButton>
+ {this.renderModalTitle()}
+ </Modal.Header>
+ <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Modal.Body>
+ {this.renderOpenLoopMessage()}
+ <div id="editor" />
+ {this.renderPdpGroupDropDown()}
+ </Modal.Body>
+ <Modal.Footer>
+ {this.renderButton()}
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js
new file mode 100644
index 000000000..1e6fac0a0
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { mount } from 'enzyme';
+import PolicyModal from './PolicyModal';
+import LoopCache from '../../../api/LoopCache';
+import LoopService from '../../../api/LoopService';
+import OnapConstant from '../../../utils/OnapConstants';
+import { shallow } from 'enzyme';
+
+describe('Verify PolicyModal', () => {
+ beforeEach(() => {
+ fetch.resetMocks();
+ fetch.mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ text: () => "OK"
+ });
+ });
+ })
+ const loopCacheStr = {
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "operationalPolicies": [{
+ "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca",
+ "configurationsJson": {
+ "operational_policy": {
+ "controlLoop": {},
+ "policies": []
+ }
+ },
+ "policyModel": {"policyPdpGroup": {"supportedPdpGroups":[{"monitoring": ["xacml"]}]}},
+ "jsonRepresentation" : {"schema": {}}
+ }]
+ };
+
+ const loopCache = new LoopCache(loopCacheStr);
+ const historyMock = { push: jest.fn() };
+ const flushPromises = () => new Promise(setImmediate);
+ const match = {params: {policyName:"OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca", policyInstanceType: OnapConstant.operationalPolicyType}}
+
+ it('Test handleClose', () => {
+ const handleClose = jest.spyOn(PolicyModal.prototype,'handleClose');
+ const component = mount(<PolicyModal history={historyMock} match={match} loopCache={loopCache}/>)
+
+ component.find('[variant="secondary"]').prop('onClick')();
+
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test handleSave', async () => {
+ const loadLoopFunction = jest.fn();
+ const handleSave = jest.spyOn(PolicyModal.prototype,'handleSave');
+ const component = mount(<PolicyModal history={historyMock}
+ loopCache={loopCache} match={match} loadLoopFunction={loadLoopFunction} />)
+
+ component.find('[variant="primary"]').get(0).props.onClick();
+ await flushPromises();
+ component.update();
+
+ expect(handleSave).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test handleRefresh', async () => {
+ LoopService.refreshOperationalPolicyJson = jest.fn().mockImplementation(() => {
+ return Promise.resolve(loopCacheStr);
+ });
+ const updateLoopFunction = jest.fn();
+ const handleRefresh = jest.spyOn(PolicyModal.prototype,'handleRefresh');
+ const component = mount(<PolicyModal loopCache={loopCache} match={match} updateLoopFunction={updateLoopFunction} />)
+
+ component.find('[variant="primary"]').get(1).props.onClick();
+ await flushPromises();
+ component.update();
+
+ expect(handleRefresh).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(true);
+ expect(component.state('showSucAlert')).toEqual(true);
+ expect(component.state('showMessage')).toEqual("Successfully refreshed");
+ });
+
+ it('Test handlePdpGroupChange', () => {
+ const component = mount(<PolicyModal loopCache={loopCache} match={match} />)
+ component.setState({
+ "pdpGroup": [{"option1":["subPdp1","subPdp2"]}],
+ "chosenPdpGroup": "option2"
+ });
+ expect(component.state('chosenPdpGroup')).toEqual("option2");
+
+ const instance = component.instance();
+ const event = {label:"option1", value:"option1"}
+ instance.handlePdpGroupChange(event);
+ expect(component.state('chosenPdpGroup')).toEqual("option1");
+ expect(component.state('chosenPdpSubgroup')).toEqual("");
+ expect(component.state('pdpSubgroupList')).toEqual([{label:"subPdp1", value:"subPdp1"}, {label:"subPdp2", value:"subPdp2"}]);
+ });
+
+ it('Test handlePdpSubgroupChange', () => {
+ const component = mount(<PolicyModal loopCache={loopCache} match={match} />)
+
+ const instance = component.instance();
+ const event = {label:"option1", value:"option1"}
+ instance.handlePdpSubgroupChange(event);
+ expect(component.state('chosenPdpSubgroup')).toEqual("option1");
+ });
+
+ it('Test the render method', () => {
+ const component = shallow(<PolicyModal loopCache={loopCache} match={match}/>)
+ expect(component).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js
new file mode 100644
index 000000000..9cd3d4172
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import styled from 'styled-components';
+import Alert from 'react-bootstrap/Alert';
+import { Input, InputLabel, Button , SvgIcon} from "@material-ui/core";
+import PublishIcon from '@material-ui/icons/Publish';
+import PolicyService from '../../../api/PolicyService';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+const StyledMessagesDiv = styled.div`
+ overflow: auto;
+ max-height: 300px;
+`
+
+
+export default class PolicyToscaFileSelector extends React.Component {
+
+ state = {
+ show: this.props.show,
+ alertMessages: [],
+ }
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.onFileChange = this.onFileChange.bind(this);
+ }
+
+ componentDidUpdate(prevProps) {
+ if (this.props.show !== this.state.show) {
+ this.setState({show: this.props.show});
+ }
+ }
+
+ handleClose() {
+ this.props.disableFunction();
+ this.setState({alertMessages:[]});
+ }
+
+ onFileChange(target) {
+ this.setState({alertMessages:[]});
+ target.currentTarget.files.forEach(file => {
+ const fileReader = new FileReader();
+ fileReader.readAsDataURL(file);
+ fileReader.onload = (content) => {
+ PolicyService.sendNewPolicyModel(atob(content.target.result.split(",")[1])).then(respModelCreate => {
+ if (typeof(respModelCreate) === "undefined") {
+ //it indicates a failure
+ this.setState(state => {
+ return {
+ alertMessages: [...state.alertMessages,(<Alert variant="danger"><Alert.Heading>{file.name}</Alert.Heading><p>Policy Tosca Model Creation Failure</p><hr/><p>Type: {file.type}</p><p>Size: {file.size}</p></Alert>)]
+ };
+ });
+ } else {
+ this.props.toscaTableUpdateFunction();
+ this.setState(state => {
+ return {
+ alertMessages: [...state.alertMessages,(<Alert variant="success"><Alert.Heading>{file.name}</Alert.Heading><p>Policy Tosca Model Created Successfully</p><hr/><p>Type: {file.type}</p><p>Size: {file.size}</p></Alert>)]
+ };
+ });
+ }
+ });
+ };
+ });
+
+ }
+
+ render() {
+ return (
+ <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
+ <Modal.Header closeButton>
+ <Modal.Title>Create New Policy Tosca Model</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form.Group as={Row} controlId="formPlaintextEmail">
+ <Col sm="10">
+ <input type="file" multiple accept=".yaml,.yml" id="fileUploadButton" style={{ display: 'none' }} onChange={this.onFileChange} />
+ <label htmlFor={'fileUploadButton'}>
+ <Button color="primary" variant="contained" component="span"
+ startIcon={
+ <SvgIcon fontSize="small">
+ <PublishIcon />
+ </SvgIcon>
+ }>
+ Upload Files
+ </Button>
+ <p>(Only YAML files are supported)</p>
+ </label>
+ <StyledMessagesDiv>
+ {this.state.alertMessages}
+ </StyledMessagesDiv>
+ </Col>
+ </Form.Group>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={this.handleClose}>Close</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+} \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js
new file mode 100644
index 000000000..fa83aa245
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js
@@ -0,0 +1,66 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import PolicyToscaService from '../../../api/PolicyToscaService';
+import styled from 'styled-components';
+import Button from 'react-bootstrap/Button';
+
+const ToscaDiv = styled.div`
+ background-color: ${props => props.theme.toscaTextareaBackgroundColor};
+ text-align: justify;
+ font-size: ${props => props.theme.toscaTextareaFontSize};
+ width: 100%;
+ height: 30%;
+`
+
+export default class ToscaViewer extends React.Component {
+
+ state = {
+ toscaData: this.props.toscaData,
+ yamlPolicyTosca: this.getToscaModelYamlFor(this.props.toscaData),
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this.getToscaModelYamlFor = this.getToscaModelYamlFor.bind(this);
+ }
+
+ getToscaModelYamlFor(toscaData) {
+ PolicyToscaService.getToscaPolicyModelYaml(toscaData["policyModelType"], toscaData["version"]).then(respYamlPolicyTosca => {
+ this.setState({
+ yamlPolicyTosca: respYamlPolicyTosca,
+ })
+ });
+ }
+
+ render() {
+ return (
+ <ToscaDiv>
+ <pre>{this.state.yamlPolicyTosca}</pre>
+ <Button variant="secondary" title="Create a new policy version from the defined parameters"
+ onClick={this.handleCreateNewVersion}>Create New Version</Button>
+ </ToscaDiv>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js
new file mode 100644
index 000000000..cc8c59a03
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import ToscaViewer from './ToscaViewer';
+import { shallow, mount } from 'enzyme';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+
+describe('Verify ToscaViewer', () => {
+ const fs = require('fs');
+
+ let toscaYaml = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.yaml', {encoding:'utf8', flag:'r'})
+
+ const toscaData = {
+ "policyModelType": "onap.policies.controlloop.Guard",
+ "version": "1.0.0",
+ "policyAcronym": "Guard",
+ "createdDate": "2021-04-09T02:29:31.407356Z",
+ "updatedDate": "2021-04-09T02:29:31.407356Z",
+ "updatedBy": "Not found",
+ "createdBy": "Not found",
+ "tableData": {
+ "id": 0
+ }
+ };
+
+ it('Test the render method',async () => {
+ PolicyToscaService.getToscaPolicyModelYaml = jest.fn().mockImplementation(() => {
+ return Promise.resolve(toscaYaml);
+ });
+ const component = shallow(<ToscaViewer toscaData={toscaData}/>);
+ await PolicyToscaService.getToscaPolicyModelYaml();
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js b/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
new file mode 100644
index 000000000..04965352b
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
@@ -0,0 +1,473 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react'
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import AddBox from '@material-ui/icons/AddBox';
+import ArrowDownward from '@material-ui/icons/ArrowDownward';
+import Check from '@material-ui/icons/Check';
+import ChevronLeft from '@material-ui/icons/ChevronLeft';
+import ChevronRight from '@material-ui/icons/ChevronRight';
+import Clear from '@material-ui/icons/Clear';
+import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded';
+import Edit from '@material-ui/icons/Edit';
+import FilterList from '@material-ui/icons/FilterList';
+import FirstPage from '@material-ui/icons/FirstPage';
+import LastPage from '@material-ui/icons/LastPage';
+import Remove from '@material-ui/icons/Remove';
+import SaveAlt from '@material-ui/icons/SaveAlt';
+import Search from '@material-ui/icons/Search';
+import ViewColumn from '@material-ui/icons/ViewColumn';
+import DehazeIcon from '@material-ui/icons/Dehaze';
+import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
+import AddIcon from '@material-ui/icons/Add';
+import PublishIcon from '@material-ui/icons/Publish';
+import Switch from '@material-ui/core/Switch';
+import MaterialTable from "material-table";
+import PolicyService from '../../../api/PolicyService';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+import Select from '@material-ui/core/Select';
+import Alert from 'react-bootstrap/Alert';
+import Tabs from 'react-bootstrap/Tabs';
+import Tab from 'react-bootstrap/Tab';
+import PolicyEditor from './PolicyEditor';
+import ToscaViewer from './ToscaViewer';
+import PolicyDeploymentEditor from './PolicyDeploymentEditor';
+import PoliciesTreeViewer from './PoliciesTreeViewer';
+import PolicyToscaFileSelector from './PolicyToscaFileSelector';
+
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
+const ModalStyled = styled(Modal)`
+ @media (min-width: 800px) {
+ .modal-xl {
+ max-width: 96%;
+ }
+ }
+ background-color: transparent;
+`
+const DetailedRow = styled.div`
+ margin: 0 auto;
+ background-color: ${props => props.theme.policyEditorBackgroundColor};
+ font-size: ${props => props.theme.policyEditorFontSize};
+ width: 97%;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 20px;
+`
+
+const PoliciesTreeViewerDiv = styled.div`
+ width: 20%;
+ float: left;
+ left: 0;
+ overflow: auto;
+`
+
+const MaterialTableDiv = styled.div`
+ float: right;
+ width: 80%;
+ left: 20%;
+`
+
+const standardCellStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' };
+const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
+const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
+export default class ViewAllPolicies extends React.Component {
+ state = {
+ show: true,
+ policiesListData: [],
+ policiesListDataFiltered: [],
+ toscaModelsListData: [],
+ toscaModelsListDataFiltered: [],
+ jsonEditorForPolicy: new Map(),
+ showSuccessAlert: false,
+ showFailAlert: false,
+ showFileSelector: false,
+ policyColumnsDefinition: [
+ {
+ title: "Policy Name", field: "name",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Policy Version", field: "version",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle,
+ },
+ {
+ title: "Policy Type", field: "type",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Policy Type Version", field: "type_version",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Deployable in PDP Group", field: "supportedPdpGroupsString",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Deployed in PDP Group", field: "pdpGroupInfoString",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ }
+ ],
+ toscaColumnsDefinition: [
+ {
+ title: "Policy Model Type", field: "policyModelType",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Policy Acronym", field: "policyAcronym",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Version", field: "version",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Uploaded By", field: "updatedBy",
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ },
+ {
+ title: "Uploaded Date", field: "updatedDate", editable: 'never',
+ cellStyle: standardCellStyle,
+ headerStyle: headerStyle
+ }
+ ],
+ tableIcons: {
+ Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
+ Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
+ Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Delete: forwardRef((props, ref) => <DeleteRoundedIcon {...props} ref={ref} />),
+ DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
+ Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
+ Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
+ FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
+ LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
+ NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
+ ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
+ SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />),
+ ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
+ ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
+ }
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.getAllPolicies = this.getAllPolicies.bind(this);
+ this.getAllToscaModels = this.getAllToscaModels.bind(this);
+ this.generateAdditionalPolicyColumns = this.generateAdditionalPolicyColumns.bind(this);
+ this.filterPolicies = this.filterPolicies.bind(this);
+ this.filterTosca = this.filterTosca.bind(this);
+ this.showFileSelector = this.showFileSelector.bind(this);
+ this.disableFileSelector = this.disableFileSelector.bind(this);
+ this.getAllPolicies();
+ this.getAllToscaModels();
+ }
+
+ generateAdditionalPolicyColumns(policiesData) {
+ policiesData.forEach(policy => {
+ let supportedPdpGroupsString = "";
+ if (typeof policy.supportedPdpGroups !== "undefined") {
+ for (const pdpGroup of policy["supportedPdpGroups"]) {
+ for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
+ supportedPdpGroupsString += (Object.keys(pdpGroup)[0] + "/" + pdpSubGroup + "\r\n");
+ }
+ }
+ policy["supportedPdpGroupsString"] = supportedPdpGroupsString;
+ }
+
+ let infoPdpGroup = "";
+ if (typeof policy.pdpGroupInfo !== "undefined") {
+ policy["pdpGroupInfo"].forEach(pdpGroupElem => {
+ let groupName = Object.keys(pdpGroupElem)[0];
+ pdpGroupElem[groupName]["pdpSubgroups"].forEach(pdpSubGroupElem => {
+ infoPdpGroup += (groupName + "/" + pdpSubGroupElem["pdpType"] + " ("
+ + pdpGroupElem[groupName]["pdpGroupState"] + ")" + "\r\n");
+ });
+ policy["pdpGroupInfoString"] = infoPdpGroup;
+ });
+ }
+ });
+ }
+
+ getAllToscaModels() {
+ PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => {
+ this.setState({ toscaModelsListData: toscaModelsList,
+ toscaModelsListDataFiltered: toscaModelsList
+ });
+ });
+ }
+
+ getAllPolicies() {
+ PolicyService.getPoliciesList().then(allPolicies => {
+ this.generateAdditionalPolicyColumns(allPolicies["policies"])
+ this.setState({ policiesListData: allPolicies["policies"],
+ policiesListDataFiltered: allPolicies["policies"],
+ })
+ });
+
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/')
+ }
+
+ handleDeletePolicy(event, rowData) {
+ PolicyService.deletePolicy(rowData["type"], rowData["type_version"], rowData["name"],rowData["version"]).then(
+ respPolicyDeletion => {
+ if (typeof(respPolicyDeletion) === "undefined") {
+ //it indicates a failure
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Policy Deletion Failure'
+ });
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Policy successfully Deleted'
+ });
+ this.getAllPolicies();
+ }
+ }
+ )
+ }
+
+ disableAlert() {
+ this.setState ({ showSuccessAlert: false, showFailAlert: false });
+ }
+
+ filterPolicies(prefixForFiltering) {
+ this.setState({policiesListDataFiltered: this.state.policiesListData.filter(element => element.name.startsWith(prefixForFiltering))});
+ }
+
+ filterTosca(prefixForFiltering) {
+ this.setState({toscaModelsListDataFiltered: this.state.toscaModelsListData.filter(element => element.policyModelType.startsWith(prefixForFiltering))});
+ }
+
+ showFileSelector() {
+ this.setState({showFileSelector:true});
+ }
+
+ disableFileSelector() {
+ this.setState({showFileSelector:false});
+ }
+
+ renderPoliciesTab() {
+ return (
+ <Tab eventKey="policies" title="Policies in Policy Framework">
+ <Modal.Body>
+ <div>
+ <PoliciesTreeViewerDiv>
+ <PoliciesTreeViewer policiesData={this.state.policiesListData} valueForTreeCreation="name" policiesFilterFunction={this.filterPolicies} />
+ </PoliciesTreeViewerDiv>
+ <MaterialTableDiv>
+ <MaterialTable
+ title={"Policies"}
+ data={this.state.policiesListDataFiltered}
+ columns={this.state.policyColumnsDefinition}
+ icons={this.state.tableIcons}
+ onRowClick={(event, rowData, togglePanel) => togglePanel()}
+ options={{
+ grouping: true,
+ exportButton: true,
+ headerStyle:rowHeaderStyle,
+ actionsColumnIndex: -1
+ }}
+ detailPanel={[
+ {
+ icon: ArrowForwardIosIcon,
+ tooltip: 'Show Configuration',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <PolicyEditor policyModelType={rowData["type"]} policyModelTypeVersion={rowData["type_version"]}
+ policyName={rowData["name"]} policyVersion={rowData["version"]} policyProperties={rowData["properties"]}
+ policiesTableUpdateFunction={this.getAllPolicies} />
+ </DetailedRow>
+ )
+ },
+ },
+ {
+ icon: DehazeIcon,
+ openIcon: DehazeIcon,
+ tooltip: 'Show Raw Data',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <pre>{JSON.stringify(rowData, null, 2)}</pre>
+ </DetailedRow>
+ )
+ },
+ },
+ {
+ icon: PublishIcon,
+ openIcon: PublishIcon,
+ tooltip: 'PDP Group Deployment',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <PolicyDeploymentEditor policyData={rowData} policiesTableUpdateFunction={this.getAllPolicies} />
+ </DetailedRow>
+ )
+ },
+ }
+ ]}
+ actions={[
+ {
+ icon: DeleteRoundedIcon,
+ tooltip: 'Delete Policy',
+ onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
+ }
+ ]}
+ />
+ </MaterialTableDiv>
+ </div>
+ </Modal.Body>
+ </Tab>
+ );
+ }
+
+ renderToscaTab() {
+ return (
+ <Tab eventKey="tosca models" title="Tosca Models in Policy Framework">
+ <Modal.Body>
+ <div>
+ <PoliciesTreeViewerDiv>
+ <PoliciesTreeViewer policiesData={this.state.toscaModelsListData} valueForTreeCreation="policyModelType" policiesFilterFunction={this.filterTosca} />
+ </PoliciesTreeViewerDiv>
+ <MaterialTableDiv>
+ <MaterialTable
+ title={"Tosca Models"}
+ data={this.state.toscaModelsListDataFiltered}
+ columns={this.state.toscaColumnsDefinition}
+ icons={this.state.tableIcons}
+ onRowClick={(event, rowData, togglePanel) => togglePanel()}
+ options={{
+ grouping: true,
+ exportButton: true,
+ headerStyle:rowHeaderStyle,
+ actionsColumnIndex: -1
+ }}
+ actions={[
+ {
+ icon: AddIcon,
+ tooltip: 'Add New Tosca Model',
+ isFreeAction: true,
+ onClick: () => this.showFileSelector()
+ }
+ ]}
+ detailPanel={[
+ {
+ icon: ArrowForwardIosIcon,
+ tooltip: 'Show Tosca',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <ToscaViewer toscaData={rowData} />
+ </DetailedRow>
+ )
+ },
+ },
+ {
+ icon: DehazeIcon,
+ openIcon: DehazeIcon,
+ tooltip: 'Show Raw Data',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <pre>{JSON.stringify(rowData, null, 2)}</pre>
+ </DetailedRow>
+ )
+ },
+ },
+ {
+ icon: AddIcon,
+ openIcon: AddIcon,
+ tooltip: 'Create a policy from this model',
+ render: rowData => {
+ return (
+ <DetailedRow>
+ <PolicyEditor policyModelType={rowData["policyModelType"]} policyModelTypeVersion={rowData["version"]} policyProperties={{}} policiesTableUpdateFunction={this.getAllPolicies} />
+ </DetailedRow>
+ )
+ },
+ },
+ ]}
+ />
+ </MaterialTableDiv>
+ </div>
+ </Modal.Body>
+ </Tab>
+ );
+ }
+
+ render() {
+ return (
+ <React.Fragment>
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}>
+ <Modal.Header closeButton>
+ </Modal.Header>
+ <Tabs id="controlled-tab-example" activeKey={this.state.key} onSelect={key => this.setState({ key, selectedRowData: {} })}>
+ {this.renderPoliciesTab()}
+ {this.renderToscaTab()}
+ </Tabs>
+ <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
+ <DivWhiteSpaceStyled>
+ {this.state.showMessage}
+ </DivWhiteSpaceStyled>
+ </Alert>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={this.handleClose}>Close</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ <PolicyToscaFileSelector show={this.state.showFileSelector} disableFunction={this.disableFileSelector} toscaTableUpdateFunction={this.getAllToscaModels}/>
+ </React.Fragment>
+ );
+ }
+ } \ No newline at end of file
diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap
new file mode 100644
index 000000000..959b52a36
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap
@@ -0,0 +1,788 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify PolicyEditor Test the render method 1`] = `
+<PolicyEditor
+ policiesTableUpdateFunction={[Function]}
+ policyModelType="onap.policies.monitoring.tcagen2"
+ policyModelTypeVersion="1.0.0"
+ policyName="org.onap.new"
+ policyProperties={
+ Object {
+ "tca.policy": Object {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": Array [
+ Object {
+ "controlLoopSchemaType": "VM",
+ "eventName": "vLoadBalancer",
+ "policyName": "DCAE.Config_tca-hi-lo",
+ "policyScope": "DCAE",
+ "policyVersion": "v0.0.1",
+ "thresholds": Array [
+ Object {
+ "closedLoopControlName": "LOOP_test",
+ "closedLoopEventStatus": "ONSET",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "version": "1.0.2",
+ },
+ ],
+ },
+ ],
+ },
+ }
+ }
+ policyVersion="1.0.0"
+>
+ <styled.div>
+ <div
+ className="sc-dlfnbm iSTbVM"
+ >
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="success"
+ >
+ <Fade
+ appear={false}
+ in={false}
+ mountOnEnter={false}
+ timeout={300}
+ unmountOnExit={true}
+ >
+ <Transition
+ addEndListener={[Function]}
+ appear={false}
+ enter={true}
+ exit={true}
+ in={false}
+ mountOnEnter={false}
+ onEnter={[Function]}
+ onEntered={[Function]}
+ onEntering={[Function]}
+ onExit={[Function]}
+ onExited={[Function]}
+ onExiting={[Function]}
+ timeout={300}
+ unmountOnExit={true}
+ />
+ </Fade>
+ </Alert>
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="danger"
+ >
+ <Fade
+ appear={false}
+ in={false}
+ mountOnEnter={false}
+ timeout={300}
+ unmountOnExit={true}
+ >
+ <Transition
+ addEndListener={[Function]}
+ appear={false}
+ enter={true}
+ exit={true}
+ in={false}
+ mountOnEnter={false}
+ onEnter={[Function]}
+ onEntered={[Function]}
+ onEntering={[Function]}
+ onExit={[Function]}
+ onExited={[Function]}
+ onExiting={[Function]}
+ timeout={300}
+ unmountOnExit={true}
+ />
+ </Fade>
+ </Alert>
+ <WithStyles(ForwardRef(TextField))
+ defaultValue="org.onap.new"
+ id="policyName"
+ label="Required"
+ onChange={[Function]}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <ForwardRef(TextField)
+ classes={
+ Object {
+ "root": "MuiTextField-root",
+ }
+ }
+ defaultValue="org.onap.new"
+ id="policyName"
+ label="Required"
+ onChange={[Function]}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <WithStyles(ForwardRef(FormControl))
+ className="MuiTextField-root"
+ color="primary"
+ disabled={false}
+ error={false}
+ fullWidth={false}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <ForwardRef(FormControl)
+ className="MuiTextField-root"
+ classes={
+ Object {
+ "fullWidth": "MuiFormControl-fullWidth",
+ "marginDense": "MuiFormControl-marginDense",
+ "marginNormal": "MuiFormControl-marginNormal",
+ "root": "MuiFormControl-root",
+ }
+ }
+ color="primary"
+ disabled={false}
+ error={false}
+ fullWidth={false}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <div
+ className="MuiFormControl-root MuiTextField-root"
+ >
+ <WithStyles(ForwardRef(InputLabel))
+ htmlFor="policyName"
+ id="policyName-label"
+ >
+ <ForwardRef(InputLabel)
+ classes={
+ Object {
+ "animated": "MuiInputLabel-animated",
+ "asterisk": "MuiInputLabel-asterisk",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "filled": "MuiInputLabel-filled",
+ "focused": "Mui-focused",
+ "formControl": "MuiInputLabel-formControl",
+ "marginDense": "MuiInputLabel-marginDense",
+ "outlined": "MuiInputLabel-outlined",
+ "required": "Mui-required",
+ "root": "MuiInputLabel-root",
+ "shrink": "MuiInputLabel-shrink",
+ }
+ }
+ htmlFor="policyName"
+ id="policyName-label"
+ >
+ <WithStyles(ForwardRef(FormLabel))
+ className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined"
+ classes={
+ Object {
+ "asterisk": "MuiInputLabel-asterisk",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "required": "Mui-required",
+ }
+ }
+ data-shrink={true}
+ htmlFor="policyName"
+ id="policyName-label"
+ >
+ <ForwardRef(FormLabel)
+ className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined"
+ classes={
+ Object {
+ "asterisk": "MuiFormLabel-asterisk MuiInputLabel-asterisk",
+ "colorSecondary": "MuiFormLabel-colorSecondary",
+ "disabled": "Mui-disabled Mui-disabled",
+ "error": "Mui-error Mui-error",
+ "filled": "MuiFormLabel-filled",
+ "focused": "Mui-focused Mui-focused",
+ "required": "Mui-required Mui-required",
+ "root": "MuiFormLabel-root",
+ }
+ }
+ data-shrink={true}
+ htmlFor="policyName"
+ id="policyName-label"
+ >
+ <label
+ className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required"
+ data-shrink={true}
+ htmlFor="policyName"
+ id="policyName-label"
+ >
+ Required
+ <span
+ aria-hidden={true}
+ className="MuiFormLabel-asterisk MuiInputLabel-asterisk"
+ >
+  
+ *
+ </span>
+ </label>
+ </ForwardRef(FormLabel)>
+ </WithStyles(ForwardRef(FormLabel))>
+ </ForwardRef(InputLabel)>
+ </WithStyles(ForwardRef(InputLabel))>
+ <WithStyles(ForwardRef(OutlinedInput))
+ autoFocus={false}
+ defaultValue="org.onap.new"
+ fullWidth={false}
+ id="policyName"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ multiline={false}
+ onChange={[Function]}
+ >
+ <ForwardRef(OutlinedInput)
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "input": "MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart",
+ "inputMarginDense": "MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiOutlinedInput-inputMultiline",
+ "marginDense": "MuiOutlinedInput-marginDense",
+ "multiline": "MuiOutlinedInput-multiline",
+ "notchedOutline": "MuiOutlinedInput-notchedOutline",
+ "root": "MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="org.onap.new"
+ fullWidth={false}
+ id="policyName"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ multiline={false}
+ onChange={[Function]}
+ >
+ <WithStyles(ForwardRef(InputBase))
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "input": "MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart",
+ "inputMarginDense": "MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiOutlinedInput-inputMultiline",
+ "marginDense": "MuiOutlinedInput-marginDense",
+ "multiline": "MuiOutlinedInput-multiline",
+ "notchedOutline": null,
+ "root": "MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="org.onap.new"
+ fullWidth={false}
+ id="policyName"
+ inputComponent="input"
+ multiline={false}
+ onChange={[Function]}
+ renderSuffix={[Function]}
+ type="text"
+ >
+ <ForwardRef(InputBase)
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiInputBase-adornedEnd MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiInputBase-adornedStart MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiInputBase-colorSecondary MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled Mui-disabled",
+ "error": "Mui-error Mui-error",
+ "focused": "Mui-focused Mui-focused",
+ "formControl": "MuiInputBase-formControl",
+ "fullWidth": "MuiInputBase-fullWidth",
+ "input": "MuiInputBase-input MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiInputBase-inputAdornedEnd MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiInputBase-inputAdornedStart MuiOutlinedInput-inputAdornedStart",
+ "inputHiddenLabel": "MuiInputBase-inputHiddenLabel",
+ "inputMarginDense": "MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiInputBase-inputMultiline MuiOutlinedInput-inputMultiline",
+ "inputTypeSearch": "MuiInputBase-inputTypeSearch",
+ "marginDense": "MuiInputBase-marginDense MuiOutlinedInput-marginDense",
+ "multiline": "MuiInputBase-multiline MuiOutlinedInput-multiline",
+ "root": "MuiInputBase-root MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="org.onap.new"
+ fullWidth={false}
+ id="policyName"
+ inputComponent="input"
+ multiline={false}
+ onChange={[Function]}
+ renderSuffix={[Function]}
+ type="text"
+ >
+ <div
+ className="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-formControl MuiInputBase-marginDense MuiOutlinedInput-marginDense"
+ onClick={[Function]}
+ >
+ <input
+ aria-invalid={false}
+ autoFocus={false}
+ className="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense"
+ defaultValue="org.onap.new"
+ disabled={false}
+ id="policyName"
+ onAnimationStart={[Function]}
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ required={true}
+ type="text"
+ />
+ <WithStyles(ForwardRef(NotchedOutline))
+ className="MuiOutlinedInput-notchedOutline"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ labelWidth={0}
+ notched={true}
+ >
+ <ForwardRef(NotchedOutline)
+ className="MuiOutlinedInput-notchedOutline"
+ classes={
+ Object {
+ "legend": "PrivateNotchedOutline-legend-2",
+ "legendLabelled": "PrivateNotchedOutline-legendLabelled-3",
+ "legendNotched": "PrivateNotchedOutline-legendNotched-4",
+ "root": "PrivateNotchedOutline-root-1",
+ }
+ }
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ labelWidth={0}
+ notched={true}
+ >
+ <fieldset
+ aria-hidden={true}
+ className="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline"
+ >
+ <legend
+ className="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4"
+ >
+ <span>
+ Required
+  *
+ </span>
+ </legend>
+ </fieldset>
+ </ForwardRef(NotchedOutline)>
+ </WithStyles(ForwardRef(NotchedOutline))>
+ </div>
+ </ForwardRef(InputBase)>
+ </WithStyles(ForwardRef(InputBase))>
+ </ForwardRef(OutlinedInput)>
+ </WithStyles(ForwardRef(OutlinedInput))>
+ </div>
+ </ForwardRef(FormControl)>
+ </WithStyles(ForwardRef(FormControl))>
+ </ForwardRef(TextField)>
+ </WithStyles(ForwardRef(TextField))>
+ <WithStyles(ForwardRef(TextField))
+ defaultValue="1.0.0"
+ id="policyVersion"
+ label="Required"
+ onChange={[Function]}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <ForwardRef(TextField)
+ classes={
+ Object {
+ "root": "MuiTextField-root",
+ }
+ }
+ defaultValue="1.0.0"
+ id="policyVersion"
+ label="Required"
+ onChange={[Function]}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <WithStyles(ForwardRef(FormControl))
+ className="MuiTextField-root"
+ color="primary"
+ disabled={false}
+ error={false}
+ fullWidth={false}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <ForwardRef(FormControl)
+ className="MuiTextField-root"
+ classes={
+ Object {
+ "fullWidth": "MuiFormControl-fullWidth",
+ "marginDense": "MuiFormControl-marginDense",
+ "marginNormal": "MuiFormControl-marginNormal",
+ "root": "MuiFormControl-root",
+ }
+ }
+ color="primary"
+ disabled={false}
+ error={false}
+ fullWidth={false}
+ required={true}
+ size="small"
+ variant="outlined"
+ >
+ <div
+ className="MuiFormControl-root MuiTextField-root"
+ >
+ <WithStyles(ForwardRef(InputLabel))
+ htmlFor="policyVersion"
+ id="policyVersion-label"
+ >
+ <ForwardRef(InputLabel)
+ classes={
+ Object {
+ "animated": "MuiInputLabel-animated",
+ "asterisk": "MuiInputLabel-asterisk",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "filled": "MuiInputLabel-filled",
+ "focused": "Mui-focused",
+ "formControl": "MuiInputLabel-formControl",
+ "marginDense": "MuiInputLabel-marginDense",
+ "outlined": "MuiInputLabel-outlined",
+ "required": "Mui-required",
+ "root": "MuiInputLabel-root",
+ "shrink": "MuiInputLabel-shrink",
+ }
+ }
+ htmlFor="policyVersion"
+ id="policyVersion-label"
+ >
+ <WithStyles(ForwardRef(FormLabel))
+ className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined"
+ classes={
+ Object {
+ "asterisk": "MuiInputLabel-asterisk",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "required": "Mui-required",
+ }
+ }
+ data-shrink={true}
+ htmlFor="policyVersion"
+ id="policyVersion-label"
+ >
+ <ForwardRef(FormLabel)
+ className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined"
+ classes={
+ Object {
+ "asterisk": "MuiFormLabel-asterisk MuiInputLabel-asterisk",
+ "colorSecondary": "MuiFormLabel-colorSecondary",
+ "disabled": "Mui-disabled Mui-disabled",
+ "error": "Mui-error Mui-error",
+ "filled": "MuiFormLabel-filled",
+ "focused": "Mui-focused Mui-focused",
+ "required": "Mui-required Mui-required",
+ "root": "MuiFormLabel-root",
+ }
+ }
+ data-shrink={true}
+ htmlFor="policyVersion"
+ id="policyVersion-label"
+ >
+ <label
+ className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required"
+ data-shrink={true}
+ htmlFor="policyVersion"
+ id="policyVersion-label"
+ >
+ Required
+ <span
+ aria-hidden={true}
+ className="MuiFormLabel-asterisk MuiInputLabel-asterisk"
+ >
+  
+ *
+ </span>
+ </label>
+ </ForwardRef(FormLabel)>
+ </WithStyles(ForwardRef(FormLabel))>
+ </ForwardRef(InputLabel)>
+ </WithStyles(ForwardRef(InputLabel))>
+ <WithStyles(ForwardRef(OutlinedInput))
+ autoFocus={false}
+ defaultValue="1.0.0"
+ fullWidth={false}
+ id="policyVersion"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ multiline={false}
+ onChange={[Function]}
+ >
+ <ForwardRef(OutlinedInput)
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "input": "MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart",
+ "inputMarginDense": "MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiOutlinedInput-inputMultiline",
+ "marginDense": "MuiOutlinedInput-marginDense",
+ "multiline": "MuiOutlinedInput-multiline",
+ "notchedOutline": "MuiOutlinedInput-notchedOutline",
+ "root": "MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="1.0.0"
+ fullWidth={false}
+ id="policyVersion"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ multiline={false}
+ onChange={[Function]}
+ >
+ <WithStyles(ForwardRef(InputBase))
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled",
+ "error": "Mui-error",
+ "focused": "Mui-focused",
+ "input": "MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart",
+ "inputMarginDense": "MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiOutlinedInput-inputMultiline",
+ "marginDense": "MuiOutlinedInput-marginDense",
+ "multiline": "MuiOutlinedInput-multiline",
+ "notchedOutline": null,
+ "root": "MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="1.0.0"
+ fullWidth={false}
+ id="policyVersion"
+ inputComponent="input"
+ multiline={false}
+ onChange={[Function]}
+ renderSuffix={[Function]}
+ type="text"
+ >
+ <ForwardRef(InputBase)
+ autoFocus={false}
+ classes={
+ Object {
+ "adornedEnd": "MuiInputBase-adornedEnd MuiOutlinedInput-adornedEnd",
+ "adornedStart": "MuiInputBase-adornedStart MuiOutlinedInput-adornedStart",
+ "colorSecondary": "MuiInputBase-colorSecondary MuiOutlinedInput-colorSecondary",
+ "disabled": "Mui-disabled Mui-disabled",
+ "error": "Mui-error Mui-error",
+ "focused": "Mui-focused Mui-focused",
+ "formControl": "MuiInputBase-formControl",
+ "fullWidth": "MuiInputBase-fullWidth",
+ "input": "MuiInputBase-input MuiOutlinedInput-input",
+ "inputAdornedEnd": "MuiInputBase-inputAdornedEnd MuiOutlinedInput-inputAdornedEnd",
+ "inputAdornedStart": "MuiInputBase-inputAdornedStart MuiOutlinedInput-inputAdornedStart",
+ "inputHiddenLabel": "MuiInputBase-inputHiddenLabel",
+ "inputMarginDense": "MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense",
+ "inputMultiline": "MuiInputBase-inputMultiline MuiOutlinedInput-inputMultiline",
+ "inputTypeSearch": "MuiInputBase-inputTypeSearch",
+ "marginDense": "MuiInputBase-marginDense MuiOutlinedInput-marginDense",
+ "multiline": "MuiInputBase-multiline MuiOutlinedInput-multiline",
+ "root": "MuiInputBase-root MuiOutlinedInput-root",
+ }
+ }
+ defaultValue="1.0.0"
+ fullWidth={false}
+ id="policyVersion"
+ inputComponent="input"
+ multiline={false}
+ onChange={[Function]}
+ renderSuffix={[Function]}
+ type="text"
+ >
+ <div
+ className="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-formControl MuiInputBase-marginDense MuiOutlinedInput-marginDense"
+ onClick={[Function]}
+ >
+ <input
+ aria-invalid={false}
+ autoFocus={false}
+ className="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense"
+ defaultValue="1.0.0"
+ disabled={false}
+ id="policyVersion"
+ onAnimationStart={[Function]}
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ required={true}
+ type="text"
+ />
+ <WithStyles(ForwardRef(NotchedOutline))
+ className="MuiOutlinedInput-notchedOutline"
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ labelWidth={0}
+ notched={true}
+ >
+ <ForwardRef(NotchedOutline)
+ className="MuiOutlinedInput-notchedOutline"
+ classes={
+ Object {
+ "legend": "PrivateNotchedOutline-legend-2",
+ "legendLabelled": "PrivateNotchedOutline-legendLabelled-3",
+ "legendNotched": "PrivateNotchedOutline-legendNotched-4",
+ "root": "PrivateNotchedOutline-root-1",
+ }
+ }
+ label={
+ <React.Fragment>
+ Required
+  *
+ </React.Fragment>
+ }
+ labelWidth={0}
+ notched={true}
+ >
+ <fieldset
+ aria-hidden={true}
+ className="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline"
+ >
+ <legend
+ className="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4"
+ >
+ <span>
+ Required
+  *
+ </span>
+ </legend>
+ </fieldset>
+ </ForwardRef(NotchedOutline)>
+ </WithStyles(ForwardRef(NotchedOutline))>
+ </div>
+ </ForwardRef(InputBase)>
+ </WithStyles(ForwardRef(InputBase))>
+ </ForwardRef(OutlinedInput)>
+ </WithStyles(ForwardRef(OutlinedInput))>
+ </div>
+ </ForwardRef(FormControl)>
+ </WithStyles(ForwardRef(FormControl))>
+ </ForwardRef(TextField)>
+ </WithStyles(ForwardRef(TextField))>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ title="Create a new policy version from the defined parameters"
+ variant="secondary"
+ >
+ <button
+ className="btn btn-secondary"
+ disabled={false}
+ onClick={[Function]}
+ title="Create a new policy version from the defined parameters"
+ type="button"
+ >
+ Create New Version
+ </button>
+ </Button>
+ <styled.div
+ id="onap.policies.monitoring.tcagen2_1.0.0_org.onap.new_1.0.0"
+ title="Policy Properties"
+ >
+ <div
+ className="sc-gsTCUz dAYWPx"
+ id="onap.policies.monitoring.tcagen2_1.0.0_org.onap.new_1.0.0"
+ title="Policy Properties"
+ />
+ </styled.div>
+ </div>
+ </styled.div>
+</PolicyEditor>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap
new file mode 100644
index 000000000..8b1261b1c
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap
@@ -0,0 +1,159 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify PolicyModal Test the render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="xl"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ Edit the policy
+ </ModalTitle>
+ </ModalHeader>
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="success"
+ >
+ <styled.div />
+ </Alert>
+ <Alert
+ closeLabel="Close alert"
+ dismissible={true}
+ onClose={[Function]}
+ show={false}
+ transition={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "appear": false,
+ "in": false,
+ "mountOnEnter": false,
+ "timeout": 300,
+ "unmountOnExit": false,
+ },
+ "render": [Function],
+ }
+ }
+ variant="danger"
+ >
+ <styled.div />
+ </Alert>
+ <ModalBody>
+ <div
+ id="editor"
+ />
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="formPlaintextEmail"
+ >
+ <FormLabel
+ column={true}
+ sm="2"
+ srOnly={false}
+ >
+ Pdp Group Info
+ </FormLabel>
+ <Col
+ sm="3"
+ >
+ <StateManager
+ defaultInputValue=""
+ defaultMenuIsOpen={false}
+ defaultValue={null}
+ onChange={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "monitoring",
+ "value": "monitoring",
+ },
+ ]
+ }
+ value={
+ Object {
+ "label": undefined,
+ "value": undefined,
+ }
+ }
+ />
+ </Col>
+ <Col
+ sm="3"
+ >
+ <StateManager
+ defaultInputValue=""
+ defaultMenuIsOpen={false}
+ defaultValue={null}
+ onChange={[Function]}
+ options={Array []}
+ value={
+ Object {
+ "label": undefined,
+ "value": undefined,
+ }
+ }
+ />
+ </Col>
+ </FormGroup>
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ key="close"
+ onClick={[Function]}
+ variant="secondary"
+ >
+ Close
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ key="save"
+ onClick={[Function]}
+ variant="primary"
+ >
+ Save Changes
+ </Button>
+ <Button
+ active={false}
+ disabled={false}
+ key="refresh"
+ onClick={[Function]}
+ variant="primary"
+ >
+ Refresh
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap
new file mode 100644
index 000000000..61fb4850d
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify ToscaViewer Test the render method 1`] = `
+<styled.div>
+ <pre>
+ tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.Guard:
+ properties: {
+ }
+ name: onap.policies.controlloop.Guard
+ version: 1.0.0
+ derived_from: tosca.policies.Root
+ metadata: {
+ }
+ description: Guard Policies for Control Loop Operational Policies
+name: ToscaServiceTemplateSimple
+version: 1.0.0
+
+ </pre>
+ <Button
+ active={false}
+ disabled={false}
+ title="Create a new policy version from the defined parameters"
+ variant="secondary"
+ >
+ Create New Version
+ </Button>
+</styled.div>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json
new file mode 100644
index 000000000..3b001b384
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json
@@ -0,0 +1,179 @@
+{
+ "title": "onap.policies.monitoring.tcagen2",
+ "type": "object",
+ "required": [
+ "tca.policy"
+ ],
+ "properties": {
+ "tca.policy": {
+ "title": "onap.datatypes.monitoring.tca_policy",
+ "type": "object",
+ "required": [
+ "domain",
+ "metricsPerEventName"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string",
+ "description": "Domain name to which TCA needs to be applied",
+ "default": "measurementsForVfScaling",
+ "const": "measurementsForVfScaling"
+ },
+ "metricsPerEventName": {
+ "type": "array",
+ "description": "Contains eventName and threshold details that need to be applied to given eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.metricsPerEventName",
+ "type": "object",
+ "required": [
+ "controlLoopSchemaType",
+ "eventName",
+ "policyName",
+ "policyScope",
+ "policyVersion",
+ "thresholds"
+ ],
+ "properties": {
+ "controlLoopSchemaType": {
+ "type": "string",
+ "description": "Specifies Control Loop Schema Type for the event Name e.g. VNF, VM",
+ "enum": [
+ "VM",
+ "VNF"
+ ]
+ },
+ "eventName": {
+ "type": "string",
+ "description": "Event name to which thresholds need to be applied"
+ },
+ "policyName": {
+ "type": "string",
+ "description": "TCA Policy Scope Name"
+ },
+ "policyScope": {
+ "type": "string",
+ "description": "TCA Policy Scope"
+ },
+ "policyVersion": {
+ "type": "string",
+ "description": "TCA Policy Scope Version"
+ },
+ "thresholds": {
+ "type": "array",
+ "description": "Thresholds associated with eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.thresholds",
+ "type": "object",
+ "required": [
+ "closedLoopControlName",
+ "closedLoopEventStatus",
+ "direction",
+ "fieldPath",
+ "severity",
+ "thresholdValue",
+ "version"
+ ],
+ "properties": {
+ "closedLoopControlName": {
+ "type": "string",
+ "description": "Closed Loop Control Name associated with the threshold"
+ },
+ "closedLoopEventStatus": {
+ "type": "string",
+ "description": "Closed Loop Event Status of the threshold",
+ "enum": [
+ "ONSET",
+ "ABATED"
+ ]
+ },
+ "direction": {
+ "type": "string",
+ "description": "Direction of the threshold",
+ "enum": [
+ "LESS",
+ "LESS_OR_EQUAL",
+ "GREATER",
+ "GREATER_OR_EQUAL",
+ "EQUAL"
+ ]
+ },
+ "fieldPath": {
+ "type": "string",
+ "description": "Json field Path as per CEF message which needs to be analyzed for TCA",
+ "enum": [
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage",
+ "$.event.measurementsForVfScalingFields.meanRequestLatency",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed",
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value"
+ ]
+ },
+ "severity": {
+ "type": "string",
+ "description": "Threshold Event Severity",
+ "enum": [
+ "CRITICAL",
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "NORMAL"
+ ]
+ },
+ "thresholdValue": {
+ "type": "integer",
+ "description": "Threshold value for the field Path inside CEF message"
+ },
+ "version": {
+ "type": "string",
+ "description": "Version number associated with the threshold"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ }
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml
new file mode 100644
index 000000000..15a3cec35
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml
@@ -0,0 +1,13 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.Guard:
+ properties: {
+ }
+ name: onap.policies.controlloop.Guard
+ version: 1.0.0
+ derived_from: tosca.policies.Root
+ metadata: {
+ }
+ description: Guard Policies for Control Loop Operational Policies
+name: ToscaServiceTemplateSimple
+version: 1.0.0
diff --git a/runtime/ui-react/src/components/dialogs/RefreshStatus.js b/runtime/ui-react/src/components/dialogs/RefreshStatus.js
new file mode 100644
index 000000000..bb0939152
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/RefreshStatus.js
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import LoopActionService from '../../api/LoopActionService';
+import Spinner from 'react-bootstrap/Spinner';
+import styled from 'styled-components';
+
+const StyledSpinnerDiv = styled.div`
+ justify-content: center !important;
+ display: flex !important;
+`;
+
+export default class RefreshStatus extends React.Component {
+ state = {
+ loopName: this.props.loopCache.getLoopName()
+ };
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopName: newProps.loopCache.getLoopName()
+ });
+ }
+
+ componentDidMount() {
+ // refresh status and update loop logs
+ LoopActionService.refreshStatus(this.state.loopName).then(data => {
+ this.props.showSucAlert("Status successfully refreshed");
+ this.props.updateLoopFunction(data);
+ this.props.history.push('/');
+ })
+ .catch(error => {
+ this.props.showFailAlert("Status refreshing failed");
+ this.props.history.push('/');
+ });
+ }
+
+ render() {
+ return (
+ <StyledSpinnerDiv>
+ <Spinner animation="border" role="status">
+ </Spinner>
+ </StyledSpinnerDiv>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/RefreshStatus.test.js b/runtime/ui-react/src/components/dialogs/RefreshStatus.test.js
new file mode 100644
index 000000000..e08c50d2e
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/RefreshStatus.test.js
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import RefreshStatus from './RefreshStatus';
+import LoopCache from '../../api/LoopCache';
+import LoopActionService from '../../api/LoopActionService';
+
+describe('Verify RefreshStatus', () => {
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca"
+ });
+
+ it('Test refresh status failed', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const showSucAlert = jest.fn();
+ const showFailAlert = jest.fn();
+
+ const component = shallow(<RefreshStatus loopCache={loopCache} history={historyMock} showSucAlert={showSucAlert} showFailAlert={showFailAlert} />)
+ await flushPromises();
+ component.update();
+
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+ it('Test refresh status successful', async () => {
+ const flushPromises = () => new Promise(setImmediate);
+ const historyMock = { push: jest.fn() };
+ const updateLoopFunction = jest.fn();
+ const showSucAlert = jest.fn();
+ const showFailAlert = jest.fn();
+
+ LoopActionService.refreshStatus = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {}
+ });
+ });
+
+ const component = shallow(<RefreshStatus loopCache={loopCache}
+ loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} />)
+ await flushPromises();
+ component.update();
+
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ });
+
+});
diff --git a/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js b/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js
new file mode 100644
index 000000000..4796b8d73
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js
@@ -0,0 +1,163 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react'
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import TemplateService from '../../../api/TemplateService';
+import ArrowUpward from '@material-ui/icons/ArrowUpward';
+import ChevronLeft from '@material-ui/icons/ChevronLeft';
+import ChevronRight from '@material-ui/icons/ChevronRight';
+import Clear from '@material-ui/icons/Clear';
+import FirstPage from '@material-ui/icons/FirstPage';
+import LastPage from '@material-ui/icons/LastPage';
+import Search from '@material-ui/icons/Search';
+import MaterialTable from "material-table";
+import LoopCache from '../../../api/LoopCache';
+import SvgGenerator from '../../loop_viewer/svg/SvgGenerator';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+const cellStyle = { border: '1px solid black' };
+const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
+const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
+export default class ViewLoopTemplatesModal extends React.Component {
+ state = {
+ show: true,
+ content: 'Please select a loop template to display it',
+ selectedRow: -1,
+ loopTemplatesData: [],
+ fakeLoopCacheWithTemplate: new LoopCache({}),
+ loopTemplateColumnsDefinition: [
+ { title: "#", field: "index", render: rowData => rowData.tableData.id + 1,
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Template Name", field: "name",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Service Model Name", field: "modelService.serviceDetails.name",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Loop Type Allowed", field: "allowedLoopType",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "# Instances Allowed", field: "maximumInstancesAllowed",
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ },
+ { title: "Modified Date", field: "updatedDate", editable: 'never',
+ cellStyle: cellStyle,
+ headerStyle: headerStyle
+ }
+ ],
+ tableIcons: {
+ FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
+ LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
+ NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
+ PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
+ ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
+ Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
+ SortArrow: forwardRef((props, ref) => <ArrowUpward {...props} ref={ref} />)
+ }
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ this.getLoopTemplate = this.getLoopTemplate.bind(this);
+ this.getAllLoopTemplates();
+ }
+
+ getAllLoopTemplates() {
+ TemplateService.getAllLoopTemplates().then(templatesData => {
+ // replace -1 in maximumInstancesAllowed with more meaningful 'No Limit'
+ for (let item in templatesData) {
+ if (templatesData[item].maximumInstancesAllowed === -1) {
+ templatesData[item].maximumInstancesAllowed = 'No Limit';
+ }
+ }
+ this.setState({ loopTemplatesData: templatesData })
+ });
+ }
+
+ getLoopTemplate(templateIdInDataArray) {
+ if (typeof templateIdInDataArray !== "undefined") {
+ this.setState({ fakeLoopCacheWithTemplate:
+ new LoopCache({
+ "loopTemplate":this.state.loopTemplatesData[templateIdInDataArray],
+ "name": "fakeLoop"
+ })
+ })
+ } else {
+ this.setState({ fakeLoopCacheWithTemplate: new LoopCache({}) })
+ }
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+ this.props.history.push('/')
+ }
+
+ renderSvg() {
+ return(
+ <SvgGenerator loopCache={this.state.fakeLoopCacheWithTemplate} clickable={false} generatedFrom={SvgGenerator.GENERATED_FROM_TEMPLATE}/>
+ )
+ }
+
+ render() {
+ return (
+ <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}>
+ <Modal.Header closeButton>
+ </Modal.Header>
+ <Modal.Body>
+ <MaterialTable
+ title={"View Blueprint MicroService Templates"}
+ data={this.state.loopTemplatesData}
+ columns={this.state.loopTemplateColumnsDefinition}
+ icons={this.state.tableIcons}
+ onRowClick={(event, rowData) => {this.getLoopTemplate(rowData.tableData.id);this.setState({selectedRow: rowData.tableData.id})}}
+ options={{
+ headerStyle:rowHeaderStyle,
+ rowStyle: rowData => ({
+ backgroundColor: (this.state.selectedRow !== -1 && this.state.selectedRow === rowData.tableData.id) ? '#EEE' : '#FFF'
+ })
+ }}
+ />
+ {this.renderSvg()}
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" onClick={this.handleClose}>Close</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+ }
diff --git a/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.test.js b/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.test.js
new file mode 100644
index 000000000..7680ec4b9
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.test.js
@@ -0,0 +1,162 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import ViewLoopTemplatesModal from './ViewLoopTemplatesModal';
+import { mount } from 'enzyme';
+import { BrowserRouter as Router } from 'react-router-dom';
+
+describe('Verify ViewLoopTemplatesModal', () => {
+ beforeEach(() => {
+ fetch.resetMocks();
+ });
+
+ it('Test API Successful', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ });
+ }
+ });
+ });
+ const component = shallow(<ViewLoopTemplatesModal/>);
+ });
+
+ it('Test API Exception', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: false,
+ status: 500,
+ json: () => {
+ return Promise.resolve({
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ });
+ }
+ });
+ });
+ const component = shallow(<ViewLoopTemplatesModal/>);
+ });
+
+ it('Test API Rejection', () => {
+ const myMockFunc = fetch.mockImplementationOnce(() => Promise.reject('error'));
+ setTimeout( () => myMockFunc().catch(e => {
+ console.info(e);
+ }),
+ 100
+ );
+ const component = shallow(<ViewLoopTemplatesModal/>);
+ expect(myMockFunc.mock.calls.length).toBe(1);
+ });
+
+ it('Test the tosca model view render method', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ });
+ }
+ });
+ });
+ const component = shallow(<ViewLoopTemplatesModal/>);
+ component.setState({ loopTemplateData: {
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ }
+ });
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Test Table icons', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ });
+ }
+ });
+ });
+ const component = mount(<Router><ViewLoopTemplatesModal/></Router>);
+ expect(component.find('[className="MuiSelect-icon MuiTablePagination-selectIcon"]')).toBeTruthy();
+ });
+
+ it('Test handleClose', () => {
+ fetch.mockImplementationOnce(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "index": "1",
+ "name": "MTCA version 1",
+ "modelService.serviceDetails.name": "MTCA",
+ "allowedLoopType" : "CLOSED",
+ "maximumInstancesAllowed":1,
+ "updatedDate":"2019-09-06 19:09:42"
+ });
+ }
+ });
+ });
+ const historyMock = { push: jest.fn() };
+ const handleClose = jest.spyOn(ViewLoopTemplatesModal.prototype,'handleClose');
+ const component = shallow(<ViewLoopTemplatesModal history={historyMock} />)
+ component.find('[variant="secondary"]').prop('onClick')();
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ expect(component.state('show')).toEqual(false);
+ expect(historyMock.push.mock.calls[0]).toEqual([ '/']);
+ handleClose.mockClear();
+ });
+ });
diff --git a/runtime/ui-react/src/components/dialogs/Tosca/__snapshots__/ViewLoopTemplatesModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Tosca/__snapshots__/ViewLoopTemplatesModal.test.js.snap
new file mode 100644
index 000000000..73f659606
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/Tosca/__snapshots__/ViewLoopTemplatesModal.test.js.snap
@@ -0,0 +1,157 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify ViewLoopTemplatesModal Test the tosca model view render method 1`] = `
+<Styled(Modal)
+ backdrop="static"
+ keyboard={false}
+ onHide={[Function]}
+ show={true}
+ size="xl"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ />
+ <ModalBody>
+ <WithStyles(Component)
+ columns={
+ Array [
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "index",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "render": [Function],
+ "title": "#",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "name",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Template Name",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "modelService.serviceDetails.name",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Service Model Name",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "allowedLoopType",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Loop Type Allowed",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "field": "maximumInstancesAllowed",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "# Instances Allowed",
+ },
+ Object {
+ "cellStyle": Object {
+ "border": "1px solid black",
+ },
+ "editable": "never",
+ "field": "updatedDate",
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "2px solid black",
+ },
+ "title": "Modified Date",
+ },
+ ]
+ }
+ data={Array []}
+ icons={
+ Object {
+ "FirstPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "LastPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "NextPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "PreviousPage": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "ResetSearch": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "Search": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ "SortArrow": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "render": [Function],
+ },
+ }
+ }
+ onRowClick={[Function]}
+ options={
+ Object {
+ "headerStyle": Object {
+ "backgroundColor": "#ddd",
+ "border": "1px solid black",
+ "fontSize": "15pt",
+ "text": "bold",
+ },
+ "rowStyle": [Function],
+ }
+ }
+ title="View Blueprint MicroService Templates"
+ />
+ <withRouter(SvgGenerator)
+ clickable={false}
+ generatedFrom="TEMPLATE"
+ loopCache={
+ LoopCache {
+ "loopJsonCache": Object {},
+ }
+ }
+ />
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ variant="secondary"
+ >
+ Close
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/dialogs/UserInfoModal.js b/runtime/ui-react/src/components/dialogs/UserInfoModal.js
new file mode 100644
index 000000000..96eabb4c2
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/UserInfoModal.js
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Button from 'react-bootstrap/Button';
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import styled from 'styled-components';
+import UserService from '../../api/UserService';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+export default class UserInfoModal extends React.Component {
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.handleClose = this.handleClose.bind(this);
+ this.renderPermissions = this.renderPermissions.bind(this);
+ this.renderUserName = this.renderUserName.bind(this);
+ this.state = {
+ show: true,
+ userInfo: {}
+ };
+ }
+ componentWillMount() {
+ UserService.getUserInfo().then(userInfo => {
+ this.setState({ userInfo: userInfo })
+ });
+ }
+
+ handleClose() {
+ this.props.history.push('/');
+ }
+ renderPermissions() {
+ if (this.state.userInfo["allPermissions"]) {
+ var listOfPermissions = this.state.userInfo["allPermissions"].map(function(perm) {
+ return <Form.Control key={perm} plaintext readOnly defaultValue={perm} />;
+ })
+ return listOfPermissions;
+ } else {
+ return;
+ }
+ }
+ renderUserName() {
+ if (this.state.userInfo["userName"]) {
+ return <Form.Control plaintext readOnly defaultValue={this.state.userInfo["userName"]} />
+ } else {
+ return;
+ }
+ }
+ renderVersion() {
+ if (this.state.userInfo["cldsVersion"]) {
+ return <Form.Control plaintext readOnly defaultValue={this.state.userInfo["cldsVersion"]} />
+ } else {
+ return;
+ }
+ }
+ render() {
+ return (
+ <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose}>
+ <Modal.Header closeButton>
+ <Modal.Title>User Info</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form.Group as={Row} controlId="userName">
+ <Form.Label column sm="3">Current User:</Form.Label>
+ <Col>{this.renderUserName()}</Col>
+ </Form.Group>
+ <Form.Group as={Row} controlId="cldsVersion">
+ <Form.Label column sm="3">CLDS Version:</Form.Label>
+ <Col>{this.renderVersion()}</Col>
+ </Form.Group>
+ <Form.Group as={Row} controlId="userPermissions">
+ <Form.Label column sm="3">User Permissions:</Form.Label>
+ <Col>
+ {this.renderPermissions()}
+ </Col>
+ </Form.Group>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
+ </Modal.Footer>
+ </ModalStyled>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/dialogs/UserInfoModal.test.js b/runtime/ui-react/src/components/dialogs/UserInfoModal.test.js
new file mode 100644
index 000000000..f5ed0ae10
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/UserInfoModal.test.js
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import UserInfoModal from './UserInfoModal';
+
+describe('Verify UserInfoModal', () => {
+
+ beforeEach(() => {
+ fetch.resetMocks();
+ fetch.mockImplementation(() => {
+ return Promise.resolve({
+ ok: true,
+ status: 200,
+ json: () => {
+ return Promise.resolve({
+ "userName": "test",
+ "cldsVersion": "1.0.0"
+ });
+ }});
+ });
+ })
+
+ it('Test the render method full permission', () => {
+ const component = shallow(<UserInfoModal />)
+ component.setState({ userInfo: {
+ "userName": "test",
+ "cldsVersion": "1.0.0",
+ "allPermissions": ["permission1","permission2"]
+ }});
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Test the render method no permission', () => {
+ const component = shallow(<UserInfoModal />)
+ component.setState({ userInfo: {}
+ });
+
+ expect(component.find('FormControl').length).toEqual(0);
+ });
+
+ it('Test the render method read permission', () => {
+ const component = shallow(<UserInfoModal />)
+ component.setState({ userInfo: {
+ "userName": "test",
+ "cldsVersion": "1.0.0",
+ "allPermissions": ["permission1","permission2"]
+ }});
+
+ expect(component.find('FormControl').length).toEqual(4);
+
+ const forms = component.find('FormControl');
+ expect(forms.get(0).props.defaultValue).toEqual("test");
+ expect(forms.get(1).props.defaultValue).toEqual("1.0.0");
+ expect(forms.get(2).props.defaultValue).toEqual("permission1");
+ expect(forms.get(3).props.defaultValue).toEqual("permission2");
+ });
+});
diff --git a/runtime/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap b/runtime/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap
new file mode 100644
index 000000000..548a2d938
--- /dev/null
+++ b/runtime/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap
@@ -0,0 +1,119 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify UserInfoModal Test the render method full permission 1`] = `
+<Styled(Modal)
+ onHide={[Function]}
+ show={true}
+ size="lg"
+>
+ <ModalHeader
+ closeButton={true}
+ closeLabel="Close"
+ >
+ <ModalTitle>
+ User Info
+ </ModalTitle>
+ </ModalHeader>
+ <ModalBody>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="userName"
+ >
+ <FormLabel
+ column={true}
+ sm="3"
+ srOnly={false}
+ >
+ Current User:
+ </FormLabel>
+ <Col>
+ <FormControl
+ defaultValue="test"
+ plaintext={true}
+ readOnly={true}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="cldsVersion"
+ >
+ <FormLabel
+ column={true}
+ sm="3"
+ srOnly={false}
+ >
+ CLDS Version:
+ </FormLabel>
+ <Col>
+ <FormControl
+ defaultValue="1.0.0"
+ plaintext={true}
+ readOnly={true}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "defaultProps": Object {
+ "noGutters": false,
+ },
+ "render": [Function],
+ }
+ }
+ controlId="userPermissions"
+ >
+ <FormLabel
+ column={true}
+ sm="3"
+ srOnly={false}
+ >
+ User Permissions:
+ </FormLabel>
+ <Col>
+ <FormControl
+ defaultValue="permission1"
+ key="permission1"
+ plaintext={true}
+ readOnly={true}
+ />
+ <FormControl
+ defaultValue="permission2"
+ key="permission2"
+ plaintext={true}
+ readOnly={true}
+ />
+ </Col>
+ </FormGroup>
+ </ModalBody>
+ <ModalFooter>
+ <Button
+ active={false}
+ disabled={false}
+ onClick={[Function]}
+ type="null"
+ variant="secondary"
+ >
+ Cancel
+ </Button>
+ </ModalFooter>
+</Styled(Modal)>
+`;
diff --git a/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.js b/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.js
new file mode 100644
index 000000000..e3d9f601f
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.js
@@ -0,0 +1,96 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import Table from 'react-bootstrap/Table';
+import LoopCache from '../../../api/LoopCache';
+import styled from 'styled-components';
+
+const LoopLogsHeaderDivStyled = styled.div`
+ background-color: ${props => props.theme.loopLogsHeaderBackgroundColor};
+ padding: 10px 10px;
+ color: ${props => props.theme.loopLogsHeaderFontColor};
+`
+const TableStyled = styled(Table)`
+
+ overflow: auto;
+`
+const TableRow = ({ logRow }) => (
+ <tr>
+ <td>{logRow.logInstant}</td>
+ <td>{logRow.logType}</td>
+ <td>{logRow.logComponent}</td>
+ <td>{logRow.message}</td>
+ </tr>
+
+)
+
+export default class LoopLogs extends React.Component {
+
+ state = {
+ loopCache: new LoopCache({})
+ }
+ constructor(props) {
+ super(props);
+ this.renderLogs = this.renderLogs.bind(this);
+ this.state.loopCache = props.loopCache;
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.loopCache !== nextState.loopCache;
+ }
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopCache: newProps.loopCache
+ });
+ }
+
+ renderLogs() {
+ let logsArray = this.state.loopCache.getLoopLogsArray();
+ if (logsArray != null) {
+ return (logsArray.map(row => <TableRow key={row.id} logRow={row} />));
+ }
+ }
+
+ render() {
+ return (
+ <LoopLogsHeaderDivStyled>
+ <label>Loop Logs</label>
+ <TableStyled striped hover variant responsive>
+ <thead>
+ <tr>
+ <th><span align="left">Date</span></th>
+ <th><span align="left">Type</span></th>
+ <th><span align="left">Component</span></th>
+ <th><span align="right">Log</span></th>
+ </tr>
+ </thead>
+ <tbody>
+ {this.renderLogs()}
+ </tbody>
+ </TableStyled>
+ </LoopLogsHeaderDivStyled>
+
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.test.js b/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.test.js
new file mode 100644
index 000000000..3b7fd413a
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/logs/LoopLogs.test.js
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import LoopLogs from './LoopLogs';
+import LoopCache from '../../../api/LoopCache';
+
+describe('Verify LoopLogs', () => {
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "loopLogs": [
+ {
+ "id": 1,
+ "logType": "INFO",
+ "logComponent": "CLAMP",
+ "message": "Operational policies UPDATED",
+ "logInstant": "2019-07-08T09:44:37Z"
+ }
+ ]
+ });
+
+ it('Test the render method', () => {
+ const component = shallow(<LoopLogs loopCache={loopCache}/>)
+ expect(component).toMatchSnapshot();
+
+ const loopCacheUpdated = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "loopLogs": [
+ {
+ "id": 1,
+ "logType": "INFO",
+ "logComponent": "CLAMP",
+ "message": "Operational policies UPDATED",
+ "logInstant": "2019-07-08T09:44:37Z"
+ },
+ {
+ "id": 2,
+ "logType": "INFO",
+ "logComponent": "CLAMP",
+ "message": "Operational policies UPDATED",
+ "logInstant": "2019-07-08T09:44:50Z"
+ }
+ ]
+ });
+
+ component.setProps({ loopCache: loopCacheUpdated });
+ expect(component.find('TableRow').length).toEqual(2);
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap b/runtime/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap
new file mode 100644
index 000000000..996c67457
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap
@@ -0,0 +1,62 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify LoopLogs Test the render method 1`] = `
+<styled.div>
+ <label>
+ Loop Logs
+ </label>
+ <Styled(Component)
+ hover={true}
+ responsive={true}
+ striped={true}
+ variant={true}
+ >
+ <thead>
+ <tr>
+ <th>
+ <span
+ align="left"
+ >
+ Date
+ </span>
+ </th>
+ <th>
+ <span
+ align="left"
+ >
+ Type
+ </span>
+ </th>
+ <th>
+ <span
+ align="left"
+ >
+ Component
+ </span>
+ </th>
+ <th>
+ <span
+ align="right"
+ >
+ Log
+ </span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <TableRow
+ key="1"
+ logRow={
+ Object {
+ "id": 1,
+ "logComponent": "CLAMP",
+ "logInstant": "2019-07-08T09:44:37Z",
+ "logType": "INFO",
+ "message": "Operational policies UPDATED",
+ }
+ }
+ />
+ </tbody>
+ </Styled(Component)>
+</styled.div>
+`;
diff --git a/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.js b/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.js
new file mode 100644
index 000000000..4b35b48e1
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.js
@@ -0,0 +1,106 @@
+/*-
+* ============LICENSE_START=======================================================
+* ONAP CLAMP
+* ================================================================================
+* Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+* ===================================================================
+*
+*/
+import React from 'react';
+import Table from 'react-bootstrap/Table';
+import styled from 'styled-components';
+import LoopCache from '../../../api/LoopCache';
+
+const LoopStatusViewDivStyled = styled.div`
+ background-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
+ padding: 10px 10px;
+ color: ${props => props.theme.loopViewerHeaderFontColor};
+`
+
+const TableStyled = styled(Table)`
+ overflow: auto;
+`
+
+const TableRow = ({ statusRow }) => (
+ <tr>
+ <td>{statusRow.componentName}</td>
+ <td>{statusRow.stateName}</td>
+ <td>{statusRow.description}</td>
+ </tr>
+
+)
+
+export default class LoopStatus extends React.Component {
+ state = {
+ loopCache: new LoopCache({})
+ }
+
+ constructor(props) {
+ super(props);
+ this.renderStatus = this.renderStatus.bind(this);
+ this.state.loopCache = props.loopCache;
+ }
+
+
+ renderStatus() {
+ let componentStates = this.state.loopCache.getComponentStates();
+ if (componentStates != null) {
+ return Object.keys(componentStates).map((key) => {
+ console.debug("Adding status for: ",key);
+ var res={}
+ res[key]=this.state.loopCache.getComponentStates()[key];
+ return (<TableRow key={key} statusRow={{'componentName':key,'stateName':this.state.loopCache.getComponentStates()[key].componentState.stateName,'description':this.state.loopCache.getComponentStates()[key].componentState.description}} />)
+ })
+
+ }
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.loopCache !== nextState.loopCache;
+ }
+
+ componentWillReceiveProps(newProps) {
+ this.setState({
+ loopCache: newProps.loopCache
+ });
+ }
+
+ render() {
+ return (
+ <LoopStatusViewDivStyled>
+ <label>Loop Status: {this.state.loopCache.getComputedState()}
+ </label>
+
+ <div >
+ <TableStyled striped hover variant responsive>
+ <thead>
+ <tr>
+ <th><span align="left">Component Name</span></th>
+ <th><span align="left">Component State</span></th>
+ <th><span align="right">Description</span></th>
+ </tr>
+ </thead>
+ <tbody>
+ {this.renderStatus()}
+ </tbody>
+ </TableStyled>
+ </div>
+ </LoopStatusViewDivStyled>
+ );
+ }
+}
+
diff --git a/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.test.js b/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.test.js
new file mode 100644
index 000000000..8d0448796
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/status/LoopStatus.test.js
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import LoopStatus from './LoopStatus';
+import LoopCache from '../../../api/LoopCache';
+
+describe('Verify LoopStatus', () => {
+
+ const loopCache = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "lastComputedState": "DESIGN",
+ "components": {
+ "POLICY": {
+ "componentState": {
+ "stateName": "NOT_SENT",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ }
+ });
+
+ it('Test the render method', () => {
+ const component = shallow(<LoopStatus loopCache={loopCache}/>)
+
+ expect(component).toMatchSnapshot();
+
+ const loopCacheUpdated = new LoopCache({
+ "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca",
+ "lastComputedState": "SUBMIT",
+ "components": {
+ "POLICY": {
+ "componentState": {
+ "stateName": "SENT",
+ "description": "The policies defined have NOT yet been created on the policy engine"
+ }
+ },
+ "DCAE": {
+ "componentState": {
+ "stateName": "BLUEPRINT_DEPLOYED",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"
+ }
+ }
+ }
+ });
+ component.setProps({ loopCache: loopCacheUpdated });
+
+ const forms = component.find('TableRow');
+ expect(forms.get(0).props.statusRow.stateName).toEqual("SENT");
+ expect(component.find('label').text()).toContain('SUBMIT');
+ });
+}); \ No newline at end of file
diff --git a/runtime/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap b/runtime/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap
new file mode 100644
index 000000000..24d879de9
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap
@@ -0,0 +1,66 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify LoopStatus Test the render method 1`] = `
+<styled.div>
+ <label>
+ Loop Status:
+ DESIGN
+ </label>
+ <div>
+ <Styled(Component)
+ hover={true}
+ responsive={true}
+ striped={true}
+ variant={true}
+ >
+ <thead>
+ <tr>
+ <th>
+ <span
+ align="left"
+ >
+ Component Name
+ </span>
+ </th>
+ <th>
+ <span
+ align="left"
+ >
+ Component State
+ </span>
+ </th>
+ <th>
+ <span
+ align="right"
+ >
+ Description
+ </span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <TableRow
+ key="POLICY"
+ statusRow={
+ Object {
+ "componentName": "POLICY",
+ "description": "The policies defined have NOT yet been created on the policy engine",
+ "stateName": "NOT_SENT",
+ }
+ }
+ />
+ <TableRow
+ key="DCAE"
+ statusRow={
+ Object {
+ "componentName": "DCAE",
+ "description": "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop",
+ "stateName": "BLUEPRINT_DEPLOYED",
+ }
+ }
+ />
+ </tbody>
+ </Styled(Component)>
+ </div>
+</styled.div>
+`;
diff --git a/runtime/ui-react/src/components/loop_viewer/svg/SvgGenerator.js b/runtime/ui-react/src/components/loop_viewer/svg/SvgGenerator.js
new file mode 100644
index 000000000..6d3cd7a21
--- /dev/null
+++ b/runtime/ui-react/src/components/loop_viewer/svg/SvgGenerator.js
@@ -0,0 +1,246 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import styled from 'styled-components';
+import { withRouter } from "react-router-dom";
+import LoopCache from '../../../api/LoopCache';
+import OnapConstant from '../../../utils/OnapConstants';
+
+const DivStyled = styled.div`
+ overflow-x: scroll;
+ display: flex;
+ width: 100%;
+ height: 100%;
+`
+
+const emptySvg = (<svg> <text x="60" y="40">No LOOP (SVG)</text> </svg>);
+
+class SvgGenerator extends React.Component {
+ boxWidth = 200;
+ boxHeight = 100;
+ boxSpace = 50;
+
+ static GENERATED_FROM_INSTANCE = "INSTANCE";
+ static GENERATED_FROM_TEMPLATE = "TEMPLATE";
+
+ state = {
+ loopCache: new LoopCache({}),
+ clickable: false,
+ generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE
+ }
+
+ constructor(props) {
+ super(props);
+ this.state.loopCache = props.loopCache;
+ this.state.clickable = props.clickable;
+ this.state.generatedFrom = props.generatedFrom;
+ this.handleSvgClick = this.handleSvgClick.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.loopCache !== nextProps.loopCache;
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.loopCache !== this.props.loopCache) {
+ this.setState({
+ loopCache: this.props.loopCache,
+ });
+ }
+ }
+
+ handleSvgClick(event) {
+ console.debug("svg click event received");
+ if (this.state.clickable) {
+ var elementName = event.target.parentNode.getAttribute('policyId');
+ console.info("SVG element clicked", elementName);
+ // Only allow movement to policy editing IF there busyLoadingCOunt is 0,
+ // meaning we are not waiting for refreshStatus to complete, for example
+ if (elementName !== null && !this.props.isBusyLoading()) {
+ this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName);
+ }
+ }
+ }
+
+ createVesBox (xPos) {
+ return this.createOneBox(xPos,null,null,'VES Collector','VES',null);
+ }
+
+ createOneArrow(xPos) {
+ return (
+ <svg width={this.boxSpace} height={this.boxHeight} x={xPos}>
+ <defs>
+ <marker viewBox="0 0 20 20" markerWidth="20" markerHeight="20" orient="auto" refX="8.5" refY="5" id="arrow">
+ <path d="m 1 5 l 0 -3 l 7 3 l -7 3 z"
+ stroke-width= "1" stroke-linecap= "butt" stroke-dasharray= "10000, 1"
+ fill="#000000" stroke="#000000" />
+ </marker>
+ </defs>
+ <line x1="0" y1="50%" x2="100%" y2="50%" stroke-width="2" color="black" stroke="black" marker-end="url(#arrow)"/>
+ </svg>
+ );
+ }
+
+ createBeginCircle(xPos, text) {
+ return (
+ <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
+ <circle cx={this.boxWidth-30} cy="50%" r="30" stroke-width="1" color="black" stroke="black" fill="#27ae60"/>
+ <text x={this.boxWidth-30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
+ </svg>
+ );
+ }
+
+ createEndCircle(xPos, text) {
+ return (
+ <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
+ <circle cx={30} cy="50%" r="30" stroke-width="2" color="black" stroke="black" fill="#27ae60"/>
+ <text x={30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
+ </svg>
+ );
+ }
+
+ createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) {
+ return (
+ <svg width={this.boxWidth} height={this.boxHeight} x={xPos} title="test">
+ <g policyId={policyId} loopElementModelId={loopElementModelId} policyType={policyType}>
+ <rect width="100%" height="100%" stroke-width="2" color="black" stroke="black" fill="#1abc9c"/>
+ <text x="50%" y="15%" color="white" fill="white" dominant-baseline="middle" text-anchor="middle" textLength="50%" lengthAdjust="spacingAndGlyphs">{title}</text>
+ <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" textLength="80%" lengthAdjust="spacingAndGlyphs" >{name}</text>
+ <text x="50%" y="80%" text-anchor="middle" dominant-baseline="middle" textLength="110%" lengthAdjust="spacingAndGlyphs" >{policyId}</text>
+ </g>
+ </svg>
+ );
+ }
+
+ createSvgFromTemplate() {
+ const allElements = [];
+ var xPos = 0;
+
+ allElements.push(this.createBeginCircle(xPos,"Start"))
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+
+ allElements.push(this.createVesBox(xPos));
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+ //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType)
+ for (var loopElement of this.state.loopCache.getAllLoopElementModels()) {
+
+ allElements.push(this.createOneBox(xPos,
+ loopElement['name'],
+ loopElement['name'],
+ loopElement['shortName'],
+ loopElement['loopElementType'],
+ loopElement['loopElementType']))
+ xPos+=(this.boxWidth+this.boxSpace);
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+ }
+
+ allElements.push(this.createEndCircle(xPos, "End"))
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ return allElements;
+ }
+
+ createSvgFromInstance() {
+ const allElements = [];
+ var xPos = 0;
+
+ allElements.push(this.createBeginCircle(xPos,"Start"))
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+
+ allElements.push(this.createVesBox(xPos));
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+
+ for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) {
+ var loopElementModelName = this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel'];
+ if (loopElementModelName !== undefined) {
+ loopElementModelName = loopElementModelName['name'];
+ }
+ allElements.push(this.createOneBox(xPos,
+ this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'],
+ loopElementModelName,
+ this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'],
+ 'microservice',
+ OnapConstant.microServiceType))
+ xPos+=(this.boxWidth+this.boxSpace);
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+ }
+
+ for (var opPolicy in this.state.loopCache.getOperationalPolicies()) {
+ loopElementModelName = this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel'];
+ if (loopElementModelName !== undefined) {
+ loopElementModelName = loopElementModelName['name'];
+ }
+ allElements.push(this.createOneBox(xPos,
+ this.state.loopCache.getOperationalPolicies()[opPolicy]['name'],
+ loopElementModelName,
+ this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'],
+ 'operational',
+ OnapConstant.operationalPolicyType))
+ xPos+=(this.boxWidth+this.boxSpace);
+ allElements.push(this.createOneArrow(xPos-this.boxSpace));
+ }
+
+ allElements.push(this.createEndCircle(xPos, "End"))
+ xPos+=(this.boxWidth+this.boxSpace);
+
+ return allElements;
+ }
+
+ renderSvg() {
+ if (this.state.loopCache.getLoopName() === undefined) {
+ return [emptySvg];
+ }
+ if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) {
+ return this.createSvgFromInstance();
+ } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) {
+ return this.createSvgFromTemplate();
+ }
+ }
+
+ render() {
+ var allTheElements = this.renderSvg();
+ var svgWidth = this.boxWidth*allTheElements.length;
+ var svgHeight = this.boxHeight+50;
+ return (
+
+ <DivStyled onClick={this.handleSvgClick} >
+ <svg key="main" height={svgHeight} width={svgWidth} viewBox="0,0,{svgWidth},{svgHeight}" preserveAspectRatio="none">
+ <svg key="content" x="-50" y="25">
+ {allTheElements}
+ </svg>
+ </svg>
+ </DivStyled>
+ );
+ }
+}
+
+export default withRouter(SvgGenerator);
diff --git a/runtime/ui-react/src/components/menu/MenuBar.js b/runtime/ui-react/src/components/menu/MenuBar.js
new file mode 100644
index 000000000..995db9e16
--- /dev/null
+++ b/runtime/ui-react/src/components/menu/MenuBar.js
@@ -0,0 +1,123 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import Nav from 'react-bootstrap/Nav';
+import Navbar from 'react-bootstrap/Navbar';
+import NavDropdown from 'react-bootstrap/NavDropdown';
+import OnapConstants from '../../utils/OnapConstants';
+import 'bootstrap-css-only/css/bootstrap.min.css';
+import styled from 'styled-components';
+import { Link } from 'react-router-dom';
+
+const StyledLink = styled(Link)`
+ color: ${props => props.theme.menuFontColor};
+ background-color: ${props => props.theme.menuBackgroundColor};
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ${props => props.theme.menuHighlightedBackgroundColor};
+ color: ${props => props.theme.menuHighlightedFontColor};
+ }
+`;
+const StyledNavLink = styled(Nav.Link)`
+ color: ${props => props.theme.menuFontColor};
+ background-color: ${props => props.theme.menuBackgroundColor};
+ font-weight: normal;
+ padding: .25rem 1.5rem;
+ :hover {
+ background-color: ${props => props.theme.menuHighlightedBackgroundColor};
+ color: ${props => props.theme.menuHighlightedFontColor};
+ }
+`;
+
+const StyledNavDropdown = styled(NavDropdown)`
+ color: ${props => props.theme.menuFontColor};
+ & .dropdown-toggle {
+ color: ${props => props.theme.menuFontColor};
+ background-color: ${props => props.theme.backgroundColor};
+ font-weight: normal;
+ :hover {
+ font-weight: bold;
+ }
+ }
+`;
+
+export default class MenuBar extends React.Component {
+ state = {
+ loopName: this.props.loopName,
+ disabled: true
+ };
+
+ componentWillReceiveProps(newProps) {
+ if (newProps.loopName !== OnapConstants.defaultLoopName) {
+ this.setState({ disabled: false });
+ } else {
+ this.setState({ disabled: true });
+ }
+ }
+
+ render () {
+ return (
+ <Navbar.Collapse>
+ <StyledNavDropdown title="POLICY Framework">
+ <NavDropdown.Item as={StyledLink} to="/viewAllPolicies">View All Policies</NavDropdown.Item>
+ </StyledNavDropdown>
+ <StyledNavDropdown title="CLAMP Options">
+ <NavDropdown.Item as={StyledLink} to="/manageDictionaries">Tosca Metadata Dictionaries</NavDropdown.Item>
+ <NavDropdown.Divider />
+ <NavDropdown.Item as={StyledLink} to="/viewLoopTemplatesModal">View All Loop Templates</NavDropdown.Item>
+ </StyledNavDropdown>
+ <StyledNavDropdown title="LOOP Instance">
+ <NavDropdown.Item as={StyledLink} to="/createLoop">Create</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/openLoop">Open</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/closeLoop" disabled={this.state.disabled}>Close</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/modifyLoop" disabled={this.state.disabled}>Modify</NavDropdown.Item>
+ <NavDropdown.Divider />
+ <NavDropdown.Item as={StyledLink} to="/loopProperties" disabled={this.state.disabled}>Properties</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/refreshStatus" disabled={this.state.disabled}>Refresh Status</NavDropdown.Item>
+ </StyledNavDropdown>
+ <StyledNavDropdown title="LOOP Operations">
+ <NavDropdown.Item as={StyledLink} to="/submit" disabled={this.state.disabled}>Create and deploy to Policy Framework (SUBMIT)</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/stop" disabled={this.state.disabled}>Undeploy from Policy Framework (STOP)</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/restart" disabled={this.state.disabled}>ReDeploy to Policy Framework (RESTART)</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/delete" disabled={this.state.disabled}>Delete loop instance (DELETE)</NavDropdown.Item>
+ <NavDropdown.Divider />
+ <NavDropdown.Item as={StyledLink} to="/deploy" disabled={this.state.disabled}>Deploy to DCAE (DEPLOY)</NavDropdown.Item>
+ <NavDropdown.Item as={StyledLink} to="/undeploy" disabled={this.state.disabled}>UnDeploy to DCAE (UNDEPLOY)</NavDropdown.Item>
+ </StyledNavDropdown>
+ <StyledNavDropdown title="Help">
+ <StyledNavLink href="https://wiki.onap.org/" target="_blank">Wiki</StyledNavLink>
+ <StyledNavLink href="mailto:onap-discuss@lists.onap.org?subject=CLAMP&body=Please send us suggestions or feature enhancements or defect. If possible, please send us the steps to replicate any defect.">Contact Us</StyledNavLink>
+ <NavDropdown.Item as={StyledLink} to="/userInfo">User Info</NavDropdown.Item>
+ </StyledNavDropdown>
+ </Navbar.Collapse>
+ );
+ }
+}
diff --git a/runtime/ui-react/src/components/menu/MenuBar.test.js b/runtime/ui-react/src/components/menu/MenuBar.test.js
new file mode 100644
index 000000000..3e96dbf38
--- /dev/null
+++ b/runtime/ui-react/src/components/menu/MenuBar.test.js
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import { shallow } from 'enzyme';
+import MenuBar from './MenuBar';
+
+describe('Verify MenuBar', () => {
+
+ it('Test the render method', () => {
+ const component = shallow(<MenuBar />)
+
+ expect(component).toMatchSnapshot();
+ });
+
+ it('Update loopName', () => {
+ const component = shallow(<MenuBar />)
+ component.setProps({ loopName: "newLoop" });
+ expect(component.state('disabled')).toBe(false);
+ });
+
+ it('Default loopName', () => {
+ const component = shallow(<MenuBar />)
+ component.setProps({ loopName: "Empty (NO loop loaded yet)" });
+ expect(component.state('disabled')).toBe(true);
+ });
+});
diff --git a/runtime/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap b/runtime/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap
new file mode 100644
index 000000000..ba19097e5
--- /dev/null
+++ b/runtime/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap
@@ -0,0 +1,1070 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify MenuBar Test the render method 1`] = `
+<NavbarCollapse>
+ <Styled(NavDropdown)
+ title="POLICY Framework"
+ >
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/viewAllPolicies"
+ >
+ View All Policies
+ </DropdownItem>
+ </Styled(NavDropdown)>
+ <Styled(NavDropdown)
+ title="CLAMP Options"
+ >
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/manageDictionaries"
+ >
+ Tosca Metadata Dictionaries
+ </DropdownItem>
+ <DropdownDivider
+ role="separator"
+ />
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/viewLoopTemplatesModal"
+ >
+ View All Loop Templates
+ </DropdownItem>
+ </Styled(NavDropdown)>
+ <Styled(NavDropdown)
+ title="LOOP Instance"
+ >
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/createLoop"
+ >
+ Create
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/openLoop"
+ >
+ Open
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/closeLoop"
+ >
+ Close
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/modifyLoop"
+ >
+ Modify
+ </DropdownItem>
+ <DropdownDivider
+ role="separator"
+ />
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/loopProperties"
+ >
+ Properties
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/refreshStatus"
+ >
+ Refresh Status
+ </DropdownItem>
+ </Styled(NavDropdown)>
+ <Styled(NavDropdown)
+ title="LOOP Operations"
+ >
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/submit"
+ >
+ Create and deploy to Policy Framework (SUBMIT)
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/stop"
+ >
+ Undeploy from Policy Framework (STOP)
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/restart"
+ >
+ ReDeploy to Policy Framework (RESTART)
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/delete"
+ >
+ Delete loop instance (DELETE)
+ </DropdownItem>
+ <DropdownDivider
+ role="separator"
+ />
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/deploy"
+ >
+ Deploy to DCAE (DEPLOY)
+ </DropdownItem>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={true}
+ to="/undeploy"
+ >
+ UnDeploy to DCAE (UNDEPLOY)
+ </DropdownItem>
+ </Styled(NavDropdown)>
+ <Styled(NavDropdown)
+ title="Help"
+ >
+ <Styled(NavLink)
+ href="https://wiki.onap.org/"
+ target="_blank"
+ >
+ Wiki
+ </Styled(NavLink)>
+ <Styled(NavLink)
+ href="mailto:onap-discuss@lists.onap.org?subject=CLAMP&body=Please send us suggestions or feature enhancements or defect. If possible, please send us the steps to replicate any defect."
+ >
+ Contact Us
+ </Styled(NavLink)>
+ <DropdownItem
+ as={
+ Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "attrs": Array [],
+ "componentStyle": e {
+ "baseHash": 1014106698,
+ "baseStyle": undefined,
+ "componentId": "sc-bdfBwQ",
+ "isStatic": false,
+ "rules": Array [
+ "
+ color: ",
+ [Function],
+ ";
+ background-color: ",
+ [Function],
+ ";
+ font-weight: normal;
+ display: block;
+ width: 100%;
+ padding: .25rem 1.5rem;
+ clear: both;
+ text-align: inherit;
+ white-space: nowrap;
+ border: 0;
+ :hover {
+ text-decoration: none;
+ background-color: ",
+ [Function],
+ ";
+ color: ",
+ [Function],
+ ";
+ }
+",
+ ],
+ "staticRulesId": "",
+ },
+ "foldedComponentIds": Array [],
+ "render": [Function],
+ "shouldForwardProp": undefined,
+ "styledComponentId": "sc-bdfBwQ",
+ "target": Object {
+ "$$typeof": Symbol(react.forward_ref),
+ "propTypes": Object {
+ "innerRef": [Function],
+ "onClick": [Function],
+ "replace": [Function],
+ "target": [Function],
+ "to": [Function],
+ },
+ "render": [Function],
+ },
+ "toString": [Function],
+ "warnTooManyClasses": [Function],
+ "withComponent": [Function],
+ }
+ }
+ disabled={false}
+ to="/userInfo"
+ >
+ User Info
+ </DropdownItem>
+ </Styled(NavDropdown)>
+</NavbarCollapse>
+`;
diff --git a/runtime/ui-react/src/index.js b/runtime/ui-react/src/index.js
new file mode 100644
index 000000000..dd83096ea
--- /dev/null
+++ b/runtime/ui-react/src/index.js
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import ReactDOM from 'react-dom';
+import OnapClamp from './OnapClamp';
+import { Route, MemoryRouter } from 'react-router-dom'
+
+
+const routing = (
+ <MemoryRouter forceRefresh={false}>
+ <Route path="/" component={OnapClamp}/>
+ </MemoryRouter>
+);
+
+export var mainClamp = ReactDOM.render(
+ routing,
+ document.getElementById('root')
+)
diff --git a/runtime/ui-react/src/logo.png b/runtime/ui-react/src/logo.png
new file mode 100644
index 000000000..c6f6857a5
--- /dev/null
+++ b/runtime/ui-react/src/logo.png
Binary files differ
diff --git a/runtime/ui-react/src/setupTests.js b/runtime/ui-react/src/setupTests.js
new file mode 100644
index 000000000..30ce019ea
--- /dev/null
+++ b/runtime/ui-react/src/setupTests.js
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import { configure } from 'enzyme';
+import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
+
+configure({ adapter: new Adapter() });
+global.fetch = require('jest-fetch-mock');
diff --git a/runtime/ui-react/src/theme/globalStyle.js b/runtime/ui-react/src/theme/globalStyle.js
new file mode 100644
index 000000000..1e316d20b
--- /dev/null
+++ b/runtime/ui-react/src/theme/globalStyle.js
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import { createGlobalStyle } from 'styled-components';
+
+export const GlobalClampStyle = createGlobalStyle`
+ body {
+ padding: 0;
+ margin: 0;
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ font-weight: normal;
+ }
+
+ span {
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ font-weight: bold;
+ }
+
+ a {
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ font-weight: bold;
+ }
+
+ div {
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ border-radius: 4px;
+ margin-top: 1px;
+ }
+
+ label {
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ font-weight: bold;
+ }
+
+ button {
+ font-family: ${props => props.theme.fontFamily};
+ font-size: ${props => props.theme.fontSize};
+ font-weight: bold;
+ }
+
+`
+
+export const DefaultClampTheme = {
+ fontDanger: '#eb238e',
+ fontWarning: '#eb238e',
+ fontLight: '#ffffff',
+ fontDark: '#888888',
+ fontHighlight: '#ffff00',
+ fontNormal: 'black',
+
+ backgroundColor: '#eeeeee',
+ fontFamily: 'Arial, Sans-serif',
+ fontSize: '16px',
+
+ loopViewerBackgroundColor: 'white',
+ loopViewerFontColor: 'yellow',
+ loopViewerHeaderBackgroundColor: '#337ab7',
+ loopViewerHeaderFontColor: 'white',
+
+ loopLogsHeaderBackgroundColor: 'white',
+ loopLogsHeaderFontColor: 'black',
+
+ menuBackgroundColor: 'white',
+ menuFontColor: 'black',
+ menuHighlightedBackgroundColor: '#337ab7',
+ menuHighlightedFontColor: 'white',
+
+ toscaTextareaBackgroundColor: 'white',
+ toscaTextareaFontSize: '13px',
+
+ policyEditorBackgroundColor: 'white',
+ policyEditorFontSize: '13px'
+};
diff --git a/runtime/ui-react/src/utils/CsvToJson.js b/runtime/ui-react/src/utils/CsvToJson.js
new file mode 100644
index 000000000..5ec19c9e2
--- /dev/null
+++ b/runtime/ui-react/src/utils/CsvToJson.js
@@ -0,0 +1,204 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default function CsvToJson(rawCsvData, delimiter, internalDelimiter, csvHeaderNames, jsonKeyNames, mandatory) {
+
+ let printDictKeys = '';
+ let result = { jsonObjArray: [], errorMessages: '' };
+
+ // Validate that all parallel arrays passed in have same number of elements;
+ // this would be a developer error.
+
+ let checkLength = csvHeaderNames.length;
+
+ if (checkLength !== jsonKeyNames.length || checkLength !== mandatory.length) {
+ result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays parameters are not the same length';
+ return result;
+ }
+
+ if (checkLength < 1) {
+ result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays have no entries';
+ return result;
+ }
+
+ // Make a nice string to print in the error case to tell user what is the
+ // required heaer row format
+
+ for (let i=0; i < csvHeaderNames.length; ++i) {
+ if (i === 0) {
+ printDictKeys = csvHeaderNames[i];
+ } else {
+ printDictKeys += ',' + csvHeaderNames[i];
+ }
+ }
+
+ let dictElems = rawCsvData.split('\n');
+ let numColumns = 0;
+ let filteredDictElems = [];
+
+ // The task of the following loop is to convert raw CSV rows into easily parseable
+ // and streamlined versions of the rows with an internalDelimiter replacing the standard
+ // comma; it is presumed (and checked) that the internalDelimiter cannot exist as a valid
+ // sequence of characters in the user's data.
+
+ // This conversion process also strips leading and trailing whitespace from each row,
+ // discards empty rows, correctly interprets and removes all double quotes that programs like
+ // Excel use to support user columns that contain special characters, most notably, the comma
+ // delimiter. A double-quote that is contained within a double-quoted column value
+ // must appear in this raw data as a sequence of two double quotes. Furthermore, any column
+ // value in the raw CSV data that does not contain a delimiter may or may not be enclosed in
+ // double quotes. It is the Excel convention to not use double qoutes unless necessary, and
+ // there is no reasonable way to tell Excel to surround every column value with double quotes.
+ // Any files that were directly "exported" by CLAMP itself from the Managing Dictionaries
+ // capability, surround all columns with double quotes.
+
+ for (let i = 0; i < dictElems.length; i++) {
+
+ let oneRow = dictElems[i].trim();
+ let j = 0;
+ let inQuote = false
+ let nextChar = undefined;
+ let prevChar = null;
+
+
+ if (oneRow === '') {
+ continue; // Skip blank rows
+ } else if (oneRow.indexOf(internalDelimiter) !== -1) {
+ result.errorMessages += '\nRow #' + i + ' contains illegal sequence of characters (' + internalDelimiter + ')';
+ break;
+ } else {
+ nextChar = oneRow[1];
+ }
+
+ let newStr = '';
+ numColumns = 1;
+
+ // This "while loop" performs the very meticulous task of removing double quotes that
+ // are used by Excel to encase special characters as user string value data,
+ // and manages to correctly identify columns that are defined with or without
+ // double quotes and to process the comma delimiter correctly when encountered
+ // as a user value within a column. Such a column would have to be encased in
+ // double quotes; a comma found outside double quotes IS a delimiter.
+
+ while (j < oneRow.length) {
+ if (oneRow[j] === '"') {
+ if (inQuote === false) {
+ if (prevChar !== delimiter && prevChar !== null) {
+ result.errorMessages += '\nMismatched double quotes or illegal whitespace around delimiter at row #' + (i + 1) + ' near column #' + numColumns;
+ break;
+ } else {
+ inQuote = true;
+ }
+ } else {
+ if (nextChar === '"') {
+ newStr += '"';
+ ++j;
+ } else if ((nextChar !== delimiter) && (nextChar !== undefined)) {
+ result.errorMessages += '\nRow #' + (i + 1) + ' is badly formatted at column #' + numColumns + '. Perhaps an unescaped double quote.';
+ break;
+ } else if (nextChar === delimiter) {
+ ++numColumns;
+ inQuote = false;
+ newStr += internalDelimiter;
+ prevChar = delimiter;
+ j += 2;
+ nextChar = oneRow[j+1];
+ continue;
+ } else {
+ ++numColumns;
+ inQuote = false;
+ break;
+ }
+ }
+ } else {
+ if (oneRow[j] === delimiter && inQuote === false) {
+ newStr += internalDelimiter;
+ ++numColumns;
+ } else {
+ newStr += oneRow[j];
+ }
+ }
+ prevChar = oneRow[j];
+ ++j;
+ nextChar = oneRow[j+1]; // can result in undefined at the end
+ }
+
+ if (result.errorMessages === '' && inQuote !== false) {
+ result.errorMessages += '\nMismatched double quotes at row #' + (i + 1);
+ break;
+ } else if (result.errorMessages === '' && numColumns < jsonKeyNames.length) {
+ result.errorMessages += '\nNot enough columns (' + jsonKeyNames.length + ') at row #' + (i + 1);
+ break;
+ }
+
+ filteredDictElems.push(newStr);
+ }
+
+ if (result.errorMessages !== '') {
+ return result;
+ }
+
+ // Perform further checks on data that is now in JSON form
+ if (filteredDictElems.length < 2) {
+ result.errorMessages += '\nNot enough row data found in import file. Need at least a header row and one row of data';
+ return result;
+ }
+
+ // Now that we have something reliably parsed into sanitized columns lets run some checks
+ // and convert it all into an array of JSON objects to push to the back end if all the
+ // checks pass.
+
+ let headers = filteredDictElems[0].split(internalDelimiter);
+
+ // check that headers are included in proper order
+ for (let i=0; i < jsonKeyNames.length; ++i) {
+ if (csvHeaderNames[i] !== headers[i]) {
+ result.errorMessages += 'Row 1 header key at column #' + (i + 1) + ' is a mismatch. Expected row header must contain at least:\n' + printDictKeys;
+ return result;
+ }
+ }
+
+ // Convert the ASCII rows of data into an array of JSON obects that omit the header
+ // row which is not sent to the back end.
+
+ for (let i = 1; i < filteredDictElems.length; i++) {
+ let data = filteredDictElems[i].split(internalDelimiter);
+ let obj = {};
+ for (let j = 0; j < data.length && j < jsonKeyNames.length; j++) {
+ let value = data[j].trim();
+ if (mandatory[j] === true && value === '') {
+ result.errorMessages += '\n' + csvHeaderNames[j] + ' at row #' + (i+1) + ' is empty but requires a value.';
+ }
+ obj[jsonKeyNames[j]] = value;
+ }
+ result.jsonObjArray.push(obj);
+ }
+
+ if (result.errorMessages !== '') {
+ // If we have errors, return empty parse result even though some things
+ // may have parsed properly. We do not want to encourage the caller
+ // to think the data is good for use.
+ result.jsonObjArray = [];
+ }
+
+ return result;
+}
diff --git a/runtime/ui-react/src/utils/CsvToJson.test.js b/runtime/ui-react/src/utils/CsvToJson.test.js
new file mode 100644
index 000000000..88fa7a472
--- /dev/null
+++ b/runtime/ui-react/src/utils/CsvToJson.test.js
@@ -0,0 +1,268 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+import CsvToJson from './CsvToJson'
+
+describe('Verify CsvToJson', () => {
+
+ const hdrNames= [
+ "Element Short Name",
+ "Element Name",
+ "Element Description",
+ "Element Type",
+ "Sub-Dictionary"
+ ];
+
+ const jsonKeyNames = [
+ "shortName",
+ "name",
+ "description",
+ "type",
+ "subDictionary"
+ ];
+
+ const mandatory = [ true, true, true, true, false ];
+
+ it('Test CsvToJson No Error Case, Quoted Columns', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = {
+ errorMessages: '',
+ jsonObjArray: [
+ {
+ description: "Type of Alert",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ]
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson No Error Case, Unquoted Columns', () => {
+
+ let rawCsv = 'Element Short Name,Element Name,Element Description,Element Type,Sub-Dictionary\n';
+ rawCsv += 'alertType,Alert Type,Type of Alert,string,,admin,2020-06-11T13:56:14.927437Z';
+
+ let expectedResult = {
+ errorMessages: '',
+ jsonObjArray: [
+ {
+ description: "Type of Alert",
+ name: "Alert Type",
+ shortName: "alertType",
+ subDictionary: "",
+ type: "string"
+ }
+ ]
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Properly Escaped Double Quote and Delimiter', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert ""Type""","Type of Alert, Varies","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let errorMessage = '';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: [
+ {
+ description: "Type of Alert, Varies",
+ name: 'Alert "Type"',
+ shortName: 'alertType',
+ subDictionary: "",
+ type: "string",
+ }
+
+ ]
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+
+ it('Test CsvToJson Error Header Mismatch Error Case', () => {
+
+ let rawCsv = '"Element Short Names","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let errorMessage = 'Row 1 header key at column #1 is a mismatch. Expected row header must contain at least:\n';
+ errorMessage += 'Element Short Name,Element Name,Element Description,Element Type,Sub-Dictionary';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Mismatched Double Quotes in Column', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alert"Type","Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let errorMessage = '\nRow #2 is badly formatted at column #1. Perhaps an unescaped double quote.'
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Illegal Whitespace', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += 'alertType , "Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let errorMessage = '\nMismatched double quotes or illegal whitespace around delimiter at row #2 near column #2';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Too Few Data Columns', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Type of Alert"';
+
+ let errorMessage = '\nNot enough columns (5) at row #2';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Wrong Header Column Order', () => {
+
+ let rawCsv = '"Element Name","Element Short Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let errorMessage = 'Row 1 header key at column #1 is a mismatch. Expected row header must contain at least:\n';
+ errorMessage += 'Element Short Name,Element Name,Element Description,Element Type,Sub-Dictionary';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Not Enough Rows', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+
+ let errorMessage = '\nNot enough row data found in import file. Need at least a header row and one row of data';
+
+ let expectedResult = {
+ errorMessages: errorMessage,
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Mandatory Field Is Empty', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"","Alert Type","Type of Alert","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+ let expectedResult = {
+ errorMessages: '\nElement Short Name at row #2 is empty but requires a value.',
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '|', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Mismatched Double Quotes At End', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Alert Type Description","string","admin","2020-06-11T13:56:14.927437Z';
+
+ let expectedResult = {
+ errorMessages: '\nMismatched double quotes at row #2',
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '||', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Mismatched Mandatory Array Parameters', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Alert Type Description","string","admin","2020-06-11T13:56:14.927437Z';
+
+ let expectedResult = {
+ errorMessages: 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays parameters are not the same length',
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '||', hdrNames, jsonKeyNames, [ true ])).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Empty Mandatory Array Parameters', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Alert Type Description","string","admin","2020-06-11T13:56:14.927437Z';
+
+ let expectedResult = {
+ errorMessages: 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays have no entries',
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '||', [], [], [])).toEqual(expectedResult);
+ });
+
+ it('Test CsvToJson Error Illegal Data Contains Internal Delimiter', () => {
+
+ let rawCsv = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+ rawCsv += '"alertType","Alert Type","Alert Type||Description","string","admin","2020-06-11T13:56:14.927437Z';
+
+ let expectedResult = {
+ errorMessages: '\nRow #1 contains illegal sequence of characters (||)',
+ jsonObjArray: []
+ };
+
+ expect(CsvToJson(rawCsv, ',', '||', hdrNames, jsonKeyNames, mandatory)).toEqual(expectedResult);
+ });
+})
diff --git a/runtime/ui-react/src/utils/OnapConstants.js b/runtime/ui-react/src/utils/OnapConstants.js
new file mode 100644
index 000000000..8460340d1
--- /dev/null
+++ b/runtime/ui-react/src/utils/OnapConstants.js
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+// Maintain a list of ONAP CLAMP UI "constants" that can be used by any componenet within CLAMP
+
+const OnapConstants = {
+ defaultLoopName: "Empty (NO loop loaded yet)",
+ microServiceType: "MICRO-SERVICE-POLICY",
+ operationalPolicyType: "OPERATIONAL_POLICY_TYPE"
+};
+
+export default OnapConstants;
diff --git a/runtime/ui-react/src/utils/OnapUtils.js b/runtime/ui-react/src/utils/OnapUtils.js
new file mode 100644
index 000000000..316a0d65f
--- /dev/null
+++ b/runtime/ui-react/src/utils/OnapUtils.js
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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============================================
+ * ===================================================================
+ *
+ */
+
+export default class OnapUtils {
+
+ constructor() {
+ this.clickBlocked = false;
+ }
+
+ static jsonEditorErrorFormatter(errors) {
+
+ let messages = [];
+ let messagesOutputString = null;
+
+ // errors is an array of JSON Editor "error" objects, where each
+ // object looks like this:
+
+ // {
+ // message: "Please populate the required property "Threshold""
+ // path: "root.signatures.0"
+ // property: "required"
+ // }
+
+ // In this function we concatenate all the messages, removing any duplicates,
+ // and adding a newline between each message. The result returned is a single
+ // string that can be displayed to the user in an alert message
+
+ if (!Array.isArray(errors)) {
+ console.error('jsoneEditorErrorFormatter was passed a non-array argument');
+ } else {
+ for (let ii=0; ii < errors.length; ++ii) {
+ if (!messages.includes(errors[ii].message)) {
+ messages.push(errors[ii].message);
+ if (messagesOutputString) {
+ messagesOutputString += '\n' + errors[ii].message;
+ } else {
+ messagesOutputString = errors[ii].message;
+ }
+ }
+ }
+ }
+
+ return messagesOutputString;
+ }
+}