aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.coveragerc2
-rw-r--r--.gitignore5
-rw-r--r--.readthedocs.yaml18
-rw-r--r--INFO.yaml155
-rw-r--r--README.md28
-rw-r--r--[-rwxr-xr-x]apps/__init__.py (renamed from osdf/logging/onap_common_v1/__init__.py)0
-rw-r--r--apps/license/__init__.py (renamed from osdf/optimizers/pciopt/__init__.py)0
-rw-r--r--apps/license/optimizers/__init__.py (renamed from osdf/optimizers/pciopt/solver/__init__.py)0
-rw-r--r--apps/license/optimizers/simple_license_allocation.py (renamed from osdf/optimizers/licenseopt/simple_license_allocation.py)2
-rw-r--r--apps/nsst/__init__.py0
-rw-r--r--apps/nsst/models/api/nsstSelectionRequest.py43
-rw-r--r--apps/nsst/optimizers/__init__.py0
-rw-r--r--apps/nsst/optimizers/conf/configIinputs.json53
-rw-r--r--apps/nsst/optimizers/nsst_select_processor.py155
-rw-r--r--apps/nst/__init__.py0
-rw-r--r--apps/nst/models/api/nstSelectionRequest.py43
-rw-r--r--apps/nst/optimizers/__init__.py0
-rw-r--r--apps/nst/optimizers/conf/configIinputs.json53
-rw-r--r--apps/nst/optimizers/nst_select_processor.py155
-rw-r--r--apps/nxi_termination/__init__.py0
-rw-r--r--apps/nxi_termination/models/api/_init_.py0
-rw-r--r--apps/nxi_termination/models/api/nxi_termination_request.py45
-rw-r--r--apps/nxi_termination/optimizers/__init__.py0
-rw-r--r--apps/nxi_termination/optimizers/remote_opt_processor.py107
-rw-r--r--[-rwxr-xr-x]apps/nxi_termination/optimizers/response_processor.py (renamed from osdf/logging/onap_common_v1/makefile)32
-rw-r--r--apps/pci/__init__.py0
-rw-r--r--apps/pci/models/__init__.py0
-rw-r--r--apps/pci/models/api/__init__.py0
-rw-r--r--apps/pci/models/api/pciOptimizationRequest.py (renamed from osdf/models/api/pciOptimizationRequest.py)10
-rw-r--r--apps/pci/models/api/pciOptimizationResponse.py (renamed from osdf/models/api/pciOptimizationResponse.py)8
-rw-r--r--apps/pci/optimizers/__init__.py2
-rw-r--r--apps/pci/optimizers/config/__init__.py0
-rw-r--r--apps/pci/optimizers/config/config_client.py37
-rw-r--r--apps/pci/optimizers/config/configdb.py51
-rw-r--r--apps/pci/optimizers/config/cps.py72
-rw-r--r--apps/pci/optimizers/config_request.py (renamed from osdf/optimizers/pciopt/configdb.py)34
-rw-r--r--apps/pci/optimizers/pci_opt_processor.py (renamed from osdf/optimizers/pciopt/pci_opt_processor.py)83
-rw-r--r--apps/pci/optimizers/solver/__init__.py0
-rw-r--r--apps/pci/optimizers/solver/min_confusion.mzn (renamed from osdf/optimizers/pciopt/solver/min_confusion.mzn)37
-rw-r--r--apps/pci/optimizers/solver/min_confusion_inl.mzn156
-rw-r--r--apps/pci/optimizers/solver/ml_model.py72
-rw-r--r--apps/pci/optimizers/solver/no_conflicts_no_confusion.mzn (renamed from osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn)43
-rw-r--r--apps/pci/optimizers/solver/optimizer.py179
-rw-r--r--apps/pci/optimizers/solver/pci_utils.py (renamed from osdf/optimizers/pciopt/solver/pci_utils.py)10
-rw-r--r--apps/placement/__init__.py0
-rw-r--r--apps/placement/models/__init__.py0
-rw-r--r--apps/placement/models/api/__init__.py0
-rw-r--r--apps/placement/models/api/placementRequest.py (renamed from osdf/models/api/placementRequest.py)8
-rw-r--r--apps/placement/models/api/placementResponse.py (renamed from osdf/models/api/placementResponse.py)2
-rw-r--r--apps/placement/optimizers/__init__.py0
-rw-r--r--apps/placement/optimizers/conductor/__init__.py (renamed from osdf/optimizers/__init__.py)0
-rw-r--r--apps/placement/optimizers/conductor/remote_opt_processor.py178
-rwxr-xr-xapps/placement/templates/plc_opt_request.jsont (renamed from osdf/templates/plc_opt_request.jsont)4
-rwxr-xr-xapps/placement/templates/plc_opt_response.jsont (renamed from osdf/templates/plc_opt_response.jsont)0
-rwxr-xr-xapps/placement/templates/policy_request.jsont (renamed from osdf/templates/policy_request.jsont)0
-rw-r--r--apps/route/__init__.py0
-rw-r--r--apps/route/optimizers/__init__.py0
-rw-r--r--apps/route/optimizers/inter_domain_route_opt.py370
-rw-r--r--apps/route/optimizers/route_opt.mzn53
-rw-r--r--apps/route/optimizers/simple_route_opt.py266
-rw-r--r--apps/slice_selection/__init__.py0
-rw-r--r--apps/slice_selection/models/api/__init__.py (renamed from osdf/optimizers/routeopt/__init__.py)2
-rw-r--r--apps/slice_selection/models/api/nsi_selection_request.py62
-rw-r--r--apps/slice_selection/models/api/nsi_selection_response.py54
-rw-r--r--apps/slice_selection/models/api/nssi_selection_request.py41
-rw-r--r--apps/slice_selection/models/api/nssi_selection_response.py40
-rw-r--r--apps/slice_selection/optimizers/__init__.py (renamed from osdf/optimizers/placementopt/__init__.py)2
-rw-r--r--apps/slice_selection/optimizers/conductor/__init__.py0
-rw-r--r--apps/slice_selection/optimizers/conductor/remote_opt_processor.py134
-rw-r--r--apps/slice_selection/optimizers/conductor/response_processor.py108
-rwxr-xr-xapps/templates/cms_opt_request.jsont (renamed from osdf/templates/cms_opt_request.jsont)0
-rwxr-xr-xapps/templates/cms_opt_request.jsont_1707_v1 (renamed from osdf/templates/cms_opt_request.jsont_1707_v1)0
-rwxr-xr-xapps/templates/cms_opt_request_1702.jsont (renamed from osdf/templates/cms_opt_request_1702.jsont)0
-rw-r--r--apps/templates/cms_opt_response.jsont (renamed from osdf/templates/cms_opt_response.jsont)0
-rw-r--r--apps/templates/license_opt_request.jsont (renamed from osdf/templates/license_opt_request.jsont)0
-rwxr-xr-xapps/templates/test_cms_nb_req_from_client.jsont (renamed from osdf/templates/test_cms_nb_req_from_client.jsont)0
-rwxr-xr-xapps/templates/test_plc_nb_req_from_client.jsont (renamed from osdf/templates/test_plc_nb_req_from_client.jsont)0
-rw-r--r--assembly.xml2
-rw-r--r--config/common_config.yaml141
-rw-r--r--config/has_config.yaml49
-rw-r--r--config/log.yml100
-rwxr-xr-xconfig/opteng_config.yaml25
-rwxr-xr-xconfig/osdf_config.yaml105
-rwxr-xr-xconfig/preload_secrets.yaml104
-rw-r--r--config/slicing_config.yaml96
-rw-r--r--csit/.gitignore2
-rwxr-xr-xcsit/plans/default/setup.sh55
-rwxr-xr-xcsit/plans/default/teardown.sh36
-rw-r--r--csit/plans/default/testplan.txt22
-rwxr-xr-xcsit/prepare-csit.sh47
-rwxr-xr-xcsit/run-csit.sh197
-rwxr-xr-xcsit/run-project-csit.sh35
-rwxr-xr-xcsit/scripts/common_functions.sh263
-rwxr-xr-xcsit/scripts/get-instance-ip.sh17
-rwxr-xr-xcsit/scripts/kill-instance.sh31
-rw-r--r--csit/scripts/osdf-properties/aaf_root_ca.cer (renamed from ssl_certs/aaf_root_ca.cer)0
-rw-r--r--csit/scripts/osdf-properties/osdf.json105
-rwxr-xr-xcsit/scripts/osdf-properties/osdf_config.yaml70
-rwxr-xr-xcsit/scripts/osdf_proxy_settings.sh35
-rwxr-xr-xcsit/scripts/osdf_script.sh70
-rwxr-xr-xcsit/scripts/setup-sms.sh71
-rwxr-xr-xcsit/scripts/simulator_script.sh68
-rwxr-xr-xcsit/scripts/wait_for_port.sh36
-rw-r--r--csit/tests/osdf/__init__.robot4
-rw-r--r--csit/tests/osdf/data/pci-opt-request.json20
-rw-r--r--csit/tests/osdf/data/placement_request.json102
-rw-r--r--csit/tests/osdf/data/termination_request.json14
-rw-r--r--csit/tests/osdf/optf_osdf_nxi_termination.robot69
-rw-r--r--csit/tests/osdf/optf_osdf_setup.robot12
-rw-r--r--csit/tests/osdf/optf_osdf_test.robot42
-rw-r--r--csit/tests/osdf/resources/common-keywords.robot51
-rw-r--r--docker/Dockerfile65
-rw-r--r--docker/opteng/Dockerfile42
-rw-r--r--docker/opteng/assembly/osdf-files.xml58
-rw-r--r--docker/osdf-lib-base/Dockerfile49
-rw-r--r--docker/osdf-lib-base/assembly/osdf-lib-files.xml43
-rw-r--r--docker/osdf/Dockerfile40
-rw-r--r--docker/osdf/assembly/osdf-files.xml65
-rwxr-xr-xdocker/osdf/build_image.sh (renamed from docker/build_image.sh)0
-rw-r--r--docs/.gitignore3
-rw-r--r--docs/_static/css/ribbon.css64
-rwxr-xr-xdocs/_static/favicon.icobin0 -> 2102 bytes
-rw-r--r--docs/_static/logo_onap_2017.pngbin0 -> 12278 bytes
-rw-r--r--docs/api/swagger/oof-optf-opteng-api.json584
-rw-r--r--docs/api/swagger/oof-osdf-has-api.json2155
-rw-r--r--docs/conf.py74
-rw-r--r--docs/index.rst3
-rw-r--r--docs/requirements-docs.txt9
-rw-r--r--docs/sections/architecture.rst1
-rw-r--r--docs/sections/offeredapis.rst25
-rw-r--r--docs/sections/release-notes.rst777
-rw-r--r--docs/sections/swaggerdoc/oof-osdf-has-api.json587
-rw-r--r--docs/sections/upgradestrategy.rst22
-rw-r--r--docs/tox.ini31
-rw-r--r--examples/policies/nsi_policies/optimization_nsi_create_new.json37
-rw-r--r--examples/policies/nsi_policies/optimization_nsi_non_shared.json37
-rw-r--r--examples/policies/nsi_policies/optimization_nsi_reuse.json37
-rw-r--r--examples/policies/nsi_policies/query_nsi.json69
-rw-r--r--examples/policies/nsi_policies/threshold_nsi.json38
-rw-r--r--examples/policies/nsi_policies/vnf_nsi_nonshared.json92
-rw-r--r--examples/policies/nsi_policies/vnf_nsi_notshared.json121
-rw-r--r--examples/policies/nsi_policies/vnf_nsi_shared.json105
-rw-r--r--examples/policies/nssi_policies/optimization_nssi.json37
-rw-r--r--examples/policies/nssi_policies/query_nssi.json39
-rw-r--r--examples/policies/nssi_policies/threshold_nssi.json44
-rw-r--r--examples/policies/nssi_policies/vnf_nssi.json37
-rw-r--r--examples/policies/nst_policies/attribute_policy_nst.json41
-rw-r--r--examples/policies/nst_policies/optimization_policy_nst.json44
-rw-r--r--examples/policies/nst_policies/query_policy_nst.json38
-rw-r--r--examples/policies/nst_policies/vnf_policy_nst.json41
-rw-r--r--examples/policies/policy_types/optimization_v2.json61
-rw-r--r--examples/policies/policy_types/threshold.json56
-rw-r--r--examples/policies/policy_utils.py192
-rw-r--r--examples/policies/requirements.txt1
-rwxr-xr-xosdf/__init__.py5
-rw-r--r--osdf/adapters/aaf/aaf_authentication.py46
-rw-r--r--osdf/adapters/aaf/sms.py116
-rw-r--r--osdf/adapters/aai/_init_.py0
-rw-r--r--osdf/adapters/aai/fetch_aai_data.py90
-rw-r--r--osdf/adapters/conductor/__init__.py (renamed from osdf/optimizers/licenseopt/__init__.py)2
-rw-r--r--osdf/adapters/conductor/api_builder.py123
-rw-r--r--osdf/adapters/conductor/conductor.py120
-rwxr-xr-xosdf/adapters/conductor/templates/conductor_interface.json (renamed from osdf/templates/conductor_interface.json)80
-rw-r--r--osdf/adapters/conductor/translation.py376
-rw-r--r--osdf/adapters/dcae/des.py47
-rwxr-xr-xosdf/adapters/dcae/message_router.py37
-rw-r--r--osdf/adapters/local_data/local_policies.py3
-rw-r--r--osdf/adapters/policy/interface.py156
-rw-r--r--osdf/adapters/policy/utils.py12
-rw-r--r--osdf/apps/__init__.py2
-rw-r--r--osdf/apps/baseapp.py222
-rw-r--r--osdf/cmd/encryptionUtil.py50
-rw-r--r--osdf/config/__init__.py2
-rw-r--r--osdf/config/base.py15
-rw-r--r--osdf/config/consulconfig.py52
-rw-r--r--osdf/config/loader.py2
-rw-r--r--osdf/logging/__init__.py4
-rw-r--r--osdf/logging/monkey.py35
-rwxr-xr-xosdf/logging/onap_common_v1/CommonLogger.py900
-rwxr-xr-xosdf/logging/onap_common_v1/CommonLogger_test.config58
-rwxr-xr-xosdf/logging/onap_common_v1/CommonLogger_testing.py143
-rwxr-xr-xosdf/logging/onap_common_v1/README.md214
-rw-r--r--osdf/logging/oof_mdc_context.py170
-rw-r--r--osdf/logging/oof_mdc_formatter.py51
-rwxr-xr-xosdf/logging/osdf_logging.py166
-rw-r--r--osdf/models/policy/placement/tosca/affinityPolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/affinityPolicy-v20180326.yml)2
-rw-r--r--osdf/models/policy/placement/tosca/distancePolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/distancePolicy-v20180326.yml)2
-rw-r--r--osdf/models/policy/placement/tosca/hpaPolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/hpaPolicy-v20180326.yml)14
-rw-r--r--osdf/models/policy/placement/tosca/optimizationPolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/optimizationPolicy-v20180326.yml)10
-rw-r--r--osdf/models/policy/placement/tosca/queryPolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/queryPolicy-v20180326.yml)4
-rw-r--r--osdf/models/policy/placement/tosca/vnfPolicy-v20181031.yml (renamed from osdf/models/policy/placement/tosca/vnfPolicy-v20180326.yml)19
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AffinityPolicy.yaml31
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AggregationPolicy.yaml42
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.DistancePolicy.yaml56
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.HpaPolicy.yaml103
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.OptimizationPolicy.yaml66
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.PciPolicy.yaml30
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.ThresholdPolicy.yaml37
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.Vim_fit.yaml28
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.VnfPolicy.yaml44
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.QueryPolicy.yaml24
-rw-r--r--osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.SubscriberPolicy.yaml34
-rw-r--r--osdf/optimizers/pciopt/solver/optimizer.py82
-rw-r--r--osdf/optimizers/placementopt/conductor/api_builder.py79
-rwxr-xr-xosdf/optimizers/placementopt/conductor/conductor.py202
-rw-r--r--osdf/optimizers/placementopt/conductor/remote_opt_processor.py79
-rw-r--r--osdf/optimizers/placementopt/conductor/translation.py254
-rw-r--r--osdf/optimizers/routeopt/simple_route_opt.py150
-rw-r--r--osdf/utils/cipherUtils.py59
-rw-r--r--osdf/utils/data_conversion.py25
-rw-r--r--osdf/utils/file_utils.py34
-rw-r--r--osdf/utils/interfaces.py26
-rw-r--r--osdf/utils/mdc_utils.py155
-rw-r--r--osdf/webapp/appcontroller.py20
-rwxr-xr-xosdfapp.py236
-rwxr-xr-xosdfapp.sh52
-rw-r--r--pom.xml254
-rw-r--r--releases/1.3.3.yaml6
-rw-r--r--releases/1.3.4.yaml5
-rw-r--r--releases/2.0.0-container.yaml10
-rw-r--r--releases/2.0.0.yaml4
-rw-r--r--releases/2.0.1-container.yaml10
-rw-r--r--releases/2.0.1.yaml4
-rw-r--r--releases/2.0.2-container.yaml10
-rw-r--r--releases/2.0.3-container.yaml10
-rw-r--r--releases/2.0.3.yaml4
-rw-r--r--releases/2.0.4-container.yaml10
-rw-r--r--releases/2.0.4.yaml4
-rw-r--r--releases/3.0.0-container.yaml10
-rw-r--r--releases/3.0.0.yaml4
-rw-r--r--releases/3.0.1-container.yaml10
-rw-r--r--releases/3.0.2-container.yaml10
-rw-r--r--releases/3.0.3-container.yaml10
-rw-r--r--releases/3.0.4-container.yaml10
-rw-r--r--releases/3.0.5-container.yaml10
-rw-r--r--releases/3.0.6-container.yaml10
-rw-r--r--releases/3.0.7-container.yaml10
-rw-r--r--releases/3.0.8-container.yaml10
-rw-r--r--requirements-opteng.txt1
-rw-r--r--requirements-osdf.txt1
-rw-r--r--requirements-sim.txt18
-rw-r--r--requirements.txt13
-rw-r--r--runtime/__init__.py (renamed from osdf/optimizers/placementopt/conductor/__init__.py)2
-rw-r--r--runtime/model_api.py221
-rw-r--r--runtime/models/__init__.py17
-rw-r--r--runtime/models/api/__init__.py17
-rw-r--r--runtime/models/api/model_request.py48
-rw-r--r--runtime/models/api/model_response.py31
-rw-r--r--runtime/models/api/optim_request.py60
-rw-r--r--runtime/models/api/optim_response.py30
-rw-r--r--runtime/optim_engine.py80
-rw-r--r--runtime/solvers/__init__.py17
-rw-r--r--runtime/solvers/mzn/__init__.py17
-rw-r--r--runtime/solvers/mzn/mzn_solver.py132
-rw-r--r--runtime/solvers/py/__init__.py17
-rw-r--r--runtime/solvers/py/py_solver.py92
-rw-r--r--script/TagVersion.groovy45
-rw-r--r--setup.py53
-rw-r--r--solverapp.py82
-rw-r--r--ssl_certs/oof.crt59
-rw-r--r--ssl_certs/oof.crt.pem25
-rw-r--r--ssl_certs/oof_new.key27
-rw-r--r--test/adapters/dcae/des_response.json47
-rw-r--r--test/adapters/dcae/test_des.py71
-rw-r--r--test/apps/nxi_termination/_init_.py0
-rw-r--r--test/apps/nxi_termination/aai_exception_response.json4
-rw-r--r--test/apps/nxi_termination/aai_response.json64
-rw-r--r--test/apps/nxi_termination/exception_response1.json7
-rw-r--r--test/apps/nxi_termination/failure_relationship_list.json66
-rw-r--r--test/apps/nxi_termination/failure_relationship_list2.json52
-rw-r--r--test/apps/nxi_termination/failure_service_profiles.json24
-rw-r--r--test/apps/nxi_termination/failure_service_profiles2.json42
-rw-r--r--test/apps/nxi_termination/invalid_request.json17
-rw-r--r--test/apps/nxi_termination/nsi_success_output.json7
-rw-r--r--test/apps/nxi_termination/nssi_failure_output.json8
-rw-r--r--test/apps/nxi_termination/nssi_termination.json17
-rw-r--r--test/apps/nxi_termination/nxi_failure_output1.json10
-rw-r--r--test/apps/nxi_termination/nxi_failure_output2.json7
-rw-r--r--test/apps/nxi_termination/nxi_termination.json17
-rw-r--r--test/apps/nxi_termination/service_profiles.json23
-rw-r--r--test/apps/nxi_termination/success_relationship_list.json34
-rw-r--r--test/apps/nxi_termination/test_fetch_aai_data.py70
-rw-r--r--test/apps/nxi_termination/test_remote_opt_processor_termination.py136
-rw-r--r--test/apps/pci_optimization/des_result.json18
-rw-r--r--test/apps/pci_optimization/test_ml_model.py87
-rw-r--r--test/apps/slice_selection/conductor_error_response.json18
-rw-r--r--test/apps/slice_selection/new_solution_conductor_response.json47
-rw-r--r--test/apps/slice_selection/new_solution_nsi_response.json35
-rw-r--r--test/apps/slice_selection/no_rec.json18
-rw-r--r--test/apps/slice_selection/no_recomm_conductor_response.json18
-rw-r--r--test/apps/slice_selection/no_recomm_nsi_response.json7
-rw-r--r--test/apps/slice_selection/nsi_error_response.json6
-rw-r--r--test/apps/slice_selection/nsi_request.json31
-rw-r--r--test/apps/slice_selection/nsi_selection_invalid_request.json80
-rw-r--r--test/apps/slice_selection/nsi_selection_request.json84
-rw-r--r--test/apps/slice_selection/nssi_conductor_response.json53
-rw-r--r--test/apps/slice_selection/nssi_error_response.json7
-rw-r--r--test/apps/slice_selection/nssi_selection_invalid_request.json23
-rw-r--r--test/apps/slice_selection/nssi_selection_request.json27
-rw-r--r--test/apps/slice_selection/shared_solution_conductor_response.json53
-rw-r--r--test/apps/slice_selection/shared_solution_nsi_response.json17
-rw-r--r--test/apps/slice_selection/shared_solution_nssi_response.json15
-rw-r--r--test/apps/slice_selection/slice_policies.txt5
-rw-r--r--test/apps/slice_selection/subnet_policies.txt5
-rw-r--r--test/apps/slice_selection/test_remote_opt_processor.py165
-rw-r--r--test/conductor/test_conductor_calls.py24
-rw-r--r--test/conductor/test_conductor_translation.py56
-rw-r--r--test/config/common_config.yaml12
-rw-r--r--test/config/log.yml100
-rwxr-xr-xtest/config/opteng_config.yaml25
-rwxr-xr-xtest/config/osdf_config.yaml62
-rw-r--r--test/configdb/test_configdb_calls.py2
-rwxr-xr-xtest/functest/scripts/start-simulators.sh7
-rwxr-xr-xtest/functest/scripts/stop-simulators.sh7
-rw-r--r--test/functest/simulators/Dockerfile24
-rw-r--r--test/functest/simulators/aai/response-payloads/nsi_instance.json13
-rw-r--r--test/functest/simulators/aai/response-payloads/nsi_instance_with_args.json45
-rwxr-xr-xtest/functest/simulators/build_sim_image.sh18
-rw-r--r--test/functest/simulators/configdb/response-payloads/getCellList-netw1000.json (renamed from test/functest/simulators/configdb/response-payloads/getCellList-1000.json)0
-rw-r--r--test/functest/simulators/configdb/response-payloads/getCellList-netw2000.json1
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell0.json25
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell1.json25
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell2.json25
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell20.json20
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell21.json10
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell22.json10
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell23.json10
-rw-r--r--test/functest/simulators/configdb/response-payloads/getNbrList-cell24.json10
-rw-r--r--[-rwxr-xr-x]test/functest/simulators/oof_dependencies_simulators.py55
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json6
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json2
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json2
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json8
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json8
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json19
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json8
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json17
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json8
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json8
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json2
-rw-r--r--test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json2
-rw-r--r--test/functest/simulators/simulated-config/common_config.yaml12
-rw-r--r--test/functest/simulators/simulated-config/log.yml100
-rwxr-xr-xtest/functest/simulators/simulated-config/opteng_config.yaml25
-rwxr-xr-xtest/functest/simulators/simulated-config/osdf_config.yaml42
-rw-r--r--test/functest/simulators/simulated-config/slicing_config.yaml96
-rwxr-xr-xtest/functest/simulators/start_sim.sh4
-rw-r--r--test/inter_domain_route_opt/bandwidth_attributes.json176
-rw-r--r--test/inter_domain_route_opt/controllers_for_interfaces.json62
-rw-r--r--test/inter_domain_route_opt/controllers_list.json16
-rw-r--r--test/inter_domain_route_opt/get_links.json157
-rw-r--r--test/inter_domain_route_opt/request.json30
-rwxr-xr-xtest/logging/test_osdf_logging.py25
-rw-r--r--test/mainapp/test_osdfapp.py33
-rw-r--r--test/optengine-tests/test_modelapi_invalid.json13
-rw-r--r--test/optengine-tests/test_modelapi_valid.json13
-rw-r--r--test/optengine-tests/test_optengine_invalid.json18
-rw-r--r--test/optengine-tests/test_optengine_invalid2.json15
-rw-r--r--test/optengine-tests/test_optengine_invalid_solver.json15
-rw-r--r--test/optengine-tests/test_optengine_modelId.json19
-rw-r--r--test/optengine-tests/test_optengine_no_modelid.json24
-rw-r--r--test/optengine-tests/test_optengine_no_optdata.json15
-rw-r--r--test/optengine-tests/test_optengine_solverid.json15
-rw-r--r--test/optengine-tests/test_optengine_valid.json20
-rw-r--r--test/optengine-tests/test_py_optengine_valid.json15
-rw-r--r--test/osdf/utils/test_interfaces.py12
-rw-r--r--test/pci-optimization-tests/fixed_pci.json42
-rw-r--r--test/pci-optimization-tests/pci_anr_request.json29
-rw-r--r--test/pci-optimization-tests/request.json6
-rw-r--r--test/placement-tests/policy_response.json872
-rw-r--r--test/placement-tests/policy_response2.json867
-rw-r--r--test/placement-tests/policy_response2_old_format.json182
-rw-r--r--test/placement-tests/policy_response_old_format.json182
-rw-r--r--test/placement-tests/request_placement_vfmod.json113
-rw-r--r--test/placement-tests/request_vfmod.json57
-rw-r--r--test/placement-tests/response_vfmod.json229
-rw-r--r--test/placement-tests/test_by_scope.yaml29
-rw-r--r--test/placement-tests/test_by_scope_old_format.yaml24
-rw-r--r--test/policy-local-files/Affinity_vCPE_1.json48
-rw-r--r--test/policy-local-files/Affinity_vFW_TD.json31
-rw-r--r--test/policy-local-files/Attribute_vNS_1.json51
-rw-r--r--test/policy-local-files/Capacity_vGMuxInfra.json48
-rw-r--r--test/policy-local-files/Capacity_vG_1.json48
-rw-r--r--test/policy-local-files/Distance_vGMuxInfra_1.json50
-rw-r--r--test/policy-local-files/Distance_vG_1.json50
-rw-r--r--test/policy-local-files/Placement_Optimization_1.json57
-rw-r--r--test/policy-local-files/QueryPolicy_vCPE.json53
-rw-r--r--test/policy-local-files/QueryPolicy_vCPE_2.json72
-rw-r--r--test/policy-local-files/QueryPolicy_vFW_TD.json47
-rw-r--r--test/policy-local-files/aggregationPolicy_URLLC_1.json37
-rw-r--r--test/policy-local-files/hpa_policy_vGMuxInfra_1.json108
-rw-r--r--test/policy-local-files/hpa_policy_vG_1.json103
-rw-r--r--test/policy-local-files/meta-valid-policies-old.txt16
-rw-r--r--test/policy-local-files/meta-valid-policies.txt5
-rw-r--r--test/policy-local-files/nst-selection-files/attribute_policy_nst.json42
-rw-r--r--test/policy-local-files/nst-selection-files/optimization_policy_nst.json37
-rw-r--r--test/policy-local-files/nst-selection-files/query_policy_nst.json31
-rw-r--r--test/policy-local-files/nst-selection-files/vnf_policy_nst.json34
-rw-r--r--test/policy-local-files/old-policies/Affinity_vCPE_1.json21
-rw-r--r--test/policy-local-files/old-policies/Attribute_vNS_1.json49
-rw-r--r--test/policy-local-files/old-policies/Capacity_vFW_1.json22
-rw-r--r--test/policy-local-files/old-policies/Capacity_vGMuxInfra.json22
-rw-r--r--test/policy-local-files/old-policies/Capacity_vG_1.json22
-rw-r--r--test/policy-local-files/old-policies/Distance_vFW_1.json22
-rw-r--r--test/policy-local-files/old-policies/Distance_vGMuxInfra_1.json22
-rw-r--r--test/policy-local-files/old-policies/Distance_vG_1.json22
-rw-r--r--test/policy-local-files/old-policies/Placement_Optimization_1.json55
-rw-r--r--test/policy-local-files/old-policies/QueryPolicy_vCPE.json21
-rw-r--r--test/policy-local-files/old-policies/QueryPolicy_vCPE_2.json24
-rw-r--r--test/policy-local-files/old-policies/QueryPolicy_vFW.json21
-rw-r--r--test/policy-local-files/old-policies/QueryPolicy_vFW_TD.json32
-rw-r--r--test/policy-local-files/old-policies/affinity_vFW_TD.json29
-rw-r--r--test/policy-local-files/old-policies/hpa_policy_vFW_1.json214
-rw-r--r--test/policy-local-files/old-policies/hpa_policy_vGMuxInfra_1.json191
-rw-r--r--test/policy-local-files/old-policies/hpa_policy_vG_1.json190
-rw-r--r--test/policy-local-files/old-policies/subscriber_policy_vCPE.json (renamed from test/policy-local-files/subscriber_policy.json)14
-rw-r--r--test/policy-local-files/old-policies/subscriber_policy_vFW.json22
-rw-r--r--test/policy-local-files/old-policies/vnfPolicy_vFW.json29
-rw-r--r--test/policy-local-files/old-policies/vnfPolicy_vFW_TD.json44
-rw-r--r--test/policy-local-files/old-policies/vnfPolicy_vG.json29
-rw-r--r--test/policy-local-files/old-policies/vnfPolicy_vGMuxInfra.json28
-rw-r--r--test/policy-local-files/old-policies/vnfPolicy_vPGN_TD.json51
-rwxr-xr-xtest/policy-local-files/pwt-it-policies/Distance_vFW_1.json22
-rwxr-xr-xtest/policy-local-files/pwt-it-policies/Placement_Optimization_1.json55
-rwxr-xr-xtest/policy-local-files/pwt-it-policies/QueryPolicy_vFW.json21
-rwxr-xr-xtest/policy-local-files/pwt-it-policies/hpa_policy_vFW_1.json214
-rwxr-xr-xtest/policy-local-files/pwt-it-policies/vnfPolicy_vFW.json29
-rw-r--r--test/policy-local-files/queryPolicy_URLLC_.json29
-rw-r--r--test/policy-local-files/slice-selection-files/opt_policy_nsi_reuse.json37
-rw-r--r--test/policy-local-files/slice-selection-files/opt_policy_nssi.json37
-rw-r--r--test/policy-local-files/slice-selection-files/query_policy_nsi.json54
-rw-r--r--test/policy-local-files/slice-selection-files/query_policy_nssi.json40
-rw-r--r--test/policy-local-files/slice-selection-files/threshold_policy_nsi.json48
-rw-r--r--test/policy-local-files/slice-selection-files/threshold_policy_nssi.json46
-rw-r--r--test/policy-local-files/slice-selection-files/vnf_policy_nsi_non_shared_case.json81
-rw-r--r--test/policy-local-files/slice-selection-files/vnf_policy_nsi_shared_case.json96
-rw-r--r--test/policy-local-files/slice-selection-files/vnf_policy_nssi_shared.json37
-rw-r--r--test/policy-local-files/subscriber_policy_URLLC_1.json26
-rw-r--r--test/policy-local-files/subscriber_policy_vCPE.json32
-rw-r--r--test/policy-local-files/thresholdPolicy_URLLC_Core_1.json41
-rw-r--r--test/policy-local-files/vnfPolicy_URLLC_Core_1.json39
-rw-r--r--test/policy-local-files/vnfPolicy_vFW_TD.json47
-rw-r--r--test/policy-local-files/vnfPolicy_vG.json61
-rw-r--r--test/policy-local-files/vnfPolicy_vGMuxInfra.json60
-rw-r--r--test/policy-local-files/vnfPolicy_vPGN_TD.json52
-rw-r--r--test/policy/test_policy_interface.py8
-rw-r--r--test/simple_route_opt/AAI.json164
-rw-r--r--test/simple_route_opt/routeOpt.json34
-rw-r--r--test/test-requirements.txt2
-rw-r--r--test/test_ConductorApiBuilder.py41
-rw-r--r--test/test_PolicyCalls.py15
-rw-r--r--test/test_aaf_authentication.py9
-rwxr-xr-xtest/test_api_data_utils.py4
-rw-r--r--test/test_api_validation.py54
-rw-r--r--test/test_get_opt_query_data.py93
-rw-r--r--test/test_inter_domain_route_opt.py151
-rw-r--r--test/test_model_api.py71
-rw-r--r--test/test_optim_engine.py78
-rw-r--r--test/test_process_fixed_pci.py79
-rw-r--r--test/test_process_pci_anr_opt.py79
-rw-r--r--test/test_process_pci_opt.py8
-rw-r--r--test/test_process_placement_opt.py26
-rw-r--r--test/test_simple_route_opt.py57
-rw-r--r--test/test_so_response_gen.py8
-rw-r--r--tox.ini33
-rw-r--r--version.properties6
466 files changed, 23448 insertions, 4564 deletions
diff --git a/.coveragerc b/.coveragerc
index a5afd52..1fa0d3b 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -2,7 +2,7 @@
[run]
branch = True
cover_pylib = False
-include = osdf/**/*.py
+include = osdf/**/*.py, apps/**/*.py, runtime/*.py, runtime/**/*.py
[report]
# Regexes for lines to exclude from consideration
diff --git a/.gitignore b/.gitignore
index 8d04c8e..91882fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,9 @@ wheels/
.installed.cfg
*.egg
MANIFEST
+AUTHORS
+ChangeLog
+logs/
# PyInstaller
# Usually these files are written by a python script from a template
@@ -116,4 +119,6 @@ xunit*.xml
# Autogenerated for simulations
simulator-logs
test/functest/simulators/config
+test/functest/simulators/policy/response-payloads
test/functest/simulators/osdf
+/pylint.out
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000..f56b3b7
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,18 @@
+---
+# .readthedocs.yml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+# Required
+
+version: 2
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3.8"
+
+python:
+ install:
+ - requirements: docs/requirements-docs.txt
+
+sphinx:
+ configuration: docs/conf.py
diff --git a/INFO.yaml b/INFO.yaml
index 74a5fb5..bd03972 100644
--- a/INFO.yaml
+++ b/INFO.yaml
@@ -1,67 +1,104 @@
---
-project: 'optf/osdf'
+project: 'optf-osdf'
project_creation_date: '2017-07-06'
-lifecycle_state: 'Incubation'
+lifecycle_state: 'Mature'
project_lead: &onap_releng_ptl
- name: 'Sarat Puthenpura'
- email: 'sarat@research.att.com'
- id: 'sarat'
- company: 'ATT'
- timezone: 'America/Bedminster'
+ name: 'Krishna Moorthy'
+ email: 'krishna.moorthy6@wipro.com'
+ id: 'krishnaa96'
+ company: 'Wipro'
+ timezone: 'India/IST UTC+5:30'
+project_category: ''
primary_contact: *onap_releng_ptl
issue_tracking:
- type: 'jira'
- url: 'https://jira.onap.org/projects/OPTFRA'
- key: 'OPTFRA'
+ type: 'jira'
+ url: 'https://jira.onap.org/projects/OPTFRA'
+ key: 'OPTFRA'
+mailing_list:
+ type: 'groups.io'
+ url: 'lists.onap.org'
+ tag: '<[sub-project_name]>'
+realtime_discussion: ''
meetings:
- - type: 'zoom'
- agenda: 'https://wiki.onap.org/display/DW/Project+Resources+for+OOF'
- url: 'https://wiki.onap.org/display/DW/Optimization+Framework+Project'
- server: 'n/a'
- channel: 'n/a'
- repeats: 'weekly'
- time: '15:00 UTC'
+ - type: 'zoom'
+ agenda: 'https://wiki.onap.org/display/DW/Project+Resources+for+OOF'
+ url: 'https://wiki.onap.org/display/DW/Optimization+Framework+Project'
+ server: 'n/a'
+ channel: 'n/a'
+ repeats: 'weekly'
+ time: '15:00 UTC'
+repositories:
+ - 'optf/osdf'
committers:
- - <<: *onap_releng_ptl
- - name: 'Shankaranarayanan Puzhavakath Narayanan'
- email: 'snarayanan@research.att.com'
- company: 'ATT'
- id: 'snarayanan'
- timezone: 'America/Bedminster'
- - name: 'ramki krishnan'
- email: 'ramkri123@gmail.com'
- company: 'VMWare'
- id: 'ramkri123'
- timezone: 'America/Los_Angeles'
- - name: 'Dileep Ranganathan'
- email: 'dileep.ranganathan@intel.com'
- company: 'Intel'
- id: 'dileep.ranganathan'
- timezone: 'America/Los_Angeles'
- - name: 'Vikas Varma'
- email: 'vikas.varma@att.com'
- company: 'ATT'
- id: 'vrvarma'
- timezone: 'America/New_York'
+ - <<: *onap_releng_ptl
+ - name: 'Sarat Puthenpura'
+ email: 'sarat@research.att.com'
+ company: 'ATT'
+ id: 'sarat'
+ timezone: 'America/Bedminster'
+ - name: 'Vikas Varma'
+ email: 'vikas.varma@att.com'
+ company: 'ATT'
+ id: 'vrvarma'
+ timezone: 'America/New_York'
+ - name: 'Arthur Martella'
+ email: 'arthur.martella.1@att.com'
+ company: 'ATT'
+ id: 'amartell'
+ timezone: 'America/New_York'
+ - name: 'Shankaranarayanan Puzhavakath Narayanan'
+ email: 'snarayanan@research.att.com'
+ company: 'ATT'
+ id: 'snarayanan'
+ timezone: 'America/Bedminster'
+ - name: 'Dhebeha MJ'
+ email: 'dhebeha.mj71@wipro.com'
+ company: 'Wipro'
+ id: 'dhebeha'
+ timezone: 'India/IST UTC+5:30'
tsc:
- approval: 'https://lists.onap.org/pipermail/onap-tsc'
- changes:
- - type: 'Addition'
- name: 'Ankitkumar Patel'
- link: 'https://lists.onap.org/pipermail/onap-tsc/2018-April/004657.html'
- - type: 'Removal'
- name: 'maopeng zhang'
- name: 'Sastry Isukapalli'
- name: 'Yoram Zini'
- link: 'https://lists.onap.org/pipermail/onap-tsc/2018-June/004975.html'
- - type: 'Addition'
- name: 'ramki krishnan'
- name: 'Dileep Ranganathan'
- link: 'https://lists.onap.org/g/ONAP-TSC/message/3205'
- - type: 'Removal'
- name: 'Ankitkumar Patel'
- link: 'https://lists.onap.org/g/ONAP-TSC/message/3550'
- - type: 'Addition'
- name: 'Vikas Varma'
- link: 'http://ircbot.wl.linuxfoundation.org/meetings/onap-meeting/2018/onap-meeting.2018-08-30-13.57.log.txt'
-
+ approval: 'https://lists.onap.org/pipermail/onap-tsc'
+ changes:
+ - type: 'Addition'
+ name: 'Ankitkumar Patel'
+ link: 'https://lists.onap.org/pipermail/onap-tsc/2018-April/004657.html'
+ - type: 'Removal'
+ name: 'maopeng zhang'
+ link: 'https://lists.onap.org/pipermail/onap-tsc/2018-June/004975.html'
+ - type: 'Removal'
+ name: 'Sastry Isukapalli'
+ link: 'https://lists.onap.org/pipermail/onap-tsc/2018-June/004975.html'
+ - type: 'Removal'
+ name: 'Yoram Zini'
+ link: 'https://lists.onap.org/pipermail/onap-tsc/2018-June/004975.html'
+ - type: 'Addition'
+ name: 'ramki krishnan'
+ link: 'https://lists.onap.org/g/ONAP-TSC/message/3205'
+ - type: 'Addition'
+ name: 'Dileep Ranganathan'
+ link: 'https://lists.onap.org/g/ONAP-TSC/message/3205'
+ - type: 'Removal'
+ name: 'Ankitkumar Patel'
+ link: 'https://lists.onap.org/g/ONAP-TSC/message/3550'
+ - type: 'Addition'
+ name: 'Vikas Varma'
+ link: 'https://wiki.onap.org/x/IplFAg'
+ - type: 'Addition'
+ name: 'Shankaranarayanan Puzhavakath Narayanan'
+ # yamllint disable-line rule:line-length
+ link: 'https://civs.cs.cornell.edu/cgi-bin/results.pl?id=E_2696d1c15c2fdd16'
+ - type: 'Addition'
+ name: 'Arthur Martella'
+ link: 'https://wiki.onap.org/x/qiVIB'
+ - type: 'Addition'
+ name: 'Krishna Moorthy'
+ link: 'https://wiki.onap.org/x/-5ELBQ'
+ - type: 'Removal'
+ name: 'Dileep Ranganathan'
+ link: 'https://lists.onap.org/g/onap-tsc/message/6416'
+ - type: 'Removal'
+ name: 'Ramki Krishnan'
+ link: 'https://lists.onap.org/g/onap-oof/message/568'
+ - type: 'Addition'
+ name: 'Dhebeha MJ'
+ link: 'https://wiki.onap.org/x/PrULBQ'
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0e2641a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+
+#osdf
+
+
+#cipher-utility
+
+ python3 setup.py install
+ export PYTHONPATH=$PYTHONPATH:`pwd`
+
diff --git a/osdf/logging/onap_common_v1/__init__.py b/apps/__init__.py
index e69de29..e69de29 100755..100644
--- a/osdf/logging/onap_common_v1/__init__.py
+++ b/apps/__init__.py
diff --git a/osdf/optimizers/pciopt/__init__.py b/apps/license/__init__.py
index e69de29..e69de29 100644
--- a/osdf/optimizers/pciopt/__init__.py
+++ b/apps/license/__init__.py
diff --git a/osdf/optimizers/pciopt/solver/__init__.py b/apps/license/optimizers/__init__.py
index e69de29..e69de29 100644
--- a/osdf/optimizers/pciopt/solver/__init__.py
+++ b/apps/license/optimizers/__init__.py
diff --git a/osdf/optimizers/licenseopt/simple_license_allocation.py b/apps/license/optimizers/simple_license_allocation.py
index 74d220f..b2aaba4 100644
--- a/osdf/optimizers/licenseopt/simple_license_allocation.py
+++ b/apps/license/optimizers/simple_license_allocation.py
@@ -15,6 +15,7 @@
#
# -------------------------------------------------------------------------
#
+from osdf.utils.mdc_utils import mdc_from_json
def license_optim(request_json):
@@ -24,6 +25,7 @@ def license_optim(request_json):
:param request_json: Request in a JSON format
:return: A tuple of licensekey-group-uuid-list and entitlement-group-uuid-list
"""
+ mdc_from_json(request_json)
req_id = request_json["requestInfo"]["requestId"]
model_name = request_json.get('placementInfo', {}).get('serviceInfo', {}).get('modelInfo', {}).get('modelName')
diff --git a/apps/nsst/__init__.py b/apps/nsst/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nsst/__init__.py
diff --git a/apps/nsst/models/api/nsstSelectionRequest.py b/apps/nsst/models/api/nsstSelectionRequest.py
new file mode 100644
index 0000000..3355ea2
--- /dev/null
+++ b/apps/nsst/models/api/nsstSelectionRequest.py
@@ -0,0 +1,43 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Huawei Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType
+from schematics.types.compound import DictType
+from schematics.types.compound import ModelType
+from schematics.types import IntType
+from schematics.types import StringType
+from schematics.types import URLType
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as SO"""
+
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ callbackUrl = URLType(required=True)
+ callbackHeader = DictType(BaseType)
+ sourceId = StringType(required=True)
+ timeout = IntType()
+
+
+class NSSTSelectionAPI(OSDFModel):
+ """Request for NST selection """
+
+ requestInfo = ModelType(RequestInfo, required=True)
+ sliceProfile = DictType(BaseType)
diff --git a/apps/nsst/optimizers/__init__.py b/apps/nsst/optimizers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nsst/optimizers/__init__.py
diff --git a/apps/nsst/optimizers/conf/configIinputs.json b/apps/nsst/optimizers/conf/configIinputs.json
new file mode 100644
index 0000000..11247bb
--- /dev/null
+++ b/apps/nsst/optimizers/conf/configIinputs.json
@@ -0,0 +1,53 @@
+{
+ "NST": [{
+ "NST1 ": {
+ "name": "EmbbNst",
+ "id": "EmbbNst_1",
+ "latency": 20,
+ "uplink": 5,
+ "downlink": 8,
+ "reliability": 95,
+ "areaTrafficCapDL": 10,
+ "areaTrafficCapUL": 100,
+ "maxNumberofUEs": 10000,
+ "areas": " area1|area2",
+ "expDataRateDL": 10,
+ "expDataRateUL": 1000,
+ "uEMobilityLevel": "stationary",
+ "resourceSharingLevel": "shared",
+ "skip_post_instantiation_configuration": "true",
+ "controller_actor": "SO-REF-DATA",
+ "sNSSAI": "01-3226E7D1",
+ "pLMNIdList": "39-00",
+ "sST": "embb",
+ "uEMobilityLevel": "stationary",
+ "activityFactor": "0",
+ "coverageAreaTAList": "Beijing;Beijing;HaidanDistrict;WanshouluStreet",
+ "modeluuid": "fe6c82b9-4e53-4322-a671-e2d8637bfbb7",
+ "modelinvariantuuid": "7d7df980-cb81-45f8-bad9-4e5ad2876393"
+
+ }
+ },
+ {
+ "NST2 ": {
+ "name": "NST_2",
+ "id": "NST_2_id",
+ "latency": 3,
+ "uplink": 7,
+ "downlink": 1,
+ "areaTrafficCapDL": 100,
+ "areaTrafficCapUL": 100,
+ "maxNumberofUEs": 300,
+ "areas": " area1|area2",
+ "expDataRateDL": 10,
+ "expDataRateUL": 30,
+ "uEMobilityLevel": "stationary",
+ "resourceSharingLevel": "shared",
+ "skip_post_instantiation_configuration": "true",
+ "controller_actor": "SO-REF-DATA",
+ "modeluuid": "7981375e-5e0a-4bf5-93fa-f3e3c02f2b15",
+ "modelinvariantuuid": "087f11b4-aca0-4341-8104-e5bb2b73285g"
+ }
+ }
+ ]
+}
diff --git a/apps/nsst/optimizers/nsst_select_processor.py b/apps/nsst/optimizers/nsst_select_processor.py
new file mode 100644
index 0000000..90f40f2
--- /dev/null
+++ b/apps/nsst/optimizers/nsst_select_processor.py
@@ -0,0 +1,155 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Huawei Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+
+"""
+This application generates NST SELECTION API calls using the information received from SO
+"""
+import os
+from osdf.adapters.conductor import conductor
+from osdf.adapters.policy.interface import get_policies
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.utils.interfaces import get_rest_client
+from requests import RequestException
+from threading import Thread
+import traceback
+BASE_DIR = os.path.dirname(__file__)
+
+
+# This is the class for NST Selection
+
+
+class NsstSelection(Thread):
+
+ def __init__(self, osdf_config, request_json):
+ super().__init__()
+ self.osdf_config = osdf_config
+ self.request_json = request_json
+ self.request_info = self.request_json['requestInfo']
+ self.request_info['numSolutions'] = 1
+
+ def run(self):
+ self.process_nsst_selection()
+
+ def process_nsst_selection(self):
+ """Process a PCI request from a Client (build config-db, policy and API call, make the call, return result)
+
+ :param req_object: Request parameters from the client
+ :param osdf_config: Configuration specific to OSDF application (core + deployment)
+ :return: response from NST Opt
+ """
+ try:
+ rest_client = get_rest_client(self.request_json, service='so')
+ solution = self.get_nsst_solution()
+ except Exception as err:
+ error_log.error("Error for {} {}".format(self.request_info.get('requestId'),
+ traceback.format_exc()))
+ error_message = str(err)
+ solution = self.error_response(error_message)
+
+ try:
+ rest_client.request(json=solution, noresponse=True)
+ except RequestException:
+ error_log.error("Error sending asynchronous notification for {} {}".
+ format(self.request_info['requestId'], traceback.format_exc()))
+
+ def get_nsst_solution(self):
+ """the file is in the same folder for now will move it to the conf folder of the has once its
+
+ integrated there...
+ """
+ req_info = self.request_json['requestInfo']
+ requirements = self.request_json['sliceProfile']
+ model_name = "nsst"
+ policies = self.get_app_policies(model_name, "nsst_selection")
+ conductor_response = self.get_conductor(req_info, requirements, policies, model_name)
+ return conductor_response
+
+ def get_nsst_selection_response(self, solutions):
+ """Get NST selection response from final solution
+
+ :param solutions: final solutions
+ :return: NST selection response to send back as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'completed',
+ 'statusMessage': '',
+ 'solutions': solutions}
+
+ def error_response(self, error_message):
+ """Form response message from the error message
+
+ :param error_message: error message while processing the request
+ :return: response json as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'error',
+ 'statusMessage': error_message}
+
+ def get_app_policies(self, model_name, app_name):
+ policy_request_json = self.request_json.copy()
+ policy_request_json['serviceInfo'] = {'serviceName': model_name}
+ debug_log.debug("policy_request_json {}".format(str(policy_request_json)))
+ return get_policies(policy_request_json, app_name) # app_name: nsst_selection
+
+ def get_conductor(self, req_info, request_parameters, policies, model_name):
+ demands = [
+ {
+ "resourceModuleName": model_name,
+ "resourceModelInfo": {}
+ }
+ ]
+
+ try:
+ template_fields = {
+ 'location_enabled': False,
+ 'version': '2020-08-13'
+ }
+ resp = conductor.request(req_info, demands, request_parameters, {}, template_fields,
+ self.osdf_config, policies)
+ except RequestException as e:
+ resp = e.response.json()
+ error = resp['plans'][0]['message']
+ if "Unable to find any" in error:
+ return self.get_nsst_selection_response([])
+ error_log.error('Error from conductor {}'.format(error))
+ return self.error_response(error)
+ debug_log.debug("Response from conductor in get_conductor method {}".format(str(resp)))
+ recommendations = resp["plans"][0].get("recommendations")
+ return self.process_response(recommendations, model_name)
+
+ def process_response(self, recommendations, model_name):
+ """Process conductor response to form the response for the API request
+
+ :param recommendations: recommendations from conductor
+ :return: response json as a dictionary
+ """
+ if not recommendations:
+ return self.get_nsst_selection_response([])
+ solutions = [self.get_solution_from_candidate(rec[model_name]['candidate'])
+ for rec in recommendations]
+ return self.get_nsst_selection_response(solutions)
+
+ def get_solution_from_candidate(self, candidate):
+ if candidate['inventory_type'] == 'nsst':
+ return {
+ 'UUID': candidate['model_version_id'],
+ 'invariantUUID': candidate['model_invariant_id'],
+ 'NSSTName': candidate['model_name'],
+ }
diff --git a/apps/nst/__init__.py b/apps/nst/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nst/__init__.py
diff --git a/apps/nst/models/api/nstSelectionRequest.py b/apps/nst/models/api/nstSelectionRequest.py
new file mode 100644
index 0000000..99c5df6
--- /dev/null
+++ b/apps/nst/models/api/nstSelectionRequest.py
@@ -0,0 +1,43 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Huawei Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType
+from schematics.types.compound import DictType
+from schematics.types.compound import ModelType
+from schematics.types import IntType
+from schematics.types import StringType
+from schematics.types import URLType
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as SO"""
+
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ callbackUrl = URLType(required=True)
+ callbackHeader = DictType(BaseType)
+ sourceId = StringType(required=True)
+ timeout = IntType()
+
+
+class NSTSelectionAPI(OSDFModel):
+ """Request for NST selection """
+
+ requestInfo = ModelType(RequestInfo, required=True)
+ serviceProfile = DictType(BaseType)
diff --git a/apps/nst/optimizers/__init__.py b/apps/nst/optimizers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nst/optimizers/__init__.py
diff --git a/apps/nst/optimizers/conf/configIinputs.json b/apps/nst/optimizers/conf/configIinputs.json
new file mode 100644
index 0000000..11247bb
--- /dev/null
+++ b/apps/nst/optimizers/conf/configIinputs.json
@@ -0,0 +1,53 @@
+{
+ "NST": [{
+ "NST1 ": {
+ "name": "EmbbNst",
+ "id": "EmbbNst_1",
+ "latency": 20,
+ "uplink": 5,
+ "downlink": 8,
+ "reliability": 95,
+ "areaTrafficCapDL": 10,
+ "areaTrafficCapUL": 100,
+ "maxNumberofUEs": 10000,
+ "areas": " area1|area2",
+ "expDataRateDL": 10,
+ "expDataRateUL": 1000,
+ "uEMobilityLevel": "stationary",
+ "resourceSharingLevel": "shared",
+ "skip_post_instantiation_configuration": "true",
+ "controller_actor": "SO-REF-DATA",
+ "sNSSAI": "01-3226E7D1",
+ "pLMNIdList": "39-00",
+ "sST": "embb",
+ "uEMobilityLevel": "stationary",
+ "activityFactor": "0",
+ "coverageAreaTAList": "Beijing;Beijing;HaidanDistrict;WanshouluStreet",
+ "modeluuid": "fe6c82b9-4e53-4322-a671-e2d8637bfbb7",
+ "modelinvariantuuid": "7d7df980-cb81-45f8-bad9-4e5ad2876393"
+
+ }
+ },
+ {
+ "NST2 ": {
+ "name": "NST_2",
+ "id": "NST_2_id",
+ "latency": 3,
+ "uplink": 7,
+ "downlink": 1,
+ "areaTrafficCapDL": 100,
+ "areaTrafficCapUL": 100,
+ "maxNumberofUEs": 300,
+ "areas": " area1|area2",
+ "expDataRateDL": 10,
+ "expDataRateUL": 30,
+ "uEMobilityLevel": "stationary",
+ "resourceSharingLevel": "shared",
+ "skip_post_instantiation_configuration": "true",
+ "controller_actor": "SO-REF-DATA",
+ "modeluuid": "7981375e-5e0a-4bf5-93fa-f3e3c02f2b15",
+ "modelinvariantuuid": "087f11b4-aca0-4341-8104-e5bb2b73285g"
+ }
+ }
+ ]
+}
diff --git a/apps/nst/optimizers/nst_select_processor.py b/apps/nst/optimizers/nst_select_processor.py
new file mode 100644
index 0000000..9e44522
--- /dev/null
+++ b/apps/nst/optimizers/nst_select_processor.py
@@ -0,0 +1,155 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Huawei Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+
+"""
+This application generates NST SELECTION API calls using the information received from SO
+"""
+import os
+from osdf.adapters.conductor import conductor
+from osdf.adapters.policy.interface import get_policies
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.utils.interfaces import get_rest_client
+from requests import RequestException
+from threading import Thread
+import traceback
+BASE_DIR = os.path.dirname(__file__)
+
+
+# This is the class for NST Selection
+
+
+class NstSelection(Thread):
+
+ def __init__(self, osdf_config, request_json):
+ super().__init__()
+ self.osdf_config = osdf_config
+ self.request_json = request_json
+ self.request_info = self.request_json['requestInfo']
+ self.request_info['numSolutions'] = 1
+
+ def run(self):
+ self.process_nst_selection()
+
+ def process_nst_selection(self):
+ """Process a PCI request from a Client (build config-db, policy and API call, make the call, return result)
+
+ :param req_object: Request parameters from the client
+ :param osdf_config: Configuration specific to OSDF application (core + deployment)
+ :return: response from NST Opt
+ """
+ try:
+ rest_client = get_rest_client(self.request_json, service='so')
+ solution = self.get_nst_solution()
+ except Exception as err:
+ error_log.error("Error for {} {}".format(self.request_info.get('requestId'),
+ traceback.format_exc()))
+ error_message = str(err)
+ solution = self.error_response(error_message)
+
+ try:
+ rest_client.request(json=solution, noresponse=True)
+ except RequestException:
+ error_log.error("Error sending asynchronous notification for {} {}".
+ format(self.request_info['requestId'], traceback.format_exc()))
+
+ def get_nst_solution(self):
+ """the file is in the same folder for now will move it to the conf folder of the has once its
+
+ integrated there...
+ """
+ req_info = self.request_json['requestInfo']
+ requirements = self.request_json['serviceProfile']
+ model_name = "nst"
+ policies = self.get_app_policies(model_name, "nst_selection")
+ conductor_response = self.get_conductor(req_info, requirements, policies, model_name)
+ return conductor_response
+
+ def get_nst_selection_response(self, solutions):
+ """Get NST selection response from final solution
+
+ :param solutions: final solutions
+ :return: NST selection response to send back as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'completed',
+ 'statusMessage': '',
+ 'solutions': solutions}
+
+ def error_response(self, error_message):
+ """Form response message from the error message
+
+ :param error_message: error message while processing the request
+ :return: response json as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'error',
+ 'statusMessage': error_message}
+
+ def get_app_policies(self, model_name, app_name):
+ policy_request_json = self.request_json.copy()
+ policy_request_json['serviceInfo'] = {'serviceName': model_name}
+ debug_log.debug("policy_request_json {}".format(str(policy_request_json)))
+ return get_policies(policy_request_json, app_name) # app_name: nst_selection
+
+ def get_conductor(self, req_info, request_parameters, policies, model_name):
+ demands = [
+ {
+ "resourceModuleName": model_name,
+ "resourceModelInfo": {}
+ }
+ ]
+
+ try:
+ template_fields = {
+ 'location_enabled': False,
+ 'version': '2020-08-13'
+ }
+ resp = conductor.request(req_info, demands, request_parameters, {}, template_fields,
+ self.osdf_config, policies)
+ except RequestException as e:
+ resp = e.response.json()
+ error = resp['plans'][0]['message']
+ if "Unable to find any" in error:
+ return self.get_nst_selection_response([])
+ error_log.error('Error from conductor {}'.format(error))
+ return self.error_response(error)
+ debug_log.debug("Response from conductor in get_conductor method {}".format(str(resp)))
+ recommendations = resp["plans"][0].get("recommendations")
+ return self.process_response(recommendations, model_name)
+
+ def process_response(self, recommendations, model_name):
+ """Process conductor response to form the response for the API request
+
+ :param recommendations: recommendations from conductor
+ :return: response json as a dictionary
+ """
+ if not recommendations:
+ return self.get_nst_selection_response([])
+ solutions = [self.get_solution_from_candidate(rec[model_name]['candidate'])
+ for rec in recommendations]
+ return self.get_nst_selection_response(solutions)
+
+ def get_solution_from_candidate(self, candidate):
+ if candidate['inventory_type'] == 'nst':
+ return {
+ 'UUID': candidate['model_version_id'],
+ 'invariantUUID': candidate['model_invariant_id'],
+ 'NSTName': candidate['model_name'],
+ }
diff --git a/apps/nxi_termination/__init__.py b/apps/nxi_termination/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nxi_termination/__init__.py
diff --git a/apps/nxi_termination/models/api/_init_.py b/apps/nxi_termination/models/api/_init_.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nxi_termination/models/api/_init_.py
diff --git a/apps/nxi_termination/models/api/nxi_termination_request.py b/apps/nxi_termination/models/api/nxi_termination_request.py
new file mode 100644
index 0000000..45456cf
--- /dev/null
+++ b/apps/nxi_termination/models/api/nxi_termination_request.py
@@ -0,0 +1,45 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType
+from schematics.types.compound import DictType
+from schematics.types.compound import ModelType
+from schematics.types import IntType
+from schematics.types import StringType
+from schematics.types import URLType
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as SO"""
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ callbackUrl = URLType(required=True)
+ callbackHeader = DictType(BaseType)
+ sourceId = StringType(required=True)
+ timeout = IntType()
+ addtnlArgs = DictType(BaseType)
+
+
+class NxiTerminationApi(OSDFModel):
+ """Request for nxi termination (specific to optimization and additional metadata"""
+ requestInfo = ModelType(RequestInfo, required=True)
+ type = StringType(required=True, choices=['NSI', 'NSSI'])
+ NxIId = StringType(required=True)
+ UUID = StringType()
+ invariantUUID = StringType()
diff --git a/apps/nxi_termination/optimizers/__init__.py b/apps/nxi_termination/optimizers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/nxi_termination/optimizers/__init__.py
diff --git a/apps/nxi_termination/optimizers/remote_opt_processor.py b/apps/nxi_termination/optimizers/remote_opt_processor.py
new file mode 100644
index 0000000..fc3bc17
--- /dev/null
+++ b/apps/nxi_termination/optimizers/remote_opt_processor.py
@@ -0,0 +1,107 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from jinja2 import Template
+
+from apps.nxi_termination.optimizers.response_processor import get_nxi_termination_response
+from osdf.adapters.aai.fetch_aai_data import AAIException
+from osdf.adapters.aai.fetch_aai_data import execute_dsl_query
+from osdf.adapters.aai.fetch_aai_data import get_aai_data
+from osdf.logging.osdf_logging import debug_log
+
+
+def process_nxi_termination_opt(request_json, osdf_config):
+ """Process the nxi Termination request from API layer
+
+ :param request_json: api request
+ :param osdf_config: configuration specific to OSDF app
+ :return: response as a success,failure
+ """
+
+ request_type = request_json["type"]
+ request_info = request_json.get("requestInfo", {})
+ addtnl_args = request_info.get("addtnlArgs", {})
+ query_templates = osdf_config.core["nxi_termination"]["query_templates"]
+
+ inputs = {
+ "instance_id": request_json["NxIId"]
+ }
+
+ try:
+ if request_type == "NSSI":
+ templates = query_templates["nssi"]
+ for template in templates:
+ resource_count = get_resource_count(template, inputs, osdf_config)
+ if resource_count == -1:
+ continue
+ elif resource_count > 1 or (resource_count == 1 and not addtnl_args.get("serviceInstanceId")):
+ terminate_response = False
+ elif resource_count == 0:
+ terminate_response = True
+ elif resource_count == 1 and addtnl_args.get("serviceInstanceId"):
+ new_template = template + "('service-instance-id','{}')".format(addtnl_args["serviceInstanceId"])
+ terminate_response = get_resource_count(new_template, inputs, osdf_config) == 1
+ return set_response("success", "", request_info, terminate_response)
+
+ if request_type == "NSI":
+ allotted_resources = get_allotted_resources(request_json, osdf_config)
+ resource_count = len(allotted_resources)
+ if resource_count == 1 and addtnl_args.get("serviceInstanceId"):
+ debug_log.debug("resource count {}".format(resource_count))
+ terminate_response = False
+ properties = allotted_resources[0]["relationship-data"]
+ for property in properties:
+ if property["relationship-key"] == "service-instance.service-instance-id" \
+ and property["relationship-value"] == addtnl_args.get("serviceInstanceId"):
+ terminate_response = True
+ elif resource_count > 1 or (resource_count == 1 and not addtnl_args.get("serviceInstanceId")):
+ terminate_response = False
+ elif resource_count == 0:
+ terminate_response = True
+
+ return set_response("success", "", request_info, terminate_response)
+ except AAIException as e:
+ reason = str(e)
+ return set_response("failure", reason, request_info)
+
+ except Exception as e:
+ reason = "{} Exception Occurred while processing".format(str(e))
+ return set_response("failure", reason, request_info)
+
+
+def set_response(status, reason, request_info, terminate_response=None):
+ res = dict()
+ res["requestStatus"] = status
+ res["terminateResponse"] = terminate_response
+ res["reason"] = reason
+ return get_nxi_termination_response(request_info, res)
+
+
+def get_resource_count(query_template, inputs, osdf_config):
+ query = Template(query_template).render(inputs)
+ dsl_response = execute_dsl_query(query, "count", osdf_config)
+ debug_log.debug("dsl_response {}".format(dsl_response))
+ # the dsl query with format "count" includes the original service-instance, hence reducing one from the result
+ count = dsl_response["results"][0]
+ return count.get("service-instance", 0) - 1
+
+
+def get_allotted_resources(request_json, osdf_config):
+ response = get_aai_data(request_json, osdf_config)
+ rel_list = response["relationship-list"]["relationship"]
+ return [rel for rel in rel_list if rel["related-to"] == "allotted-resource"]
diff --git a/osdf/logging/onap_common_v1/makefile b/apps/nxi_termination/optimizers/response_processor.py
index 498127e..3ea35c0 100755..100644
--- a/osdf/logging/onap_common_v1/makefile
+++ b/apps/nxi_termination/optimizers/response_processor.py
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,25 +16,17 @@
# -------------------------------------------------------------------------
#
-test:
- rm -f /tmp/cl.*.log
- python CommonLogger.py
- rm -f /tmp/cl.*.log
- python3 CommonLogger.py -k -v
- # python CommonLogger_test.py
- # python3 CommonLogger_test.py
-# STAGEDIR is overridden in ../makefile
-STAGEDIR=/tmp
+def get_nxi_termination_response(request_info, response):
-build: CommonLogger.html
- mkdir -p $(STAGEDIR)/python
- cp -p *.py *.config *.md CommonLogger.html $(STAGEDIR)/python
- chmod a+x $(STAGEDIR)/python/*.py
+ """Get NXI termination response from final solution
-CommonLogger.html: CommonLogger.py
- pydoc -w ./CommonLogger.py
-
-clean:
- rm -rf __pycache__ *.pyc CommonLogger.html
- rm -rf *~
+ :param request_info: request info
+ :param response: response to be send
+ :return: NxI Termination response to send back as dictionary
+ """
+ return {'requestId': request_info['requestId'],
+ 'transactionId': request_info['transactionId'],
+ 'requestStatus': response["requestStatus"],
+ 'terminateResponse': response["terminateResponse"],
+ 'reason': response['reason']}
diff --git a/apps/pci/__init__.py b/apps/pci/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/pci/__init__.py
diff --git a/apps/pci/models/__init__.py b/apps/pci/models/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/pci/models/__init__.py
diff --git a/apps/pci/models/api/__init__.py b/apps/pci/models/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/pci/models/api/__init__.py
diff --git a/osdf/models/api/pciOptimizationRequest.py b/apps/pci/models/api/pciOptimizationRequest.py
index 47b4eba..2aa22f1 100644
--- a/osdf/models/api/pciOptimizationRequest.py
+++ b/apps/pci/models/api/pciOptimizationRequest.py
@@ -19,7 +19,7 @@
from schematics.types import BaseType, StringType, URLType, IntType
from schematics.types.compound import ModelType, ListType, DictType
-from .common import OSDFModel
+from osdf.models.api.common import OSDFModel
class RequestInfo(OSDFModel):
@@ -35,10 +35,18 @@ class RequestInfo(OSDFModel):
timeout = IntType()
+class ANRInfo(OSDFModel):
+ cellId = StringType(required=True)
+ removeableNeighbors = ListType(StringType())
+
+
class CellInfo(OSDFModel):
"""Information specific to CellInfo """
networkId = StringType(required=True)
cellIdList = ListType(StringType(required=True))
+ anrInputList = ListType(ModelType(ANRInfo))
+ fixedPCICells = ListType(StringType())
+ priorityTreatmentCells = ListType(StringType())
trigger = StringType()
diff --git a/osdf/models/api/pciOptimizationResponse.py b/apps/pci/models/api/pciOptimizationResponse.py
index 876c380..019a43a 100644
--- a/osdf/models/api/pciOptimizationResponse.py
+++ b/apps/pci/models/api/pciOptimizationResponse.py
@@ -19,7 +19,7 @@
from schematics.types import StringType, IntType
from schematics.types.compound import ModelType, ListType
-from .common import OSDFModel
+from osdf.models.api.common import OSDFModel
class PCISolution(OSDFModel):
@@ -27,9 +27,15 @@ class PCISolution(OSDFModel):
pci = IntType(required=True)
+class ANRSolution(OSDFModel):
+ cellId = StringType(required=True)
+ removeableNeighbors = ListType(StringType())
+
+
class Solution(OSDFModel):
networkId = StringType(required=True)
pciSolutions = ListType(ListType(ModelType(PCISolution), min_size=1))
+ anrSolutions = ListType(ListType(ModelType(ANRSolution), min_size=1))
class PCIOptimizationResponse(OSDFModel):
diff --git a/apps/pci/optimizers/__init__.py b/apps/pci/optimizers/__init__.py
new file mode 100644
index 0000000..35bc5a0
--- /dev/null
+++ b/apps/pci/optimizers/__init__.py
@@ -0,0 +1,2 @@
+from apps.pci.optimizers.config import configdb
+from apps.pci.optimizers.config import cps
diff --git a/apps/pci/optimizers/config/__init__.py b/apps/pci/optimizers/config/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/pci/optimizers/config/__init__.py
diff --git a/apps/pci/optimizers/config/config_client.py b/apps/pci/optimizers/config/config_client.py
new file mode 100644
index 0000000..7e5a737
--- /dev/null
+++ b/apps/pci/optimizers/config/config_client.py
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+
+class ConfigClient(object):
+
+ subclasses = {}
+
+ @classmethod
+ def register_subclass(cls, type):
+ def decorator(subclass):
+ cls.subclasses[type] = subclass
+ return subclass
+
+ return decorator
+
+ @classmethod
+ def create(cls, type):
+ if type not in cls.subclasses:
+ raise ValueError('Bad config client type {}'.format(type))
+
+ return cls.subclasses[type]()
diff --git a/apps/pci/optimizers/config/configdb.py b/apps/pci/optimizers/config/configdb.py
new file mode 100644
index 0000000..cfc7ce1
--- /dev/null
+++ b/apps/pci/optimizers/config/configdb.py
@@ -0,0 +1,51 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from datetime import datetime as dt
+import uuid
+
+from apps.pci.optimizers.config.config_client import ConfigClient
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import debug_log
+from osdf.utils.interfaces import RestClient
+
+
+@ConfigClient.register_subclass('configdb')
+class ConfigDb(ConfigClient):
+
+ def __init__(self):
+ self.config = osdf_config.deployment
+ uid, passwd = self.config['configDbUserName'], self.config['configDbPassword']
+ headers = dict(transaction_id=str(uuid.uuid4()))
+ self.rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
+
+ def get_cell_list(self, network_id):
+ ts = dt.strftime(dt.now(), '%Y-%m-%d %H:%M:%S%z')
+ cell_list_url = '{}/{}/{}/{}'.format(self.config['configDbUrl'],
+ self.config['configDbGetCellListUrl'], network_id, ts)
+ return self.rc.request(raw_response=True, url=cell_list_url).json()
+
+ def get_nbr_list(self, network_id, cell_id):
+ ts = dt.strftime(dt.now(), '%Y-%m-%d %H:%M:%S%z')
+ nbr_list_url = '{}/{}/{}/{}'.format(self.config['configDbUrl'],
+ self.config['configDbGetNbrListUrl'], cell_id, ts)
+ response = self.rc.request(url=nbr_list_url, raw_response=True).json()
+
+ debug_log.debug("cell_id {} nbr_list {}".format(cell_id, response.get('nbrList')))
+
+ return response.get('nbrList', [])
diff --git a/apps/pci/optimizers/config/cps.py b/apps/pci/optimizers/config/cps.py
new file mode 100644
index 0000000..9cf1b1f
--- /dev/null
+++ b/apps/pci/optimizers/config/cps.py
@@ -0,0 +1,72 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+
+from apps.pci.optimizers.config.config_client import ConfigClient
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import debug_log
+from osdf.utils.interfaces import RestClient
+
+
+@ConfigClient.register_subclass('cps')
+class Cps(ConfigClient):
+
+ def __init__(self):
+ self.config = osdf_config.deployment
+ username, password = self.config['cpsUsername'], self.config['cpsPassword']
+ headers = {
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ }
+ self.rc = RestClient(userid=username, passwd=password, method="POST",
+ log_func=debug_log.debug, headers=headers)
+
+ def get_cell_list(self, network_id):
+ cell_list_url = '{}/{}'.format(self.config['cpsUrl'], self.config['cpsCellListUrl'])
+ data = {
+ 'inputParameters': {
+ 'regionId': network_id
+ }
+ }
+ response = self.rc.request(url=cell_list_url, data=json.dumps(data))
+ debug_log.debug("cell list response {}".format(response))
+ return sorted([x['idNRCellCU'] for x in response.get('NRCellCU')])
+
+ def get_nbr_list(self, network_id, cell_id):
+ nbr_list_url = '{}/{}'.format(self.config['cpsUrl'], self.config['cpsNbrListUrl'])
+ data = {
+ 'inputParameters': {
+ 'regionId': network_id,
+ 'idNRCellCU': cell_id
+ }
+ }
+ response = self.rc.request(url=nbr_list_url, data=json.dumps(data))
+ debug_log.debug("nbr list response {}".format(response))
+ nbr_list = []
+ for cell_relation in response.get('NRCellRelation'):
+ nbr = {
+ 'targetCellId': cell_relation['attributes']['nRTCI'],
+ 'pciValue': int(cell_relation['attributes']['nRPCI']),
+ 'ho': cell_relation['attributes']['isHOAllowed']
+ }
+ nbr_list.append(nbr)
+
+ debug_log.debug("cell_id {} nbr_list {}".format(cell_id, nbr_list))
+
+ return nbr_list
diff --git a/osdf/optimizers/pciopt/configdb.py b/apps/pci/optimizers/config_request.py
index bebc5c0..f62641d 100644
--- a/osdf/optimizers/pciopt/configdb.py
+++ b/apps/pci/optimizers/config_request.py
@@ -16,50 +16,40 @@
# -------------------------------------------------------------------------
#
-from datetime import datetime as dt
-
-from osdf.logging.osdf_logging import debug_log
-from osdf.utils.interfaces import RestClient
+from apps.pci.optimizers.config.config_client import ConfigClient
def request(req_object, osdf_config, flat_policies):
- """
- Process a configdb request from a Client (build Conductor API call, make the call, return result)
+ """Process a configdb request from a Client (build Conductor API call, make the call, return result)
+
:param req_object: Request parameters from the client
:param osdf_config: Configuration specific to OSDF application (core + deployment)
:param flat_policies: policies related to PCI Opt (fetched based on request)
:return: response from ConfigDB (accounting for redirects from Conductor service
"""
cell_list_response = {}
- config = osdf_config.deployment
- local_config = osdf_config.core
- uid, passwd = config['configDbUserName'], config['configDbPassword']
- req_id = req_object['requestInfo']['requestId']
- transaction_id = req_object['requestInfo']['transactionId']
- headers = dict(transaction_id=transaction_id)
network_id = req_object['cellInfo']['networkId']
cell_list_response['network_id'] = network_id
- rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
+ config = osdf_config.deployment
- cell_list_url = '{}/{}?networkId={}'.format(config['configDbUrl'], config['configDbGetCellListUrl'], network_id)
+ config_client = ConfigClient.create(config['configClientType'])
- cell_list_resp = rc.request(raw_response=True, url=cell_list_url)
- cell_resp = cell_list_resp.json()
- ts = dt.strftime(dt.now(), '%Y-%m-%dT%H:%M:%S%z')
+ cell_resp = config_client.get_cell_list(network_id)
cell_list = []
count = 0
for cell_id in cell_resp:
- cell_info = {'cell_id': cell_id, 'id': count}
- nbr_list_url = '{}/{}?cellId={}&ts={}'.format(config['configDbUrl'], config['configDbGetNbrListUrl'], cell_id,
- ts)
- nbr_list_raw = rc.request(url=nbr_list_url, raw_response=True)
- cell_info['nbr_list'] = nbr_list_raw.json()
+ cell_info = {
+ 'cell_id': cell_id,
+ 'id': count,
+ 'nbr_list': config_client.get_nbr_list(network_id, cell_id)
+ }
cell_list.append(cell_info)
count += 1
cell_list_response['cell_list'] = cell_list
+
return cell_resp, cell_list_response
diff --git a/osdf/optimizers/pciopt/pci_opt_processor.py b/apps/pci/optimizers/pci_opt_processor.py
index 989f578..a58d2f4 100644
--- a/osdf/optimizers/pciopt/pci_opt_processor.py
+++ b/apps/pci/optimizers/pci_opt_processor.py
@@ -17,14 +17,20 @@
#
import traceback
+
+from onaplogging.mdcContext import MDC
from requests import RequestException
-from osdf.logging.osdf_logging import metrics_log, MH, error_log
+from apps.pci.optimizers.config_request import request as config_request
+from apps.pci.optimizers.solver.optimizer import pci_optimize as optimize
+from apps.pci.optimizers.solver.pci_utils import get_cell_id
+from apps.pci.optimizers.solver.pci_utils import get_pci_value
+from osdf.logging.osdf_logging import error_log
+from osdf.logging.osdf_logging import metrics_log
+from osdf.logging.osdf_logging import MH
from osdf.operation.error_handling import build_json_error_body
from osdf.utils.interfaces import get_rest_client
-from .configdb import request as config_request
-from .solver.optimizer import pci_optimize as optimize
-from .solver.pci_utils import get_cell_id, get_pci_value
+from osdf.utils.mdc_utils import mdc_from_json
"""
This application generates PCI Optimization API calls using the information received from PCI-Handler-MS, SDN-C
@@ -33,18 +39,18 @@ and Policy.
def process_pci_optimation(request_json, osdf_config, flat_policies):
- """
- Process a PCI request from a Client (build config-db, policy and API call, make the call, return result)
+ """Process a PCI request from a Client (build config-db, policy and API call, make the call, return result)
+
:param req_object: Request parameters from the client
:param osdf_config: Configuration specific to OSDF application (core + deployment)
:param flat_policies: policies related to pci (fetched based on request)
:return: response from PCI Opt
"""
try:
+ mdc_from_json(request_json)
rc = get_rest_client(request_json, service="pcih")
req_id = request_json["requestInfo"]["requestId"]
cell_info_list, network_cell_info = config_request(request_json, osdf_config, flat_policies)
-
pci_response = get_solutions(cell_info_list, network_cell_info, request_json)
metrics_log.info(MH.inside_worker_thread(req_id))
@@ -56,40 +62,71 @@ def process_pci_optimation(request_json, osdf_config, flat_policies):
metrics_log.info(MH.sending_response(req_id, "ERROR"))
rc.request(json=body, noresponse=True)
except RequestException:
+ MDC.put('requestID', req_id)
error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
- return
+ raise err
try:
metrics_log.info(MH.calling_back_with_body(req_id, rc.url, pci_response))
+ error_log.error("pci response: {}".format(str(pci_response)))
rc.request(json=pci_response, noresponse=True)
except RequestException: # can't do much here but log it and move on
error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
def get_solutions(cell_info_list, network_cell_info, request_json):
+ status, pci_solutions, anr_solutions = build_solution_list(cell_info_list, network_cell_info, request_json)
return {
"transactionId": request_json['requestInfo']['transactionId'],
"requestId": request_json["requestInfo"]["requestId"],
"requestStatus": "completed",
- "statusMessage": "success",
- "solutions": [
- {
- 'networkId': request_json['cellInfo']['networkId'],
- 'pciSolutions': build_solution_list(cell_info_list, network_cell_info, request_json)
- }
- ]
+ "statusMessage": status,
+ "solutions": {
+ 'networkId': request_json['cellInfo']['networkId'],
+ 'pciSolutions': pci_solutions,
+ 'anrSolutions': anr_solutions
+ }
}
def build_solution_list(cell_info_list, network_cell_info, request_json):
- solution_list = []
- for cell in request_json['cellInfo']['cellIdList']:
- opt_solution = optimize(cell, network_cell_info, cell_info_list)
- sol = opt_solution[0]['pci']
- for k, v in sol.items():
+ status = "success"
+ req_id = request_json["requestInfo"]["requestId"]
+ pci_solutions = []
+ anr_solutions = []
+ try:
+ opt_solution = optimize(network_cell_info, cell_info_list, request_json)
+ if opt_solution == 'UNSATISFIABLE':
+ status = 'inconsistent input'
+ return status, pci_solutions, anr_solutions
+ else:
+ pci_solutions = build_pci_solution(network_cell_info, opt_solution['pci'])
+ anr_solutions = build_anr_solution(network_cell_info, opt_solution.get('removables', {}))
+ except RuntimeError:
+ error_log.error("Failed finding solution for {} {}".format(req_id, traceback.format_exc()))
+ status = "failed"
+ return status, pci_solutions, anr_solutions
+
+
+def build_pci_solution(network_cell_info, pci_solution):
+ pci_solutions = []
+ for k, v in pci_solution.items():
+ old_pci = get_pci_value(network_cell_info, k)
+ if old_pci != v:
response = {
'cellId': get_cell_id(network_cell_info, k),
- 'pci': get_pci_value(network_cell_info, v)
+ 'pci': v
}
- solution_list.append(response)
- return solution_list
+ pci_solutions.append(response)
+ return pci_solutions
+
+
+def build_anr_solution(network_cell_info, removables):
+ anr_solutions = []
+ for k, v in removables.items():
+ response = {
+ 'cellId': get_cell_id(network_cell_info, k),
+ 'removeableNeighbors': list(map(lambda x: get_cell_id(network_cell_info, x), v))
+ }
+ anr_solutions.append(response)
+ return anr_solutions
diff --git a/apps/pci/optimizers/solver/__init__.py b/apps/pci/optimizers/solver/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/pci/optimizers/solver/__init__.py
diff --git a/osdf/optimizers/pciopt/solver/min_confusion.mzn b/apps/pci/optimizers/solver/min_confusion.mzn
index 803f914..ff56c18 100644
--- a/osdf/optimizers/pciopt/solver/min_confusion.mzn
+++ b/apps/pci/optimizers/solver/min_confusion.mzn
@@ -15,6 +15,7 @@
%
% -------------------------------------------------------------------------
%
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Parameters and its assertions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -27,21 +28,21 @@ int: NUM_PCIS;
% Number of edges between neighbor nodes. There is a edge (i,j) if and only
% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
-% handoff between i and j. Such edges are used to avoid **CONFLICTS**, i.e.,
+% handoff between i and j. Such edges are used to avoid **COLLISION**, i.e.,
% to guarantee that nodes i and j have different PCIs.
-int: NUM_CONFLICT_EDGES;
+int: NUM_NEIGHBORS;
% Each line represents an edge between direct neighbors as defined before.
-array[1..NUM_CONFLICT_EDGES, 1..2] of int: CONFLICT_EDGES;
+array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
% Number of undirect neighbor pairs (j, k) such that both j and k are direct
-% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
+% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
-int: NUM_CONFUSION_EDGES;
+int: NUM_SECOND_LEVEL_NEIGHBORS;
% Each line represents an edge between undirect neighbors as defined before.
-array[1..NUM_CONFUSION_EDGES, 1..2] of int: CONFUSION_EDGES;
+array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Decision variables
@@ -54,10 +55,10 @@ array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
% Constraints
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Direct neighbors must have different PCIs for avoid **CONFLICTS**.
-constraint
-forall(i in 1..NUM_CONFLICT_EDGES)(
- pci[CONFLICT_EDGES[i, 1]] != pci[CONFLICT_EDGES[i, 2]]
+% Direct neighbors must have different PCIs for avoid **COLLISION**.
+constraint
+forall(i in 1..NUM_NEIGHBORS)(
+ pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -66,8 +67,9 @@ forall(i in 1..NUM_CONFLICT_EDGES)(
% Total number of confusions.
var int: total_confusions =
- sum([bool2int(pci[CONFUSION_EDGES[i, 1]] == pci[CONFUSION_EDGES[i, 2]])
- | i in 1..NUM_CONFUSION_EDGES]);
+ sum([bool2int(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] ==
+ pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
+ | i in 1..NUM_SECOND_LEVEL_NEIGHBORS]);
% Minimize the total number of confusions.
solve :: int_search(pci, smallest, indomain_min, complete)
@@ -78,18 +80,19 @@ minimize total_confusions;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
output
-["PCI assigment"] ++
+["PCI assigment"] ++
["\nnode,pci"] ++
[
"\n" ++ show(node) ++ "," ++ show(pci[node])
| node in 0..NUM_NODES-1
] ++
-["\n\nConfusions"] ++
+["\n\nConfusions"] ++
["\nTotal confusions: " ++ show(total_confusions)] ++
["\nConfusion pairs"] ++
[
- "\n" ++ show(CONFUSION_EDGES[i, 1]) ++ "," ++ show(CONFUSION_EDGES[i, 2])
-| i in 1..NUM_CONFUSION_EDGES where
- fix(pci[CONFUSION_EDGES[i, 1]] == pci[CONFUSION_EDGES[i, 2]])
+ "\n" ++ show(SECOND_LEVEL_NEIGHBORS[i, 1]) ++ "," ++
+ show(SECOND_LEVEL_NEIGHBORS[i, 2])
+| i in 1..NUM_SECOND_LEVEL_NEIGHBORS where
+ fix(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] == pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
]
diff --git a/apps/pci/optimizers/solver/min_confusion_inl.mzn b/apps/pci/optimizers/solver/min_confusion_inl.mzn
new file mode 100644
index 0000000..e677e27
--- /dev/null
+++ b/apps/pci/optimizers/solver/min_confusion_inl.mzn
@@ -0,0 +1,156 @@
+% -------------------------------------------------------------------------
+% Copyright (c) 2018 AT&T Intellectual Property
+%
+% Licensed under the Apache License, Version 2.0 (the "License");
+% you may not use this file except in compliance with the License.
+% You may obtain a copy of the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+% See the License for the specific language governing permissions and
+% limitations under the License.
+%
+% -------------------------------------------------------------------------
+%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters and its assertions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Number of cells/radios.
+int: NUM_NODES;
+
+% Maximum number of Physical Cell Identifiers to be assigned to the nodes.
+int: NUM_PCIS;
+
+% Number of edges between neighbor nodes. There is a edge (i,j) if and only
+% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
+% handoff between i and j. Such edges are used to avoid **COLLISION**, i.e.,
+% to guarantee that nodes i and j have different PCIs.
+int: NUM_NEIGHBORS;
+
+% Each line represents an edge between direct neighbors as defined before.
+array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
+
+% Number of undirect neighbor pairs (j, k) such that both j and k are direct
+% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
+% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
+% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
+int: NUM_SECOND_LEVEL_NEIGHBORS;
+
+% Each line represents an edge between undirect neighbors as defined before.
+array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
+
+% Number of ignorable neighbor links. Such links can be ignored during
+% optimization if needed.
+int: NUM_IGNORABLE_NEIGHBOR_LINKS;
+
+% The links that can be ignored if needed. Each line represents the two ends
+% of the links, like the previous structures.
+array[1..NUM_IGNORABLE_NEIGHBOR_LINKS, 1..2] of int: IGNORABLE_NEIGHBOR_LINKS;
+
+% ids of cells for which the pci should remain unchanged
+set of int: PCI_UNCHANGEABLE_CELLS;
+
+% This array has the original pcis of all the cells. array is indexed by the ids
+% of the cell. eg. ORIGINAL_PCIS[3] returns the pci of cell whose id is 3.
+% ids start from 0
+array[1..NUM_NODES] of 0..NUM_PCIS-1: ORIGINAL_PCIS;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Decision variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Defines the PCI for each node.
+array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
+
+array[1..NUM_IGNORABLE_NEIGHBOR_LINKS] of var 0..1: used_ignorables;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Constraints
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% fixed pci cells
+constraint
+if(length(PCI_UNCHANGEABLE_CELLS) !=0) then
+forall(i in PCI_UNCHANGEABLE_CELLS)(
+ pci[i] == ORIGINAL_PCIS[i+1]
+)
+endif;
+
+% Direct neighbors must have different PCIs for avoid **COLLISION**.
+% Forced links.
+constraint
+forall(i in 1..NUM_NEIGHBORS, j in 1..NUM_IGNORABLE_NEIGHBOR_LINKS
+ where
+ NEIGHBORS[i, 1] != IGNORABLE_NEIGHBOR_LINKS[j, 1] \/
+ NEIGHBORS[i, 2] != IGNORABLE_NEIGHBOR_LINKS[j, 2]
+)(
+ pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
+);
+
+
+% Ignorable links.
+constraint
+forall(i in 1..NUM_NEIGHBORS, j in 1..NUM_IGNORABLE_NEIGHBOR_LINKS
+ where
+ NEIGHBORS[i, 1] == IGNORABLE_NEIGHBOR_LINKS[j, 1] /\
+ NEIGHBORS[i, 2] == IGNORABLE_NEIGHBOR_LINKS[j, 2]
+)(
+ used_ignorables[j] >= bool2int(pci[NEIGHBORS[i, 1]] == pci[NEIGHBORS[i, 2]])
+);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Objective function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Total number of confusions.
+var int: total_confusions =
+ sum([bool2int(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] ==
+ pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
+ | i in 1..NUM_SECOND_LEVEL_NEIGHBORS]);
+
+% Total number of used ignorables links.
+var int: total_used_ignorables = sum(used_ignorables);
+
+solve :: int_search(pci, smallest, indomain_min, complete)
+
+% Minimize the total number of confusions.
+%minimize total_confusions;
+
+% Minimize the total number of confusions first,
+% then the number of used ignorables links.
+minimize (2 * NUM_IGNORABLE_NEIGHBOR_LINKS * total_confusions) +
+ total_used_ignorables;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+output
+["PCI assigment"] ++
+["\nnode,pci"] ++
+[
+ "\n" ++ show(node) ++ "," ++ show(pci[node])
+| node in 0..NUM_NODES-1
+] ++
+["\n\nTotal used ignorables links: " ++ show(total_used_ignorables)] ++
+["\nUsed ignorables links: "] ++
+[
+ "\n" ++ show(IGNORABLE_NEIGHBOR_LINKS[i, 1]) ++
+ "," ++ show(IGNORABLE_NEIGHBOR_LINKS[i, 2])
+ | i in 1..NUM_IGNORABLE_NEIGHBOR_LINKS where fix(used_ignorables[i] > 0)
+] ++
+["\n\nConfusions"] ++
+["\nTotal confusions: " ++ show(total_confusions)] ++
+["\nConfusion pairs"] ++
+[
+ "\n" ++ show(SECOND_LEVEL_NEIGHBORS[i, 1]) ++ "," ++
+ show(SECOND_LEVEL_NEIGHBORS[i, 2])
+ | i in 1..NUM_SECOND_LEVEL_NEIGHBORS where
+ fix(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] == pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
+]
+
diff --git a/apps/pci/optimizers/solver/ml_model.py b/apps/pci/optimizers/solver/ml_model.py
new file mode 100644
index 0000000..c239be8
--- /dev/null
+++ b/apps/pci/optimizers/solver/ml_model.py
@@ -0,0 +1,72 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+
+from apps.pci.optimizers.solver.pci_utils import get_id
+from osdf.adapters.dcae import des
+from osdf.adapters.dcae.des import DESException
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import error_log
+
+
+class MlModel(object):
+ def __init__(self):
+ self.config = osdf_config.core['PCI']
+
+ def get_additional_inputs(self, dzn_data, network_cell_info):
+ """Add/update additional info to the existing models.
+
+ The method returns nothing. Instead, it modifies the dzn_data
+ :params: dzn_data: map with data for the optimization
+ """
+ self.compute_ml_model(dzn_data, network_cell_info)
+
+ def compute_ml_model(self, dzn_data, network_cell_info):
+ average_ho_threshold = self.config['ML']['average_ho_threshold']
+ latest_ho_threshold = self.config['ML']['latest_ho_threshold']
+
+ fixed_cells = set()
+ for cell in network_cell_info['cell_list']:
+ cell_id = cell['cell_id']
+ average_ho, latest_ho = self.get_ho_details(cell['cell_id'])
+ if average_ho > average_ho_threshold or latest_ho > latest_ho_threshold:
+ fixed_cells.add(get_id(network_cell_info, cell_id))
+
+ fixed_cells.update(dzn_data.get('PCI_UNCHANGEABLE_CELLS', []))
+ dzn_data['PCI_UNCHANGEABLE_CELLS'] = fixed_cells
+
+ def get_ho_details(self, cell_id):
+ service_id = self.config['DES']['service_id']
+ request_data = self.config['DES']['filter']
+ request_data['cell_id'] = cell_id
+ try:
+ result = des.extract_data(service_id, json.dumps(request_data))
+ except DESException as e:
+ error_log.error("Error while calling DES {}".format(e))
+ return 0, 0
+
+ if not result:
+ return 0, 0
+
+ ho_list = []
+ for pm_data in result:
+ ho = pm_data['overallHoAtt']
+ ho_list.append(ho)
+
+ return sum(ho_list) / len(ho_list), ho_list[0]
diff --git a/osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn b/apps/pci/optimizers/solver/no_conflicts_no_confusion.mzn
index 19fabb9..f059d4a 100644
--- a/osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn
+++ b/apps/pci/optimizers/solver/no_conflicts_no_confusion.mzn
@@ -28,21 +28,30 @@ int: NUM_PCIS;
% Number of edges between neighbor nodes. There is a edge (i,j) if and only
% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
-% handoff between i and j. Such edges are used to avoid **CONFLICTS**, i.e.,
+% handoff between i and j. Such edges are used to avoid **COLLISIONS**, i.e.,
% to guarantee that nodes i and j have different PCIs.
-int: NUM_CONFLICT_EDGES;
+int: NUM_NEIGHBORS;
% Each line represents an edge between direct neighbors as defined before.
-array[1..NUM_CONFLICT_EDGES, 1..2] of int: CONFLICT_EDGES;
+array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
% Number of undirect neighbor pairs (j, k) such that both j and k are direct
-% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
+% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
-int: NUM_CONFUSION_EDGES;
+int: NUM_SECOND_LEVEL_NEIGHBORS;
% Each line represents an edge between undirect neighbors as defined before.
-array[1..NUM_CONFUSION_EDGES, 1..2] of int: CONFUSION_EDGES;
+array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
+
+% ids of cells for which the pci should remain unchanged
+set of int: PCI_UNCHANGEABLE_CELLS;
+
+% This array has the original pcis of all the cells. array is indexed by the ids
+% of the cell. eg. ORIGINAL_PCIS[3] returns the pci of cell whose id is 3.
+% ids start from 0
+% array[0..NUM_NODES-1] of 0..NUM_PCIS-1: ORIGINAL_PCIS;
+array[1..NUM_NODES] of 0..NUM_PCIS-1: ORIGINAL_PCIS;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Decision variables
@@ -55,16 +64,24 @@ array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
% Constraints
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Direct neighbors must have different PCIs for avoid **CONFLICTS**.
-constraint
-forall(i in 1..NUM_CONFLICT_EDGES)(
- pci[CONFLICT_EDGES[i, 1]] != pci[CONFLICT_EDGES[i, 2]]
+constraint
+if(length(PCI_UNCHANGEABLE_CELLS) !=0) then
+forall(i in PCI_UNCHANGEABLE_CELLS)(
+ pci[i] == ORIGINAL_PCIS[i+1]
+)
+endif;
+
+
+% Direct neighbors must have different PCIs for avoid **COLLISION**.
+constraint
+forall(i in 1..NUM_NEIGHBORS)(
+ pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
);
% Undirect neighbors must have different PCIs for avoid **CONFUSIONS**.
-constraint
-forall(i in 1..NUM_CONFUSION_EDGES)(
- pci[CONFUSION_EDGES[i, 1]] != pci[CONFUSION_EDGES[i, 2]]
+constraint
+forall(i in 1..NUM_SECOND_LEVEL_NEIGHBORS)(
+ pci[SECOND_LEVEL_NEIGHBORS[i, 1]] != pci[SECOND_LEVEL_NEIGHBORS[i, 2]]
);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/apps/pci/optimizers/solver/optimizer.py b/apps/pci/optimizers/solver/optimizer.py
new file mode 100644
index 0000000..13298ed
--- /dev/null
+++ b/apps/pci/optimizers/solver/optimizer.py
@@ -0,0 +1,179 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from collections import defaultdict
+import itertools
+import os
+import pymzn
+
+from apps.pci.optimizers.solver.ml_model import MlModel
+from apps.pci.optimizers.solver.pci_utils import get_id
+from apps.pci.optimizers.solver.pci_utils import mapping
+from osdf.config.base import osdf_config
+
+BASE_DIR = os.path.dirname(__file__)
+cell_id_mapping = dict()
+id_cell_mapping = dict()
+
+
+def pci_optimize(network_cell_info, cell_info_list, request_json):
+ global cell_id_mapping, id_cell_mapping
+ cell_id_mapping, id_cell_mapping = mapping(network_cell_info)
+ original_pcis = get_original_pci_list(network_cell_info)
+ unchangeable_pcis = get_ids_of_fixed_pci_cells(request_json['cellInfo'].get('fixedPCICells', []))
+ neighbor_edges = get_neighbor_list(network_cell_info)
+ second_level_edges = get_second_level_neighbor(network_cell_info)
+ ignorable_links = get_ignorable_links(network_cell_info, request_json)
+ anr_flag = is_anr(request_json)
+
+ dzn_data = build_dzn_data(cell_info_list, ignorable_links, neighbor_edges, second_level_edges, anr_flag,
+ original_pcis, unchangeable_pcis)
+
+ ml_enabled = osdf_config.core['PCI']['ml_enabled']
+ if ml_enabled:
+ MlModel().get_additional_inputs(dzn_data, network_cell_info)
+
+ return build_pci_solution(dzn_data, ignorable_links, anr_flag)
+
+
+def get_ids_of_fixed_pci_cells(fixed_pci_list):
+ fixed_pci_ids = set()
+ for cell in fixed_pci_list:
+ fixed_pci_ids.add(cell_id_mapping[cell])
+ return fixed_pci_ids
+
+
+def get_cell_id_pci_mapping(network_cell_info):
+ original_pcis = dict()
+ for cell in network_cell_info['cell_list']:
+ for nbr in cell['nbr_list']:
+ if cell_id_mapping[nbr['targetCellId']] not in original_pcis:
+ original_pcis[cell_id_mapping[nbr['targetCellId']]] = nbr['pciValue']
+ return original_pcis
+
+
+def get_original_pci_list(network_cell_info):
+ cell_id_pci_mapping = get_cell_id_pci_mapping(network_cell_info)
+ original_pcis_list = []
+ for i in range(len(cell_id_pci_mapping)):
+ original_pcis_list.append(cell_id_pci_mapping.get(i))
+ return original_pcis_list
+
+
+def build_pci_solution(dzn_data, ignorable_links, anr_flag):
+ mzn_solution = solve(get_mzn_model(anr_flag), dzn_data)
+ if mzn_solution == 'UNSATISFIABLE':
+ return mzn_solution
+ solution = {'pci': mzn_solution[0]['pci']}
+
+ if anr_flag:
+ removables = defaultdict(list)
+ used_ignorables = mzn_solution[0]['used_ignorables']
+ index = 0
+ for i in ignorable_links:
+ if used_ignorables[index] > 0:
+ removables[i[0]].append(i[1])
+ index += 1
+ solution['removables'] = removables
+ return solution
+
+
+def build_dzn_data(cell_info_list, ignorable_links, neighbor_edges, second_level_edges, anr_flag, original_pcis,
+ unchangeable_pcis):
+ dzn_data = {
+ 'NUM_NODES': len(cell_info_list),
+ 'NUM_PCIS': len(cell_info_list),
+ 'NUM_NEIGHBORS': len(neighbor_edges),
+ 'NEIGHBORS': get_list(neighbor_edges),
+ 'NUM_SECOND_LEVEL_NEIGHBORS': len(second_level_edges),
+ 'SECOND_LEVEL_NEIGHBORS': get_list(second_level_edges),
+ 'PCI_UNCHANGEABLE_CELLS': unchangeable_pcis,
+ 'ORIGINAL_PCIS': original_pcis
+ }
+ if anr_flag:
+ dzn_data['NUM_IGNORABLE_NEIGHBOR_LINKS'] = len(ignorable_links)
+ dzn_data['IGNORABLE_NEIGHBOR_LINKS'] = get_list(ignorable_links)
+ return dzn_data
+
+
+def get_mzn_model(anr_flag):
+ if anr_flag:
+ mzn_model = os.path.join(BASE_DIR, 'min_confusion_inl.mzn')
+ else:
+ mzn_model = os.path.join(BASE_DIR, 'no_conflicts_no_confusion.mzn')
+ return mzn_model
+
+
+def is_anr(request_json):
+ return 'pci-anr' in request_json["requestInfo"]["optimizers"]
+
+
+def get_list(edge_list):
+ array_list = []
+ for s in edge_list:
+ array_list.append([s[0], s[1]])
+ return sorted(array_list)
+
+
+def solve(mzn_model, dzn_data):
+ return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
+
+
+def get_neighbor_list(network_cell_info):
+ neighbor_list = set()
+ for cell in network_cell_info['cell_list']:
+ add_to_neighbor_list(network_cell_info, cell, neighbor_list)
+ return neighbor_list
+
+
+def add_to_neighbor_list(network_cell_info, cell, neighbor_list):
+ for nbr in cell.get('nbr_list', []):
+ host_id = cell['id']
+ nbr_id = get_id(network_cell_info, nbr['targetCellId'])
+ if nbr_id and host_id != nbr_id:
+ neighbor_list.add((host_id, nbr_id))
+
+
+def get_second_level_neighbor(network_cell_info):
+ second_neighbor_list = set()
+ for cell in network_cell_info['cell_list']:
+ comb_list = build_second_level_list(network_cell_info, cell)
+ for comb in comb_list:
+ if comb[0] and comb[1]:
+ second_neighbor_list.add((comb[0], comb[1]))
+ return sorted(second_neighbor_list)
+
+
+def build_second_level_list(network_cell_info, cell):
+ second_nbr_list = []
+ for nbr in cell.get('nbr_list', []):
+ second_nbr_list.append(get_id(network_cell_info, nbr['targetCellId']))
+ return [list(elem) for elem in list(itertools.combinations(second_nbr_list, 2))]
+
+
+def get_ignorable_links(network_cell_info, request_json):
+ ignorable_list = set()
+ anr_input_list = request_json["cellInfo"].get('anrInputList', [])
+ if anr_input_list:
+ for anr_info in anr_input_list:
+ cell_id = get_id(network_cell_info, anr_info['cellId'])
+ anr_removable = anr_info.get('removeableNeighbors', [])
+ for anr in anr_removable:
+ ignorable_list.add((cell_id, get_id(network_cell_info, anr)))
+ return ignorable_list
diff --git a/osdf/optimizers/pciopt/solver/pci_utils.py b/apps/pci/optimizers/solver/pci_utils.py
index 71b5dd2..7db3a6f 100644
--- a/osdf/optimizers/pciopt/solver/pci_utils.py
+++ b/apps/pci/optimizers/solver/pci_utils.py
@@ -16,6 +16,13 @@
# -------------------------------------------------------------------------
#
+def mapping(network_cell_info):
+ cell_id_mapping= dict()
+ id_cell_mapping = dict()
+ for i in network_cell_info['cell_list']:
+ cell_id_mapping[i['cell_id']] = i['id']
+ id_cell_mapping[i['id']] = i['cell_id']
+ return cell_id_mapping, id_cell_mapping
def get_id(network_cell_info, cell_id):
for i in network_cell_info['cell_list']:
@@ -30,10 +37,11 @@ def get_cell_id(network_cell_info, id):
return i['cell_id']
return None
+
def get_pci_value(network_cell_info, id):
cell_id = get_cell_id(network_cell_info, id)
for i in network_cell_info['cell_list']:
for j in i['nbr_list']:
- if cell_id == j['cellId']:
+ if cell_id == j['targetCellId']:
return j['pciValue']
return None
diff --git a/apps/placement/__init__.py b/apps/placement/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/placement/__init__.py
diff --git a/apps/placement/models/__init__.py b/apps/placement/models/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/placement/models/__init__.py
diff --git a/apps/placement/models/api/__init__.py b/apps/placement/models/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/placement/models/api/__init__.py
diff --git a/osdf/models/api/placementRequest.py b/apps/placement/models/api/placementRequest.py
index aa71eac..e04c2af 100644
--- a/osdf/models/api/placementRequest.py
+++ b/apps/placement/models/api/placementRequest.py
@@ -16,8 +16,8 @@
# -------------------------------------------------------------------------
#
-from .common import OSDFModel
-from schematics.types import BaseType, StringType, URLType, IntType
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType, StringType, URLType, IntType, BooleanType
from schematics.types.compound import ModelType, ListType, DictType
@@ -48,7 +48,7 @@ class ModelMetaData(OSDFModel):
modelName = StringType()
modelType = StringType()
modelVersion = StringType()
- modelCustomizationName = StringType(required=True)
+ modelCustomizationName = StringType()
class LicenseModel(OSDFModel):
@@ -102,4 +102,4 @@ class PlacementAPI(OSDFModel):
requestInfo = ModelType(RequestInfo, required=True)
placementInfo = ModelType(PlacementInfo, required=True)
licenseInfo = ModelType(LicenseInfo)
- serviceInfo = ModelType(ServiceInfo, required=True)
+ serviceInfo = ModelType(ServiceInfo, required=True) \ No newline at end of file
diff --git a/osdf/models/api/placementResponse.py b/apps/placement/models/api/placementResponse.py
index 063a9a8..13b8d7a 100644
--- a/osdf/models/api/placementResponse.py
+++ b/apps/placement/models/api/placementResponse.py
@@ -16,7 +16,7 @@
# -------------------------------------------------------------------------
#
-from .common import OSDFModel
+from osdf.models.api.common import OSDFModel
from schematics.types import BaseType, StringType
from schematics.types.compound import ModelType, ListType, DictType
diff --git a/apps/placement/optimizers/__init__.py b/apps/placement/optimizers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/placement/optimizers/__init__.py
diff --git a/osdf/optimizers/__init__.py b/apps/placement/optimizers/conductor/__init__.py
index 4b25e5b..4b25e5b 100644
--- a/osdf/optimizers/__init__.py
+++ b/apps/placement/optimizers/conductor/__init__.py
diff --git a/apps/placement/optimizers/conductor/remote_opt_processor.py b/apps/placement/optimizers/conductor/remote_opt_processor.py
new file mode 100644
index 0000000..2e681be
--- /dev/null
+++ b/apps/placement/optimizers/conductor/remote_opt_processor.py
@@ -0,0 +1,178 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from jinja2 import Template
+import json
+from requests import RequestException
+import traceback
+
+from apps.license.optimizers.simple_license_allocation import license_optim
+from osdf.adapters.conductor import conductor
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.logging.osdf_logging import metrics_log
+from osdf.logging.osdf_logging import MH
+from osdf.operation.error_handling import build_json_error_body
+from osdf.utils.interfaces import get_rest_client
+from osdf.utils.mdc_utils import mdc_from_json
+
+
+def conductor_response_processor(conductor_response, req_id, transaction_id):
+ """Build a response object to be sent to client's callback URL from Conductor's response
+
+ This includes Conductor's placement optimization response, and required ASDC license artifacts
+ :param conductor_response: JSON response from Conductor
+ :param raw_response: Raw HTTP response corresponding to above
+ :param req_id: Id of a request
+ :return: JSON object that can be sent to the client's callback URL
+ """
+ composite_solutions = []
+ name_map = {"physical-location-id": "cloudClli", "host_id": "vnfHostName",
+ "cloud_version": "cloudVersion", "cloud_owner": "cloudOwner",
+ "cloud": "cloudRegionId", "service": "serviceInstanceId", "is_rehome": "isRehome",
+ "location_id": "locationId", "location_type": "locationType", "directives": "oof_directives"}
+ for reco in conductor_response['plans'][0]['recommendations']:
+ for resource in reco.keys():
+ c = reco[resource]['candidate']
+ solution = {
+ 'resourceModuleName': resource,
+ 'serviceResourceId': reco[resource].get('service_resource_id', ""),
+ 'solution': {"identifierType": name_map.get(c['inventory_type'], c['inventory_type']),
+ 'identifiers': [c['candidate_id']],
+ 'cloudOwner': c.get('cloud_owner', "")},
+ 'assignmentInfo': []
+ }
+ for key, value in c.items():
+ if key in ["location_id", "location_type", "is_rehome", "host_id"]:
+ try:
+ solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
+ except KeyError:
+ debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info"
+ .format(key))
+
+ for key, value in reco[resource]['attributes'].items():
+ try:
+ solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
+ except KeyError:
+ debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info"
+ .format(key))
+ composite_solutions.append(solution)
+
+ request_status = "completed" if conductor_response['plans'][0]['status'] == "done" \
+ else conductor_response['plans'][0]['status']
+ status_message = conductor_response.get('plans')[0].get('message', "")
+
+ solution_info = {}
+ if composite_solutions:
+ solution_info.setdefault('placementSolutions', [])
+ solution_info['placementSolutions'].append(composite_solutions)
+
+ resp = {
+ "transactionId": transaction_id,
+ "requestId": req_id,
+ "requestStatus": request_status,
+ "statusMessage": status_message,
+ "solutions": solution_info
+ }
+ return resp
+
+
+def conductor_no_solution_processor(conductor_response, request_id, transaction_id,
+ template_placement_response="templates/plc_opt_response.jsont"):
+ """Build a response object to be sent to client's callback URL from Conductor's response
+
+ This is for case where no solution is found
+ :param conductor_response: JSON response from Conductor
+ :param raw_response: Raw HTTP response corresponding to above
+ :param request_id: request Id associated with the client request (same as conductor response's "name")
+ :param template_placement_response: the template for generating response to client (plc_opt_response.jsont)
+ :return: JSON object that can be sent to the client's callback URL
+ """
+ status_message = conductor_response["plans"][0].get("message")
+ templ = Template(open(template_placement_response).read())
+ return json.loads(templ.render(composite_solutions=[], requestId=request_id, license_solutions=[],
+ transactionId=transaction_id,
+ requestStatus="completed", statusMessage=status_message, json=json))
+
+
+def process_placement_opt(request_json, policies, osdf_config):
+ """Perform the work for placement optimization (e.g. call SDC artifact and make conductor request)
+
+ NOTE: there is scope to make the requests to policy asynchronous to speed up overall performance
+ :param request_json: json content from original request
+ :param policies: flattened policies corresponding to this request
+ :param osdf_config: configuration specific to OSDF app
+ :param prov_status: provStatus retrieved from Subscriber policy
+ :return: None, but make a POST to callback URL
+ """
+
+ try:
+ mdc_from_json(request_json)
+ rc = get_rest_client(request_json, service="so")
+ req_id = request_json["requestInfo"]["requestId"]
+ transaction_id = request_json['requestInfo']['transactionId']
+
+ metrics_log.info(MH.inside_worker_thread(req_id))
+ license_info = None
+ if request_json.get('licenseInfo', {}).get('licenseDemands'):
+ license_info = license_optim(request_json)
+
+ # Conductor only handles placement, only call Conductor if placementDemands exist
+ if request_json.get('placementInfo', {}).get('placementDemands'):
+ metrics_log.info(MH.requesting("placement/conductor", req_id))
+ req_info = request_json['requestInfo']
+ demands = request_json['placementInfo']['placementDemands']
+ request_parameters = request_json['placementInfo']['requestParameters']
+ service_info = request_json['serviceInfo']
+ template_fields = {
+ 'location_enabled': True,
+ 'version': '2017-10-10'
+ }
+ resp = conductor.request(req_info, demands, request_parameters, service_info, template_fields,
+ osdf_config, policies)
+ if resp["plans"][0].get("recommendations"):
+ placement_response = conductor_response_processor(resp, req_id, transaction_id)
+ else: # "solved" but no solutions found
+ placement_response = conductor_no_solution_processor(resp, req_id, transaction_id)
+ if license_info: # Attach license solution if it exists
+ placement_response['solutionInfo']['licenseInfo'] = license_info
+ else: # License selection only scenario
+ placement_response = {
+ "transactionId": transaction_id,
+ "requestId": req_id,
+ "requestStatus": "completed",
+ "statusMessage": "License selection completed successfully",
+ "solutionInfo": {"licenseInfo": license_info}
+ }
+ except Exception as err:
+ error_log.error("Error for {} {}".format(req_id, traceback.format_exc()))
+
+ try:
+ body = build_json_error_body(err)
+ metrics_log.info(MH.sending_response(req_id, "ERROR"))
+ rc.request(json=body, noresponse=True)
+ except RequestException:
+ error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
+ return
+
+ try:
+ metrics_log.info(MH.calling_back_with_body(req_id, rc.url, placement_response))
+ rc.request(json=placement_response, noresponse=True)
+ except RequestException: # can't do much here but log it and move on
+ error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
diff --git a/osdf/templates/plc_opt_request.jsont b/apps/placement/templates/plc_opt_request.jsont
index cd78b3e..a218b8a 100755
--- a/osdf/templates/plc_opt_request.jsont
+++ b/apps/placement/templates/plc_opt_request.jsont
@@ -2,7 +2,7 @@
"name": "{{ name }}",
"files": "{{ files }}",
"timeout": "{{ timeout }}",
- "limit": "{{ limit }}",
+ "num_solution": "{{ limit }}",
"template": {
"CUST_ID": "{{ cust_id }}",
"E2EVPNKEY": "{{ e2evpnkey }}",
@@ -139,4 +139,4 @@
{% endfor %}
}
}
-} \ No newline at end of file
+}
diff --git a/osdf/templates/plc_opt_response.jsont b/apps/placement/templates/plc_opt_response.jsont
index e5709e7..e5709e7 100755
--- a/osdf/templates/plc_opt_response.jsont
+++ b/apps/placement/templates/plc_opt_response.jsont
diff --git a/osdf/templates/policy_request.jsont b/apps/placement/templates/policy_request.jsont
index 3a9e201..3a9e201 100755
--- a/osdf/templates/policy_request.jsont
+++ b/apps/placement/templates/policy_request.jsont
diff --git a/apps/route/__init__.py b/apps/route/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/route/__init__.py
diff --git a/apps/route/optimizers/__init__.py b/apps/route/optimizers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/route/optimizers/__init__.py
diff --git a/apps/route/optimizers/inter_domain_route_opt.py b/apps/route/optimizers/inter_domain_route_opt.py
new file mode 100644
index 0000000..253c7b2
--- /dev/null
+++ b/apps/route/optimizers/inter_domain_route_opt.py
@@ -0,0 +1,370 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Fujitsu Limited Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+
+
+import os
+import itertools
+import json
+import requests
+from requests.auth import HTTPBasicAuth
+import urllib3
+
+from osdf.logging.osdf_logging import audit_log
+import pymzn
+from sklearn import preprocessing
+
+BASE_DIR = os.path.dirname(__file__)
+urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+
+
+class InterDomainRouteOpt:
+
+ """
+ This values will need to deleted..
+ only added for the debug purpose
+ """
+ aai_headers = {
+ "X-TransactionId": "9999",
+ "X-FromAppId": "OOF",
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ }
+
+
+ def get_route(self, request, osdf_config):
+ """
+ This method processes the mdons route request
+ and returns an optimised path for the given
+ two ports
+ """
+
+ try:
+ route_info = request["routeInfo"]["routeRequest"]
+ src_controller_id = route_info["srcDetails"]["controllerId"]
+ src_port_id = route_info["srcDetails"]["interfaceId"]
+ dst_controller_id = route_info["dstDetails"]["controllerId"]
+ dst_port_id = route_info["dstDetails"]["interfaceId"]
+ service_rate = route_info["serviceRate"]
+ dzn_data, mapping_table = self.build_dzn_data(osdf_config, src_controller_id,
+ dst_controller_id, service_rate)
+ audit_log.info("Dzn data")
+ audit_log.info(dzn_data)
+ mzn_model = os.path.join(BASE_DIR, 'route_opt.mzn')
+ links_list = self.find_suitable_path(mzn_model, dzn_data, mapping_table)
+ ordered_list = self.get_ordered_route_list(links_list,
+ src_controller_id, dst_controller_id)
+ solution = self.get_solution_object(ordered_list, src_port_id, dst_port_id)
+ return {
+ "requestId": request["requestInfo"]["requestId"],
+ "transactionId": request["requestInfo"]["transactionId"],
+ "statusMessage": "SUCCESS",
+ "requestStatus": "accepted",
+ "solutions": solution
+ }
+ except Exception as err:
+ audit_log.info(err)
+ raise err
+
+ def get_solution_object(self, ordered_list, src_port_id, dst_port_id):
+ """
+ :param ordered_list: service_route list
+ :param src_port_id: source port id of route
+ :param dst_port_id: destination port id of route
+ :return: solution object of the route respone
+ """
+ service_route_list = []
+ link_list = []
+ for value in ordered_list:
+ service_route_object = {}
+ service_route_object["srcInterfaceId"] = src_port_id
+ service_route_object["dstInterfaceId"] = value["srcPortId"]
+ service_route_object["controllerId"] = value["srcControllerId"]
+ service_route_list.append(service_route_object)
+ link_list.append(value["linkName"])
+ src_port_id = value["dstPortId"]
+ dst_controller_id = value["dstControllerId"]
+ service_route_object = {}
+ service_route_object["srcInterfaceId"] = src_port_id
+ service_route_object["dstInterfaceId"] = dst_port_id
+ service_route_object["controllerId"] = dst_controller_id
+ service_route_list.append(service_route_object)
+ route_info_object = {
+ "serviceRoute" : service_route_list,
+ "linkList" : link_list
+ }
+ solution = {
+ "routeInfo" : route_info_object
+ }
+ return solution
+
+
+ def get_ordered_route_list(self, link_list, src_controller_id, dst_controller_id):
+ """
+ :param link_list: link list from the minizinc response
+ :param src_controller_id: source port id of route
+ :param dst_controller_id: destination port id of route
+ :return: route list in order
+ """
+ ordered_link_list = []
+ flag = True
+ while flag:
+ for item in link_list:
+ if item["srcControllerId"] == src_controller_id:
+ ordered_link_list.append(item)
+ src_controller_id = item["dstControllerId"]
+ if src_controller_id == dst_controller_id:
+ flag = False
+ return ordered_link_list
+
+
+ def find_suitable_path(self, mzn_model, dzn_data, mapping_table):
+ """
+ :param mzn_model: minizinc model details
+ :param dzn_data: minizinc data
+ :param mapping_table: list that maintains AAI link details
+ :return: list of link from after running minizinc
+ """
+ minizinc_solution = self.solve(mzn_model, dzn_data)
+ audit_log.info("Minizinc Solution ==========>")
+ routes = list(minizinc_solution)
+ audit_log.info(routes)
+ try:
+ arr = routes[0]['x']
+ except Exception as err:
+ audit_log.info("No minizinc solutions found")
+ raise err
+ links_list = []
+ for i in range(0, len(routes[0]['x'])):
+ if arr[i] == 1:
+ links_list.append(mapping_table[i])
+ return links_list
+
+
+ def process_inter_domain_link(self, logical_link, osdf_config):
+ """
+ :param logical_link: logical links from AAI
+ :param osdf_config: OSDF config details
+ :return: list of link object with src and dst controller details
+ """
+ link_details = {}
+ link_details["linkName"] = logical_link["link-name"]
+ relationship = logical_link["relationship-list"]["relationship"]
+ flag = 1
+
+ for value in relationship:
+ if value["related-to"] == "p-interface" and flag == 1:
+ src_port_id = value["relationship-data"][1]["relationship-value"]
+ src_controller_id = self.get_controller_for_interface(osdf_config, src_port_id)
+ link_details["srcPortId"] = src_port_id
+ link_details["srcControllerId"] = src_controller_id
+ flag += 1
+ elif value["related-to"] == "p-interface" and flag == 2:
+ dest_port_id = value["relationship-data"][1]["relationship-value"]
+ dest_controller_id = self.get_controller_for_interface(osdf_config, dest_port_id)
+ link_details["dstPortId"] = dest_port_id
+ link_details["dstControllerId"] = dest_controller_id
+ return link_details
+
+
+ def prepare_map_table(self, osdf_config, logical_links):
+ """
+ :param logical_links: logical links from AAI
+ :param osdf_config: OSDF config details
+ :return: list of link object with src and dst controller details
+ """
+ results = map(self.process_inter_domain_link, logical_links,
+ itertools.repeat(osdf_config, len(logical_links)))
+ new_results = list(results)
+
+ new_list = []
+ new_list += new_results
+ for i in new_results:
+ link_details = {}
+ link_details["linkName"] = i["linkName"]
+ link_details["srcPortId"] = i["dstPortId"]
+ link_details["srcControllerId"] = i["dstControllerId"]
+ link_details["dstPortId"] = i["srcPortId"]
+ link_details["dstControllerId"] = i["srcControllerId"]
+ new_list.append(link_details)
+ return new_list
+
+
+ def solve(self, mzn_model, dzn_data):
+ """
+ :param mzn_model: minizinc template
+ :param dzn_data: minizinc data model
+ :return: minizinc response
+ """
+ return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
+
+
+ def get_links_based_on_bandwidth_attributes(self, logical_links_list,
+ osdf_config, service_rate):
+ """
+ This method filters the logical links based on the
+ bandwidth attribute availability of the interfaces
+ from AAI
+ :return: filtered_list[]
+ """
+ filtered_list = []
+ for logical_link in logical_links_list:
+ relationship = logical_link["relationship-list"]["relationship"]
+ count = 0
+ for value in relationship:
+ if value["related-to"] == "p-interface":
+ interface_url = value["related-link"]
+ if self.get_available_bandwidth_aai(interface_url, osdf_config, service_rate):
+ count += 1
+ if count == 2:
+ filtered_list.append(logical_link)
+
+ return filtered_list
+
+
+ def build_dzn_data(self, osdf_config, src_controller_id, dst_controller_id, service_rate):
+ """
+ :param osdf_config: OSDF config details
+ :param src_controller_id: controller Id of the source port
+ :param dst_controller_id: controller id of the destination port
+ :param service_rate: service rate
+ :return: mapping atble which maintains link details from AAI
+ and minizinc data model to be used by template
+ """
+ logical_links = self.get_inter_domain_links(osdf_config)
+ logical_links_list = logical_links["logical-link"]
+ mapping_table = self.prepare_map_table(osdf_config,
+ self.get_links_based_on_bandwidth_attributes(logical_links_list, osdf_config, service_rate))
+
+ edge_start = []
+ edge_end = []
+ for item in mapping_table:
+ edge_start.append(item["srcControllerId"])
+ edge_end.append(item["dstControllerId"])
+ link_cost = []
+ for k in range(0, len(edge_start)):
+ link_cost.append(1)
+ list_controllers = self.get_controllers_from_aai(osdf_config)
+ le = preprocessing.LabelEncoder()
+ le.fit(list_controllers)
+
+ start_edge = le.transform(edge_start)
+ end_edge = le.transform(edge_end)
+ source = le.transform([src_controller_id])
+ destination = le.transform([dst_controller_id])
+
+ final_dzn_start_arr = []
+ for i in start_edge:
+ final_dzn_start_arr.append(i)
+
+ final_dzn_end_arr = []
+ for j in end_edge:
+ final_dzn_end_arr.append(j)
+
+ contollers_length = len(list_controllers)
+ no_of_edges = len(final_dzn_start_arr)
+ dzn_data = {
+ 'N': contollers_length,
+ 'M': no_of_edges,
+ 'Edge_Start': final_dzn_start_arr,
+ 'Edge_End': final_dzn_end_arr,
+ 'L': link_cost,
+ 'Start': source[0],
+ 'End' : destination[0]
+ }
+ return dzn_data, mapping_table
+
+
+ def get_inter_domain_links(self, osdf_config):
+ """
+ This method returns list of all cross ONAP links
+ from /aai/v19/network/logical-links?link-type=inter-domain&operational-status="Up"
+ :return: logical-links[]
+ """
+
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["aaiGetInterDomainLinksUrl"]
+ response = requests.get(aai_req_url, headers=self.aai_headers,
+ auth=HTTPBasicAuth("AAI", "AAI"), verify=False)
+ if response.status_code == 200:
+ return response.json()
+
+
+ def get_controller_for_interface(self, osdf_config, port_id):
+ """
+ This method returns returns the controller id
+ given a p-interface from the below query
+ :return: controller_id
+ """
+ data = {
+ "start": ["external-system"],
+ "query": "query/getDomainController?portid="
+ }
+ query = data.get("query") + port_id
+ data.update(query=query)
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["controllerQueryUrl"]
+ response = requests.put(aai_req_url, data=json.dumps(data),
+ headers=self.aai_headers,
+ auth=HTTPBasicAuth("AAI", "AAI"),
+ verify=False)
+ if response.status_code == 200:
+ response_body = response.json()
+ return response_body["results"][0]["esr-thirdparty-sdnc"]["thirdparty-sdnc-id"]
+
+
+ def get_controllers_from_aai(self, osdf_config):
+ """
+ This method returns returns the list of
+ controller names in AAI
+ :return: controllers_list[]
+ """
+ controllers_list = []
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["aaiGetControllersUrl"]
+ response = requests.get(aai_req_url,
+ headers=self.aai_headers,
+ auth=HTTPBasicAuth("AAI", "AAI"),
+ verify=False)
+ if response.status_code == 200:
+ response_body = response.json()
+ esr_thirdparty_list = response_body["esr-thirdparty-sdnc"]
+
+ for item in esr_thirdparty_list:
+ controllers_list.append(item["thirdparty-sdnc-id"])
+ return controllers_list
+
+
+ def get_available_bandwidth_aai(self, interface_url, osdf_config, service_rate):
+ """
+ Checks if the given interface has the required bandwidth
+ :return: boolean flag
+ """
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + interface_url + "?depth=all"
+ response = requests.get(aai_req_url,
+ headers=self.aai_headers,
+ auth=HTTPBasicAuth("AAI", "AAI"), verify=False)
+ if response.status_code == 200:
+ response_body = response.json()
+ available_bandwidth = response_body["bandwidth-attributes"]["bandwidth-attribute"][0]["available-bandwidth-map"]["available-bandwidth"]
+ for i in available_bandwidth:
+ if i["odu-type"] == service_rate and i["number"] > 0:
+ return True
diff --git a/apps/route/optimizers/route_opt.mzn b/apps/route/optimizers/route_opt.mzn
new file mode 100644
index 0000000..7aa73cb
--- /dev/null
+++ b/apps/route/optimizers/route_opt.mzn
@@ -0,0 +1,53 @@
+
+% Number of nodes
+int: N;
+ % Start node
+0..N-1: Start;
+ % End node
+0..N-1: End;
+ % Number of edges (directed arcs)
+int: M;
+ % The actual edges
+set of int: Edges = 1..M;
+ % Edge lengths
+array[Edges] of int: L;
+ % Edge start node
+array[Edges] of 0..N-1: Edge_Start;
+array[Edges] of 0..N-1: Edge_End;
+
+ % Variable indicating if edge is used
+array[Edges] of var 0..1: x;
+
+constraint
+ forall( i in 0..N-1 ) (
+ if i = Start then
+ % outgoing flow
+ sum(e in Edges where Edge_Start[e] = i)(x[e]) -
+ % incoming flow
+ sum(e in Edges where Edge_End[e] = i)(x[e])
+ = 1
+ elseif i = End then
+ sum(e in Edges where Edge_Start[e] = i)(x[e]) -
+ sum(e in Edges where Edge_End[e] = i)(x[e])
+ = -1
+ else
+ sum(e in Edges where Edge_Start[e] = i)(x[e]) -
+ sum(e in Edges where Edge_End[e] = i)(x[e])
+ = 0
+ endif
+ );
+
+
+solve minimize sum(e in Edges)( L[e] * x[e] );
+%solve satisfy;
+
+output ["Length: ", show(sum(e in Edges)(L[e] * x[e])), "\n"] ++
+ ["Start : ", show(Start), "\n"] ++
+ ["End : ", show(End), "\n\n"] ++
+ ["Edges in shortest path:\n"] ++
+ [ if fix(x[e]) = 1
+ then show(Edge_Start[e]) ++ " -> " ++ show(Edge_End[e]) ++ "\n"
+ else ""
+ endif | e in Edges
+ ];
+
diff --git a/apps/route/optimizers/simple_route_opt.py b/apps/route/optimizers/simple_route_opt.py
new file mode 100644
index 0000000..9113516
--- /dev/null
+++ b/apps/route/optimizers/simple_route_opt.py
@@ -0,0 +1,266 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Huawei Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import requests
+import json
+from requests.auth import HTTPBasicAuth
+
+from osdf.utils.mdc_utils import mdc_from_json
+from osdf.logging.osdf_logging import MH, audit_log, error_log, debug_log
+import pymzn
+from sklearn import preprocessing
+
+import os
+BASE_DIR = os.path.dirname(__file__)
+
+class RouteOpt:
+
+ """
+ This values will need to deleted..
+ only added for the debug purpose
+ """
+ # DNS server and standard port of AAI..
+ # TODO: read the port from the configuration and add to DNS
+ aai_headers = {
+ "X-TransactionId": "9999",
+ "X-FromAppId": "OOF",
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ }
+
+ def is_cross_onap_link(self, logical_link):
+ """
+ This method checks if cross link is cross onap
+ :param logical_link:
+ :return:
+ """
+ for relationship in logical_link["relationship-list"]["relationship"]:
+ if relationship["related-to"] == "ext-aai-network":
+ return True
+ return False
+
+ def get_links_name(self, routes,initial_start_edge,initial_end_edge, mappingTable):
+ routes=list(routes)
+ try:
+ arr=routes[0]['x']
+ except Exception as err:
+ audit_log.info("No satisfiable solutions found")
+ raise err
+ listOfLinks=[]
+ for i in range(0, len(routes[0]['x'])):
+ individual_link = {}
+ if arr[i] == 1 :
+ # listOfLinks.append(self.fetchLogicalLinks(initial_start_edge[i], initial_end_edge[i], mappingTable))
+ individual_link["link"] = mappingTable[initial_start_edge[i] + ":" + initial_end_edge[i]]
+ individual_link["start_node"] = initial_start_edge[i]
+ individual_link["end_node"] = initial_end_edge[i]
+ listOfLinks.append(individual_link)
+
+ return listOfLinks
+
+ def solve(self, mzn_model, dzn_data):
+ return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
+
+ def get_links(self, mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable):
+ routes = self.solve(mzn_model, dzn_data)
+ audit_log.info("mocked minizinc solution====>")
+ audit_log.info(routes)
+
+ converted_links=self.get_links_name(routes, initial_start_edge,initial_end_edge, mappingTable)
+ audit_log.info("converted links===>")
+ audit_log.info(converted_links)
+ return converted_links
+
+ def addition(self, data):
+ res = ""
+ if 'relationship-list' in data.keys():
+ relationship = data["relationship-list"]["relationship"]
+ for index, eachItem in enumerate(relationship):
+ temp = eachItem["relationship-data"][0]
+ if index == len(relationship) - 1:
+ res += temp['relationship-value']
+ else:
+ res += temp['relationship-value'] + ":"
+
+ return data["link-name"], res
+ else:
+ return data["link-name"], res
+
+ def create_map_table(self, logical_links):
+ result = map(self.addition, logical_links)
+
+ parseTemplate = {}
+
+ for eachItem in result:
+ parseTemplate[eachItem[1]] = eachItem[0]
+ audit_log.info("mapping table")
+ audit_log.info(parseTemplate)
+ return parseTemplate
+
+ def build_dzn_data(self, src_access_node_id, dst_access_node_id, osdf_config):
+ Edge_Start = []
+ Edge_End = []
+ logical_links = self.get_logical_links(osdf_config)
+
+
+ logical_links = logical_links['logical-link']
+ audit_log.info("mocked response of AAI received (logical links) successful===>")
+ audit_log.info(logical_links)
+ # prepare map table
+ mappingTable = self.create_map_table(logical_links)
+ audit_log.info("mapping table created successfully====>")
+ audit_log.info(mappingTable)
+ # take the logical link where both the p-interface in same onap
+ if logical_links is not None:
+ audit_log.info('logical links not empty=====>')
+ for logical_link in logical_links:
+ audit_log.info('logical_link')
+ audit_log.info(logical_link)
+
+ if 'relationship-list' in logical_link.keys():
+ if not self.is_cross_onap_link(logical_link):
+ # link is in local ONAP
+ audit_log.info('link is inside onap===>')
+ relationship = logical_link["relationship-list"]["relationship"]
+
+ relationshipStartNode = relationship[0]
+ audit_log.info('relationshipStartNode')
+ audit_log.info(relationshipStartNode)
+ relationshipStartNodeID = relationshipStartNode["related-link"].split("/")[-4]
+ audit_log.info('relationshipStartNodeID')
+ audit_log.info(relationshipStartNodeID)
+ Edge_Start.append(relationshipStartNodeID)
+
+ relationshipEndtNode = relationship[1]
+ relationshipEndNodeID = relationshipEndtNode["related-link"].split("/")[-4]
+ audit_log.info('relationshipEndNodeID')
+ audit_log.info(relationshipEndNodeID)
+ Edge_End.append(relationshipEndNodeID)
+ else:
+ continue
+
+ audit_log.info("edge start and end array of i/p address are===>")
+ audit_log.info(Edge_Start)
+ audit_log.info(Edge_End)
+ # labeling ip to number for mapping
+ le = preprocessing.LabelEncoder()
+ le.fit(Edge_Start + Edge_End)
+ dzn_start_edge = le.transform(Edge_Start)
+
+ final_dzn_start_arr = []
+ for i in range(0, len(dzn_start_edge)):
+ final_dzn_start_arr.append(dzn_start_edge[i])
+
+ final_dzn_end_arr = []
+ dzn_end_edge = le.transform(Edge_End)
+ for j in range(0, len(dzn_end_edge)):
+ final_dzn_end_arr.append(dzn_end_edge[j])
+
+ audit_log.info("start and end array that passed in dzn_data===>")
+ audit_log.info(final_dzn_start_arr)
+ audit_log.info(final_dzn_end_arr)
+
+ link_cost = []
+ for k in range(0, len(final_dzn_start_arr)):
+ link_cost.append(1)
+
+ audit_log.info("src_access_node_id")
+ audit_log.info(src_access_node_id)
+ source= le.transform([src_access_node_id])
+ audit_log.info("vallue of source===>")
+ audit_log.info(source)
+ if source in final_dzn_start_arr :
+ start = source[0]
+ audit_log.info("source node")
+ audit_log.info(start)
+
+ audit_log.info("dst_access_node_id")
+ audit_log.info(dst_access_node_id)
+ destination= le.transform([dst_access_node_id])
+ if destination in final_dzn_end_arr :
+ end = destination[0]
+ audit_log.info("destination node")
+ audit_log.info(end)
+ # data to be prepared in the below format:
+ dzn_data = {
+ 'N': self.total_node(final_dzn_start_arr + final_dzn_end_arr),
+ 'M': len(final_dzn_start_arr),
+ 'Edge_Start': final_dzn_start_arr,
+ 'Edge_End': final_dzn_end_arr,
+ 'L': link_cost,
+ 'Start': start,
+ 'End': end,
+ }
+ # can not do reverse mapping outside of this scope, so doing here
+ audit_log.info("reverse mapping after prepared dzn_data")
+ initial_start_edge=le.inverse_transform(final_dzn_start_arr)
+ initial_end_edge=le.inverse_transform(final_dzn_end_arr)
+ audit_log.info(initial_start_edge)
+ audit_log.info(initial_end_edge)
+ return dzn_data, initial_start_edge,initial_end_edge, mappingTable
+
+ def total_node(self, node):
+ nodeSet = set()
+ for i in range(0, len(node)):
+ nodeSet.add(node[i])
+ total_node = len(nodeSet)
+ return total_node
+
+ def get_route(self, request, osdf_config):
+ """
+ This method checks
+ :param logical_link:
+ :return:
+ """
+ try:
+ routeInfo = request["routeInfo"]["routeRequests"]
+ routeRequest = routeInfo[0]
+ src_access_node_id = routeRequest["srcPort"]["accessNodeId"]
+ dst_access_node_id = routeRequest["dstPort"]["accessNodeId"]
+
+ dzn_data, initial_start_edge, initial_end_edge, mappingTable = self.build_dzn_data(src_access_node_id, dst_access_node_id, osdf_config)
+ #mzn_model = "/home/root1/Videos/projects/osdf/test/functest/simulators/osdf/optimizers/routeopt/route_opt.mzn"
+ mzn_model = os.path.join(BASE_DIR, 'route_opt.mzn')
+
+ routeSolutions = self.get_links(mzn_model, dzn_data, initial_start_edge,initial_end_edge, mappingTable)
+
+ return {
+ "requestId": request["requestInfo"]["requestId"],
+ "transactionId": request["requestInfo"]["transactionId"],
+ "statusMessage": " ",
+ "requestStatus": "accepted",
+ "solutions": routeSolutions
+ }
+ except Exception as err:
+ audit_log.info(err)
+ raise err
+
+ def get_logical_links(self, osdf_config):
+ """
+ This method returns list of all cross ONAP links
+ from /aai/v14/network/logical-links?operation-status="Up"
+ :return: logical-links[]
+ """
+
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["aaiGetLinksUrl"]
+
+ response = requests.get(aai_req_url,headers=self.aai_headers,auth=HTTPBasicAuth("AAI", "AAI"),verify=False)
+ if response.status_code == 200:
+ return response.json() \ No newline at end of file
diff --git a/apps/slice_selection/__init__.py b/apps/slice_selection/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/slice_selection/__init__.py
diff --git a/osdf/optimizers/routeopt/__init__.py b/apps/slice_selection/models/api/__init__.py
index c235f2a..b45f74d 100644
--- a/osdf/optimizers/routeopt/__init__.py
+++ b/apps/slice_selection/models/api/__init__.py
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------
-# Copyright (c) 2018 Huawei Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/apps/slice_selection/models/api/nsi_selection_request.py b/apps/slice_selection/models/api/nsi_selection_request.py
new file mode 100644
index 0000000..b395012
--- /dev/null
+++ b/apps/slice_selection/models/api/nsi_selection_request.py
@@ -0,0 +1,62 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType
+from schematics.types import BooleanType
+from schematics.types.compound import DictType
+from schematics.types.compound import ListType
+from schematics.types.compound import ModelType
+from schematics.types import IntType
+from schematics.types import StringType
+from schematics.types import URLType
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as SO"""
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ callbackUrl = URLType(required=True)
+ sourceId = StringType(required=True)
+ callbackHeader = DictType(BaseType)
+ timeout = IntType()
+ numSolutions = IntType()
+ addtnlArgs = DictType(BaseType)
+
+
+class NxTInfo(OSDFModel):
+ """Information about NST/NSST model"""
+ invariantUUID = StringType(required=True)
+ UUID = StringType(required=True)
+ name = StringType(required=True)
+
+
+class SubnetCapability(OSDFModel):
+ """Subnet capability of every subnet"""
+ domainType = StringType(required=True)
+ capabilityDetails = DictType(BaseType, required=True)
+
+
+class NSISelectionAPI(OSDFModel):
+ """Request for nsi selection (specific to optimization and additional metadata"""
+ requestInfo = ModelType(RequestInfo, required=True)
+ NSTInfo = ModelType(NxTInfo, required=True)
+ NSSTInfo = ListType(ModelType(NxTInfo), required=False)
+ serviceProfile = DictType(BaseType, required=True)
+ subnetCapabilities = ListType(ModelType(SubnetCapability), required=True)
+ preferReuse = BooleanType()
diff --git a/apps/slice_selection/models/api/nsi_selection_response.py b/apps/slice_selection/models/api/nsi_selection_response.py
new file mode 100644
index 0000000..3c6d35b
--- /dev/null
+++ b/apps/slice_selection/models/api/nsi_selection_response.py
@@ -0,0 +1,54 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType, StringType, BooleanType
+from schematics.types.compound import ModelType, ListType, DictType
+
+
+# TODO: update osdf.models
+class SharedNSISolution(OSDFModel):
+ """Represents the shared NSI Solution object"""
+ invariantUUID = StringType(required=True)
+ UUID = StringType(required=True)
+ NSIName = StringType(required=True)
+ NSIId = StringType(required=True)
+ matchLevel = StringType(required=True)
+
+
+class NewNSISolution(OSDFModel):
+ """Represents the New NSI Solution object containing tuple of slice profiles"""
+ sliceProfiles = ListType(DictType(BaseType), required=True)
+ matchLevel = StringType(required=True)
+
+
+class NSISolution(OSDFModel):
+ """Represents the NSI Solution object"""
+ """This solution object contains either sharedNSISolution or newNSISolution"""
+ existingNSI = BooleanType(required=True)
+ sharedNSISolution = ModelType(SharedNSISolution)
+ newNSISolution = ModelType(NewNSISolution)
+
+
+class NSISelectionResponse(OSDFModel):
+ """Response sent to NSMF(SO)"""
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ requestStatus = StringType(required=True)
+ solutions = ListType(ModelType(NSISolution), required=True)
+ statusMessage = StringType()
diff --git a/apps/slice_selection/models/api/nssi_selection_request.py b/apps/slice_selection/models/api/nssi_selection_request.py
new file mode 100644
index 0000000..c670abe
--- /dev/null
+++ b/apps/slice_selection/models/api/nssi_selection_request.py
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+from osdf.models.api.common import OSDFModel
+from schematics.types import BaseType, StringType, URLType, IntType
+from schematics.types.compound import ModelType, DictType
+
+from apps.slice_selection.models.api.nsi_selection_request import NxTInfo
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as SO"""
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ callbackUrl = URLType(required=True)
+ sourceId = StringType(required=True)
+ callbackHeader = DictType(BaseType)
+ timeout = IntType()
+ numSolutions = IntType()
+ addtnlArgs = DictType(BaseType)
+
+
+class NSSISelectionAPI(OSDFModel):
+ """Request for NSSI selection (specific to optimization and additional metadata"""
+ requestInfo = ModelType(RequestInfo, required=True)
+ NSSTInfo = ModelType(NxTInfo, required=True)
+ sliceProfile = DictType(BaseType, required=True)
diff --git a/apps/slice_selection/models/api/nssi_selection_response.py b/apps/slice_selection/models/api/nssi_selection_response.py
new file mode 100644
index 0000000..af67f65
--- /dev/null
+++ b/apps/slice_selection/models/api/nssi_selection_response.py
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from osdf.models.api.common import OSDFModel
+from schematics.types import StringType
+from schematics.types.compound import ModelType, ListType
+
+
+# TODO: update osdf.models
+class SharedNSSISolution(OSDFModel):
+ """Represents the shared NSSI Solution object"""
+ invariantUUID = StringType(required=True)
+ UUID = StringType(required=True)
+ NSSIName = StringType(required=True)
+ NSSIId = StringType(required=True)
+ matchLevel = StringType(required=True)
+
+
+class NSSISelectionResponse(OSDFModel):
+ """Response sent to NSSMF(SO)"""
+ transactionId = StringType(required=True)
+ requestId = StringType(required=True)
+ requestStatus = StringType(required=True)
+ solutions = ListType(ModelType(SharedNSSISolution), required=True)
+ statusMessage = StringType()
diff --git a/osdf/optimizers/placementopt/__init__.py b/apps/slice_selection/optimizers/__init__.py
index 4b25e5b..b45f74d 100644
--- a/osdf/optimizers/placementopt/__init__.py
+++ b/apps/slice_selection/optimizers/__init__.py
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------
-# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/apps/slice_selection/optimizers/conductor/__init__.py b/apps/slice_selection/optimizers/conductor/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/slice_selection/optimizers/conductor/__init__.py
diff --git a/apps/slice_selection/optimizers/conductor/remote_opt_processor.py b/apps/slice_selection/optimizers/conductor/remote_opt_processor.py
new file mode 100644
index 0000000..68c9409
--- /dev/null
+++ b/apps/slice_selection/optimizers/conductor/remote_opt_processor.py
@@ -0,0 +1,134 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+"""
+Module for processing slice selection request
+"""
+
+from requests import RequestException
+from threading import Thread
+import traceback
+
+from apps.slice_selection.optimizers.conductor.response_processor import ResponseProcessor
+from osdf.adapters.conductor import conductor
+from osdf.adapters.policy.interface import get_policies
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.utils.interfaces import get_rest_client
+from osdf.utils.mdc_utils import mdc_from_json
+
+
+class SliceSelectionOptimizer(Thread):
+ def __init__(self, osdf_config, slice_config, request_json, model_type):
+ super().__init__()
+ self.osdf_config = osdf_config
+ self.slice_config = slice_config
+ self.request_json = request_json
+ self.model_type = model_type
+ self.response_processor = ResponseProcessor(request_json['requestInfo'], slice_config)
+
+ def run(self):
+ self.process_slice_selection_opt()
+
+ def process_slice_selection_opt(self):
+ """Process the slice selection request from the API layer"""
+ req_info = self.request_json['requestInfo']
+ rc = get_rest_client(self.request_json, service='so')
+
+ try:
+ if self.model_type == 'NSSI' \
+ and self.request_json['sliceProfile'].get('resourceSharingLevel', "") \
+ in ['not-shared', 'non-shared']:
+ final_response = self.response_processor.get_slice_selection_response([])
+
+ else:
+ final_response = self.do_slice_selection()
+
+ except Exception as ex:
+ error_log.error("Error for {} {}".format(req_info.get('requestId'),
+ traceback.format_exc()))
+ error_message = str(ex)
+ final_response = self.response_processor.process_error_response(error_message)
+
+ try:
+ rc.request(json=final_response, noresponse=True)
+ except RequestException:
+ error_log.error("Error sending asynchronous notification for {} {}".format(req_info['request_id'],
+ traceback.format_exc()))
+
+ def do_slice_selection(self):
+ req_info = self.request_json['requestInfo']
+ app_info = self.slice_config['app_info'][self.model_type]
+ mdc_from_json(self.request_json)
+ requirements = self.request_json.get(app_info['requirements_field'], {})
+ model_info = self.request_json.get(app_info['model_info'])
+ model_name = model_info['name']
+ policies = self.get_app_policies(model_name, app_info['app_name'])
+ request_parameters = self.get_request_parameters(requirements, model_info)
+
+ demands = [
+ {
+ "resourceModuleName": model_name,
+ "resourceModelInfo": {}
+ }
+ ]
+
+ try:
+ template_fields = {
+ 'location_enabled': False,
+ 'version': '2020-08-13'
+ }
+ resp = conductor.request(req_info, demands, request_parameters, {}, template_fields,
+ self.osdf_config, policies)
+ except RequestException as e:
+ resp = e.response.json()
+ error = resp['plans'][0]['message']
+ if isinstance(error, list) and "Unable to find any" in error[0]:
+ return self.response_processor.get_slice_selection_response([])
+ error_log.error('Error from conductor {}'.format(error))
+ return self.response_processor.process_error_response(error)
+
+ debug_log.debug("Response from conductor {}".format(str(resp)))
+ recommendations = resp["plans"][0].get("recommendations")
+ subnets = [subnet['domainType'] for subnet in self.request_json['subnetCapabilities']] \
+ if self.request_json.get('subnetCapabilities') else []
+ return self.response_processor.process_response(recommendations, model_info, subnets, self.model_type)
+
+ def get_request_parameters(self, requirements, model_info):
+ camel_to_snake = self.slice_config['attribute_mapping']['camel_to_snake']
+ request_params = {camel_to_snake[key]: value for key, value in requirements.items()}
+ subnet_capabilities = self.request_json.get('subnetCapabilities')
+ if subnet_capabilities:
+ for subnet_capability in subnet_capabilities:
+ domain_type = f"{subnet_capability['domainType']}_"
+ capability_details = subnet_capability['capabilityDetails']
+ for key, value in capability_details.items():
+ request_params[f"{domain_type}{camel_to_snake[key]}"] = value
+ request_params.update(model_info)
+ return request_params
+
+ def get_app_policies(self, model_name, app_name):
+ policy_request_json = self.request_json.copy()
+ policy_request_json['serviceInfo'] = {'serviceName': model_name}
+ if 'serviceProfile' in self.request_json:
+ slice_scope = self.request_json['serviceProfile']['resourceSharingLevel']
+ if 'preferReuse' in self.request_json and slice_scope == "shared":
+ slice_scope = slice_scope + "," + ("reuse" if self.request_json['preferReuse'] else "create_new")
+ policy_request_json['slice_scope'] = slice_scope
+ debug_log.debug("policy_request_json {}".format(str(policy_request_json)))
+ return get_policies(policy_request_json, app_name)
diff --git a/apps/slice_selection/optimizers/conductor/response_processor.py b/apps/slice_selection/optimizers/conductor/response_processor.py
new file mode 100644
index 0000000..2357ab9
--- /dev/null
+++ b/apps/slice_selection/optimizers/conductor/response_processor.py
@@ -0,0 +1,108 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+"""
+Module for processing response from conductor for slice selection
+"""
+
+import re
+
+
+class ResponseProcessor(object):
+ def __init__(self, request_info, slice_config):
+ self.request_info = request_info
+ self.slice_config = slice_config
+
+ def process_response(self, recommendations, model_info, subnets, model_type):
+ """Process conductor response to form the response for the API request
+
+ :param recommendations: recommendations from conductor
+ :param model_info: model info from the request
+ :param subnets: list of subnets
+ :param model_type: NSI or NSSI
+ :return: response json as a dictionary
+ """
+ if not recommendations:
+ return self.get_slice_selection_response([])
+ model_name = model_info['name']
+ solutions = [self.get_solution_from_candidate(rec[model_name]['candidate'], model_info, subnets, model_type)
+ for rec in recommendations]
+ return self.get_slice_selection_response(solutions)
+
+ def get_solution_from_candidate(self, candidate, model_info, subnets, model_type):
+ if candidate['inventory_type'] == 'slice_profiles':
+ return {
+ 'existingNSI': False,
+ 'newNSISolution': {
+ 'sliceProfiles': self.get_slice_profiles_from_candidate(candidate, subnets)
+ }
+ }
+ elif model_type == 'NSSI':
+ return {
+ 'UUID': model_info['UUID'],
+ 'invariantUUID': model_info['invariantUUID'],
+ 'NSSIName': candidate['instance_name'],
+ 'NSSIId': candidate['instance_id']
+ }
+
+ elif model_type == 'NSI':
+ return {
+ 'existingNSI': True,
+ 'sharedNSISolution': {
+ 'UUID': model_info['UUID'],
+ 'invariantUUID': model_info['invariantUUID'],
+ 'NSIName': candidate['instance_name'],
+ 'NSIId': candidate['instance_id']
+ }
+ }
+
+ def get_slice_profiles_from_candidate(self, candidate, subnets):
+ slice_profiles = []
+ for subnet in subnets:
+ slice_profile = {self.get_profile_attribute(k, subnet): v for k, v in candidate.items()
+ if k.startswith(subnet)}
+ slice_profile['domainType'] = subnet
+ slice_profiles.append(slice_profile)
+ return slice_profiles
+
+ def get_profile_attribute(self, attribute, subnet):
+ snake_to_camel = self.slice_config['attribute_mapping']['snake_to_camel']
+ return snake_to_camel[re.sub(f'^{subnet}_', '', attribute)]
+
+ def process_error_response(self, error_message):
+ """Form response message from the error message
+
+ :param error_message: error message while processing the request
+ :return: response json as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'error',
+ 'statusMessage': error_message}
+
+ def get_slice_selection_response(self, solutions):
+ """Get NSI selection response from final solution
+
+ :param solutions: final solutions
+ :return: NSI selection response to send back as dictionary
+ """
+ return {'requestId': self.request_info['requestId'],
+ 'transactionId': self.request_info['transactionId'],
+ 'requestStatus': 'completed',
+ 'statusMessage': '',
+ 'solutions': solutions}
diff --git a/osdf/templates/cms_opt_request.jsont b/apps/templates/cms_opt_request.jsont
index 006562b..006562b 100755
--- a/osdf/templates/cms_opt_request.jsont
+++ b/apps/templates/cms_opt_request.jsont
diff --git a/osdf/templates/cms_opt_request.jsont_1707_v1 b/apps/templates/cms_opt_request.jsont_1707_v1
index 75ecbe5..75ecbe5 100755
--- a/osdf/templates/cms_opt_request.jsont_1707_v1
+++ b/apps/templates/cms_opt_request.jsont_1707_v1
diff --git a/osdf/templates/cms_opt_request_1702.jsont b/apps/templates/cms_opt_request_1702.jsont
index bcafa45..bcafa45 100755
--- a/osdf/templates/cms_opt_request_1702.jsont
+++ b/apps/templates/cms_opt_request_1702.jsont
diff --git a/osdf/templates/cms_opt_response.jsont b/apps/templates/cms_opt_response.jsont
index a8817df..a8817df 100644
--- a/osdf/templates/cms_opt_response.jsont
+++ b/apps/templates/cms_opt_response.jsont
diff --git a/osdf/templates/license_opt_request.jsont b/apps/templates/license_opt_request.jsont
index 7baa759..7baa759 100644
--- a/osdf/templates/license_opt_request.jsont
+++ b/apps/templates/license_opt_request.jsont
diff --git a/osdf/templates/test_cms_nb_req_from_client.jsont b/apps/templates/test_cms_nb_req_from_client.jsont
index a60c8ff..a60c8ff 100755
--- a/osdf/templates/test_cms_nb_req_from_client.jsont
+++ b/apps/templates/test_cms_nb_req_from_client.jsont
diff --git a/osdf/templates/test_plc_nb_req_from_client.jsont b/apps/templates/test_plc_nb_req_from_client.jsont
index 998ffb3..998ffb3 100755
--- a/osdf/templates/test_plc_nb_req_from_client.jsont
+++ b/apps/templates/test_plc_nb_req_from_client.jsont
diff --git a/assembly.xml b/assembly.xml
index 24379d4..b966691 100644
--- a/assembly.xml
+++ b/assembly.xml
@@ -28,8 +28,10 @@
<include>*.txt</include>
<include>*.ini</include>
<include>*.md</include>
+ <include>ssl_certs/**</include>
</includes>
<excludes>
+ <exclude>**/__pycache__/**</exclude>
<exclude>**/*.pyc</exclude>
<exclude>config/preload_secrets.yaml</exclude>
</excludes>
diff --git a/config/common_config.yaml b/config/common_config.yaml
index 9a4f1d7..713e15f 100644
--- a/config/common_config.yaml
+++ b/config/common_config.yaml
@@ -11,54 +11,167 @@ osdf_temp: # special configuration required for "workarounds" or testing
local_policies:
global_disabled: True
local_placement_policies_enabled: True
+ local_slice_selection_policies_enabled: True
+ local_nst_selection_policies_enabled: True
placement_policy_dir_vcpe: "./test/policy-local-files/"
placement_policy_files_vcpe: # workaroud for policy platform glitches (or "work-arounds" for other components)
- Affinity_vCPE_1.json
+ - Attribute_vNS_1.json
#- Capacity_vGMuxInfra.json
#- Capacity_vG_1.json
- - Distance_vGMuxInfra_1.json
- Distance_vG_1.json
+ - Distance_vGMuxInfra_1.json
+ - hpa_policy_vG_1.json
+ - hpa_policy_vGMuxInfra_1.json
- Placement_Optimization_1.json
- QueryPolicy_vCPE.json
- #- hpa_policy_vGMuxInfra_1.json
- #- hpa_policy_vG_1.json
- vnfPolicy_vG.json
- vnfPolicy_vGMuxInfra.json
+ placement_policy_dir_vfw: "./test/policy-local-files/"
+ placement_policy_files_vfw: # workaroud for policy platform glitches (or "work-arounds" for other components)
+ #- Capacity_vFW_1.json
+ - Distance_vFW_1.json
+ - hpa_policy_vFW_1.json
+ - Placement_Optimization_1.json
+ - QueryPolicy_vFW.json
+ - vnfPolicy_vFW.json
+ placement_policy_dir_vfw_td: "./test/policy-local-files/"
+ placement_policy_files_vfw_td:
+ - vnfPolicy_vFW_TD.json
+ - vnfPolicy_vPGN_TD.json
+ - Affinity_vFW_TD.json
+ - QueryPolicy_vFW_TD.json
+ slice_selection_policy_dir_embb-nst: "./test/policy-local-files/slice-selection-files/"
+ slice_selection_policy_files_embb-nst:
+ - query_policy_nsi.json
+ - threshold_policy_nsi.json
+ - vnf_policy_nsi_shared_case.json
+ nst_selection_policy_dir_embb-nst: "./test/policy-local-files/nst-selection-files/"
+ nst_selection_policy_files_embb-nst:
+ - query_policy_nst.json
+ - attribute_policy_nst.json
+ - vnf_policy_nst.json
+ nst_selection_policy_dir_nst: "./test/policy-local-files/nst-selection-files/"
+ nst_selection_policy_files_nst:
+ - query_policy_nst.json
+ - attribute_policy_nst.json
+ - vnf_policy_nst.json
+ - optimization_policy_nst.json
+
service_info:
vCPE:
vcpeHostName: requestParameters.vcpeHostName
e2eVpnKey: requestParameters.e2eVpnKey
+ vFW:
+ vcpeHostName: requestParameters.vcpeHostName
+ e2eVpnKey: requestParameters.e2eVpnKey
references:
service_name:
source: request
value: serviceInfo.serviceName
+ resource:
+ source: request
+ value: placementInfo.placementDemands.resourceModuleName
subscriber_role:
- source: SubscriberPolicy
- value: content.properties.subscriberRole
+ source: onap.policies.optimization.SubscriberPolicy
+ value: properties.properties.subscriberRole
+ slice_scope:
+ source: request
+ value: slice_scope
policy_info:
prioritization_attributes:
policy_type:
- - content.policyType
+ - type
resources:
- - content.resources
- - content.objectiveParameter.parameterAttributes.resources
+ - properties.resources
+ - properties.objectiveParameter.parameterAttributes.resources
service_name:
- - content.serviceName
+ - properties.services
- placement:
+ slice_selection:
policy_fetch: by_scope
policy_scope:
- default_scope: OSDF_R2
- vcpe_scope: OSDF_R2
- secondary_scopes:
- -
+ -
+ scope:
+ - get_param: slice_scope
+ services:
+ - get_param: service_name
+ resources:
- get_param: service_name
+
+ nst_selection:
+ policy_fetch: by_scope
+ policy_scope:
+ -
+ scope:
+ - OSDF_GUILIN
+ services:
+ - nst
+ resources:
+ - nst
+
+ nsst_selection:
+ policy_fetch: by_scope
+ policy_scope:
+ -
+ scope:
+ - OSDF_GUILIN
+ services:
+ - nsst
+ resources:
+ - nsst
+
+ subnet_selection:
+ policy_fetch: by_scope
+ policy_scope:
+ - scope:
+ - OSDF_GUILIN
+ services:
+ - get_param: service_name
+ resources:
+ - get_param: service_name
+
+ placement:
+ policy_fetch: by_scope
+ policy_scope:
+ -
+ scope:
+ - OSDF_FRANKFURT
+ geography:
- US
+ services:
+ - get_param: service_name
+ resources:
+ - get_param: resource
# -
# - get_param: service_name
# - get_param: subscriber_role
default: # if no explicit service related information is needed
policy_fetch: by_name
policy_scope: none
+
+PCI:
+ ML:
+ average_ho_threshold: 10000
+ latest_ho_threshold: 500
+ DES:
+ service_id: ho_metric
+ filter:
+ interval: 10
+ ml_enabled: false
+
+nxi_termination:
+ query_templates:
+ nsi: "service-instance*('service-instance-id','{{instance_id}}') > service-instance*('service-role','e2eserviceprofile-service')"
+ nsi_with_profile: "service-instance*('service-instance-id','{{instance_id}}') > service-instance*('service-role','e2eserviceprofile-service')('service-instance-id','{{profile_id}}')"
+ nssi:
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'CN') > service-instance*('service-role','nsi')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'CN') > service-instance*('service-role','nsi')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'TN-BH') > service-instance*('service-role','nsi')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'AN') > service-instance*('service-role','nsi')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'AN-NF') > service-instance*('workload-context','AN')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'TN-MH') > service-instance*('workload-context','AN')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'TN-FH') > service-instance*('workload-context','AN')"
+ - "service-instance*('service-instance-id','{{instance_id}}')('workload-context', 'AN-NF') > service-instance*('workload-context','AN')"
diff --git a/config/has_config.yaml b/config/has_config.yaml
index 9200daf..2f4a1cd 100644
--- a/config/has_config.yaml
+++ b/config/has_config.yaml
@@ -1,26 +1,35 @@
policy_config_mapping:
- attributes:
- hypervisor: hypervisor,
- cloud_version: cloudVersion,
- cloud_type: cloudType,
- dataplane: dataPlane,
- network_roles: networkRoles,
- complex: complex,
- state: state,
- country: country,
- geo_region: geoRegion,
- exclusivity_groups: exclusivityGroups,
- replication_role: replicationRole,
- customer-id: customerId,
- service-type: serviceResourceId,
- equipment-role: equipmentRole,
- model-invariant-id: modelInvariantId,
- model-version-id: modelVersionId
+ filtering_attributes:
+ hypervisor: hypervisor
+ cloudVersion: cloud_version
+ cloudType: cloud_type
+ dataPlane: dataplane
+ networkRoles: network_roles
+ complex: complex
+ state: state
+ country: country
+ geoRegion: geo_region
+ exclusivityGroups: exclusivity_groups
+ replicationRole: replication_role
+ customerId: customer_id
+ serviceResourceId: service-type
+ equipmentRole: equipment-role
+ modelInvariantId: model-invariant-id
+ modelVersionId: model-version-id
+ cloudRegionId: cloud-region-id
+ orchestrationStatus: orchestration-status
+ provStatus: prov-status
+ cloudRegion: cloud-region
+ cloud_region_attributes:
+ serviceRequests: service-requests
+ cloudRequests: cloud-requests
+ passthrough_attributes: {}
+ default_attributes: {}
candidates:
# for (k1, v1), if k1 is in demand, set prop[k2] = _get_candidates(demand[k1])
- exclusionCandidateInfo: excluded_candidates,
- requiredCandidateInfo: required_candidates
+ excludedCandidates: excluded_candidates
+ requiredCandidates: required_candidates
extra_fields:
# we have [k1, k2, k3, k4] type items and x is policy-content-properties
# if x[k1] == k2: set prop[k3] = k4
- - [inventoryType, cloud, region, {get_param: CHOSEN_REGION}] \ No newline at end of file
+ - [inventoryType, cloud, region, {get_param: CHOSEN_REGION}]
diff --git a/config/log.yml b/config/log.yml
new file mode 100644
index 0000000..ad0de21
--- /dev/null
+++ b/config/log.yml
@@ -0,0 +1,100 @@
+version: 1
+disable_existing_loggers: True
+
+loggers:
+ error:
+ handlers: [error_handler, console_handler]
+ level: "WARN"
+ propagate: True
+ debug:
+ handlers: [debug_handler, console_handler]
+ level: "DEBUG"
+ propagate: True
+ metrics:
+ handlers: [metrics_handler, console_handler]
+ level: "INFO"
+ propagate: True
+ audit:
+ handlers: [audit_handler, console_handler]
+ level: "INFO"
+ propagate: True
+handlers:
+ debug_handler:
+ level: "DEBUG"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/debug.log"
+ formatter: "debugFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ error_handler:
+ level: "WARN"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/error.log"
+ formatter: "errorFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ metrics_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/metrics.log"
+ formatter: "metricsFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ audit_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/audit.log"
+ formatter: "auditFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ console_handler:
+ level: "DEBUG"
+ class: "logging.StreamHandler"
+ formatter: "metricsFormat"
+
+formatters:
+ standard:
+ format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s"
+ debugFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{server}|%(levelname)s|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ errorFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{serviceName}|{partnerName}\
+ |{targetEntity}|{targetServiceName}|%(levelname)s|{errorCode}|{errorDescription}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ auditFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ metricsFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{targetEntity}|{targetServiceName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{TargetVirtualEntity}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ mdcFormat:
+ format: "%(asctime)s.%(msecs)03d+00:00|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s"
+ mdcfmt: "{requestID} {invocationID} {serviceName} {serverIPAddress}"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
diff --git a/config/opteng_config.yaml b/config/opteng_config.yaml
new file mode 100755
index 0000000..6b61eb0
--- /dev/null
+++ b/config/opteng_config.yaml
@@ -0,0 +1,25 @@
+# Policy Platform -- requires Authorization
+policyPlatformUrl: https://policy-xacml-pdp:6969/policy/pdpx/decision/v1 # Policy Dev platform URL
+
+# AAF Authentication config
+is_aaf_enabled: False
+aaf_cache_expiry_mins: 5
+aaf_url: https://aaftest.simpledemo.onap.org:8095
+aaf_user_roles:
+ - '/optmodel:org.onap.oof.access|*|read ALL'
+ - '/optengine:org.onap.oof.access|*|read ALL'
+
+# Secret Management Service from AAF
+aaf_sms_url: http://localhost:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+
+osdfDatabaseHost: localhost
+osdfDatabaseSchema: osdf
+osdfDatabaseUsername: osdf
+osdfDatabasePassword: osdf
+osdfDatabasePort: 3306
+
+#key
+appkey: os35@rrtky400fdntc#001t5
diff --git a/config/osdf_config.yaml b/config/osdf_config.yaml
index b522919..6780d13 100755
--- a/config/osdf_config.yaml
+++ b/config/osdf_config.yaml
@@ -1,4 +1,4 @@
-placementVersioningEnabled: False
+placementVersioningEnabled: True
# Placement API latest version numbers to be set in HTTP header
placementMajorVersion: "1"
@@ -10,60 +10,34 @@ placementDefaultMajorVersion: "1"
placementDefaultMinorVersion: "0"
placementDefaultPatchVersion: "0"
-# Credentials for SO
-soUsername: "" # SO username for call back.
-soPassword: "" # SO password for call back.
-
-# Credentials for Conductor
+# Config for Conductor
conductorUrl: http://172.17.0.6:8091/v1/plans/
-conductorUsername: admin1
-conductorPassword: plan.15
conductorPingWaitTime: 60 # seconds to wait before calling the conductor retry URL
conductorMaxRetries: 30 # if we don't get something in 30 minutes, give up
# versions to be set in HTTP header
conductorMinorVersion: 0
-# Policy Platform -- requires ClientAuth, Authorization, and Environment
-policyPlatformUrl: http://policy.api.simpledemo.onap.org:8081/pdp/api/getConfig # Policy Dev platform URL
-policyPlatformEnv: TEST # Environment for policy platform
-policyPlatformUsername: testpdp # Policy platform username.
-policyPlatformPassword: alpha123 # Policy platform password.
-policyClientUsername: python # For use with ClientAuth
-policyClientPassword: test # For use with ClientAuth
+# Policy Platform -- requires Authorization
+policyPlatformUrl: https://policy-xacml-pdp:6969/policy/pdpx/v1/decision # Policy Dev platform URL
+# URL for policy model uploading
+policyPlatformUrlModelUpload: https://policy.api.simpledemo.onap.org:8081/policy/api/v1/policytypes
+pathPolicyModelUpload: ../../models/policy/placement/tosca_upload/
-# Credentials for DMaaP
+# Config for DMaaP
messageReaderHosts: NA
messageReaderTopic: NA
-messageReaderAafUserId: NA
-messageReaderAafPassword: NA
-# Credentials for SDC
+# Config for SDC
sdcUrl: NA
-sdcUsername: NA
-sdcPassword: NA
sdcONAPInstanceID: NA
-# Credentials for the OOF placement service - Generic
-osdfPlacementUsername: test
-osdfPlacementPassword: testpwd
-
-# Credentials for the OOF placement service - SO
-osdfPlacementSOUsername: so_test
-osdfPlacementSOPassword: so_testpwd
-
-# Credentials for the OOF placement service - VFC
-osdfPlacementVFCUsername: vfc_test
-osdfPlacementVFCPassword: vfc_testpwd
-
-# Credentials for the OOF CM scheduling service - Generic
-osdfCMSchedulerUsername: test1
-osdfCMSchedulerPassword: testpwd1
-
+# AAF Authentication config
is_aaf_enabled: False
-aaf_cache_expiry_hrs: 3
+aaf_cache_expiry_mins: 5
aaf_url: https://aaftest.simpledemo.onap.org:8095
aaf_user_roles:
- - /api/oof/v1/placement:org.onap.osdf.access|*|read ALL
+ - '/placement:org.onap.oof.access|*|read ALL'
+ - '/pci:org.onap.oof.access|*|read ALL'
# Secret Management Service from AAF
aaf_sms_url: https://aaf-sms.onap:10443
@@ -71,17 +45,50 @@ aaf_sms_timeout: 30
secret_domain: osdf
aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+configClientType: configdb
+
# config db api
configDbUrl: http://config.db.url:8080
-configDbUserName: osdf
-configDbPassword: passwd
configDbGetCellListUrl: 'SDNCConfigDBAPI/getCellList'
configDbGetNbrListUrl: 'SDNCConfigDBAPI/getNbrList'
-
-# Credentials for PCIHandler
-pciHMSUsername: "" # pcihandler username for call back.
-pciHMSPassword: "" # pcihandler password for call back.
-
-# Credentials for the OOF PCI Opt service
-osdfPCIOptUsername: pci_test
-osdfPCIOptPassword: pci_testpwd
+configDbUserName: ''
+configDbPassword: ''
+
+# cps api
+cpsUrl: http://cps-tbdmt:8000/execute
+cpsCellListUrl: 'ran-network/getCellList'
+cpsNbrListUrl: 'ran-network/getNbrList'
+cpsUsername: ''
+cpsPassword: ''
+
+#aai api
+aaiUrl: "https://aai.url:30233"
+aaiGetLinksUrl: "/aai/v16/network/logical-links"
+aaiServiceInstanceUrl : "/aai/v20/nodes/service-instances/service-instance/"
+aaiGetControllersUrl: /aai/v19/external-system/esr-thirdparty-sdnc-list
+controllerQueryUrl: /aai/v19/query?format=resource
+aaiGetInterDomainLinksUrl: /aai/v19/network/logical-links?link-type=inter-domain&operational-status=up
+dslQueryPath: /aai/v23/dsl?format=
+
+#DES api
+desUrl: http://des.url:9000
+desApiPath: /datalake/v1/exposure/
+desHeaders:
+ Accept: application/json
+ Content-Type: application/json
+desUsername:
+desPassword:
+
+pciHMSUsername: test
+pciHMSPassword: passwd
+
+#key
+#appkey: os35@rrtky400fdntc#001t5
+
+#consulconfig
+consulHost: '127.0.0.1'
+consulPort: 8500
+consulScheme: 'http'
+consulVerify: True
+consulCert: None
+activateConsulConfig: False
diff --git a/config/preload_secrets.yaml b/config/preload_secrets.yaml
index 1d2ea01..b95f1c1 100755
--- a/config/preload_secrets.yaml
+++ b/config/preload_secrets.yaml
@@ -1,55 +1,55 @@
---
domain: osdf
secrets:
-- name: so
- values:
- UserName: ''
- Password: ''
-- name: conductor
- values:
- UserName: admin1
- Password: plan.15
-- name: policyPlatform
- values:
- UserName: testpdp
- Password: alpha123
-- name: policyClient
- values:
- UserName: python
- Password: test
-- name: dmaap
- values:
- UserName: NA
- Password: NA
-- name: sdc
- values:
- UserName: NA
- Password: NA
-- name: osdfPlacement
- values:
- UserName: test
- Password: testpwd
-- name: osdfPlacementSO
- values:
- UserName: so_test
- Password: so_testpwd
-- name: osdfPlacementVFC
- values:
- UserName: vfc_test
- Password: vfc_testpwd
-- name: osdfCMScheduler
- values:
- UserName: test1
- Password: testpwd1
-- name: configDb
- values:
- UserName: osdf
- Password: passwd
-- name: pciHMS
- values:
- UserName: ''
- Password: ''
-- name: osdfPCIOpt
- values:
- UserName: pci_test
- Password: pci_testpwd
+ - name: so
+ values:
+ UserName: ''
+ Password: ''
+ - name: conductor
+ values:
+ UserName: admin1
+ Password: 22234d3472ef5da8ecba5a096110a024f1db5cf195c665f910d558c9e83db19d
+ - name: policyPlatform
+ values:
+ UserName: healthcheck
+ Password: 49a03554e86ecdb8e9e224127791c579b44993b264549a333172af77c2ae95fc
+ - name: dmaap
+ values:
+ UserName: NA
+ Password: NA
+ - name: sdc
+ values:
+ UserName: NA
+ Password: NA
+ - name: osdfPlacement
+ values:
+ UserName: test
+ Password: c66b1570ae257375e500f9fe0e62b2a325466137ac5f29581e2e05cce1170212
+ - name: osdfPlacementSO
+ values:
+ UserName: so_test
+ Password: 3d62d49b3e4ada38fd4146d2d82f4ba2f09345a46f15970cd439924c991b8202
+ - name: osdfPlacementVFC
+ values:
+ UserName: vfc_test
+ Password: 1fb1cd581f96060d29ecad06be97151656bf29bce66bad587cd2fbaf5ea1e66d
+ - name: osdfCMScheduler
+ values:
+ UserName: test1
+ Password: c5279fb02d7bac5269b1a644ac8e36f41f6ba7a2eae03dc469cb80d71811322b
+ - name: configDb
+ values:
+ UserName: osdf
+ Password: 40697f254409c2b97763892ecdeb50c847d605f5beb6f988f1c142a7e0344d0c
+ - name: pciHMS
+ values:
+ UserName: ''
+ Password: ''
+ - name: osdfPCIOpt
+ values:
+ UserName: pci_test
+ Password: fbf4dcb7f7cda8fdfb742838b0c90ae5bea249801f3f725fdc98941a6e4c347c
+ - name: osdfOptEngine
+ values:
+ UserName: opt_test
+ Password: 02946408ce6353d45540cd01d912686f19f48c3d8a955d5effdc14c6a43477e5
diff --git a/config/slicing_config.yaml b/config/slicing_config.yaml
new file mode 100644
index 0000000..179f54a
--- /dev/null
+++ b/config/slicing_config.yaml
@@ -0,0 +1,96 @@
+app_info:
+ NSI:
+ app_name: slice_selection
+ requirements_field: serviceProfile
+ model_info: NSTInfo
+ NSSI:
+ app_name: subnet_selection
+ requirements_field: sliceProfile
+ model_info: NSSTInfo
+
+attribute_mapping:
+ camel_to_snake:
+ maxBandwidth: max_bandwidth
+ jitter: jitter
+ sST: sst
+ latency: latency
+ resourceSharingLevel: resource_sharing_level
+ uEMobilityLevel: ue_mobility_level
+ maxNumberofUEs: max_number_of_ues
+ dLThptPerUE: dl_thpt_per_ue
+ uLThptPerUE: ul_thpt_per_ue
+ sNSSAI: s_nssai
+ pLMNIdList: plmn_id_list
+ activityFactor: activity_factor
+ coverageAreaTAList: coverage_area_ta_list
+ availability: availability
+ cSAvailabilityTarget: cs_availability_target
+ reliability: reliability
+ cSReliabilityMeanTime: cs_reliability_mean_time
+ dLThptPerSlice: dl_thpt_per_slice
+ expDataRateDL: exp_data_rate_dl
+ uLThptPerSlice: ul_thpt_per_slice
+ expDataRateUL: exp_data_rate_ul
+ maxPktSize: max_pkt_size
+ msgSizeByte: msg_size_byte
+ maxNumberofConns: max_number_of_conns
+ maxNumberofPDUSession: max_number_of_pdu_session
+ termDensity: terminal_density
+ survivalTime: survival_time
+ areaTrafficCapDL: area_traffic_cap_dl
+ areaTrafficCapUL: area_traffic_cap_ul
+ overallUserDensity: overall_user_density
+ transferIntervalTarget: transfer_interval_target
+ expDataRate: exp_data_rate
+ security: security
+ maxThroughput: max_throughput
+ sliceProfileId: slice_profile_id
+ snssaiList: s_nssai_list
+ domainType: domain_type
+ logicInterfaceId: logical_interface_id
+ ipAddress: ip_address
+ nextHopInfo: next_hop_info
+ perfReq: perf_req
+
+ snake_to_camel:
+ max_bandwidth: maxBandwidth
+ jitter: jitter
+ sst: sST
+ latency: latency
+ resource_sharing_level: resourceSharingLevel
+ ue_mobility_level: uEMobilityLevel
+ max_number_of_ues: maxNumberofUEs
+ dl_thpt_per_ue: dLThptPerUE
+ ul_thpt_per_ue: uLThptPerUE
+ s_nssai: sNSSAI
+ plmn_id_list: pLMNIdList
+ activity_factor: activityFactor
+ coverage_area_ta_list: coverageAreaTAList
+ availability: availability
+ cs_availability_target: cSAvailabilityTarget
+ reliability: reliability
+ cs_reliability_mean_time: cSReliabilityMeanTime
+ dl_thpt_per_slice: dLThptPerSlice
+ exp_data_rate_dl: expDataRateDL
+ ul_thpt_per_slice: uLThptPerSlice
+ exp_data_rate_ul: expDataRateUL
+ max_pkt_size: maxPktSize
+ msg_size_byte: msgSizeByte
+ max_number_of_conns: maxNumberofConns
+ max_number_of_pdu_session: maxNumberofPDUSession
+ terminal_density: termDensity
+ survival_time: survivalTime
+ area_traffic_cap_dl: areaTrafficCapDL
+ area_traffic_cap_ul: areaTrafficCapUL
+ overall_user_density: overallUserDensity
+ transfer_interval_target: transferIntervalTarget
+ exp_data_rate: expDataRate
+ security: security
+ max_throughput: maxThroughput
+ slice_profile_id: sliceProfileId
+ s_nssai_list: snssaiList
+ domain_type: domainType
+ logical_interface_id: logicInterfaceId
+ ip_address: ipAddress
+ next_hop_info: nextHopInfo
+ perf_req: perfReq
diff --git a/csit/.gitignore b/csit/.gitignore
new file mode 100644
index 0000000..c8865c2
--- /dev/null
+++ b/csit/.gitignore
@@ -0,0 +1,2 @@
+env.properties
+archives/
diff --git a/csit/plans/default/setup.sh b/csit/plans/default/setup.sh
new file mode 100755
index 0000000..76f071f
--- /dev/null
+++ b/csit/plans/default/setup.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+#
+echo "# aaf-sms setup.sh script";
+source ${WORKSPACE}/scripts/setup-sms.sh
+
+echo "# simulator scripts calling";
+source ${WORKSPACE}/scripts/simulator_script.sh
+
+# add here eventual scripts needed for optf/osdf
+#
+echo "# optf/osdf scripts calling";
+source ${WORKSPACE}/scripts/osdf_script.sh
+
+#
+# add here below the start of all docker containers needed for optf/osdf CSIT testing
+#
+echo "# optf/osdf scripts docker containers spinoff";
+
+#
+# add here all the configuration steps eventually needed to be carried out for optf/osdf CSIT testing
+#
+echo "# optf/osdf configuration step";
+
+
+#
+# add here all ROBOT_VARIABLES settings
+#
+echo "# optf/osdf robot variables settings";
+echo "osdf ip = ${OSDF_IP}"
+
+ROBOT_VARIABLES="-v OSDF_HOSTNAME:http://${OSDF_IP} -v OSDF_PORT:8699"
+
+echo ${ROBOT_VARIABLES}
+
+
+
diff --git a/csit/plans/default/teardown.sh b/csit/plans/default/teardown.sh
new file mode 100755
index 0000000..02aa669
--- /dev/null
+++ b/csit/plans/default/teardown.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+
+#
+# add here below the killing of all docker containers used for optf/osdf CSIT testing
+#
+
+#
+# optf/osdf scripts docker containers killing";
+#
+
+${WORKSPACE}/scripts/kill-instance.sh optf-osdf
+${WORKSPACE}/scripts/kill-instance.sh osdf_sim
+
+echo "# aaf-sms teardown.sh script";
+${WORKSPACE}/scripts/kill-instance.sh sms
+${WORKSPACE}/scripts/kill-instance.sh vault
+
diff --git a/csit/plans/default/testplan.txt b/csit/plans/default/testplan.txt
new file mode 100644
index 0000000..239cc37
--- /dev/null
+++ b/csit/plans/default/testplan.txt
@@ -0,0 +1,22 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+# Test suites are relative paths under [integration.git]/test/csit/tests/.
+# Place the suites in run order.
+osdf
diff --git a/csit/prepare-csit.sh b/csit/prepare-csit.sh
new file mode 100755
index 0000000..d46b17a
--- /dev/null
+++ b/csit/prepare-csit.sh
@@ -0,0 +1,47 @@
+#!/bin/bash -x
+#
+# Copyright 2019-2021 © Samsung Electronics Co., Ltd.
+# Modifications Copyright (C) 2021 Pantheon.tech
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script installs common libraries required by CSIT tests
+#
+# Branched from ccsdk/distribution to this repository Feb 23, 2021
+#
+
+if [ -z "$WORKSPACE" ]; then
+ export WORKSPACE=`git rev-parse --show-toplevel`
+fi
+
+TESTPLANDIR=${WORKSPACE}/${TESTPLAN}
+
+# Assume that if ROBOT_VENV is set and virtualenv with system site packages can be activated,
+# ci-management/jjb/integration/include-raw-integration-install-robotframework.sh has already
+# been executed
+
+if [ -f ${WORKSPACE}/env.properties ]; then
+ source ${WORKSPACE}/env.properties
+fi
+if [ -f ${ROBOT_VENV}/bin/activate ]; then
+ source ${ROBOT_VENV}/bin/activate
+else
+ rm -rf /tmp/ci-management
+ rm -f ${WORKSPACE}/env.properties
+ cd /tmp
+ git clone "https://gerrit.onap.org/r/ci-management"
+ source /tmp/ci-management/jjb/integration/include-raw-integration-install-robotframework.sh
+fi
+
+pip freeze
+
diff --git a/csit/run-csit.sh b/csit/run-csit.sh
new file mode 100755
index 0000000..9220ef9
--- /dev/null
+++ b/csit/run-csit.sh
@@ -0,0 +1,197 @@
+#!/bin/bash -x
+#
+# Copyright 2016-2017 Huawei Technologies Co., Ltd.
+# Modification Copyright 2019-2021 © Samsung Electronics 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.
+#
+# $1 project/functionality
+# $2 robot options
+
+# Branched from ccsdk/distribution to this repository Feb 23, 2021
+
+#
+# functions
+#
+
+function on_exit(){
+ rc=$?
+ if [[ ${WORKSPACE} ]]; then
+ if [[ ${WORKDIR} ]]; then
+ rsync -av "$WORKDIR/" "$WORKSPACE/archives/$TESTPLAN"
+ fi
+ # Record list of active docker containers
+ docker ps --format "{{.Image}}" > "$WORKSPACE/archives/$TESTPLAN/_docker-images.log"
+
+ # show memory consumption after all docker instances initialized
+ docker_stats | tee "$WORKSPACE/archives/$TESTPLAN/_sysinfo-2-after-robot.txt"
+ fi
+ # Run teardown script plan if it exists
+ cd "${TESTPLANDIR}"
+ TEARDOWN="${TESTPLANDIR}/teardown.sh"
+ if [ -f "${TEARDOWN}" ]; then
+ echo "Running teardown script ${TEARDOWN}"
+ source_safely "${TEARDOWN}"
+ fi
+ # TODO: do something with the output
+ exit $rc
+}
+# ensure that teardown and other finalizing steps are always executed
+trap on_exit EXIT
+
+function docker_stats(){
+ #General memory details
+ echo "> top -bn1 | head -3"
+ top -bn1 | head -3
+ echo
+
+ echo "> free -h"
+ free -h
+ echo
+
+ #Memory details per Docker
+ echo "> docker ps"
+ docker ps
+ echo
+
+ echo "> docker stats --no-stream"
+ docker stats --no-stream
+ echo
+}
+
+# save current set options
+function save_set() {
+ RUN_CSIT_SAVE_SET="$-"
+ RUN_CSIT_SHELLOPTS="$SHELLOPTS"
+}
+
+# load the saved set options
+function load_set() {
+ _setopts="$-"
+
+ # bash shellopts
+ for i in $(echo "$SHELLOPTS" | tr ':' ' ') ; do
+ set +o ${i}
+ done
+ for i in $(echo "$RUN_CSIT_SHELLOPTS" | tr ':' ' ') ; do
+ set -o ${i}
+ done
+
+ # other options
+ for i in $(echo "$_setopts" | sed 's/./& /g') ; do
+ set +${i}
+ done
+ set -${RUN_CSIT_SAVE_SET}
+}
+
+# set options for quick bailout when error
+function harden_set() {
+ set -xeo pipefail
+ set +u # enabled it would probably fail too many often
+}
+
+# relax set options so the sourced file will not fail
+# the responsibility is shifted to the sourced file...
+function relax_set() {
+ set +e
+ set +o pipefail
+}
+
+# wrapper for sourcing a file
+function source_safely() {
+ [ -z "$1" ] && return 1
+ relax_set
+ . "$1"
+ load_set
+}
+
+#
+# main
+#
+
+# set and save options for quick failure
+harden_set && save_set
+
+if [ $# -eq 0 ]
+then
+ echo
+ echo "Usage: $0 plans/<project>/<functionality> [<robot-options>]"
+ echo
+ echo " <project>, <functionality>, <robot-options>: "
+ echo " The same values as for the '{project}-csit-{functionality}' JJB job template."
+ echo
+ exit 1
+fi
+
+if [ -z "$WORKSPACE" ]; then
+ export WORKSPACE=$(git rev-parse --show-toplevel)
+fi
+
+if [ -f "${WORKSPACE}/${1}/testplan.txt" ]; then
+ export TESTPLAN="${1}"
+else
+ echo "testplan not found: ${WORKSPACE}/${TESTPLAN}/testplan.txt"
+ exit 2
+fi
+
+export TESTOPTIONS="${2}"
+
+rm -rf "$WORKSPACE/archives/$TESTPLAN"
+mkdir -p "$WORKSPACE/archives/$TESTPLAN"
+
+TESTPLANDIR="${WORKSPACE}/${TESTPLAN}"
+
+# Run installation of prerequired libraries
+source_safely "${WORKSPACE}/prepare-csit.sh"
+
+# Activate the virtualenv containing all the required libraries installed by prepare-csit.sh
+source_safely "${ROBOT_VENV}/bin/activate"
+
+WORKDIR=$(mktemp -d --suffix=-robot-workdir)
+cd "${WORKDIR}"
+
+# Add csit scripts to PATH
+export PATH="${PATH}:${WORKSPACE}/docker/scripts:${WORKSPACE}/scripts:${ROBOT_VENV}/bin"
+export SCRIPTS="${WORKSPACE}/scripts"
+export ROBOT_VARIABLES=
+
+# Sign in to nexus3 docker repo
+docker login -u docker -p docker nexus3.onap.org:10001
+
+# Run setup script plan if it exists
+cd "${TESTPLANDIR}"
+SETUP="${TESTPLANDIR}/setup.sh"
+if [ -f "${SETUP}" ]; then
+ echo "Running setup script ${SETUP}"
+ source_safely "${SETUP}"
+fi
+
+# show memory consumption after all docker instances initialized
+docker_stats | tee "$WORKSPACE/archives/$TESTPLAN/_sysinfo-1-after-setup.txt"
+
+# Run test plan
+cd "$WORKDIR"
+echo "Reading the testplan:"
+cat "${TESTPLANDIR}/testplan.txt" | egrep -v '(^[[:space:]]*#|^[[:space:]]*$)' | sed "s|^|${WORKSPACE}/tests/|" > testplan.txt
+cat testplan.txt
+SUITES=$( xargs -a testplan.txt )
+
+echo ROBOT_VARIABLES="${ROBOT_VARIABLES}"
+echo "Starting Robot test suites ${SUITES} ..."
+relax_set
+python -m robot.run -N ${TESTPLAN} -v WORKSPACE:/tmp ${ROBOT_VARIABLES} ${TESTOPTIONS} ${SUITES}
+RESULT=$?
+load_set
+echo "RESULT: $RESULT"
+# Note that the final steps are done in on_exit function after this exit!
+exit $RESULT
diff --git a/csit/run-project-csit.sh b/csit/run-project-csit.sh
new file mode 100755
index 0000000..a231c5e
--- /dev/null
+++ b/csit/run-project-csit.sh
@@ -0,0 +1,35 @@
+#!/bin/bash -x
+#
+# Copyright 2020-2021 © Samsung Electronics Co., Ltd.
+# Modifications Copyright (C) 2021 Pantheon.tech
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Branched from ccsdk/distribution to this repository Feb 23, 2021
+#
+
+# $1 test options (passed on to run-csit.sh as such)
+
+export TESTOPTIONS=${1}
+export WORKSPACE=$(git rev-parse --show-toplevel)/csit
+
+rm -rf ${WORKSPACE}/archives
+mkdir -p ${WORKSPACE}/archives
+cd ${WORKSPACE}
+
+# Execute all test-suites defined under plans subdirectory
+for dir in plans/*/
+do
+ dir=${dir%*/} # remove the trailing /
+ ./run-csit.sh ${dir} ${TESTOPTIONS}
+done
diff --git a/csit/scripts/common_functions.sh b/csit/scripts/common_functions.sh
new file mode 100755
index 0000000..684c418
--- /dev/null
+++ b/csit/scripts/common_functions.sh
@@ -0,0 +1,263 @@
+#!/bin/bash
+
+# Copyright 2016-2017 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.
+
+function memory_details(){
+ #General memory details
+ echo "> top -bn1 | head -3"
+ top -bn1 | head -3
+ echo
+
+ echo "> free -h"
+ free -h
+ echo
+
+ #Memory details per Docker
+ echo "> docker ps"
+ docker ps
+ echo
+
+ echo "> docker stats --no-stream"
+ docker stats --no-stream
+ echo
+}
+function fibonacci_number(){
+ set +x
+ if [ $1 -le 1 ]
+ then
+ echo "1"
+ elif [ $1 -le 10 ]
+ then
+ Num=$1
+ f1=0
+ f2=1
+ fn=-1
+ for i in `eval echo {1..$Num}`;do
+ fn=$((f1+f2))
+ f1=$f2
+ f2=$fn
+ done
+ echo $fn
+ else
+ echo "30"
+ fi
+}
+function wait_curl_driver(){
+ #Parameters:
+ #CURL_COMMAND - the URL on which the curl command will be executed
+ #GREP_STRING - Desired string to be found inside the body response of the
+ # previous curl command
+ #EXCLUDE_STRING - If the filtered string (GREP_STRING) must not exist in
+ # the body response of the curl
+ #WAIT_MESSAGE - the message to be displayed for logging purpose. (optional)
+ #REPEAT_NUMBER - the maximum number of tries before abandoning the curl
+ # command (optional, by default = 15)
+ #MAX_TIME - Maximum time allowed for the transfer (in seconds)
+ #STATUS_CODE - A HTTP status code desired to be found by getting the link
+ # /!\ IMPORTANT NOTICE: the usage of STATUS_CODE option turn GREP_STRING/
+ # /!\ EXCLUDE_STRING/and the MAX_TIME options becomes obsolete with no
+ # /!\ execution impact
+ #MEMORY_USAGE - If Parameters exists shows the memory usage after curl
+ # execution(s)
+
+ repeat_max=15
+ parameters="$@"
+
+ #WAIT_MESSAGE
+ if [[ $parameters == *"WAIT_MESSAGE"* ]]
+ then
+ wait_message=`echo $parameters | sed -e "s/.*WAIT_MESSAGE=//g"`
+ wait_message=`echo $wait_message | sed -e "s/ .*//g"`
+ else
+ wait_message="wait ..."
+ fi
+
+ #REPEAT_NUMBER
+ if [[ $parameters == *"REPEAT_NUMBER"* ]]
+ then
+ repeat_max=`echo $parameters | sed -e "s/.*REPEAT_NUMBER=//g"`
+ repeat_max=`echo $repeat_max | sed -e "s/ .*//g"`
+ fi
+
+ #CURL_COMMAND
+ if [[ $parameters == *"CURL_COMMAND"* ]]
+ then
+ curl_command=`echo $parameters | sed -e 's/.*CURL_COMMAND=//g'`
+ curl_command=`echo $curl_command | sed -e 's/ .*//g'`
+ else
+ echo "-Curl is empty-" # Or no parameterseter passed.
+ return 0
+ fi
+
+ #MAX_TIME
+ if [[ $parameters == *"MAX_TIME"* ]]
+ then
+ max_time=`echo $parameters | sed -e 's/.*MAX_TIME=//g'`
+ max_time=`echo $max_time | sed -e 's/ .*//g'`
+ else
+ max_time="5"
+ fi
+
+ exclude_string=""
+ #EXCLUDE_STRING
+ if [[ $parameters == *"EXCLUDE_STRING"* ]]
+ then
+ exclude_string="-v"
+ fi
+
+ status_code=""
+ #STATUS_CODE
+ if [[ $parameters == *"STATUS_CODE"* ]]
+ then
+ status_code=`echo $parameters | sed -e 's/.*STATUS_CODE=//g'`
+ status_code=`echo $status_code | sed -e 's/ .*//g'`
+ fi
+
+ for i in `eval echo {1..$repeat_max}`; do
+ response_code=`curl -o /dev/null --silent --head --write-out '%{http_code}' $curl_command`
+ echo "..."
+ if [[ ! -z $status_code ]] ; then
+ if [ "$status_code" -eq "$response_code" ]
+ then
+ echo "SUCCESS:Actual Status code <$response_code> match the expected code <$status_code>"
+ return 0
+ else
+ echo "WARNING:Expected <$status_code> but Actual <$response_code>"
+ fi
+ else
+ #GREP_STRING
+ if [[ $parameters == *"GREP_STRING"* ]]
+ then
+ grep_command=`echo $parameters | sed -e 's/.*GREP_STRING=//g'`
+ grep_command=`echo $grep_command | sed -e 's/ REPEAT_NUMBER=.*//g' | sed -e 's/ CURL_COMMAND=.*//g' | sed -e 's/ WAIT_MESSAGE=.*//g' | sed -e 's/ MAX_TIME=.*//g' | sed -e 's/ EXCLUDE_STRING.*//g'`
+ else
+ echo "-Grep_command is empty-" # Or no parameters passed.
+ return 0
+ fi
+
+ str=`curl -sS -m$max_time $curl_command | grep "$grep_command"`
+ echo "BODY::$str"
+ if [[ ! -z $exclude_string ]]
+ then
+ if [[ -z $str ]]
+ then
+ echo "SUCCESS: body response does not contains '$grep_command'";
+ break;
+ else
+ echo "Fall_Short: Body response still contains '$grep_command'"
+ fi
+ else
+ if [[ ! -z $str ]]
+ then
+ echo "SUCCESS: body response contains '$grep_command'";
+ break;
+ else
+ echo "Fall_Short: Element '$grep_command' not found yet # "$i""
+ fi
+ fi
+
+ if [ "$?" = "7" ]; then
+ echo 'Connection refused or can not connect to server/proxy';
+ str=''
+ fi
+ fi
+ seconds2sleep=`fibonacci_number $i`
+ echo $wait_message
+ echo "Iteration::$i out of $repeat_max "
+ echo "Quiet time for $seconds2sleep seconds ..."
+ sleep $seconds2sleep
+
+ # if waiting for a long time, log system load
+ if [ $i -gt 45 ]
+ then
+ memory_details
+ fi
+ done
+ #MEMORY_USAGE
+ if [[ $parameters == *"MEMORY_USAGE"* ]]
+ then
+ echo "==========================MEMORY USAGE=================================="
+ memory_details
+ echo "========================================================================"
+ fi
+ return 0
+}
+
+function run_simulator ()
+{
+ run_robottestlib
+ run_simulator_docker $1
+}
+
+function run_robottestlib ()
+{
+ #Start the robottest REST library if not started
+ if ! pgrep -f robottest > /dev/null
+ then
+ #Download the latest robottest jar
+ wget -q -O ${SCRIPTS}/integration/mockserver/org.openo.robottest.jar "https://nexus.open-o.org/service/local/artifact/maven/redirect?r=snapshots&g=org.openo.integration&a=org.openo.robottest&e=jar&v=LATEST"
+ chmod +x ${SCRIPTS}/integration/mockserver/org.openo.robottest.jar
+ eval `java -cp ${SCRIPTS}/integration/mockserver/org.openo.robottest.jar org.openo.robot.test.robottest.MyRemoteLibrary` &
+ fi
+}
+
+function run_simulator_docker ()
+{
+ #Start the simulator docker if not started
+ SIMULATOR_IP=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' simulator`
+ if [[ -z $SIMULATOR_IP ]]
+ then
+ echo "Starting simulator docker..."
+ SIMULATOR_JSON=$1
+ if [[ -z $SIMULATOR_JSON ]]
+ then
+ SIMULATOR_JSON=main.json
+ fi
+ docker run -d -i -t --name simulator -e SIMULATOR_JSON=$SIMULATOR_JSON -p 18009:18009 -p 18008:18008 openoint/simulate-test-docker
+ SIMULATOR_IP=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' simulator`
+ fi
+
+ #Set the simulator IP in robot variables
+ ROBOT_VARIABLES=${ROBOT_VARIABLES}" -v SIMULATOR_IP:${SIMULATOR_IP} -v SCRIPTS:${SCRIPTS}"
+ echo ${ROBOT_VARIABLES}
+}
+
+function get_docker_compose_service ()
+{
+ local service=$1
+ local compose_file=${2:-docker-compose.yml}
+
+ echo $(docker-compose --file ./${compose_file} ps | grep $service | cut -d " " -f1 )
+}
+
+function bypass_ip_adress ()
+{
+ local ip_address=$1
+
+ if [[ $no_proxy && $no_proxy != *$ip_address* ]]; then
+ export no_proxy=$no_proxy,$ip_address
+ fi
+}
+
+function wait_for_service_init ()
+{
+ local service_url=$1
+
+ for delay in {1..50}; do
+ curl -sS ${service_url} && break
+ echo "$delay - Waiting for $service_url..."
+ sleep $delay
+ done
+}
diff --git a/csit/scripts/get-instance-ip.sh b/csit/scripts/get-instance-ip.sh
new file mode 100755
index 0000000..a236c02
--- /dev/null
+++ b/csit/scripts/get-instance-ip.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016-2017 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.
+#
+docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $1
diff --git a/csit/scripts/kill-instance.sh b/csit/scripts/kill-instance.sh
new file mode 100755
index 0000000..5997098
--- /dev/null
+++ b/csit/scripts/kill-instance.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright 2016-2017 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.
+#
+# $1 nickname for the instance
+
+mkdir -p $WORKSPACE/archives
+
+running_containers=$(docker ps --filter name=$1 -q)
+if [ -z "$running_containers" ]
+then
+ echo "$1 already terminated"
+else
+ echo "Stopping and removing containers"
+ docker logs $running_containers >> $WORKSPACE/archives/$1.log
+ docker stop $running_containers
+ docker rm $running_containers
+fi
+
diff --git a/ssl_certs/aaf_root_ca.cer b/csit/scripts/osdf-properties/aaf_root_ca.cer
index e9a50d7..e9a50d7 100644
--- a/ssl_certs/aaf_root_ca.cer
+++ b/csit/scripts/osdf-properties/aaf_root_ca.cer
diff --git a/csit/scripts/osdf-properties/osdf.json b/csit/scripts/osdf-properties/osdf.json
new file mode 100644
index 0000000..ae059f3
--- /dev/null
+++ b/csit/scripts/osdf-properties/osdf.json
@@ -0,0 +1,105 @@
+{
+ "domain": {
+ "name": "osdf",
+ "secrets": [
+ {
+ "name": "so",
+ "values": {
+ "UserName": "",
+ "Password": ""
+ }
+ },
+ {
+ "name": "conductor",
+ "values": {
+ "UserName": "admin1",
+ "Password": "plan.15"
+ }
+ },
+ {
+ "name": "policyPlatform",
+ "values": {
+ "UserName": "testpdp",
+ "Password": "alpha123"
+ }
+ },
+ {
+ "name": "policyClient",
+ "values": {
+ "UserName": "python",
+ "Password": "test"
+ }
+ },
+ {
+ "name": "dmaap",
+ "values": {
+ "UserName": "NA",
+ "Password": "NA"
+ }
+ },
+ {
+ "name": "sdc",
+ "values": {
+ "UserName": "NA",
+ "Password": "NA"
+ }
+ },
+ {
+ "name": "osdfPlacement",
+ "values": {
+ "UserName": "test",
+ "Password": "testpwd"
+ }
+ },
+ {
+ "name": "osdfPlacementSO",
+ "values": {
+ "UserName": "so_test",
+ "Password": "so_testpwd"
+ }
+ },
+ {
+ "name": "osdfPlacementVFC",
+ "values": {
+ "UserName": "vfc_test",
+ "Password": "vfc_testpwd"
+ }
+ },
+ {
+ "name": "osdfCMScheduler",
+ "values": {
+ "UserName": "test1",
+ "Password": "testpwd1"
+ }
+ },
+ {
+ "name": "configDb",
+ "values": {
+ "UserName": "osdf",
+ "Password": "passwd"
+ }
+ },
+ {
+ "name": "pciHMS",
+ "values": {
+ "UserName": "",
+ "Password": ""
+ }
+ },
+ {
+ "name": "osdfPCIOpt",
+ "values": {
+ "UserName": "pci_test",
+ "Password": "pci_testpwd"
+ }
+ },
+ {
+ "name": "osdfOptEngine",
+ "values": {
+ "UserName": "opt_test",
+ "Password": "opt_testpwd"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/csit/scripts/osdf-properties/osdf_config.yaml b/csit/scripts/osdf-properties/osdf_config.yaml
new file mode 100755
index 0000000..f97a743
--- /dev/null
+++ b/csit/scripts/osdf-properties/osdf_config.yaml
@@ -0,0 +1,70 @@
+placementVersioningEnabled: False
+
+# Placement API latest version numbers to be set in HTTP header
+placementMajorVersion: "1"
+placementMinorVersion: "0"
+placementPatchVersion: "0"
+
+# Placement API default version numbers to be set in HTTP header
+placementDefaultMajorVersion: "1"
+placementDefaultMinorVersion: "0"
+placementDefaultPatchVersion: "0"
+
+# Config for Conductor
+conductorUrl: "http://127.0.0.1:5000/simulated/oof/has-api/flow1-success-simple/main.json"
+conductorPingWaitTime: 2 # seconds to wait before calling the conductor retry URL
+conductorMaxRetries: 5 # if we don't get something in 30 minutes, give up
+# versions to be set in HTTP header
+conductorMinorVersion: 0
+
+# Policy Platform -- requires ClientAuth, Authorization, and Environment
+policyPlatformUrl: http://127.0.0.1:5000/simulated/policy/pdpx/decision/v1 # Policy Dev platform URL
+policyPlatformEnv: TEST # Environment for policy platform
+
+# Config for DMaaP
+messageReaderHosts: https://DMAAP-HOST1:3905,https://DMAAP-HOST2:3905,https://DMAAP-HOST3:3905
+messageReaderTopic: org.onap.oof.osdf.multicloud
+
+# Config for SDC
+sdcUrl: https://SDC-HOST:8443/sdc/v1/catalog
+sdcONAPInstanceID: ONAP-OSDF
+
+osdfPlacementUrl: "http://127.0.0.1:24699/osdf/api/v2/placement"
+
+is_aaf_enabled: False
+aaf_cache_expiry_hrs: 3
+aaf_url: https://aaftest.simpledemo.onap.org:8095
+aaf_user_roles:
+ - /api/oof/v1/placement:org.onap.osdf.access|*|read ALL
+
+# Secret Management Service from AAF
+aaf_sms_url: http://aaf-sms.onap:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: /opt/aaf_root_ca.cer
+
+configClientType: configdb
+
+# config db api
+configDbUrl: http://127.0.0.1:5000/simulated/configdb
+configDbGetCellListUrl: 'getCellList'
+configDbGetNbrListUrl: 'getNbrList'
+
+# cps api
+cpsUrl: http://localhost:8080/execute
+cpsCellListUrl: 'e2e-cavsta-schemaset/get-cell-list'
+cpsNbrListUrl: 'e2e-cavsta-schemaset/get-nbr-list'
+cpsUsername: ''
+cpsPassword: ''
+
+#aai api
+aaiUrl: "http://127.0.0.1:5000"
+aaiGetLinksUrl: "/aai/v16/network/logical-links"
+aaiServiceInstanceUrl : "/simulated/aai/v23/nodes/service-instances/service-instance/"
+aaiGetControllersUrl: /aai/v19/external-system/esr-thirdparty-sdnc-list
+controllerQueryUrl: /aai/v19/query?format=resource
+aaiGetInterDomainLinksUrl: /aai/v19/network/logical-links?link-type=inter-domain&operational-status=up
+dslQueryPath: /simulated/aai/v23/dsl?format=
+
+#key
+appkey:
diff --git a/csit/scripts/osdf_proxy_settings.sh b/csit/scripts/osdf_proxy_settings.sh
new file mode 100755
index 0000000..c17d9d5
--- /dev/null
+++ b/csit/scripts/osdf_proxy_settings.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+# put into this file local proxy settings in case they are needed on your local environment
+echo "### This is ${WORKSPACE}/scripts/osdf_proxy_settings.sh"
+
+echo "optf/osdf proxy settings"
+if [ "$#" -eq "1" ]; then
+ echo "$1"
+ cd $1
+ pwd
+else
+ exit 1
+fi
+
+# don't remove following lines: commands can be attached here
+
+
diff --git a/csit/scripts/osdf_script.sh b/csit/scripts/osdf_script.sh
new file mode 100755
index 0000000..0d86a63
--- /dev/null
+++ b/csit/scripts/osdf_script.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+echo "### This is ${WORKSPACE}/scripts/osdf_script.sh"
+#
+# add here whatever commands is needed to prepare the optf/osdf CSIT testing
+#
+
+# assume the base is /tmp dir
+DIR=/tmp
+
+# the directory of the script
+echo ${DIR}
+cd ${DIR}
+
+# create directory for volume and copy configuration file
+# run docker containers
+OSDF_CONF=/tmp/osdf/properties/osdf_config.yaml
+AAF_CER=/tmp/osdf/properties/aaf_root_ca.cer
+IMAGE_NAME=nexus3.onap.org:10003/onap/optf-osdf
+IMAGE_VER=latest
+
+mkdir -p /tmp/osdf/properties
+mkdir -p /tmp/sms/properties
+
+cp ${WORKSPACE}/scripts/osdf-properties/*.yaml /tmp/osdf/properties/.
+cp ${WORKSPACE}/scripts/osdf-properties/aaf_root_ca.cer /tmp/osdf/properties/.
+cp ${WORKSPACE}/scripts/osdf-properties/osdf.json /tmp/sms/properties/.
+
+#change conductor/configdb simulator urls
+OSDF_SIM_IP=`${WORKSPACE}/scripts/get-instance-ip.sh osdf_sim`
+echo "OSDF_SIM_IP=${OSDF_SIM_IP}"
+SMS_IP=`${WORKSPACE}/scripts/get-instance-ip.sh sms`
+echo "SMS_IP=${SMS_IP}"
+
+sed -i -e "s%127.0.0.1:5000%${OSDF_SIM_IP}:5000%g" $OSDF_CONF
+sed -i -e "s%aaf-sms.onap:10443%${SMS_IP}:10443%g" $OSDF_CONF
+
+#Preload secrets
+docker exec --user root -i sms /bin/sh -c "mkdir -p /preload/config"
+docker cp /tmp/sms/properties/osdf.json sms:/preload/config/osdf.json
+docker exec --user root -i sms /bin/sh -c "/sms/bin/preload -cacert /sms/certs/aaf_root_ca.cer -jsondir /preload/config -serviceport 10443 -serviceurl http://localhost"
+
+docker logs vault
+docker run -d --name optf-osdf -v ${AAF_CER}:/opt/aaf_root_ca.cer -v ${OSDF_CONF}:/opt/osdf/config/osdf_config.yaml -p "8698:8699" ${IMAGE_NAME}:${IMAGE_VER}
+
+sleep 20
+
+OSDF_IP=`${WORKSPACE}/scripts/get-instance-ip.sh optf-osdf`
+${WORKSPACE}/scripts/wait_for_port.sh ${OSDF_IP} 8699
+
+echo "inspect docker things for tracing purpose"
+docker inspect optf-osdf
diff --git a/csit/scripts/setup-sms.sh b/csit/scripts/setup-sms.sh
new file mode 100755
index 0000000..180bd0a
--- /dev/null
+++ b/csit/scripts/setup-sms.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+#
+# Copyright 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Not sure why this is needed.
+source ${WORKSPACE}/scripts/common_functions.sh
+
+CONFIG_FILE=$(pwd)/config/smsconfig.json
+
+mkdir -p $(pwd)/config
+
+docker login -u docker -p docker nexus3.onap.org:10001
+docker pull nexus3.onap.org:10001/onap/aaf/sms:4.0.0
+docker pull docker.io/vault:1.3.3
+
+#
+# Running vault in dev server mode here for CSIT
+# In HELM it runs in production mode
+#
+docker run -e "VAULT_DEV_ROOT_TOKEN_ID=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" \
+ -e SKIP_SETCAP=true \
+ --name vault -d -p 8200:8200 vault:1.3.3
+
+SMSDB_IP=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' vault)
+cat << EOF > $CONFIG_FILE
+{
+ "cafile": "auth/selfsignedca.pem",
+ "servercert": "auth/server.cert",
+ "serverkey": "auth/server.key",
+
+ "smsdbaddress": "http://$SMSDB_IP:8200",
+ "vaulttoken": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
+ "disable_tls": true
+}
+EOF
+
+cat $CONFIG_FILE
+
+docker run --workdir /sms -v $CONFIG_FILE:/sms/smsconfig.json \
+ --name sms -d -p 10443:10443 --user root nexus3.onap.org:10001/onap/aaf/sms:4.0.0
+
+SMS_IP=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' sms)
+
+echo "###### WAITING FOR ALL CONTAINERS TO COME UP"
+sleep 20
+for i in {1..20}; do
+ curl -sS -m 1 http://${SMSDB_IP}:8200/v1/sys/seal-status && break
+ echo sleep $i
+ sleep $i
+done
+
+#
+# add here all ROBOT_VARIABLES settings
+#
+echo "# sms robot variables settings";
+ROBOT_VARIABLES="-v SMS_HOSTNAME:http://${SMS_IP} -v SMS_PORT:10443"
+
+echo ${ROBOT_VARIABLES}
diff --git a/csit/scripts/simulator_script.sh b/csit/scripts/simulator_script.sh
new file mode 100755
index 0000000..f6daab6
--- /dev/null
+++ b/csit/scripts/simulator_script.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+echo "### This is ${WORKSPACE}/scripts/simulator_script.sh"
+#
+# add here whatever commands is needed to prepare the optf/osdf CSIT testing
+#
+
+#echo "i am ${USER} : only non jenkins users may need proxy settings"
+if [ ${USER} != 'jenkins' ]; then
+
+ # add proxy settings into this script when you work behind a proxy
+ ${WORKSPACE}/scripts/osdf_proxy_settings.sh ${WORK_DIR}
+
+fi
+
+# prepare osdf_sim
+cd ${WORKSPACE}/../test/functest/simulators
+
+# check Dockerfile content
+cat ./Dockerfile
+
+# build osdf_sim
+chmod +x ./build_sim_image.sh
+./build_sim_image.sh
+
+# run osdf_sim
+docker run -d --name osdf_sim -p "5000:5000" osdf_sim:latest;
+
+#wait for docker setup a while
+sleep 10
+
+docker ps -a
+
+echo "logs of the osdf_sim"
+sudo cat `docker inspect -f '{{.LogPath}}' osdf_sim`
+
+
+OSDF_SIM_IP=`${WORKSPACE}/scripts/get-instance-ip.sh osdf_sim`
+echo "OSDF_SIM_IP=${OSDF_SIM_IP}"
+
+docker inspect osdf_sim
+
+${WORKSPACE}/scripts/wait_for_port.sh ${OSDF_SIM_IP} 5000
+
+
+# wait a while before continuing
+sleep 2
+
+echo "inspect docker things for tracing purpose"
+
diff --git a/csit/scripts/wait_for_port.sh b/csit/scripts/wait_for_port.sh
new file mode 100755
index 0000000..360fc21
--- /dev/null
+++ b/csit/scripts/wait_for_port.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+if [[ $# -ne 2 ]]; then
+ echo "Usage: wait-for-port hostname port" >&2
+ exit 1
+fi
+
+host=$1
+port=$2
+
+echo "Waiting for $host port $port open"
+until telnet $host $port </dev/null 2>/dev/null | grep -q '^Connected'; do
+ sleep 1
+done
+
+echo "$host port $port is open"
+
+exit 0
diff --git a/csit/tests/osdf/__init__.robot b/csit/tests/osdf/__init__.robot
new file mode 100644
index 0000000..fb654d7
--- /dev/null
+++ b/csit/tests/osdf/__init__.robot
@@ -0,0 +1,4 @@
+*** Settings ***
+Documentation Integration - Suite 1
+
+
diff --git a/csit/tests/osdf/data/pci-opt-request.json b/csit/tests/osdf/data/pci-opt-request.json
new file mode 100644
index 0000000..09a2f97
--- /dev/null
+++ b/csit/tests/osdf/data/pci-opt-request.json
@@ -0,0 +1,20 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestId": "yyy-yyy-yyyy",
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl/",
+ "sourceId": "SO",
+ "requestType": "create",
+ "numSolutions": 1,
+ "optimizers": [
+ "placement"
+ ],
+ "timeout": 600
+ },
+ "cellInfo": {
+ "networkId": "netw1000",
+ "cellIdList": [
+ "cell0"
+ ]
+ }
+} \ No newline at end of file
diff --git a/csit/tests/osdf/data/placement_request.json b/csit/tests/osdf/data/placement_request.json
new file mode 100644
index 0000000..d9b16ca
--- /dev/null
+++ b/csit/tests/osdf/data/placement_request.json
@@ -0,0 +1,102 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestId": "yyy-yyy-yyyy",
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl/",
+ "sourceId": "SO",
+ "requestType": "create",
+ "numSolutions": 1,
+ "optimizers": ["placement"],
+ "timeout": 600
+ },
+ "placementInfo": {
+ "requestParameters": { "customerLatitude": 32.89748, "customerLongitude": -97.040443, "customerName": "xyz" },
+ "subscriberInfo": {"globalSubscriberId": "xxx-xx-xxx", "subscriberName": "subscriber_x"},
+ "placementDemands": [
+ {
+ "resourceModuleName": "vGMuxInfra",
+ "serviceResourceId": "vGMuxInfra-xx",
+ "tenantId": "vGMuxInfra-tenant",
+ "resourceModelInfo": {
+ "modelInvariantId": "vGMuxInfra-modelInvariantId",
+ "modelVersionId": "vGMuxInfra-versionId",
+ "modelName": "vGMuxInfra-model",
+ "modelType": "resource",
+ "modelVersion": "1.0",
+ "modelCustomizationName": "vGMuxInfra-customeModelName"
+ }
+ },
+ {
+ "resourceModuleName": "vG",
+ "serviceResourceId": "71d563e8-e714-4393-8f99-cc480144a05e",
+ "tenantId": "vG-tenant",
+ "resourceModelInfo": {
+ "modelInvariantId": "vG-modelInvariantId",
+ "modelVersionId": "vG-versionId",
+ "modelName": "vG-model",
+ "modelType": "resource",
+ "modelVersion": "1.0",
+ "modelCustomizationName": "vG-customeModelName"
+ },
+ "existingCandidates": [
+ {
+ "identifierType": "serviceInstanceId",
+ "cloudOwner": "",
+ "identifiers": ["gjhd-098-fhd-987"]
+ }
+ ],
+ "excludedCandidates": [
+ {
+ "identifierType": "serviceInstanceId",
+ "cloudOwner": "",
+ "identifiers": ["gjhd-098-fhd-987"]
+ },
+ {
+ "identifierType": "vimId",
+ "cloudOwner": "vmware",
+ "identifiers": ["NYMDT67"]
+ }
+ ],
+ "requiredCandidates": [
+ {
+ "identifierType": "vimId",
+ "cloudOwner": "amazon",
+ "identifiers": ["TXAUS219"]
+ }
+ ]
+ }
+ ]
+ },
+ "serviceInfo": {
+ "serviceInstanceId": "d61b2543-5914-4b8f-8e81-81e38575b8ec",
+ "serviceName": "vCPE",
+ "modelInfo": {
+ "modelInvariantId": "vCPE-invariantId",
+ "modelVersionId": "vCPE-versionId",
+ "modelName": "vCPE-model",
+ "modelType": "service",
+ "modelVersion": "1.0",
+ "modelCustomizationName": "vCPE-customeModelName"
+ }
+ },
+ "licenseInfo": {
+ "licenseDemands": [
+ {
+ "resourceModuleName": "vGMuxInfra",
+ "serviceResourceId": "vGMuxInfra-xx",
+ "resourceModelInfo": {
+ "modelInvariantId": "vGMuxInfra-modelInvariantId",
+ "modelVersionId": "vGMuxInfra-versionId",
+ "modelName": "vGMuxInfra-model",
+ "modelType": "resource",
+ "modelVersion": "1.0",
+ "modelCustomizationName": "vGMuxInfra-customeModelName"
+ },
+ "existingLicenses": {
+ "entitlementPoolUUID": ["87257b49-9602-4ca1-9817-094e52bc873b", "43257b49-9602-4fe5-9337-094e52bc9435"],
+ "licenseKeyGroupUUID": ["87257b49-9602-4ca1-9817-094e52bc873b", "43257b49-9602-4fe5-9337-094e52bc9435"]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/csit/tests/osdf/data/termination_request.json b/csit/tests/osdf/data/termination_request.json
new file mode 100644
index 0000000..b219645
--- /dev/null
+++ b/csit/tests/osdf/data/termination_request.json
@@ -0,0 +1,14 @@
+{
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5,
+ "addtnlArgs": {}
+ },
+ "type":"NSI",
+ "NxIId":"9629e36c-a3d9-4aed-8368-f72b8be1cd34",
+ "UUID":"9629e36c-a3d9-4aed-8368-f72b8be1cd34",
+ "invariantUUID":"9629e36c-a3d9-4aed-8368-f72b8be1cd34"
+} \ No newline at end of file
diff --git a/csit/tests/osdf/optf_osdf_nxi_termination.robot b/csit/tests/osdf/optf_osdf_nxi_termination.robot
new file mode 100644
index 0000000..881d4cd
--- /dev/null
+++ b/csit/tests/osdf/optf_osdf_nxi_termination.robot
@@ -0,0 +1,69 @@
+*** Settings ***
+Library copy
+Library json
+Library Collections
+Library OperatingSystem
+Resource ./resources/common-keywords.robot
+
+Suite Teardown Delete All Sessions
+
+*** Variables ***
+&{placement_auth} = username=test password=testpwd
+
+*** Keywords ***
+
+NxiTerminationRequest
+ [Documentation] Sends request to NxiTermination API
+ [Arguments] ${data}
+ ${data_str}= json.dumps ${data}
+ ${resp}= Http Post host=${osdf_host} restUrl=/api/oof/terminate/nxi/v1 data=${data_str} auth=${placement_auth}
+ ${response_json} json.loads ${resp.content}
+ Should Be Equal As Integers ${resp.status_code} 200
+ [Return] ${response_json}
+
+*** Test Cases ***
+
+TerminationRequestGeneration
+ [Documentation] This test case will generate request json for different scenarios
+ ${data}= Get Binary File ${CURDIR}${/}data${/}termination_request.json
+ ${nsi_termination_request}= json.loads ${data}
+ Set Global Variable ${nsi_termination_request}
+ ${nssi_termination_request}= copy.deepcopy ${nsi_termination_request}
+ Set To Dictionary ${nssi_termination_request} type=NSSI
+ Set Global Variable ${nssi_termination_request}
+ ${nsi_termination_request_args}= copy.deepcopy ${nsi_termination_request}
+ ${request_info}= Set Variable ${nsi_termination_request_args["requestInfo"]}
+ ${addtnl_args}= Create Dictionary serviceInstanceId=660ca85c-1a0f-4521-a559-65f23e794699
+ Set To Dictionary ${request_info} addtnlArgs=${addtnl_args}
+ Set To Dictionary ${nsi_termination_request_args} requestInfo=${request_info}
+ Set Global Variable ${nsi_termination_request_args}
+ ${nssi_termination_request_args}= copy.deepcopy ${nssi_termination_request}
+ ${request_info}= Set Variable ${nssi_termination_request_args["requestInfo"]}
+ ${addtnl_args}= Create Dictionary serviceInstanceId=660ca85c-1a0f-4521-a559-65f23e794699
+ Set To Dictionary ${request_info} addtnlArgs=${addtnl_args}
+ Set To Dictionary ${nssi_termination_request_args} requestInfo=${request_info}
+ Set Global Variable ${nssi_termination_request_args}
+
+NSITermination
+ [Documentation] It sends a NSI termination request with no additional arguments
+ ${response_json}= NxiTerminationRequest ${nsi_termination_request}
+ Should Be Equal success ${response_json['requestStatus']}
+ Should Be True ${response_json['terminateResponse']}
+
+NSSITermination
+ [Documentation] It sends a NSSI termination request with no additional arguments
+ ${response_json}= NxiTerminationRequest ${nssi_termination_request}
+ Should Be Equal success ${response_json['requestStatus']}
+ Should Be True ${response_json['terminateResponse']}
+
+NSITerminationWithAddtnlArgs
+ [Documentation] It sends a NSSI termination request with additional arguments
+ ${response_json}= NxiTerminationRequest ${nsi_termination_request_args}
+ Should Be Equal success ${response_json['requestStatus']}
+ Should Be True ${response_json['terminateResponse']}
+
+NSSITerminationWithAddtnlArgs
+ [Documentation] It sends a NSSI termination request with additional arguments
+ ${response_json}= NxiTerminationRequest ${nssi_termination_request_args}
+ Should Be Equal success ${response_json['requestStatus']}
+ Should Be True ${response_json['terminateResponse']}
diff --git a/csit/tests/osdf/optf_osdf_setup.robot b/csit/tests/osdf/optf_osdf_setup.robot
new file mode 100644
index 0000000..ae3c271
--- /dev/null
+++ b/csit/tests/osdf/optf_osdf_setup.robot
@@ -0,0 +1,12 @@
+*** Settings ***
+Documentation Suite description
+Resource ./resources/common-keywords.robot
+
+*** Test Cases ***
+Check OSDF_SIM Docker Container
+ [Documentation] It checks osdf_simulator docker container is running
+ Verify Docker RC Status osdf_sim
+
+Check OSDF Docker Container
+ [Documentation] It checks optf-osdf docker container is running
+ Verify Docker RC Status optf-osdf
diff --git a/csit/tests/osdf/optf_osdf_test.robot b/csit/tests/osdf/optf_osdf_test.robot
new file mode 100644
index 0000000..292df64
--- /dev/null
+++ b/csit/tests/osdf/optf_osdf_test.robot
@@ -0,0 +1,42 @@
+*** Settings ***
+Library json
+Library OperatingSystem
+Resource ./resources/common-keywords.robot
+
+Suite Teardown Delete All Sessions
+
+*** Variables ***
+&{placement_auth} = username=test password=testpwd
+&{wrong_authorization} = username=test password=test
+&{pci_auth}= username=pci_test password=pci_testpwd
+
+*** Test Cases ***
+Healthcheck
+ [Documentation] It sends a REST GET request to healthcheck url
+ ${resp}= Http Get ${osdf_host} /api/oof/v1/healthcheck
+ Should Be Equal As Integers ${resp.status_code} 200
+
+SendPlacementWithInvalidAuth
+ [Documentation] It sends a POST request to osdf fail authentication
+ ${data}= Get Binary File ${CURDIR}${/}data${/}placement_request.json
+ ${resp}= Http Post host=${osdf_host} restUrl=/api/oof/v1/placement data=${data} auth=${wrong_authorization}
+ ${response_json} json.loads ${resp.content}
+ Should Be Equal Unauthorized, check username and password ${response_json['serviceException']['text']}
+ Should Be Equal As Integers ${resp.status_code} 401
+
+SendPlacementWithValidAuth
+ [Documentation] It sends a POST request to osdf with correct authentication
+ ${data}= Get Binary File ${CURDIR}${/}data${/}placement_request.json
+ ${resp}= Http Post host=${osdf_host} restUrl=/api/oof/v1/placement data=${data} auth=${placement_auth}
+ ${response_json} json.loads ${resp.content}
+ Should Be Equal As Integers ${resp.status_code} 202
+ Should Be Equal accepted ${response_json['requestStatus']}
+
+SendPCIOptimizationWithAuth
+ [Documentation] It sends a POST request PCI Optimization service
+
+ ${data}= Get Binary File ${CURDIR}${/}data${/}pci-opt-request.json
+ ${resp}= Http Post host=${osdf_host} restUrl=/api/oof/v1/pci data=${data} auth=${pci_auth}
+ ${response_json} json.loads ${resp.content}
+ Should Be Equal As Integers ${resp.status_code} 202
+ Should Be Equal accepted ${response_json['requestStatus']}
diff --git a/csit/tests/osdf/resources/common-keywords.robot b/csit/tests/osdf/resources/common-keywords.robot
new file mode 100644
index 0000000..114c8a0
--- /dev/null
+++ b/csit/tests/osdf/resources/common-keywords.robot
@@ -0,0 +1,51 @@
+*** Settings ***
+Documentation Suite description
+Library OperatingSystem
+Library RequestsLibrary
+Library json
+Library RequestsLibrary
+*** Variables ***
+&{headers}= Content-Type=application/json Accept=application/json
+${osdf_host} ${OSDF_HOSTNAME}:${OSDF_PORT}
+*** Keywords ***
+Verify Docker RC Status
+ [Documentation] Method to verify whether docker instance is up and running
+ [Arguments] ${process_name}
+ ${rc} ${output}= Run and Return RC and Output docker ps
+ Log To Console *********************
+ Log To Console retrurn_code = ${rc}
+ Log To Console output = ${output}
+ Should Be Equal As Integers ${rc} 0
+ Should Contain ${output} ${process_name}
+
+Http Get
+ [Documentation] Wrapper for Http GET
+ [Arguments] ${host} ${restUrl}
+ Create Session optf-osdf ${host}
+ ${resp}= Get Request optf-osdf ${restUrl}
+ Log To Console *********************
+ Log To Console response = ${resp}
+ Log To Console body = ${resp.text}
+ [Return] ${resp}
+
+Http Post
+ [Documentation] Wrapper for Http POST
+ [Arguments] ${host} ${restUrl} ${auth} ${data}
+ ${pci_auth}= Create List ${auth['username']} ${auth['password']}
+ Create Session optf-osdf ${host} headers=${headers} auth=${pci_auth}
+ ${resp}= Post Request optf-osdf ${restUrl} data=${data} headers=${headers}
+ Log To Console *********************
+ Log To Console response = ${resp}
+ Log To Console body = ${resp.text}
+ [Return] ${resp}
+
+Http Put
+ [Documentation] Wrapper for Http PUT
+ [Arguments] ${host} ${restUrl} ${auth} ${data}
+ ${pci_auth}= Create List ${auth['username']} ${auth['password']}
+ Create Session optf-osdf ${host} headers=${headers} auth=${pci_auth}
+ ${resp}= Put Request optf-osdf ${restUrl} data=${data} headers=${headers}
+ Log To Console *********************
+ Log To Console response = ${resp}
+ Log To Console body = ${resp.text}
+ [Return] ${resp}
diff --git a/docker/Dockerfile b/docker/Dockerfile
deleted file mode 100644
index 5a2c460..0000000
--- a/docker/Dockerfile
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-FROM ubuntu:16.04
-
-ARG MVN_ARTIFACT_VERSION
-ARG REPO
-ARG HTTP_PROXY=${HTTP_PROXY}
-ARG HTTPS_PROXY=${HTTPS_PROXY}
-
-ENV http_proxy $HTTP_PROXY
-ENV https_proxy $HTTPS_PROXY
-
-ENV OSDF_PORT "8699"
-EXPOSE ${OSDF_PORT}
-
-ENV MZN 2.1.6
-ENV MZN_BASENAME MiniZincIDE-${MZN}-bundle-linux-x86_64
-ENV MZN_GH_BASE https://github.com/MiniZinc/MiniZincIDE
-ENV MZN_DL_URL ${MZN_GH_BASE}/releases/download/${MZN}/${MZN_BASENAME}.tgz
-
-RUN apt-get update -y \
- && apt-get install -y vim unzip wget libmpfr-dev \
- && apt-get install -y git libqt5printsupport5 build-essential \
- && apt-get install -y python3 python3-setuptools python3-dev \
- && easy_install3 pip \
- && pip install --upgrade virtualenv pip wheel
-
-RUN ln -s /usr/bin/python3.5 /usr/bin/python
-
-# Minizinc
-RUN wget -q $MZN_DL_URL -O mz.tgz \
- && tar xzf mz.tgz \
- && mv $MZN_BASENAME /mz-dist \
- && rm mz.tgz \
- && echo PATH=/mz-dist:$PATH >> ~/.bashrc
-
-ENV SHELL /bin/bash
-ENV PATH /mz-dist:$PATH
-
-# OSDF
-WORKDIR /opt/osdf
-RUN wget -O /opt/osdf.zip "https://nexus.onap.org/service/local/artifact/maven/redirect?r=${REPO}&g=org.onap.optf.osdf&a=optf-osdf&e=zip&v=${MVN_ARTIFACT_VERSION}" && \
- unzip -q -o -B /opt/osdf.zip -d /opt/ && \
- rm -f /opt/osdf.zip
-RUN mkdir -p /var/log/onap/optf/osdf/
-RUN pip install --no-cache-dir -r requirements.txt
-
-CMD [ "/opt/osdf/osdfapp.sh" ]
diff --git a/docker/opteng/Dockerfile b/docker/opteng/Dockerfile
new file mode 100644
index 0000000..037771a
--- /dev/null
+++ b/docker/opteng/Dockerfile
@@ -0,0 +1,42 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+FROM osdf-base:latest
+
+EXPOSE 8699
+
+# OSDF
+WORKDIR /opt/osdf
+
+COPY onap-osdf-tm/requirements-opteng.txt /tmp/requirements-opteng.txt
+
+RUN pip install --no-cache-dir -r /tmp/requirements-opteng.txt
+
+COPY onap-osdf-tm/ /opt/osdf
+
+RUN mkdir -p /var/log/onap/optf/osdf/ \
+ && chown onap:onap /var/log/onap -R \
+ && chown onap:onap /opt/osdf -R
+
+USER onap
+
+ENV OSDF_CONFIG_FILE "/opt/osdf/config/opteng_config.yaml"
+
+CMD [ "python", "solverapp.py" ]
diff --git a/docker/opteng/assembly/osdf-files.xml b/docker/opteng/assembly/osdf-files.xml
new file mode 100644
index 0000000..03a6c45
--- /dev/null
+++ b/docker/opteng/assembly/osdf-files.xml
@@ -0,0 +1,58 @@
+<!--
+ 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.
+
+-->
+<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>osdf-files</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+
+ <fileSets>
+ <fileSet>
+ <includes>
+ <include>${project.build.finalName}.zip</include>
+ </includes>
+ <directory>${project.build.directory}</directory>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <includes>
+ <include>runtime/**</include>
+ <include>osdf/**</include>
+ <include>config/**</include>
+ <include>setup.py</include>
+ <include>solverapp.py</include>
+ </includes>
+ <excludes>
+ <exclude>**/*.pyc</exclude>
+ <exclude>**/__pycache__/**</exclude>
+ </excludes>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <includes>
+ <include>requirements-opteng.txt</include>
+ </includes>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/docker/osdf-lib-base/Dockerfile b/docker/osdf-lib-base/Dockerfile
new file mode 100644
index 0000000..e8de5ab
--- /dev/null
+++ b/docker/osdf-lib-base/Dockerfile
@@ -0,0 +1,49 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+FROM python:3.9-slim-buster
+
+ARG HTTP_PROXY=${HTTP_PROXY}
+ARG HTTPS_PROXY=${HTTPS_PROXY}
+ARG DEBIAN_FRONTEND=noninteractive
+
+ENV http_proxy $HTTP_PROXY
+ENV https_proxy $HTTPS_PROXY
+
+RUN groupadd onap \
+ && useradd -m -g onap onap
+
+# Minizinc
+RUN apt-get update \
+ && apt-get install -y wget \
+ && wget -q https://github.com/MiniZinc/MiniZincIDE/releases/download/2.4.3/MiniZincIDE-2.4.3-bundle-linux-x86_64.tgz -O /tmp/mz.tgz \
+ && mkdir -p /mz-dist && tar xzf /tmp/mz.tgz -C /mz-dist --strip-components 1\
+ && rm /tmp/mz.tgz \
+ && wget -q https://github.com/google/or-tools/releases/download/v7.8/or-tools_ubuntu-20.04_v7.8.7959.tar.gz -O /tmp/flatzinc.tar.gz \
+ && mkdir -p /ortools \
+ && tar zxf /tmp/flatzinc.tar.gz -C /ortools --strip-components 1 \
+ && rm /tmp/flatzinc.tar.gz \
+ && apt-get remove -y wget
+
+ENV SHELL /bin/bash
+ENV PATH /mz-dist/bin:$PATH
+
+COPY onap-osdf-tm/requirements.txt /tmp/requirements.txt
+
+RUN pip install --no-cache-dir -r /tmp/requirements.txt
diff --git a/docker/osdf-lib-base/assembly/osdf-lib-files.xml b/docker/osdf-lib-base/assembly/osdf-lib-files.xml
new file mode 100644
index 0000000..d3cb5dd
--- /dev/null
+++ b/docker/osdf-lib-base/assembly/osdf-lib-files.xml
@@ -0,0 +1,43 @@
+<!--
+ Copyright (C) 2021 Wipro Limited.
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ License for the specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<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>osdf-lib-files</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+
+ <fileSets>
+ <fileSet>
+ <includes>
+ <include>requirements.txt</include>
+ </includes>
+ <excludes>
+ <exclude>**/*.pyc</exclude>
+ <exclude>**/__pycache__/**</exclude>
+ </excludes>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+
+ </fileSets>
+</assembly>
diff --git a/docker/osdf/Dockerfile b/docker/osdf/Dockerfile
new file mode 100644
index 0000000..d1fd2c4
--- /dev/null
+++ b/docker/osdf/Dockerfile
@@ -0,0 +1,40 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+# Copyright (C) 2021 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+FROM osdf-base:latest
+
+EXPOSE 8699
+
+# OSDF
+WORKDIR /opt/osdf
+
+COPY onap-osdf-tm/requirements-osdf.txt /tmp/requirements-osdf.txt
+
+RUN pip install --no-cache-dir -r /tmp/requirements-osdf.txt
+
+COPY onap-osdf-tm /opt/osdf
+
+RUN mkdir -p /var/log/onap/optf/osdf/ \
+ && chown -R onap:onap /var/log/onap \
+ && chown -R onap:onap /opt/osdf
+
+USER onap
+
+CMD [ "python", "osdfapp.py" ]
diff --git a/docker/osdf/assembly/osdf-files.xml b/docker/osdf/assembly/osdf-files.xml
new file mode 100644
index 0000000..1b7c349
--- /dev/null
+++ b/docker/osdf/assembly/osdf-files.xml
@@ -0,0 +1,65 @@
+<!--
+ 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.
+
+-->
+
+<!--
+ Copyright (c) 2018 Intel Corporation. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ License for the specific language governing permissions and limitations
+ under the License.
+-->
+
+<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>osdf-files</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+
+ <fileSets>
+ <fileSet>
+ <includes>
+ <include>apps/**</include>
+ <include>osdf/**</include>
+ <include>config/**</include>
+ <include>setup.py</include>
+ <include>osdfapp.py</include>
+ <include>requirements.txt</include>
+ <include>requirements-osdf.txt</include>
+ </includes>
+ <excludes>
+ <exclude>**/*.pyc</exclude>
+ <exclude>**/__pycache__/**</exclude>
+ </excludes>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+
+ </fileSets>
+</assembly>
diff --git a/docker/build_image.sh b/docker/osdf/build_image.sh
index 3d9d823..3d9d823 100755
--- a/docker/build_image.sh
+++ b/docker/osdf/build_image.sh
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..43ca5b6
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,3 @@
+/.tox
+/_build/*
+/__pycache__/*
diff --git a/docs/_static/css/ribbon.css b/docs/_static/css/ribbon.css
new file mode 100644
index 0000000..db927a4
--- /dev/null
+++ b/docs/_static/css/ribbon.css
@@ -0,0 +1,64 @@
+.ribbon {
+ z-index: 1000;
+ background-color: #a00;
+ overflow: hidden;
+ white-space: nowrap;
+ position: fixed;
+ top: 25px;
+ right: -50px;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+ -webkit-box-shadow: 0 0 10px #888;
+ -moz-box-shadow: 0 0 10px #888;
+ box-shadow: 0 0 10px #888;
+
+ }
+
+ .ribbon a {
+ border: 1px solid #faa;
+ color: #fff;
+ display: block;
+ font: bold 81.25% 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ margin: 1px 0;
+ padding: 10px 50px;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: 0 0 5px #444;
+ transition: 0.5s;
+ }
+
+ .ribbon a:hover {
+ background: #c11;
+ color: #fff;
+ }
+
+
+ /* override table width restrictions */
+ @media screen and (min-width: 767px) {
+
+ .wy-table-responsive table td, .wy-table-responsive table th {
+ /* !important prevents the common CSS stylesheets from overriding
+ this as on RTD they are loaded after this stylesheet */
+ white-space: normal !important;
+ }
+
+ .wy-table-responsive {
+ overflow: visible !important;
+ }
+ }
+
+ @media screen and (max-width: 767px) {
+ .wy-table-responsive table td {
+ white-space: nowrap;
+ }
+ }
+
+ /* fix width of the screen */
+
+ .wy-nav-content {
+ max-width: 800px;
+ }
+ \ No newline at end of file
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100755
index 0000000..cb712eb
--- /dev/null
+++ b/docs/_static/favicon.ico
Binary files differ
diff --git a/docs/_static/logo_onap_2017.png b/docs/_static/logo_onap_2017.png
new file mode 100644
index 0000000..5d064f4
--- /dev/null
+++ b/docs/_static/logo_onap_2017.png
Binary files differ
diff --git a/docs/api/swagger/oof-optf-opteng-api.json b/docs/api/swagger/oof-optf-opteng-api.json
new file mode 100644
index 0000000..4e77f76
--- /dev/null
+++ b/docs/api/swagger/oof-optf-opteng-api.json
@@ -0,0 +1,584 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "description": "This is the ONAP Optimization Engine (Generic Solver) API",
+ "version": "1.0.0",
+ "title": "ONAP Optimization ENGINE API",
+ "contact": {
+ "email": "vikas.varma@att.com"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ },
+ "securityDefinitions": {
+ "basicAuth": {
+ "type": "basic",
+ "description": "HTTP Basic Auth"
+ }
+ },
+ "security": [
+ {
+ "basicAuth": []
+ }
+ ],
+ "paths": {
+ "/optengine/v1": {
+ "post": {
+ "tags": [
+ "Generic Solver Optimization"
+ ],
+ "summary": "Call the Generic Optimization engine",
+ "operationId": "optimizationRequest",
+ "description": "call optimization engine",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "optimizationRequest",
+ "description": "optimization request",
+ "schema": {
+ "$ref": "#/definitions/OptimizationRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/OptimizationResponse"
+ }
+ },
+ "202": {
+ "description": "An optimization request is accepted"
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/optmodel/v1": {
+ "post": {
+ "tags": [
+ "Request to add the Optimizer model, metadata"
+ ],
+ "summary": "Add/Insert the optimization models in the database",
+ "operationId": "optimModelRequestAPI",
+ "description": "Request to add update the Optimizer model, metadata",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "optimModelRequest",
+ "description": "optimization model request",
+ "schema": {
+ "$ref": "#/definitions/OptimModelRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/OptimModelResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ },
+ "put": {
+ "tags": [
+ "Request to update the Optimizer model, metadata"
+ ],
+ "summary": "Add/update the optimization models in the database",
+ "operationId": "updateModelRequestAPI",
+ "description": "Request to add update the Optimizer model, metadata",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "optimModelRequest",
+ "description": "optimization model request",
+ "schema": {
+ "$ref": "#/definitions/OptimModelRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/OptimModelResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ },
+ "get": {
+ "tags": [
+ "Retrieve all models"
+ ],
+ "summary": "Gets all Optim Model data",
+ "description": "Retrieves all Optim Models",
+ "operationId": "getAllOptModelData",
+ "produces": [
+ "application/json"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/ArrayOfOptimModelResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/optmodel/v1/{model_id}": {
+ "get": {
+ "tags": [
+ "Retrieve Model Data"
+ ],
+ "summary": "Gets the Optim Model data",
+ "description": "Retrieves the Optim Model data given modelId",
+ "operationId": "getOptModelById",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "model_id",
+ "description": "Model ID",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/OptimModelResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Delete Model Data"
+ ],
+ "summary": "Delete the Optim Model data",
+ "description": "Deletes the Optim Model data given modelId",
+ "operationId": "deleteOptModelById",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "model_id",
+ "description": "Model ID",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/DeleteModelResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "OptimizationResponse": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestID",
+ "requestStatus"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestStatus": {
+ "type": "string",
+ "description": "request status (accepted, done, completed,failed)",
+ "example": "done"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Status message (incomplete, complete, unsatisfiable, unknown, unbounded, unsat_or_unbounded, error)",
+ "example": "complete"
+ },
+ "solutions": {
+ "additionalProperties": {
+ "type": "object"
+ },
+ "example": {
+ "SCHEDULED": [
+ [
+ 0,
+ 1
+ ],
+ [
+ 0,
+ 1
+ ]
+ ],
+ "OPTIMIZED": 2
+ }
+ }
+ }
+ },
+ "OptimizationRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "optimInfo"
+ ],
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo"
+ },
+ "optimInfo": {
+ "$ref": "#/definitions/OptimInfo"
+ }
+ }
+ },
+ "RequestInfo": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestID",
+ "sourceId"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "url",
+ "description": "The end point of a callback service where recommendations are posted.",
+ "example": "myDomain.com/myCallback"
+ },
+ "sourceId": {
+ "type": "string",
+ "description": "The unique ID of a client making an optimization call.",
+ "example": "son-handler"
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "A tolerance window (in second) for expecting solutions",
+ "example": 5
+ }
+ }
+ },
+ "OptimInfo": {
+ "type": "object",
+ "properties": {
+ "modelId": {
+ "type": "string",
+ "description": "ModelId from the database, if its not populated, assume that solverModel will be populated",
+ "example": "pci_model1"
+ },
+ "solver": {
+ "type": "string",
+ "description": "type of solver (mzn, py, etc.)",
+ "example": "mzn"
+ },
+ "solverArgs": {
+ "type": "object",
+ "description": "Arguments for solver",
+ "additionalProperties": {
+ "type": "object"
+ },
+ "example": {
+ "solver": "cbc",
+ "timeout": 5
+ }
+ },
+ "modelContent": {
+ "type": "string",
+ "description": "a large blob string containing the model (which is not that problematic since models are fairly small)."
+ },
+ "optData": {
+ "$ref": "#/definitions/DataInfo"
+ }
+ }
+ },
+ "DataInfo": {
+ "type": "object",
+ "description": "Data Payload, input data for the solver, either text or json",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "Solver data as a string",
+ "example": "flour = 8000; \r\nbanana = 11;\r\n "
+ },
+ "json": {
+ "type": "object",
+ "description": "Solver data as a json",
+ "additionalProperties": {
+ "type": "object"
+ },
+ "example": {
+ "flour": 8000,
+ "banana": 11
+ }
+ }
+ }
+ },
+ "OptimModelRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "modelInfo"
+ ],
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/ModelRequestInfo"
+ },
+ "modelInfo": {
+ "$ref": "#/definitions/OptimModelInfo"
+ }
+ }
+ },
+ "ModelRequestInfo": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestID",
+ "sourceId"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "sourceId": {
+ "type": "string",
+ "description": "The unique ID of a client making an optimization call.",
+ "example": "optf-osdf"
+ }
+ }
+ },
+ "OptimModelInfo": {
+ "type": "object",
+ "required": [
+ "modelId",
+ "solver",
+ "description",
+ "modelContent"
+ ],
+ "properties": {
+ "modelId": {
+ "type": "string",
+ "description": "ModelId from the database",
+ "example": "pci_anr_model1"
+ },
+ "solver": {
+ "type": "string",
+ "description": "type of solver (mzn, py, etc.)",
+ "example": "mzn"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description of the model",
+ "example": "mzn model to optimize pci/anr models"
+ },
+ "modelContent": {
+ "type": "string",
+ "description": "a large blob string containing the model (which is not that problematic since models are fairly small).",
+ "example": "mzn content"
+ }
+ }
+ },
+ "ArrayOfOptimModelResponse": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/OptimModelResponse"
+ }
+ },
+ "OptimModelResponse": {
+ "type": "object",
+ "required": [
+ "modelId",
+ "solver",
+ "modelContent"
+ ],
+ "properties": {
+ "modelId": {
+ "type": "string",
+ "description": "ModelId from the database",
+ "example": "pci_anr_model1"
+ },
+ "solver": {
+ "type": "string",
+ "description": "type of solver (mzn, py, etc.)",
+ "example": "mzn"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description of the model",
+ "example": "mzn model to optimize pci/anr models"
+ },
+ "modelContent": {
+ "type": "string",
+ "description": "a large blob string containing the model (which is not that problematic since models are fairly small).",
+ "example": "mzn content"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "status message.",
+ "example": "mzn content"
+ }
+ }
+ },
+ "DeleteModelResponse": {
+ "type": "object",
+ "required": [
+ "statusMessage"
+ ],
+ "properties": {
+ "statusMessage": {
+ "type": "string",
+ "description": "status message.",
+ "example": "model data for modelId pci_anr_model1 deleted"
+ }
+ }
+ }
+ },
+ "schemes": [
+ "https"
+ ],
+ "host": "virtserver.swaggerhub.com",
+ "basePath": "/api/oof/"
+}
diff --git a/docs/api/swagger/oof-osdf-has-api.json b/docs/api/swagger/oof-osdf-has-api.json
new file mode 100644
index 0000000..a2fa43f
--- /dev/null
+++ b/docs/api/swagger/oof-osdf-has-api.json
@@ -0,0 +1,2155 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "description": "This is the ONAP OOF OSDF (Optimization Service Design Framework) API",
+ "version": "1.0.0",
+ "title": "OSDF API",
+ "contact": {
+ "email": "frank.sandoval@oamtechnologies.com"
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ }
+ },
+ "securityDefinitions": {
+ "basicAuth": {
+ "type": "basic",
+ "description": "HTTP Basic Auth"
+ }
+ },
+ "security": [
+ {
+ "basicAuth": []
+ }
+ ],
+ "paths": {
+ "/v2/placement": {
+ "post": {
+ "tags": [
+ "Placement Optimization"
+ ],
+ "summary": "create/update a placement",
+ "operationId": "createPlacement",
+ "description": "create/update a placement",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "placementRequest",
+ "description": "placement request",
+ "schema": {
+ "$ref": "#/definitions/PlacementRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "An optimization solution is found."
+ },
+ "202": {
+ "description": "An optimization request is accepted"
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/placement/v1": {
+ "post": {
+ "tags": [
+ "Placement Optimization"
+ ],
+ "summary": "create/update a placement",
+ "operationId": "createPlacementv1",
+ "description": "create/update a placement",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "placementRequest",
+ "description": "placement request",
+ "schema": {
+ "$ref": "#/definitions/PlacementRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "An optimization solution is found."
+ },
+ "202": {
+ "description": "An optimization request is accepted"
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/v1/pci": {
+ "post": {
+ "tags": [
+ "PCI/ANR Optimization"
+ ],
+ "summary": "Initiate PCI/ANR Optimization",
+ "operationId": "initiatePCIOptRequest",
+ "description": "Initiate PCI/ANR Optimization",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "PCIOptimizationRequest",
+ "description": "PCI request",
+ "schema": {
+ "$ref": "#/definitions/PCIOptRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "An optimization solution is found."
+ },
+ "202": {
+ "description": "An optimization request is accepted"
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/pci/v1": {
+ "post": {
+ "tags": [
+ "PCI/ANR Optimization"
+ ],
+ "summary": "Initiate PCI/ANR Optimization",
+ "operationId": "initiatePCIOptRequestv1",
+ "description": "Initiate PCI/ANR Optimization",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "PCIOptimizationRequest",
+ "description": "PCI request",
+ "schema": {
+ "$ref": "#/definitions/PCIOptRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "An optimization solution is found."
+ },
+ "202": {
+ "description": "An optimization request is accepted"
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/selection/nst/v1": {
+ "post": {
+ "tags": [
+ "NST Selection"
+ ],
+ "summary": "NST selection",
+ "operationId": "selectNstRequest",
+ "description": "Request for NST selection",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "NSTSelectionRequest",
+ "description": "nst selection request",
+ "schema": {
+ "$ref": "#/definitions/NSTSelectionRequest"
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "An optimization request is accepted",
+ "schema": {
+ "$ref": "#/definitions/SynchronousResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/selection/nsi/v1": {
+ "post": {
+ "tags": [
+ "NSI Selection"
+ ],
+ "summary": "NSI selection",
+ "operationId": "selectNsiRequest",
+ "description": "Request for NSI selection",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "NSISelectionRequest",
+ "description": "NSI selection request",
+ "schema": {
+ "$ref": "#/definitions/NSISelectionRequest"
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "An optimization request is accepted",
+ "schema": {
+ "$ref": "#/definitions/SynchronousResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/selection/nssi/v1": {
+ "post": {
+ "tags": [
+ "NSSI Selection"
+ ],
+ "summary": "NSSI selection",
+ "operationId": "selectNssiRequest",
+ "description": "Request for NSSI selection",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "NSSISelectionRequest",
+ "description": "NSSI selection request",
+ "schema": {
+ "$ref": "#/definitions/NSSISelectionRequest"
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "An optimization request is accepted",
+ "schema": {
+ "$ref": "#/definitions/SynchronousResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/terminate/nxi/v1": {
+ "post": {
+ "tags": [
+ "NSSI/NSI Termination"
+ ],
+ "summary": "NSSI/NSI Termination",
+ "operationId": "terminateNxiRequest",
+ "description": "Request for NSSI/NSI Termination",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "NxITerminationRequest",
+ "description": "NSSI/NSI termination request",
+ "schema": {
+ "$ref": "#/definitions/NxITerminationRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "request has succeeded",
+ "schema": {
+ "$ref": "#/definitions/SynchronousTerminationResponse"
+ }
+ },
+ "400": {
+ "description": "bad request"
+ },
+ "401": {
+ "description": "Request body is not compliant with the API definition"
+ },
+ "404": {
+ "description": "The server cannot find the requested URI"
+ },
+ "405": {
+ "description": "The requested method is not supported by a server."
+ },
+ "500": {
+ "description": "The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ },
+ "/api/oof/route/v1": {
+ "post": {
+ "tags": [
+ "Route Select"
+ ],
+ "summary": "Find the optimistic route between OTN domains",
+ "description": "",
+ "operationId": "getRoute",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "body",
+ "description": "Source and Destination nodes across which optmistic route have to be obtained.",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/RouteRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/routeResponseBody"
+ }
+ }
+ },
+ "405": {
+ "description": "Invalid input"
+ }
+ }
+ }
+ },
+ "/api/oof/mdons/route/v1": {
+ "post": {
+ "tags": [
+ "Inter Domain Route Select"
+ ],
+ "summary":"Find the optimistic inter domain route for multi domain optical system",
+ "description":"",
+ "operationId":"getInterDomainRoute",
+ "consumes": [
+ "application/json"
+ ],
+ "produces":[
+ "application/json"
+ ],
+ "parameters":[
+ {
+ "in":"body",
+ "name":"body",
+ "description":"Source and Destination interfaces across which optmistic route have to be obtained.",
+ "required":true,
+ "schema":{
+ "$ref":"#/definitions/InterDomainRouteRequest"
+ }
+ }
+ ],
+ "responses":{
+ "200":{
+ "description":"successful operation",
+ "schema":{
+ "$ref":"#/definitions/InterDomainRouteResponseBody"
+ }
+ },
+ "400":{
+ "description":"bad request"
+ },
+ "401":{
+ "description":"Request body is not compliant with the API definition"
+ },
+ "404":{
+ "description":"The server cannot find the requested URI"
+ },
+ "405":{
+ "description":"The requested method is not supported by a server."
+ },
+ "500":{
+ "description":"The server encountered an internal server error or timed out"
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "InterDomainRouteRequest":{
+ "type":"object",
+ "properties":{
+ "requestInfo":{
+ "$ref":"#/definitions/requestInfo"
+ },
+ "routeInfo":{
+ "$ref":"#/definitions/interDomainRouteInfo"
+ }
+ }
+ },
+ "interDomainRouteInfo":{
+ "type":"object",
+ "properties":{
+ "routeRequest":{
+ "$ref":"#/definitions/interDomainRouteRequest"
+ }
+ }
+ },
+ "interDomainRouteRequest":{
+ "type":"object",
+ "properties":{
+ "srcDetails":{
+ "$ref":"#/definitions/interDomainPortDetails"
+ },
+ "dstDetails":{
+ "$ref":"#/definitions/interDomainPortDetails"
+ },
+ "serviceRate":{
+ "type":"string",
+ "description":"The rate of the service."
+ }
+ }
+ },
+ "interDomainPortDetails":{
+ "type":"object",
+ "properties":{
+ "interfaceId":{
+ "type":"string",
+ "description":"The port id."
+ },
+ "nodeId":{
+ "type":"string",
+ "description":"The node id."
+ },
+ "controllerId":{
+ "type":"string",
+ "description":"The controller id to which the node belongs to."
+ }
+ }
+ },
+ "InterDomainRouteResponseBody":{
+ "type":"object",
+ "properties":{
+ "requestId":{
+ "type":"string",
+ "description":"A unique Id for an ONAP transaction."
+ },
+ "transactionId":{
+ "type":"string",
+ "description":"A unique ID to track multiple requests associated with a transaction."
+ },
+ "statusMessage":{
+ "type":"string",
+ "description":"Reasoning if a requestStatus is failure."
+ },
+ "requestStatus":{
+ "type":"string",
+ "description":"The status of a request."
+ },
+ "solutions":{
+ "$ref":"#/definitions/InterDomainRouteSolutionInfo"
+ }
+ }
+ },
+ "InterDomainRouteSolutionInfo":{
+ "type":"object",
+ "properties":{
+ "routeInfo":{
+ "$ref":"#/definitions/interDomainResponseRouteinfo"
+ }
+ }
+ },
+ "interDomainResponseRouteinfo":{
+ "type":"object",
+ "properties":{
+ "serviceRoute":{
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/serviceRouteDetails"
+ }
+ },
+ "linkList":{
+ "type":"array",
+ "items":{
+ "type":"string"
+ },
+ "description":"A list of link names of the route.",
+ "example":[
+ "link1",
+ "link2"
+ ]
+ }
+ }
+ },
+ "serviceRouteDetails":{
+ "type":"object",
+ "properties":{
+ "srcInterfaceId":{
+ "type":"string",
+ "description":"Source port Id of the domain Service."
+ },
+ "dstInterfaceId":{
+ "type":"string",
+ "description":"Destination Port Id of the domain Service."
+ },
+ "controllerId":{
+ "type":"string",
+ "description":"Controller Id of the domain."
+ }
+ }
+ },
+ "RouteRequest": {
+ "type": "object",
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/requestInfo"
+ },
+ "routeInfo": {
+ "$ref": "#/definitions/routeInfo"
+ }
+ }
+ },
+ "requestInfo": {
+ "type": "object",
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "description": "A unique ID to track an ONAP transaction."
+ },
+ "requestId": {
+ "type": "string",
+ "description": "A unique ID to track multiple requests associated with a transaction."
+ },
+ "callbackUrl": {
+ "type": "string",
+ "description": "The end point of a callback service where recommendations are posted."
+ },
+ "callbackHeader": {
+ "type": "string",
+ "description": "The header information a client expecting in a async callback."
+ },
+ "sourceId": {
+ "type": "string",
+ "description": "The unique ID of a client making an optimization call."
+ },
+ "requestType": {
+ "type": "string",
+ "format": "string",
+ "description": "The type of request being placed.",
+ "enum": [
+ "create",
+ "update",
+ "delete"
+ ]
+ },
+ "numSolutions": {
+ "type": "integer",
+ "format": "int32",
+ "description": "Expected number of solutions. numSolution can also be specified using an optimization query policies, where the default configured value is 1. The value from a request gets higher precedence over the value defined in a policy."
+ },
+ "optimizers": {
+ "description": "A list of optimization services that can be used to resolve the route",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "timeout": {
+ "type": "integer",
+ "format": "int32",
+ "description": "A tolerance window (in secs) for expecting solutions. Default is 600 secs."
+ }
+ }
+ },
+ "routeInfo": {
+ "type": "object",
+ "properties": {
+ "routeRequest": {
+ "$ref": "#/definitions/routeRequest"
+ }
+ }
+ },
+ "routeRequest": {
+ "type": "object",
+ "properties": {
+ "srcPort": {
+ "$ref": "#/definitions/routePortInfo"
+ },
+ "destPort": {
+ "$ref": "#/definitions/routePortInfo"
+ }
+ }
+ },
+ "routePortInfo": {
+ "type": "object",
+ "properties": {
+ "accessTopologyId": {
+ "type": "string",
+ "description": "A unique ID of the Access Topology."
+ },
+ "accessClientId": {
+ "type": "string",
+ "format": "string",
+ "description": "A unique ID of the client which provides the access."
+ },
+ "accessProviderId": {
+ "type": "string",
+ "format": "string",
+ "description": "A unique ID of the access provider"
+ },
+ "accessNodeId": {
+ "type": "string",
+ "format": "string",
+ "description": "A unique ID of the node to/from which the route has to be established."
+ },
+ "accessLtpId": {
+ "type": "integer",
+ "format": "int32",
+ "description": "A unique ID of the Termination Point to/from which the route has to be established."
+ }
+ }
+ },
+ "routeResponseBody": {
+ "type": "object",
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "description": "A unique Id for an ONAP transaction."
+ },
+ "transactionId": {
+ "type": "string",
+ "description": "A unique ID to track multiple requests associated with a transaction."
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failure."
+ },
+ "requestStatus": {
+ "type": "string",
+ "description": "The status of a request."
+ },
+ "solutions": {
+ "$ref": "#/definitions/RouteSolutionInfo"
+ }
+ }
+ },
+ "RouteSolutionInfo": {
+ "type": "object",
+ "properties": {
+ "startTime": {
+ "type": "string",
+ "format": "date-time",
+ "description": "start time of the operation in RFC 3339 notation for example, 2017-07-21T17:32:28Z."
+ },
+ "finishTime": {
+ "type": "string",
+ "format": "date-time",
+ "description": "end time of the operation in RFC 3339 notation for example, 2017-07-21T17:32:28Z."
+ },
+ "links": {
+ "description": "A list of vpn info that can be used to establish the route between source and destination port/node.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/link"
+ }
+ }
+ }
+ },
+ "link": {
+ "type": "object",
+ "properties": {
+ "linkId": {
+ "type": "string",
+ "description": "Id or name identifies a link uniquely."
+ }
+ }
+ },
+ "PlacementRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "placementInfo",
+ "licenseInfo",
+ "serviceInfo"
+ ],
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo"
+ },
+ "placementInfo": {
+ "$ref": "#/definitions/PlacementInfo"
+ },
+ "licenseInfo": {
+ "$ref": "#/definitions/LicenseInfo"
+ },
+ "serviceInfo": {
+ "$ref": "#/definitions/ServiceInfo"
+ }
+ }
+ },
+ "RequestInfo": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestId",
+ "callbackUrl",
+ "sourceId",
+ "requestType",
+ "optimizers",
+ "timeout"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "url",
+ "description": "The end point of a callback service where recommendations are posted.",
+ "example": "myDomain.com/myCallback"
+ },
+ "callbackHeader": {
+ "type": "string",
+ "description": "JSON blob. The header information a client expecting in a async callback.",
+ "example": {
+ "blob": "content"
+ }
+ },
+ "sourceId": {
+ "type": "string",
+ "description": "The unique ID of a client making an optimization call.",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestType": {
+ "type": "string",
+ "enum": [
+ "create",
+ "update",
+ "delete"
+ ],
+ "description": "The type of a request",
+ "example": "create"
+ },
+ "numSolutions": {
+ "type": "integer",
+ "description": "Expected number of solutions.",
+ "example": 1
+ },
+ "optimizers": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "placement",
+ "pci",
+ "pci-anr"
+ ]
+ },
+ "description": "A list of optimization services.",
+ "example": [
+ "placement"
+ ]
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "A tolerance window (in second) for expecting solutions.",
+ "example": 5
+ }
+ }
+ },
+ "PlacementInfo": {
+ "type": "object",
+ "required": [
+ "requestParameters",
+ "placementDemands"
+ ],
+ "properties": {
+ "requestParameters": {
+ "type": "string",
+ "description": "JSON blob. A service ordering information",
+ "example": {
+ "blob": "content"
+ }
+ },
+ "placementDemands": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PlacementDemand"
+ },
+ "description": "The resource information for a placement service"
+ },
+ "subscriberInfo": {
+ "type": "object",
+ "items": {
+ "$ref": "#/definitions/SubscriberInfo"
+ },
+ "description": "The information of a service subscriber."
+ }
+ }
+ },
+ "PlacementDemand": {
+ "type": "object",
+ "required": [
+ "resourceModuleName",
+ "serviceResourceId",
+ "resourceModelInfo"
+ ],
+ "properties": {
+ "resourceModuleName": {
+ "type": "string",
+ "description": "A resource name as defined in a service mode",
+ "example": "myResourceName"
+ },
+ "serviceResourceId": {
+ "type": "string",
+ "description": "A unique resource Id with a local scope between client and OOF.",
+ "example": "myResourceId"
+ },
+ "givenPlacement": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ }
+ }
+ },
+ "description": "placement parameters defined in the ordering system, keyname include tenantId",
+ "example": {
+ "tenantId": "1"
+ }
+ },
+ "resourceModelInfo": {
+ "$ref": "#/definitions/ModelMetaData"
+ },
+ "existingCandidates": {
+ "$ref": "#/definitions/Candidates"
+ },
+ "excludedCandidates": {
+ "$ref": "#/definitions/Candidates"
+ },
+ "requiredCandidates": {
+ "$ref": "#/definitions/Candidates"
+ }
+ }
+ },
+ "ModelMetaData": {
+ "type": "object",
+ "required": [
+ "modelInvariantId",
+ "modelVersionId"
+ ],
+ "properties": {
+ "modelInvariantId": {
+ "type": "string",
+ "description": "A model invariant Id as defined in a service model.",
+ "example": "my model invariant Id"
+ },
+ "modelVersionId": {
+ "type": "string",
+ "description": "A unique model Id as defined in a service model.",
+ "example": "my unique model Id"
+ },
+ "modelName": {
+ "type": "string",
+ "description": "A model name as defined in a service model",
+ "example": "my model name"
+ },
+ "modelType": {
+ "type": "string",
+ "description": "A model type as defined in a service model.",
+ "example": "my model type"
+ },
+ "modelVersion": {
+ "type": "string",
+ "description": "A model version as defined in a service model.",
+ "example": "my model version"
+ },
+ "modelCustomizationName": {
+ "type": "string",
+ "description": "A model customization name as defined in a service model.",
+ "example": "my model customization"
+ }
+ }
+ },
+ "Candidates": {
+ "type": "object",
+ "required": [
+ "identifierType",
+ "identifiers"
+ ],
+ "properties": {
+ "identifierType": {
+ "type": "string",
+ "enum": [
+ "service_instance_id",
+ "vnf_name",
+ "cloud_region_id"
+ ],
+ "description": "The type of a candidate.",
+ "example": "service_instance_id"
+ },
+ "identifiers": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "A list of identifiers.",
+ "example": "candidateId"
+ },
+ "cloudOwner": {
+ "type": "string",
+ "description": "The name of a cloud owner. Only required if identifierType is cloud_region_id",
+ "example": "cloud_owner"
+ }
+ }
+ },
+ "SubscriberInfo": {
+ "type": "object",
+ "required": [
+ "globalSubscriberId",
+ "subscriberName",
+ "subscriberCommonSiteId"
+ ],
+ "properties": {
+ "globalSubscriberId": {
+ "type": "string",
+ "description": "An ID of a subscriber.",
+ "example": "subscriber_id"
+ },
+ "subscriberName": {
+ "type": "string",
+ "description": "The name of a subscriber. If the name is not known, the value must be 'unknown'",
+ "example": "subscriber_name"
+ },
+ "subscriberCommonSiteId": {
+ "type": "string",
+ "description": "Id representing a subscriber location",
+ "example": "subscriber_location_id"
+ }
+ }
+ },
+ "LicenseInfo": {
+ "type": "object",
+ "required": [
+ "licenseDemands"
+ ],
+ "properties": {
+ "licenseDemands": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/LicenseDemands"
+ },
+ "description": "A list of resources for license selection"
+ }
+ }
+ },
+ "LicenseDemands": {
+ "type": "object",
+ "required": [
+ "resourceModuleName",
+ "serviceResourceId",
+ "resourceModelInfo"
+ ],
+ "properties": {
+ "resourceModuleName": {
+ "type": "string",
+ "description": "A resource name as defined in a service model.",
+ "example": "service_instance_id"
+ },
+ "serviceResourceId": {
+ "type": "string",
+ "description": "A unique resource Id with a local scope between client and OOF.",
+ "example": "service_instance_id"
+ },
+ "resourceModelInfo": {
+ "$ref": "#/definitions/ModelMetaData"
+ },
+ "existingLicenses": {
+ "$ref": "#/definitions/LicenseModel"
+ }
+ }
+ },
+ "LicenseModel": {
+ "type": "object",
+ "required": [
+ "entitlementPoolUUID",
+ "licenseKeyGroupUUID"
+ ],
+ "properties": {
+ "entitlementPoolUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "Entitlement pool UUIDs associated with a resource.",
+ "example": "candidateId"
+ },
+ "licenseKeyGroupUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "License key groups associated with a resource",
+ "example": "candidateId"
+ }
+ }
+ },
+ "SynchronousResponse": {
+ "type": "object",
+ "required": [
+ "requestId",
+ "transactionId",
+ "requestStatus"
+ ],
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique Id for an ONAP transaction",
+ "example": "ONAP transaction id"
+ },
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction.",
+ "example": "requests id"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failure.",
+ "example": "requestStatus"
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "success",
+ "failure"
+ ],
+ "description": "The status of a request.",
+ "example": "success"
+ }
+ }
+ },
+ "SynchronousTerminationResponse": {
+ "type": "object",
+ "required": [
+ "requestId",
+ "transactionId",
+ "requestStatus",
+ "terminateResponse"
+ ],
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique Id for an ONAP transaction",
+ "example": "ONAP transaction id"
+ },
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction.",
+ "example": "requests id"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failure.",
+ "example": "requestStatus"
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "success",
+ "failure"
+ ],
+ "description": "The status of a request.",
+ "example": "success"
+ },
+ "terminateResponse": {
+ "type": "boolean"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Reason if terminateResponse is false",
+ "example": "Restricted by Policy"
+ }
+ }
+ },
+ "PlacementAsynchronousResponse": {
+ "type": "object",
+ "required": [
+ "requestId",
+ "transactionId",
+ "requestStatus",
+ "solutions"
+ ],
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique Id for an ONAP transaction",
+ "example": "ONAP transaction id"
+ },
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction.",
+ "example": "requests id"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failure.",
+ "example": "requestStatus"
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "success",
+ "failure"
+ ],
+ "description": "The status of a request.",
+ "example": "success"
+ },
+ "solutions": {
+ "$ref": "#/definitions/Solutions"
+ }
+ }
+ },
+ "Solutions": {
+ "type": "object",
+ "required": [
+ "placementSolutions",
+ "licenseSolutions"
+ ],
+ "properties": {
+ "placementSolutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ComprehensiveSolution"
+ },
+ "description": "A list of placement solutions."
+ },
+ "licenseSolutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/LicenseSolution"
+ },
+ "description": "A list of license solutions."
+ }
+ }
+ },
+ "ComprehensiveSolution": {
+ "type": "object",
+ "required": [
+ "placementSolutions"
+ ],
+ "properties": {
+ "placementSolutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PlacementSolution"
+ },
+ "description": "A list of placement solutions."
+ }
+ }
+ },
+ "PlacementSolution": {
+ "type": "object",
+ "required": [
+ "resourceModuleName",
+ "serviceResourceId",
+ "identifierType",
+ "identifier"
+ ],
+ "properties": {
+ "resourceModuleName": {
+ "type": "string",
+ "description": "The name of a resource as defined in the service model",
+ "example": "resource name"
+ },
+ "serviceResourceId": {
+ "type": "string",
+ "description": "A resource Id as defined in a service model.",
+ "example": "resource id"
+ },
+ "identifierType": {
+ "type": "string",
+ "enum": [
+ "service_instance_id"
+ ],
+ "description": "The type of a candidate.",
+ "example": "candidate type"
+ },
+ "identifier": {
+ "type": "string",
+ "description": "The id of a candidate.",
+ "example": "candidate id"
+ },
+ "assignmentInfo": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/AssignmentInfo"
+ },
+ "description": "Additional information related to a candidate."
+ }
+ }
+ },
+ "AssignmentInfo": {
+ "type": "object",
+ "required": [
+ "key",
+ "value"
+ ],
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "An attribute name",
+ "example": "attribute name"
+ },
+ "value": {
+ "type": "string",
+ "description": "An attribute value.",
+ "example": "attribute value"
+ }
+ }
+ },
+ "LicenseSolution": {
+ "type": "object",
+ "required": [
+ "resourceModuleName",
+ "serviceResourceId",
+ "entitlementPoolUUID",
+ "licenseKeyGroupUUID",
+ "entitlementPoolInvariantUUID",
+ "licenseKeyGroupInvariantUUID"
+ ],
+ "properties": {
+ "resourceModuleName": {
+ "type": "string",
+ "description": "A resource name as defined in a service",
+ "example": "resource name"
+ },
+ "serviceResourceId": {
+ "type": "string",
+ "description": "A resource Id as defined in a service.",
+ "example": "resource Id"
+ },
+ "entitlementPoolUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "A list of entitlementPoolUUIDs",
+ "example": "entitlementPoolUUID"
+ },
+ "licenseKeyGroupUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "A list of licenseKeyGroupUUID.",
+ "example": "licenseKeyGroupUUID"
+ },
+ "entitlementPoolInvariantUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "A list of entitlementPoolInvariantUUID",
+ "example": "entitlementPoolInvariantUUID"
+ },
+ "licenseKeyGroupInvariantUUID": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "description": "A list of licenseKeyGroupInvariantUUID",
+ "example": "licenseKeyGroupInvariantUUID"
+ }
+ }
+ },
+ "ServiceInfo": {
+ "type": "object",
+ "required": [
+ "serviceInstanceId",
+ "modelInfo",
+ "serviceName"
+ ],
+ "properties": {
+ "serviceInstanceId": {
+ "type": "string",
+ "description": "A service instance id associated with a request.",
+ "example": "service_instance_id"
+ },
+ "modelInfo": {
+ "$ref": "#/definitions/ModelMetaData"
+ },
+ "serviceName": {
+ "type": "string",
+ "description": "The name of a service",
+ "example": "service_name"
+ }
+ }
+ },
+ "PCIOptRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "cellInfo"
+ ],
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo"
+ },
+ "cellInfo": {
+ "$ref": "#/definitions/CellInfo"
+ }
+ }
+ },
+ "CellInfo": {
+ "type": "object",
+ "required": [
+ "networkId",
+ "cellIdList",
+ "anrInputList",
+ "trigger"
+ ],
+ "properties": {
+ "networkId": {
+ "type": "string",
+ "description": "Id of network requiring PCI optimization",
+ "example": 100
+ },
+ "cellIdList": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of cellIds triggering need for PCI optimization (eg.potential confusion)",
+ "example": [
+ "cell0001",
+ "cell0002"
+ ]
+ },
+ "anrInputList": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ANRInfo"
+ },
+ "description": "A list of ANR Input."
+ },
+ "fixedPCICells": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of blacklisted cells whose PCI values should not be changed",
+ "example": [
+ "cell0007",
+ "cell0009"
+ ]
+ },
+ "priorityTreatmentCells": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of cells which should be given special treatment during optimization",
+ "example": [
+ "cell0010",
+ "cell0003"
+ ]
+ },
+ "trigger": {
+ "type": "string",
+ "description": "Type of trigger causing need for PCI optimization",
+ "example": "NbrListChange"
+ }
+ }
+ },
+ "PCIAsynchronousResponse": {
+ "type": "object",
+ "required": [
+ "requestId",
+ "transactionId",
+ "requestStatus",
+ "solutions"
+ ],
+ "properties": {
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique Id for an ONAP transaction",
+ "example": "ONAP transaction id"
+ },
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction.",
+ "example": "requests id"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failure.",
+ "example": "requestStatus"
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "success",
+ "failure"
+ ],
+ "description": "The status of a request.",
+ "example": "success"
+ },
+ "solutions": {
+ "$ref": "#/definitions/PCIANRSolutions"
+ }
+ }
+ },
+ "PCIANRSolutions": {
+ "type": "object",
+ "required": [
+ "networkId",
+ "pciSolutions",
+ "anrSolutions"
+ ],
+ "properties": {
+ "networkId": {
+ "type": "string",
+ "description": "Id of network requiring PCI optimization",
+ "example": 100
+ },
+ "pciSolutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/PCISolution"
+ },
+ "description": "A list of PCI solutions."
+ },
+ "anrSolutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/ANRInfo"
+ },
+ "description": "A list of ANR solutions."
+ }
+ }
+ },
+ "PCISolution": {
+ "type": "object",
+ "required": [
+ "cellId",
+ "pci"
+ ],
+ "properties": {
+ "cellId": {
+ "type": "string",
+ "description": "cellId with modified PCI value",
+ "example": "cell0001"
+ },
+ "pci": {
+ "type": "integer",
+ "description": "New PCI value for cellId",
+ "example": 1
+ }
+ }
+ },
+ "ANRInfo": {
+ "type": "object",
+ "required": [
+ "cellId",
+ "removeableNeighbors"
+ ],
+ "properties": {
+ "cellId": {
+ "type": "string",
+ "description": "cellId with modified PCI value",
+ "example": "cell0001"
+ },
+ "removeableNeighbors": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of neighbors to be removed",
+ "example": [
+ "cell0002",
+ "cell0003"
+ ]
+ }
+ }
+ },
+ "NSTSelectionRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "serviceProfile"
+ ],
+ "properties": {
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo2"
+ },
+ "serviceProfile": {
+ "$ref": "#/definitions/ServiceProfile"
+ }
+ }
+ },
+ "NSISelectionRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "serviceProfile",
+ "NSTInfo",
+ "NSSTInfo",
+ "subnetCapabilities"
+ ],
+ "properties": {
+ "serviceProfile": {
+ "$ref": "#/definitions/ServiceProfile"
+ },
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo2"
+ },
+ "NSTInfo": {
+ "$ref": "#/definitions/NSTInfo"
+ },
+ "NSSTInfo": {
+ "type": "array",
+ "description": "List of constituent NSST(s) of the NST",
+ "items": {
+ "$ref": "#/definitions/NSSTInfo"
+ }
+ },
+ "preferReuse": {
+ "type": "boolean",
+ "description": "true if reusing an existing NSI is preferred/false if creating a new NSI is preferred "
+ },
+ "subnetCapabilities": {
+ "type": "array",
+ "description": "List of subnet capabilities",
+ "items": {
+ "$ref": "#/definitions/SubnetCapability"
+ }
+ }
+ }
+ },
+ "NSSISelectionRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "NSSTInfo",
+ "sliceProfile"
+ ],
+ "properties": {
+ "sliceProfile": {
+ "$ref": "#/definitions/SliceProfile"
+ },
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo2"
+ },
+ "NSSTInfo": {
+ "$ref": "#/definitions/NSSTInfo"
+ }
+ }
+ },
+ "NxITerminationRequest": {
+ "type": "object",
+ "required": [
+ "requestInfo",
+ "type",
+ "NxIId"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "NSI",
+ "NSSI"
+ ],
+ "description": "indicates if the request is for NSI/NSSI termination"
+ },
+ "NxIId": {
+ "type": "string",
+ "format": "UUID",
+ "description": "Id of NSI / NSSI"
+ },
+ "UUID": {
+ "type": "string",
+ "format": "UUID",
+ "description": "UUID of NST/NSST model"
+ },
+ "invariantUUID": {
+ "type": "string",
+ "format": "UUID",
+ "description": "invariant UUID of NST/NSST model"
+ },
+ "requestInfo": {
+ "$ref": "#/definitions/RequestInfo2"
+ }
+ }
+ },
+ "SubnetCapability": {
+ "type": "object",
+ "required": [
+ "domainType",
+ "capabilityDetails"
+ ],
+ "properties": {
+ "domainType": {
+ "type": "string",
+ "description": "type of the subnet"
+ },
+ "capabilityDetails": {
+ "type": "string",
+ "description": "A JSON object containing capability parameters",
+ "example": {
+ "blob": "content"
+ }
+ }
+ }
+ },
+ "NSTInfo": {
+ "type": "object",
+ "required": [
+ "UUID",
+ "invariantUUID",
+ "name"
+ ],
+ "properties": {
+ "UUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "UUID of NST"
+ },
+ "invariantUUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Invariant UUID"
+ },
+ "name": {
+ "type": "string",
+ "description": "name of the NST model"
+ }
+ }
+ },
+ "NSSTInfo": {
+ "type": "object",
+ "required": [
+ "UUID",
+ "invariantUUID",
+ "name"
+ ],
+ "properties": {
+ "UUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "UUID of NSST"
+ },
+ "invariantUUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Invariant UUID"
+ },
+ "name": {
+ "type": "string",
+ "description": "name of the NSST model"
+ }
+ }
+ },
+ "ServiceProfile": {
+ "type": "string",
+ "description": "JSON blob. Containing service profile parameters. The contents are based on 3GPP TS 23.541 Release 16 contents, and will be in the form of attribute value pairs.",
+ "example": {
+ "blob": "content"
+ }
+ },
+ "SliceProfile": {
+ "type": "string",
+ "description": "JSON blob. Containing slice profile parameters. The contents are based on 3GPP TS 23.541 Release 16 contents, and will be in the form of attribute value pairs.",
+ "example": {
+ "blob": "content"
+ }
+ },
+ "RequestInfo2": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestId",
+ "callbackUrl",
+ "sourceId"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "callbackUrl": {
+ "type": "string",
+ "format": "url",
+ "description": "The end point of a callback service where recommendations are posted.",
+ "example": "myDomain.com/myCallback"
+ },
+ "callbackHeader": {
+ "type": "string",
+ "description": "JSON blob. The header information a client expecting in a async callback.",
+ "example": {
+ "blob": "content"
+ }
+ },
+ "sourceId": {
+ "type": "string",
+ "description": "The unique ID of a client making an optimization call.",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "A tolerance window (in second) for expecting solutions.",
+ "example": 5
+ },
+ "numSolutions": {
+ "type": "integer",
+ "description": "Expected number of solutions.",
+ "example": 1
+ },
+ "addtnlArgs": {
+ "type": "string",
+ "description": "Any additional parameters that have to be considered during selection",
+ "example": {
+ "blob": "content"
+ }
+ }
+ }
+ },
+ "NSTAsynchronousResponse": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestId",
+ "requestStatus",
+ "solutions"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failed."
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "completed",
+ "failed",
+ "pending"
+ ],
+ "description": "The status of a request."
+ },
+ "solutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/NSTSolution"
+ },
+ "description": "A list of NST solutions"
+ }
+ }
+ },
+ "NSTSolution": {
+ "type": "object",
+ "required": [
+ "UUID",
+ "NSTName",
+ "invariantUUID",
+ "matchLevel"
+ ],
+ "properties": {
+ "invariantUUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Invariant UUID of NST"
+ },
+ "UUID": {
+ "type": "string",
+ "format": "UUID of NST"
+ },
+ "NSTName": {
+ "type": "string",
+ "description": "NST name"
+ },
+ "matchLevel": {
+ "type": "string",
+ "description": "JSON blob. Containing details of match of requirements in slice profile and percentage of fit"
+ }
+ }
+ },
+ "NSIAsynchronousResponse": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestId",
+ "requestStatus",
+ "solutions"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failed."
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "completed",
+ "failed",
+ "pending"
+ ],
+ "description": "The status of a request."
+ },
+ "solutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/NSISolution"
+ },
+ "description": "A list of NSI solutions"
+ }
+ }
+ },
+ "NSISolution": {
+ "type": "object",
+ "required": [
+ "existingNSI"
+ ],
+ "properties": {
+ "existingNSI": {
+ "type": "boolean",
+ "description": "true if NSISolution object has shareNSISolution/false if NSISolution object has newNSISolution"
+ },
+ "sharedNSISolution": {
+ "$ref": "#/definitions/SharedNSISolution"
+ },
+ "newNSISolution": {
+ "$ref": "#/definitions/NewNSISolution"
+ }
+ }
+ },
+ "SharedNSISolution": {
+ "type": "object",
+ "required": [
+ "invariantUUID",
+ "UUID",
+ "NSIName",
+ "NSIId",
+ "matchLevel"
+ ],
+ "properties": {
+ "invariantUUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Invariant UUID of NST"
+ },
+ "UUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "UUID of NST"
+ },
+ "NSIName": {
+ "type": "string",
+ "description": "Name of NSI"
+ },
+ "NSIId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Instance Id of NSI"
+ },
+ "matchLevel": {
+ "type": "string",
+ "description": "JSON blob. Containing details of match of requirements in service profile, and recommendation rank"
+ }
+ }
+ },
+ "NewNSISolution": {
+ "type": "object",
+ "required": [
+ "sliceProfiles",
+ "matchLevel"
+ ],
+ "properties": {
+ "sliceProfiles": {
+ "type": "array",
+ "description": "List of slice profiles",
+ "items": {
+ "$ref": "#/definitions/SliceProfile"
+ }
+ },
+ "matchLevel": {
+ "type": "string",
+ "description": "JSON blob. Containing details of match of requirements in service profile, and recommendation rank"
+ }
+ }
+ },
+ "NSSIAsynchronousResponse": {
+ "type": "object",
+ "required": [
+ "transactionId",
+ "requestId",
+ "requestStatus",
+ "solutions"
+ ],
+ "properties": {
+ "transactionId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "unique ID to track an ONAP transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "requestId": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique ID to track multiple requests associated with a transaction",
+ "example": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ "statusMessage": {
+ "type": "string",
+ "description": "Reasoning if a requestStatus is failed."
+ },
+ "requestStatus": {
+ "type": "string",
+ "enum": [
+ "completed",
+ "failed",
+ "pending"
+ ],
+ "description": "The status of a request."
+ },
+ "solutions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/SharedNSSISolution"
+ },
+ "description": "A list of NSSI solutions, empty list will be returned if no solution is found"
+ }
+ }
+ },
+ "SharedNSSISolution": {
+ "type": "object",
+ "required": [
+ "invariantUUID",
+ "UUID",
+ "NSSIName",
+ "NSSIId",
+ "matchLevel"
+ ],
+ "properties": {
+ "invariantUUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Invariant UUID of NSST"
+ },
+ "UUID": {
+ "type": "string",
+ "format": "uuid",
+ "description": "UUID of NSST"
+ },
+ "NSSIName": {
+ "type": "string",
+ "description": "Name of NSSI"
+ },
+ "NSSIId": {
+ "type": "string",
+ "description": "Instance Id of NSSI"
+ },
+ "matchLevel": {
+ "type": "string",
+ "description": "JSON blob. Containing details of match of requirements in slice profile and percentage of fit"
+ }
+ }
+ }
+ },
+ "schemes": [
+ "https"
+ ],
+ "host": "virtserver.swaggerhub.com",
+ "basePath": "/oof-osdf/v1"
+}
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..172975d
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,74 @@
+project = "onap"
+release = "master"
+version = "master"
+
+author = "Open Network Automation Platform"
+# yamllint disable-line rule:line-length
+copyright = "ONAP. Licensed under Creative Commons Attribution 4.0 International License"
+
+pygments_style = "sphinx"
+html_theme = "sphinx_rtd_theme"
+html_theme_options = {
+ "style_nav_header_background": "white",
+ "sticky_navigation": "False" }
+html_logo = "_static/logo_onap_2017.png"
+html_favicon = "_static/favicon.ico"
+html_static_path = ["_static"]
+html_show_sphinx = False
+
+extensions = [
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.graphviz',
+ 'sphinxcontrib.blockdiag',
+ 'sphinxcontrib.seqdiag',
+ 'sphinxcontrib.swaggerdoc',
+ 'sphinxcontrib.plantuml',
+ 'sphinxcontrib.redoc'
+]
+
+#
+# Map to 'latest' if this file is used in 'latest' (master) 'doc' branch.
+# Change to {releasename} after you have created the new 'doc' branch.
+#
+
+branch = 'latest'
+
+intersphinx_mapping = {}
+doc_url = 'https://docs.onap.org/projects'
+master_doc = 'index'
+
+exclude_patterns = ['.tox']
+
+spelling_word_list_filename='spelling_wordlist.txt'
+spelling_lang = "en_GB"
+
+#
+# Example:
+# intersphinx_mapping['onap-aai-aai-common'] = ('{}/onap-aai-aai-common/en/%s'.format(doc_url) % branch, None)
+#
+
+html_last_updated_fmt = '%d-%b-%y %H:%M'
+
+def setup(app):
+ app.add_css_file("css/ribbon.css")
+
+linkcheck_ignore = [
+ r'http://localhost:\d+/'
+]
+
+redoc = [
+ {
+ 'name': 'OSDF API',
+ 'page': 'sections/osdf-api',
+ 'spec': './api/swagger/oof-osdf-has-api.json',
+ 'embed': True,
+ },
+ {
+ 'name': 'OPTENG API',
+ 'page': 'sections/opteng-api',
+ 'spec': './api/swagger/oof-optf-opteng-api.json',
+ 'embed': True,
+ }
+ ]
+
+redoc_uri = 'https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js'
diff --git a/docs/index.rst b/docs/index.rst
index c3ea9da..9a8302b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,4 +1,5 @@
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. _master_index:
Optimization Framework: Optimization Service Design Framework (OSDF)
@@ -17,4 +18,4 @@ Optimization Framework: Optimization Service Design Framework (OSDF)
./sections/administration.rst
./sections/humaninterfaces.rst
./sections/release-notes.rst
-
+ ./sections/upgradestrategy.rst
diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt
new file mode 100644
index 0000000..38643a1
--- /dev/null
+++ b/docs/requirements-docs.txt
@@ -0,0 +1,9 @@
+sphinx>=4.2.0 # BSD
+sphinx-rtd-theme>=1.0.0 # MIT
+sphinxcontrib-blockdiag # BSD
+sphinxcontrib-seqdiag # BSD
+sphinxcontrib-swaggerdoc
+sphinxcontrib-spelling
+sphinxcontrib-plantuml
+sphinxcontrib-redoc
+six
diff --git a/docs/sections/architecture.rst b/docs/sections/architecture.rst
index 64bc43c..b11eec2 100644
--- a/docs/sections/architecture.rst
+++ b/docs/sections/architecture.rst
@@ -1,4 +1,5 @@
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. _architecture:
Architecture
=============================================
diff --git a/docs/sections/offeredapis.rst b/docs/sections/offeredapis.rst
index 5151431..c9af97d 100644
--- a/docs/sections/offeredapis.rst
+++ b/docs/sections/offeredapis.rst
@@ -1,8 +1,9 @@
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0
+.. _offeredapis:
Offered APIs
-=============================================
+============
This document describes the OSDF HAS (Homing and Allocation Service) API
@@ -10,8 +11,20 @@ This document describes the OSDF HAS (Homing and Allocation Service) API
To view API documentation in the interactive swagger UI download the following and
paste into the swagger tool here: https://editor.swagger.io
-:download:`oof-osdf-has-api.json <./swaggerdoc/oof-osdf-has-api.json>`
-
-.. swaggerv2doc:: ./swaggerdoc/oof-osdf-has-api.json
-
-
+.. csv-table::
+ :header: "API name", "Swagger JSON"
+ :widths: 10,5
+
+ "OOF OSDF HAS API", ":download:`link <../api/swagger/oof-osdf-has-api.json>`"
+ "OOF OPTENG API", ":download:`link <../api/swagger/oof-optf-opteng-api.json>`"
+
+.. OOF OSDF HAS API
+.. ................
+..
+.. `OSDF API <osdf-api.html>`_
+..
+..
+.. OOF OPTENG API
+.. ..............
+..
+.. `OPTENG API <opteng-api.html>`_
diff --git a/docs/sections/release-notes.rst b/docs/sections/release-notes.rst
index d8088dd..63ab538 100644
--- a/docs/sections/release-notes.rst
+++ b/docs/sections/release-notes.rst
@@ -1,13 +1,764 @@
..
This work is licensed under a Creative Commons Attribution 4.0
International License.
+.. _release_notes:
=============
Release Notes
=============
-Version: 1.1.1
+.. ===========================
+.. * * * KOHN * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the KOHN release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 3.0.7 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 11.0.0 kohn |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 10/11/2022 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+Bug Fixes
+---------
+
+- OPTFRA-1080 - Fix timeout issue in OSDF on sending plan request to HAS-API
+
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+References
+==========
+
+For more information on the ONAP Jakarta release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+
+- `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+- `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+
+.. ===========================
+.. * * * JAKARTA * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the JAKARTA release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 3.0.6 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 10.0.0 jakarta |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 02/06/2022 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+
+
+Bug Fixes
+---------
+
+- OPTFRA-1059 - Update configuration for TN-FH in NxI termination app
+
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+
+References
+==========
+
+For more information on the ONAP Jakarta release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+
+- `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+- `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+
+
+.. ===========================
+.. * * * ISTANBUL * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the Istanbul release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 3.0.6 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 9.0.0 istanbul |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 28/10/2021 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+- Enhancements in NxI termination to support second level NSSIs
+- Update NxI termination app to use AAI DSL query
+- Add CPS client for PCI app
+- OSDF image optimization
+
+Bug Fixes
+---------
+
+- OPTFRA-511 Return error when policies are not present
+- OPTFRA-943 Fix issues in NSI selection response
+- OPTFRA-853 Remove unwanted gplv3 components from docker image
+
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+
+References
+==========
+
+For more information on the ONAP Honolulu release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+ - `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+ - `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+
+.. ===========================
+.. * * * HONOLULU * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the Honolulu release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 3.0.4 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 8.0.0 honolulu |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 04/08/2021 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+- Add NST selection feature with AAI & SDC
+- Configuration management with consul KV store
+
+Bug Fixes
+---------
+
+- OPTFRA-906 Update slice/service profile attributes
+- OPTFRA-871 Bug Fix in ML SON - convert cell_id before sending it to Minizinc
+
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+
+References
+==========
+
+For more information on the ONAP Honolulu release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+ - `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+ - `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+.. ===========================
+.. * * * GUILIN * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the Guilin release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 3.0.2 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 7.0.0 guilin |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 2020-11-19 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+- NSI selection enhancements
+- Support for NSSI selection
+- Support for NSI/NSSI Termination
+- Support for Inter domain route optimization
+- Support for ML based SON optimization
+- Upgrade python version to 3.8
+
+Bug Fixes
+---------
+
+- OPTFRA-839 Remove python 2.7 from OSDF docker image
+- OPTFRA-855 Fix slice selection API
+- OPTFRA-852 Callback implementation for NST selection
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+
+References
+==========
+
+For more information on the ONAP Guilin release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+ - `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+ - `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+.. ===========================
+.. * * * FRANKFURT * * *
+.. ===========================
+
+Abstract
+========
+
+This document provides the release notes for the Frankfurt release.
+
+Summary
+=======
+
+
+Release Data
+============
+
+
++--------------------------------------+--------------------------------------+
+| **OOF Project** | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Docker images** | optf-osdf 2.0.4 |
+| | |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release designation** | 6.0.0 frankfurt |
+| | |
++--------------------------------------+--------------------------------------+
+| **Release date** | 2020-05-07 (TBD) |
+| | |
++--------------------------------------+--------------------------------------+
+
+
+New features
+------------
+
+- Project is restructured into apps and libs.
+- A Generic optimizing engine is implemented.
+- New optimizer model for route optimization is added.
+- Policy apis are migrated from legacy apis to new decision api.
+- The Conductor adapter is moved from placement to adapters.
+- NST and NSI selection function has been implemented for Network
+ Slicing use case.
+- PCI optimization is enhanced to support fixed cells field.
+
+Bug Fixes
+---------
+
+- OPTFRA-482 The field "unique" should be defined in vnf policy.
+- OPTFRA-729 OSDF fails to start in the k8s environment.
+- OPTFRA-731 OSDF Policy interface is not working
+- OPTFRA-754 Return slice profile when service profile indicates the
+ resource sharing level as not shared
+- OPTFRA-755 OOF Policy filtering does not work.
+
+Known Limitations, Issues and Workarounds
+=========================================
+
+System Limitations
+------------------
+
+
+Known Vulnerabilities
+---------------------
+
+
+Workarounds
+-----------
+
+
+Security Notes
+--------------
+
+
+References
+==========
+
+For more information on the ONAP Frankfurt release, please see:
+
+#. `ONAP Home Page`_
+#. `ONAP Documentation`_
+#. `ONAP Release Downloads`_
+#. `ONAP Wiki Page`_
+
+
+.. _`ONAP Home Page`: https://www.onap.org
+.. _`ONAP Wiki Page`: https://wiki.onap.org
+.. _`ONAP Documentation`: https://docs.onap.org
+.. _`ONAP Release Downloads`: https://git.onap.org
+
+Quick Links:
+ - `OOF project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+ - `Passing Badge information for OOF <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+
+
+Version: 5.0.1
+--------------
+
+:Release Date: 2019-09-30 (El Alto Release)
+
+The El Alto release is the fourth release for ONAP Optimization Framework (OOF).
+
+Artifacts released:
+
+optf-has:1.3.3
+optf-osdf:1.3.4
+optf-cmso:2.1.1
+
+**New Features**
+
+While no new features were added in the release, the following Stories were delivered as enhancements.
+
+ * [OPTFRA-415] Automation on policy model uploading
+ * [OPTFRA-427] CMSO - Schedule a workflow in SO and track status to completion
+
+* Platform Maturity Level 1
+ * ~65.1+ unit test coverage
+
+
+**Bug Fixes**
+
+The El Alto release for OOF fixed the following Bugs.
+
+ * [OPTFRA-579] Json error in homing solution
+ * [OPTFRA-521] oof-has-api exposes plain text HTTP endpoint using port 30275
+ * [OPTFRA-522] oof-osdf exposes plain text HTTP endpoint using port 30248
+ * [OPTFRA-577] Need for "ReadWriteMany" access on storage when deploying on Kubernetes?
+ * [OPTFRA-517] Clean up optf/cmso in integration/csit for Dublin
+ * [OPTFRA-486] Support "identifiers" field as a list of values
+ * [OPTFRA-403] OOF CMSO Service kubernetes resources allocation is not done
+ * [OPTFRA-526] OOF pods not running
+ * [OPTFRA-409] Template example : purpose to be explained
+ * [OPTFRA-593] OOF-CSMO healthcheck is failing in Master
+
+
+**Known Issues**
+
+ * [OPTFRA-576] optf-has-master-csit-has is testing Dublin image
+ * [OPTFRA-596] CMSO - Sonar and CSIT jobs failing
+ * [OPTFRA-608] Error in Homing with multiple policies
+
+**Security Notes**
+
+*Fixed Security Issues*
+
+ * [OJSI-122] In default deployment OPTFRA (oof-osdf) exposes HTTP port 30248 outside of cluster.
+ * [OPTFRA-521] oof-has-api exposes plain text HTTP endpoint using port 30275
+ * [OPTFRA-522] oof-osdf exposes plain text HTTP endpoint using port 30248
+ * [OPTFRA-455] CMSO - Mitigate License Threat tomcat-embed-core
+
+*Known Security Issues*
+
+ * [OPTFRA-481] Fix Vulnerability with spring-data-jpa package
+ * [OPTFRA-431] Fix Vulnerability with spring-security-web package
+
+*Known Vulnerabilities in Used Modules*
+
+**Upgrade Notes**
+
+
+**Deprecation Notes**
+
+
+**Other**
+
+
+Version: 4.0.0
+--------------
+
+:Release Date: 2019-06-06 (Dublin Release)
+
+**New Features**
+
+The Dublin release is the third release for ONAP Optimization Framework (OOF).
+
+A summary of features includes
+
+* Support SON (PCI/ANR) optimization using OSDF
+* Implement encryption for OSDF internal and external communication
+
+* Platform Maturity Level 1
+ * ~65.1+ unit test coverage
+
+The Dublin release for OOF delivered the following Epics.
+
+ * [OPTFRA-426] Track the changes to CMSO to support change management schedule optimization
+ * [OPTFRA-424] Extend OOF to support traffic distribution optimization
+ * [OPTFRA-422] Move OOF projects' CSIT to run on OOM
+ * [OPTFRA-276] Implementing a POC for 5G SON Optimization
+ * [OPTFRA-270] This epic captures stories related to maintaining current S3P levels of the project as new functional requirements are supported
+
+
+**Bug Fixes**
+
+* The full list of implemented user stories and epics is available on `DUBLIN RELEASE <https://jira.onap.org/projects/OPTFRA/versions/10463>`_
+
+**Known Issues**
+
+
+
+**Security Notes**
+
+*Fixed Security Issues*
+
+*Known Security Issues*
+
+ * [`OJSI-122 <https://jira.onap.org/browse/OJSI-122>`_] In default deployment OPTFRA (oof-osdf) exposes HTTP port 30248 outside of cluster.
+
+*Known Vulnerabilities in Used Modules*
+
+OPTFRA osdf code has been formally scanned during build time using NexusIQ and no Critical vulnerability was found.
+The OPTF open Critical security vulnerabilities and their risk assessment have been documented as part of the `project <https://wiki.onap.org/pages/viewpage.action?pageId=64005463>`__.
+
+Quick Links:
+ - `OPTFRA project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`__
+ - `Passing Badge information for OPTFRA <https://bestpractices.coreinfrastructure.org/en/projects/1720>`__
+ - `Project Vulnerability Review Table for OPTF <https://wiki.onap.org/pages/viewpage.action?pageId=64005463>`__
+
+**Upgrade Notes**
+
+None.
+
+**Deprecation Notes**
+
+None.
+
+**Other**
+
+None
+
+Version: 3.0.1
+--------------
+
+:Release Date: 2019-01-31 (Casablanca Maintenance Release)
+
+The following items were deployed with the Casablanca Maintenance Release:
+
+
+**New Features**
+
+None.
+
+**Bug Fixes**
+
+* [OPTFRA-401] - Need flavor id while launching vm.
+
+
+
+Version: 3.0.0
+--------------
+
+:Release Date: 2018-11-30 (Casablanca Release)
+
+**New Features**
+
+The Casablanca release is the second release for ONAP Optimization Framework (OOF).
+
+A summary of features includes
+
+* Homing enhancements for improving service deployability
+ * Discovering and reusing shared resources when processing multiple homing requests in parallel
+ * Considering Latency Reduction (in addition to geographical distances) for homing optimization
+ * Enhanced capacity checks during VNF homing
+ * Asynchronous communication between HAS components
+* OOF Casablanca S3P Usability enhancement
+ * Adherence to ONAP API Common Versioning Strategy (CVS) Proposal
+ * Move all internal and external facing APIs to Swagger 2.0
+* OOF Casablanca S3P Performance enhancements
+ * Creating a plan for performance improvements based on the baseline measured metrics
+* OOF development platform hardening
+ * Deployment scripts
+ * Fix Build Docker image script for supporting multiple versions
+ * Fix OOM, HEAT deployment scripts (versioning)
+ * CSIT functional tests for each repo
+ * CI Jobs for different streams (Beijing, master etc)
+ * Clean up nexus binaries and maven versioning
+* Integrate OOF with Certificate and Secret Management Service (CSM)
+* Support SON (PCI) optimization using OSDF
+
+* Platform Maturity Level 1
+ * ~65.1+ unit test coverage
+
+The Casablanca release for OOF delivered the following Epics.
+
+ * [OPTFRA-273] - Epic Name: OOF Casablanca S3P Manageability enhancement
+ * [OPTFRA-270] - Maintain current S3P levels
+ * [OPTFRA-271] - OOF Casablanca S3P Security enhancement
+ * [OPTFRA-267] - OOF - HPA Enhancements
+ * [OPTFRA-276] - Implementing a POC for 5G SON Optimization
+
+
+**Bug Fixes**
+
+* The full list of implemented user stories and epics is available on `CASABLANCA RELEASE <https://jira.onap.org/projects/OPTFRA/versions/10445>`_
+
+**Known Issues**
+
+ * [OPTFRA-223] - On boarding and testing AAF certificates for OSDF.
+ * [OPTFRA-293] - Implement encryption for all OSDF internal and external communication
+ * [OPTFRA-329] - role based access control for OSDF-Policy interface
+
+**Security Notes**
+
+OPTFRA osdf code has been formally scanned during build time using NexusIQ and no Critical vulnerability was found.
+The OPTF open Critical security vulnerabilities and their risk assessment have been documented as part of the `project <https://wiki.onap.org/pages/viewpage.action?pageId=43385924>`__.
+
+Quick Links:
+ - `OPTFRA project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
+ - `Passing Badge information for OPTFRA <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
+ - `Project Vulnerability Review Table for OPTF <https://wiki.onap.org/pages/viewpage.action?pageId=43385924>`_
+
+**Upgrade Notes**
+
+None.
+
+**Deprecation Notes**
+
+None.
+
+**Other**
+
+None
+
+Version: 2.0.0
--------------
:Release Date: 2018-06-07
@@ -15,7 +766,7 @@ Version: 1.1.1
**New Features**
-The ONAP Optimization Framework (OOF) is new in Beijing. A summary of features includes:
+The ONAP Optimization Framework (OOF) is new in Beijing. A summary of features includes:
* Baseline HAS functionality
* support for VCPE use case
@@ -23,37 +774,28 @@ The ONAP Optimization Framework (OOF) is new in Beijing. A summary of features i
* Integration with OOF OSDF, SO, Policy, AAI, and Multi-Cloud
* Platform Maturity Level 1
* ~50%+ unit test coverage
-
-The Beijing release for OOF delivered the following Epics.
- * [OPTFRA-2] - On-boarding and Stabilization of the OOF seed code
+The Beijing release for OOF delivered the following Epics.
+ * [OPTFRA-2] - On-boarding and Stabilization of the OOF seed code
* [OPTFRA-6] - Integrate OOF with other ONAP components
-
* [OPTFRA-7] - Integration with R2 Use Cases [HPA, Change Management, Scaling]
-
* [OPTFRA-20] - OOF Adapters for Retrieving and Resolving Policies
-
* [OPTFRA-21] - OOF Packaging
-
* [OPTFRA-28] - OOF Adapters for Beijing Release (Policy, SDC, A&AI, Multi Cloud, etc.)
-
* [OPTFRA-29] - Policies and Specifications for Initial Applications [Change Management, HPA]
-
* [OPTFRA-32] - Platform Maturity Requirements for Beijing release
-
* [OPTFRA-33] - OOF Support for HPA
-
* [OPTFRA-105] - All Documentation Related User Stories and Tasks
**Bug Fixes**
-None. Initial release R2 Beijing. No previous versions
+None. Initial release R2 Beijing. No previous versions
**Known Issues**
-None.
+None.
**Security Notes**
@@ -61,16 +803,15 @@ OPTFRA code has been formally scanned during build time using NexusIQ and no Cri
Quick Links:
- `OPTFRA project page <https://wiki.onap.org/display/DW/Optimization+Framework+Project>`_
-
- `Passing Badge information for OPTFRA <https://bestpractices.coreinfrastructure.org/en/projects/1720>`_
**Upgrade Notes**
-None. Initial release R2 Beijing. No previous versions
+None. Initial release R2 Beijing. No previous versions
**Deprecation Notes**
-None. Initial release R2 Beijing. No previous versions
+None. Initial release R2 Beijing. No previous versions
**Other**
diff --git a/docs/sections/swaggerdoc/oof-osdf-has-api.json b/docs/sections/swaggerdoc/oof-osdf-has-api.json
deleted file mode 100644
index 2fe2b97..0000000
--- a/docs/sections/swaggerdoc/oof-osdf-has-api.json
+++ /dev/null
@@ -1,587 +0,0 @@
-{
- "swagger" : "2.0",
- "info" : {
- "description" : "This is the ONAP OOF OSDF (Optimization Service Design Framework) API",
- "version" : "1.0.0",
- "title" : "OSDF API",
- "contact" : {
- "email" : "frank.sandoval@oamtechnologies.com"
- },
- "license" : {
- "name" : "Apache 2.0",
- "url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
- }
- },
- "securityDefinitions" : {
- "basicAuth" : {
- "type" : "basic",
- "description" : "HTTP Basic Auth"
- }
- },
- "security" : [ {
- "basicAuth" : [ ]
- } ],
- "paths" : {
- "/v2/placement" : {
- "post" : {
- "summary" : "create/update a placement",
- "operationId" : "createPlacement",
- "description" : "create/update a placement",
- "consumes" : [ "application/json" ],
- "produces" : [ "application/json" ],
- "parameters" : [ {
- "in" : "body",
- "name" : "placementRequest",
- "description" : "placement request",
- "schema" : {
- "$ref" : "#/definitions/PlacementRequest"
- }
- } ],
- "responses" : {
- "201" : {
- "description" : "An optimization solution is found."
- },
- "202" : {
- "description" : "An optimization request is accepted"
- },
- "400" : {
- "description" : "bad request"
- },
- "401" : {
- "description" : "Request body is not compliant with the API definition"
- },
- "404" : {
- "description" : "The server cannot find the requested URI"
- },
- "405" : {
- "description" : "The requested method is not supported by a server."
- },
- "500" : {
- "description" : "The server encountered an internal server error or timed out"
- }
- }
- }
- }
- },
- "definitions" : {
- "PlacementRequest" : {
- "type" : "object",
- "required" : [ "requestInfo", "placementInfo", "licenseInfo", "serviceInfo" ],
- "properties" : {
- "requestInfo" : {
- "$ref" : "#/definitions/RequestInfo"
- },
- "placementInfo" : {
- "$ref" : "#/definitions/PlacementInfo"
- },
- "licenseInfo" : {
- "$ref" : "#/definitions/LicenseInfo"
- },
- "serviceInfo" : {
- "$ref" : "#/definitions/ServiceInfo"
- }
- }
- },
- "RequestInfo" : {
- "type" : "object",
- "required" : [ "transactionId", "requestId", "callbackUrl", "sourceId", "requestType", "optimizers", "timeout" ],
- "properties" : {
- "transactionId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "unique ID to track an ONAP transaction",
- "example" : "d290f1ee-6c54-4b01-90e6-d701748f0851"
- },
- "requestId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "A unique ID to track multiple requests associated with a transaction",
- "example" : "d290f1ee-6c54-4b01-90e6-d701748f0851"
- },
- "callbackUrl" : {
- "type" : "string",
- "format" : "url",
- "description" : "The end point of a callback service where recommendations are posted.",
- "example" : "myDomain.com/myCallback"
- },
- "callbackHeader" : {
- "type" : "string",
- "description" : "JSON blob. The header information a client expecting in a async callback.",
- "example" : {
- "blob" : "content"
- }
- },
- "sourceId" : {
- "type" : "string",
- "description" : "The unique ID of a client making an optimization call.",
- "example" : "d290f1ee-6c54-4b01-90e6-d701748f0851"
- },
- "requestType" : {
- "type" : "string",
- "enum" : [ "create", "update", "delete" ],
- "description" : "The type of a request",
- "example" : "create"
- },
- "numSolutions" : {
- "type" : "integer",
- "description" : "Expected number of solutions.",
- "example" : 1
- },
- "optimizers" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "enum" : [ "placement" ]
- },
- "description" : "A list of optimization services.",
- "example" : "placement"
- },
- "timeout" : {
- "type" : "integer",
- "description" : "A tolerance window (in second) for expecting solutions.",
- "example" : 5
- }
- }
- },
- "PlacementInfo" : {
- "type" : "object",
- "required" : [ "requestParameters", "placementDemands" ],
- "properties" : {
- "requestParameters" : {
- "type" : "string",
- "description" : "JSON blob. A service ordering information",
- "example" : {
- "blob" : "content"
- }
- },
- "placementDemands" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/PlacementDemand"
- },
- "description" : "The resource information for a placement service"
- },
- "subscriberInfo" : {
- "type" : "object",
- "items" : {
- "$ref" : "#/definitions/SubscriberInfo"
- },
- "description" : "The information of a service subscriber."
- }
- }
- },
- "PlacementDemand" : {
- "type" : "object",
- "required" : [ "resourceModuleName", "serviceResourceId", "resourceModelInfo" ],
- "properties" : {
- "resourceModuleName" : {
- "type" : "string",
- "description" : "A resource name as defined in a service mode",
- "example" : "myResourceName"
- },
- "serviceResourceId" : {
- "type" : "string",
- "description" : "A unique resource Id with a local scope between client and OOF.",
- "example" : "myResourceId"
- },
- "givenPlacement" : {
- "type" : "object",
- "additionalProperties" : {
- "type" : "object",
- "properties" : {
- "key" : {
- "type" : "string"
- },
- "value" : {
- "type" : "string"
- }
- }
- },
- "description" : "placement parameters defined in the ordering system, keyname include tenantId",
- "example" : {
- "tenantId" : "1"
- }
- },
- "resourceModelInfo" : {
- "$ref" : "#/definitions/ModelMetaData",
- "description" : "Resource model information as defined in SDC"
- },
- "existingCandidates" : {
- "$ref" : "#/definitions/Candidates",
- "description" : "The existing placement information of a resource."
- },
- "excludedCandidates" : {
- "$ref" : "#/definitions/Candidates",
- "description" : "Candidates that need to be excluded from solutions."
- },
- "requiredCandidates" : {
- "$ref" : "#/definitions/Candidates",
- "description" : "Candidates that must be included in solutions."
- }
- }
- },
- "ModelMetaData" : {
- "type" : "object",
- "required" : [ "modelInvariantId", "modelVersionId" ],
- "properties" : {
- "modelInvariantId" : {
- "type" : "string",
- "description" : "A model invariant Id as defined in a service model.",
- "example" : "my model invariant Id"
- },
- "modelVersionId" : {
- "type" : "string",
- "description" : "A unique model Id as defined in a service model.",
- "example" : "my unique model Id"
- },
- "modelName" : {
- "type" : "string",
- "description" : "A model name as defined in a service model",
- "example" : "my model name"
- },
- "modelType" : {
- "type" : "string",
- "description" : "A model type as defined in a service model.",
- "example" : "my model type"
- },
- "modelVersion" : {
- "type" : "string",
- "description" : "A model version as defined in a service model.",
- "example" : "my model version"
- },
- "modelCustomizationName" : {
- "type" : "string",
- "description" : "A model customization name as defined in a service model.",
- "example" : "my model customization"
- }
- }
- },
- "Candidates" : {
- "type" : "object",
- "required" : [ "identifierType", "identifiers" ],
- "properties" : {
- "identifierType" : {
- "type" : "string",
- "enum" : [ "service_instance_id", "vnf_name", "cloud_region_id" ],
- "description" : "The type of a candidate.",
- "example" : "service_instance_id"
- },
- "identifiers" : {
- "type" : "array",
- "items" : {
- "type" : "string"
- },
- "description" : "A list of identifiers.",
- "example" : "candidateId"
- },
- "cloudOwner" : {
- "type" : "string",
- "description" : "The name of a cloud owner. Only required if identifierType is cloud_region_id",
- "example" : "cloud_owner"
- }
- }
- },
- "SubscriberInfo" : {
- "type" : "object",
- "required" : [ "globalSubscriberId", "subscriberName", "subscriberCommonSiteId" ],
- "properties" : {
- "globalSubscriberId" : {
- "type" : "string",
- "description" : "An ID of a subscriber.",
- "example" : "subscriber_id"
- },
- "subscriberName" : {
- "type" : "string",
- "description" : "The name of a subscriber. If the name is not known, the value must be 'unknown'",
- "example" : "subscriber_name"
- },
- "subscriberCommonSiteId" : {
- "type" : "string",
- "description" : "Id representing a subscriber location",
- "example" : "subscriber_location_id"
- }
- }
- },
- "LicenseInfo" : {
- "type" : "object",
- "required" : [ "licenseDemands" ],
- "properties" : {
- "licenseDemands" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/LicenseDemands"
- },
- "description" : "A list of resources for license selection"
- }
- }
- },
- "LicenseDemands" : {
- "type" : "object",
- "required" : [ "resourceModuleName", "serviceResourceId", "resourceModelInfo" ],
- "properties" : {
- "resourceModuleName" : {
- "type" : "string",
- "description" : "A resource name as defined in a service model.",
- "example" : "service_instance_id"
- },
- "serviceResourceId" : {
- "type" : "string",
- "description" : "A unique resource Id with a local scope between client and OOF.",
- "example" : "service_instance_id"
- },
- "resourceModelInfo" : {
- "$ref" : "#/definitions/ModelMetaData",
- "description" : "Resource model information as defined in a service model."
- },
- "existingLicenses" : {
- "$ref" : "#/definitions/LicenseModel",
- "description" : "Existing license information assigned to a resource."
- }
- }
- },
- "LicenseModel" : {
- "type" : "object",
- "required" : [ "entitlementPoolUUID", "licenseKeyGroupUUID" ],
- "properties" : {
- "entitlementPoolUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "Entitlement pool UUIDs associated with a resource.",
- "example" : "candidateId"
- },
- "licenseKeyGroupUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "License key groups associated with a resource",
- "example" : "candidateId"
- }
- }
- },
- "SynchronousResponse" : {
- "type" : "object",
- "required" : [ "requestId", "transactionId", "requestStatus" ],
- "properties" : {
- "requestId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "A unique Id for an ONAP transaction",
- "example" : "ONAP transaction id"
- },
- "transactionId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "A unique ID to track multiple requests associated with a transaction.",
- "example" : "requests id"
- },
- "statusMessage" : {
- "type" : "string",
- "description" : "Reasoning if a requestStatus is failure.",
- "example" : "requestStatus"
- },
- "requestStatus" : {
- "type" : "string",
- "enum" : [ "success", "failure" ],
- "description" : "The status of a request.",
- "example" : "success"
- }
- }
- },
- "AsynchronousResponse" : {
- "type" : "object",
- "required" : [ "requestId", "transactionId", "requestStatus", "solutions" ],
- "properties" : {
- "requestId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "A unique Id for an ONAP transaction",
- "example" : "ONAP transaction id"
- },
- "transactionId" : {
- "type" : "string",
- "format" : "uuid",
- "description" : "A unique ID to track multiple requests associated with a transaction.",
- "example" : "requests id"
- },
- "statusMessage" : {
- "type" : "string",
- "description" : "Reasoning if a requestStatus is failure.",
- "example" : "requestStatus"
- },
- "requestStatus" : {
- "type" : "string",
- "enum" : [ "success", "failure" ],
- "description" : "The status of a request.",
- "example" : "success"
- },
- "solutions" : {
- "$ref" : "#/definitions/Solutions",
- "description" : "Solutions related to a request."
- }
- }
- },
- "Solutions" : {
- "type" : "object",
- "required" : [ "placementSolutions", "licenseSolutions" ],
- "properties" : {
- "placementSolutions" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/ComprehensiveSolution"
- },
- "description" : "A list of placement solutions."
- },
- "licenseSolutions" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/LicenseSolution"
- },
- "description" : "A list of license solutions."
- }
- }
- },
- "ComprehensiveSolution" : {
- "type" : "object",
- "required" : [ "placementSolutions" ],
- "properties" : {
- "placementSolutions" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/PlacementSolution"
- },
- "description" : "A list of placement solutions."
- }
- }
- },
- "PlacementSolution" : {
- "type" : "object",
- "required" : [ "resourceModuleName", "serviceResourceId", "identifierType", "identifier" ],
- "properties" : {
- "resourceModuleName" : {
- "type" : "string",
- "description" : "The name of a resource as defined in the service model",
- "example" : "resource name"
- },
- "serviceResourceId" : {
- "type" : "string",
- "description" : "A resource Id as defined in a service model.",
- "example" : "resource id"
- },
- "identifierType" : {
- "type" : "string",
- "enum" : [ "service_instance_id" ],
- "description" : "The type of a candidate.",
- "example" : "candidate type"
- },
- "identifier" : {
- "type" : "string",
- "description" : "The id of a candidate.",
- "example" : "candidate id"
- },
- "assignmentInfo" : {
- "type" : "array",
- "items" : {
- "$ref" : "#/definitions/AssignmentInfo"
- },
- "description" : "Additional information related to a candidate."
- }
- }
- },
- "AssignmentInfo" : {
- "type" : "object",
- "required" : [ "key", "value" ],
- "properties" : {
- "key" : {
- "type" : "string",
- "description" : "An attribute name",
- "example" : "attribute name"
- },
- "value" : {
- "type" : "string",
- "description" : "An attribute value.",
- "example" : "attribute value"
- }
- }
- },
- "LicenseSolution" : {
- "type" : "object",
- "required" : [ "resourceModuleName", "serviceResourceId", "entitlementPoolUUID", "licenseKeyGroupUUID", "entitlementPoolInvariantUUID", "licenseKeyGroupInvariantUUID" ],
- "properties" : {
- "resourceModuleName" : {
- "type" : "string",
- "description" : "A resource name as defined in a service",
- "example" : "resource name"
- },
- "serviceResourceId" : {
- "type" : "string",
- "description" : "A resource Id as defined in a service.",
- "example" : "resource Id"
- },
- "entitlementPoolUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "A list of entitlementPoolUUIDs",
- "example" : "entitlementPoolUUID"
- },
- "licenseKeyGroupUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "A list of licenseKeyGroupUUID.",
- "example" : "licenseKeyGroupUUID"
- },
- "entitlementPoolInvariantUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "A list of entitlementPoolInvariantUUID",
- "example" : "entitlementPoolInvariantUUID"
- },
- "licenseKeyGroupInvariantUUID" : {
- "type" : "array",
- "items" : {
- "type" : "string",
- "format" : "uuid"
- },
- "description" : "A list of licenseKeyGroupInvariantUUID",
- "example" : "licenseKeyGroupInvariantUUID"
- }
- }
- },
- "ServiceInfo" : {
- "type" : "object",
- "required" : [ "serviceInstanceId", "modelInfo", "serviceName" ],
- "properties" : {
- "serviceInstanceId" : {
- "type" : "string",
- "description" : "A service instance id associated with a request.",
- "example" : "service_instance_id"
- },
- "modelInfo" : {
- "$ref" : "#/definitions/ModelMetaData",
- "description" : "A list of identifiers."
- },
- "serviceName" : {
- "type" : "string",
- "description" : "The name of a service",
- "example" : "service_name"
- }
- }
- }
- },
- "schemes" : [ "https" ],
- "host" : "virtserver.swaggerhub.com",
- "basePath" : "/oof-osdf/v1"
-} \ No newline at end of file
diff --git a/docs/sections/upgradestrategy.rst b/docs/sections/upgradestrategy.rst
new file mode 100644
index 0000000..6357fac
--- /dev/null
+++ b/docs/sections/upgradestrategy.rst
@@ -0,0 +1,22 @@
+..
+ This work is licensed under a Creative Commons Attribution 4.0
+ International License.
+
+================
+Upgrade Strategy
+================
+
+OSDF can be upgraded in place(remove and replace) or in a blue-green
+strategy.
+
+There is no need for database migration. Since, there is no database
+being used by OSDF.
+
+Supporting Facts
+================
+
+OSDF is a stateless component. It doesn't store any information in the
+database. It holds on to the optimization request in memory only until
+the optimization process is complete. The optimization is done either by
+OSDF itself or other external components(such as HAS) are leveraged for
+optimization.
diff --git a/docs/tox.ini b/docs/tox.ini
new file mode 100644
index 0000000..9d0f3ee
--- /dev/null
+++ b/docs/tox.ini
@@ -0,0 +1,31 @@
+[tox]
+minversion = 1.6
+envlist = docs,docs-linkcheck,docs-spellcheck
+skipsdist = true
+
+[testenv:docs]
+basepython = python3.8
+deps =
+ -r{toxinidir}/requirements-docs.txt
+ -chttps://raw.githubusercontent.com/openstack/requirements/stable/yoga/upper-constraints.txt
+ -chttps://git.onap.org/doc/plain/etc/upper-constraints.onap.txt?h=master
+commands =
+ sphinx-build -q -b html -n -d {envtmpdir}/doctrees {toxinidir} {toxinidir}/_build/html
+
+[testenv:docs-linkcheck]
+basepython = python3.8
+deps =
+ -r{toxinidir}/requirements-docs.txt
+ -chttps://raw.githubusercontent.com/openstack/requirements/stable/yoga/upper-constraints.txt
+ -chttps://git.onap.org/doc/plain/etc/upper-constraints.onap.txt?h=master
+commands =
+ sphinx-build -q -b linkcheck -d {envtmpdir}/doctrees {toxinidir} {toxinidir}/_build/linkcheck
+
+[testenv:docs-spellcheck]
+basepython = python3.8
+deps =
+ -r{toxinidir}/requirements-docs.txt
+ -chttps://raw.githubusercontent.com/openstack/requirements/stable/yoga/upper-constraints.txt
+ -chttps://git.onap.org/doc/plain/etc/upper-constraints.onap.txt?h=master
+commands =
+ sphinx-build -q -b spelling -d {envtmpdir}/doctrees {toxinidir} {toxinidir}/_build/spellcheck
diff --git a/examples/policies/nsi_policies/optimization_nsi_create_new.json b/examples/policies/nsi_policies/optimization_nsi_create_new.json
new file mode 100644
index 0000000..af79be2
--- /dev/null
+++ b/examples/policies/nsi_policies/optimization_nsi_create_new.json
@@ -0,0 +1,37 @@
+{
+ "maximizeCost_{{ service_name }}": {
+ "metadata": {
+ "policy-id": "maximizeCost_{{ service_name }}",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "maximize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "creation_cost",
+ "demand": "{{ service_name }}"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "{{ service_name }}"
+ ],
+ "scope": [
+ "shared,create_new"
+ ],
+ "services": [
+ "{{ service_name }}"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/examples/policies/nsi_policies/optimization_nsi_non_shared.json b/examples/policies/nsi_policies/optimization_nsi_non_shared.json
new file mode 100644
index 0000000..12d7d24
--- /dev/null
+++ b/examples/policies/nsi_policies/optimization_nsi_non_shared.json
@@ -0,0 +1,37 @@
+{
+ "minimizeLatency_{{ service_name }}": {
+ "metadata": {
+ "policy-id": "minimizeLatency_{{ service_name }}",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "latency",
+ "demand": "{{ service_name }}"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "{{ service_name }}"
+ ],
+ "scope": [
+ "non-shared"
+ ],
+ "services": [
+ "{{ service_name }}"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/examples/policies/nsi_policies/optimization_nsi_reuse.json b/examples/policies/nsi_policies/optimization_nsi_reuse.json
new file mode 100644
index 0000000..459cf33
--- /dev/null
+++ b/examples/policies/nsi_policies/optimization_nsi_reuse.json
@@ -0,0 +1,37 @@
+{
+ "minimizeCost_{{ service_name }}": {
+ "metadata": {
+ "policy-id": "minimizeCost_{{ service_name }}",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "creation_cost",
+ "demand": "{{ service_name }}"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "{{ service_name }}"
+ ],
+ "scope": [
+ "shared,reuse"
+ ],
+ "services": [
+ "{{ service_name }}"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/examples/policies/nsi_policies/query_nsi.json b/examples/policies/nsi_policies/query_nsi.json
new file mode 100644
index 0000000..e888a99
--- /dev/null
+++ b/examples/policies/nsi_policies/query_nsi.json
@@ -0,0 +1,69 @@
+{
+ "queryPolicy_{{ service_name }}":{
+ "type":"onap.policies.optimization.service.QueryPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"queryPolicy_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "shared,reuse",
+ "shared,create_new",
+ "non-shared"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "identity":"queryPolicy_{{ service_name }}",
+ "queryProperties":[
+ {
+ "attribute":"latency",
+ "attribute_location":"latency"
+ },
+ {
+ "attribute":"max_number_of_ues",
+ "attribute_location":"max_number_of_ues"
+ },
+ {
+ "attribute":"s_nssai",
+ "attribute_location":"s_nssai"
+ },
+ {
+ "attribute":"resource_sharing_level",
+ "attribute_location":"resource_sharing_level"
+ },
+ {
+ "attribute":"ue_mobility_level",
+ "attribute_location":"ue_mobility_level"
+ },
+ {
+ "attribute":"sst",
+ "attribute_location":"sst"
+ },
+ {
+ "attribute":"AN_latency",
+ "attribute_location":"AN_latency"
+ },
+ {
+ "attribute":"CN_latency",
+ "attribute_location":"CN_latency"
+ },
+ {
+ "attribute":"TN_BH_latency",
+ "attribute_location":"TN_BH_latency"
+ },
+ {
+ "attribute":"model_invariant_id",
+ "attribute_location":"invariantUUID"
+ },
+ {
+ "attribute":"model_version_id",
+ "attribute_location":"UUID"
+ }
+ ]
+ }
+ }
+}
diff --git a/examples/policies/nsi_policies/threshold_nsi.json b/examples/policies/nsi_policies/threshold_nsi.json
new file mode 100644
index 0000000..ef4c362
--- /dev/null
+++ b/examples/policies/nsi_policies/threshold_nsi.json
@@ -0,0 +1,38 @@
+{
+ "Threshold_{{ service_name }}":{
+ "metadata":{
+ "policy-id":"Threshold_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "geography":[
+
+ ],
+ "identity":"Threshold_{{ service_name }}",
+ "resources":[
+ "{{ service_name }}"
+ ],
+ "scope":[
+ "shared,reuse",
+ "shared,create_new",
+ "non-shared"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "thresholdProperties":[
+ {
+ "attribute":"latency",
+ "operator":"lte",
+ "threshold":{
+ "get_param":"latency"
+ },
+ "unit":"ms"
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+}
diff --git a/examples/policies/nsi_policies/vnf_nsi_nonshared.json b/examples/policies/nsi_policies/vnf_nsi_nonshared.json
new file mode 100644
index 0000000..49b1c95
--- /dev/null
+++ b/examples/policies/nsi_policies/vnf_nsi_nonshared.json
@@ -0,0 +1,92 @@
+{
+ "vnfPolicy_{{ service_name }}_non_shared":{
+ "metadata":{
+ "policy-id":"vnfPolicy_{{ service_name }}_non_shared",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_{{ service_name }}",
+ "resources":["{{ service_name }}"],
+ "scope":[
+ "non-shared"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "service_profile": {
+ "latency": {"value": {"get_param": "latency"}, "operator": "lte"},
+ "s_nssai": {"value": {"get_param": "s_nssai"}, "operator": "eq"},
+ "resource_sharing_level": {"value": {"get_param": "resource_sharing_level"}, "operator": "eq"},
+ "ue_mobility_level": {"value": {"get_param": "ue_mobility_level"}, "operator": "eq"},
+ "sst": {"value": {"get_param": "sst"}, "operator": "eq"},
+ "max_number_of_ues": {"value": {"get_param": "max_number_of_ues"}, "operator": "eq"}
+ },
+ "subnets": {
+ "CN":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"CN_latency"},
+ "steps":5
+ },
+ "s_nssai":{
+ "values":[
+ {"get_param": "s_nssai"}
+ ]
+ },
+ "max_number_of_ues": {"values":[{"get_param": "max_number_of_ues"}]},
+ "sst": {"values":[{"get_param": "sst"}]},
+ "resource_sharing_level": {"values":[{"get_param": "resource_sharing_level"}]},
+ "plmn_id_list": {"values":["39-00"]},
+ "survival_time": {"values":["10"]},
+ "ue_mobility_level": {"values":[{"get_param": "ue_mobility_level"}]}
+ },
+ "AN":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"AN_latency"},
+ "steps":5
+ },
+ "s_nssai":{
+ "values":[
+ {"get_param": "s_nssai"}
+ ]
+ },
+ "max_number_of_ues": {"values":[{"get_param": "max_number_of_ues"}]},
+ "sst": {"values":[{"get_param": "sst"}]},
+ "plmn_id_list": {"values":["39-00"]},
+ "survival_time": {"values":["10"]},
+ "resource_sharing_level": {"values":[{"get_param": "resource_sharing_level"}]},
+ "ue_mobility_level": {"values":[{"get_param": "ue_mobility_level"}]}
+ },
+ "TN_BH":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"TN_BH_latency"},
+ "steps":5
+ },
+ "s_nssai": {"values": [{"get_param": "s_nssai"}]},
+ "plmn_id_list": {"values":["39-00"]},
+ "max_bandwidth": {"values":[1000]},
+ "sst": {"values":[{"get_param": "sst"}]}
+ }
+ }
+ },
+ "inventoryProvider":"generator",
+ "inventoryType":"slice_profiles",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation_cost" : 0.9
+ }
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+}
+
diff --git a/examples/policies/nsi_policies/vnf_nsi_notshared.json b/examples/policies/nsi_policies/vnf_nsi_notshared.json
new file mode 100644
index 0000000..afdbd50
--- /dev/null
+++ b/examples/policies/nsi_policies/vnf_nsi_notshared.json
@@ -0,0 +1,121 @@
+{
+ "vnfPolicy_{{ service_name }}_not_shared":{
+ "metadata":{
+ "policy-id":"vnfPolicy_{{ service_name }}_not_shared",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_{{ service_name }}",
+ "resources":["{{ service_name }}"],
+ "scope":[
+ "non-shared"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "service_profile": {
+ "latency": {"value": {"get_param": "latency"}, "operator": "lte"},
+ "max_throughput": {"value": {"get_param": "max_throughput"}, "operator": "gte"},
+ "max_number_of_ues": {"value": {"get_param": "max_number_of_ues"}, "operator": "gte"},
+ "terminal_density": {"value": {"get_param": "terminal_density"}, "operator": "gte"},
+ "s_nssai_list": {"value": {"get_param": "s_nssai_list"}, "operator": "eq"},
+ "plmn_id_list": {"value": {"get_param": "plmn_id_list"}, "operator": "eq"}
+ },
+ "subnets": {
+ "AN_NF":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"AN_NF_latency"},
+ "steps":1
+ },
+ "max_throughput":{
+ "values":[
+ {"get_param": "AN_NF_max_throughput"}
+ ]
+ },
+ "max_number_of_ues":{
+ "values":[
+ {"get_param": "AN_NF_max_number_of_ues"}
+ ]
+ },
+ "terminal_density":{
+ "values":[
+ {"get_param": "AN_NF_terminal_density"}
+ ]
+ },
+ "s_nssai_list":{
+ "values":[
+ {"get_param": "s_nssai_list"}
+ ]
+ },
+ "plmn_id_list":{
+ "values":[
+ {"get_param": "plmn_id_list"}
+ ]
+ }
+ },
+ "TN_FH":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"TN_FH_latency"},
+ "steps":1
+ },
+ "max_throughput":{
+ "values":[
+ {"get_param": "TN_FH_max_throughput"}
+ ]
+ },
+ "s_nssai_list":{
+ "values":[
+ {"get_param": "s_nssai_list"}
+ ]
+ },
+ "plmn_id_list":{
+ "values":[
+ {"get_param": "plmn_id_list"}
+ ]
+ }
+ },
+ "TN_MH":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"TN_MH_latency"},
+ "steps":1
+ },
+ "max_throughput":{
+ "values":[
+ {"get_param": "TN_MH_max_throughput"}
+ ]
+ },
+ "s_nssai_list":{
+ "values":[
+ {"get_param": "s_nssai_list"}
+ ]
+ },
+ "plmn_id_list":{
+ "values":[
+ {"get_param": "plmn_id_list"}
+ ]
+ }
+ }
+ }
+ },
+ "inventoryProvider":"generator",
+ "inventoryType":"slice_profiles",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation_cost" : 0.9
+ }
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+}
+
diff --git a/examples/policies/nsi_policies/vnf_nsi_shared.json b/examples/policies/nsi_policies/vnf_nsi_shared.json
new file mode 100644
index 0000000..cce2f73
--- /dev/null
+++ b/examples/policies/nsi_policies/vnf_nsi_shared.json
@@ -0,0 +1,105 @@
+{
+ "vnfPolicy_{{ service_name }}":{
+ "metadata":{
+ "policy-id":"vnfPolicy_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_{{ service_name }}",
+ "resources":["{{ service_name }}"],
+ "scope":[
+ "shared,reuse",
+ "shared,create_new"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "modelInvariantId":{"get_param": "model_invariant_id"},
+ "modelVersionId":{"get_param": "model_version_id"},
+ "service-role":"nsi"
+ },
+ "inventoryProvider":"aai",
+ "inventoryType":"nsi",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation_cost" : 0.1
+ }
+ },
+ {
+ "attributes":{
+ "service_profile": {
+ "latency": {"value": {"get_param": "latency"}, "operator": "lte"},
+ "s_nssai": {"value": {"get_param": "s_nssai"}, "operator": "eq"},
+ "resource_sharing_level": {"value": {"get_param": "resource_sharing_level"}, "operator": "eq"},
+ "ue_mobility_level": {"value": {"get_param": "ue_mobility_level"}, "operator": "eq"},
+ "sst": {"value": {"get_param": "sst"}, "operator": "eq"},
+ "max_number_of_ues": {"value": {"get_param": "max_number_of_ues"}, "operator": "eq"}
+ },
+ "subnets": {
+ "CN":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"CN_latency"},
+ "steps":5
+ },
+ "s_nssai":{
+ "values":[
+ {"get_param": "s_nssai"}
+ ]
+ },
+ "sst": {"values":[{"get_param": "sst"}]},
+ "resource_sharing_level": {"values":[{"get_param": "resource_sharing_level"}]},
+ "plmn_id_list": {"values":["39-00"]},
+ "survival_time": {"values":["10"]},
+ "max_number_of_ues": {"values":[{"get_param": "max_number_of_ues"}]},
+ "ue_mobility_level": {"values":[{"get_param": "ue_mobility_level"}]}
+ },
+ "AN":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"AN_latency"},
+ "steps":5
+ },
+ "s_nssai":{
+ "values":[
+ {"get_param": "s_nssai"}
+ ]
+ },
+ "sst": {"values":[{"get_param": "sst"}]},
+ "plmn_id_list": {"values":["39-00"]},
+ "survival_time": {"values":["10"]},
+ "max_number_of_ues": {"values":[{"get_param": "max_number_of_ues"}]},
+ "resource_sharing_level": {"values":[{"get_param": "resource_sharing_level"}]},
+ "ue_mobility_level": {"values":[{"get_param": "ue_mobility_level"}]}
+ },
+ "TN_BH":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"TN_BH_latency"},
+ "steps":5
+ },
+ "s_nssai": {"values":[{"get_param": "s_nssai"}]},
+ "max_bandwidth": {"values":[1000]},
+ "plmn_id_list": {"values":["39-00"]},
+ "sst": {"values":[{"get_param": "sst"}]}
+ }
+ }
+ },
+ "inventoryProvider":"generator",
+ "inventoryType":"slice_profiles",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation_cost" : 0.9
+ }
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+}
diff --git a/examples/policies/nssi_policies/optimization_nssi.json b/examples/policies/nssi_policies/optimization_nssi.json
new file mode 100644
index 0000000..9d744e9
--- /dev/null
+++ b/examples/policies/nssi_policies/optimization_nssi.json
@@ -0,0 +1,37 @@
+{
+ "{{ goal }}_{{ attribute }}_{{ service_name }}": {
+ "metadata": {
+ "policy-id": "{{ goal }}_{{ attribute }}_{{ service_name }}",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "{{ goal }}",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "{{ attribute }}",
+ "demand": "{{ service_name }}"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "{{ service_name }}"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "{{ service_name }}"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/examples/policies/nssi_policies/query_nssi.json b/examples/policies/nssi_policies/query_nssi.json
new file mode 100644
index 0000000..c5eea26
--- /dev/null
+++ b/examples/policies/nssi_policies/query_nssi.json
@@ -0,0 +1,39 @@
+{
+ "queryPolicy_{{ service_name }}":{
+ "type":"onap.policies.optimization.service.QueryPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"queryPolicy_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "identity":"queryPolicy_{{ service_name }}",
+ "queryProperties":[
+ {
+ "attribute":"latency",
+ "attribute_location":"latency"
+ },
+ {
+ "attribute":"reliability",
+ "attribute_location":"reliability"
+ },
+ {
+ "attribute":"model_invariant_id",
+ "attribute_location":"invariantUUID"
+ },
+ {
+ "attribute":"model_version_id",
+ "attribute_location":"UUID"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/examples/policies/nssi_policies/threshold_nssi.json b/examples/policies/nssi_policies/threshold_nssi.json
new file mode 100644
index 0000000..f7b7ff6
--- /dev/null
+++ b/examples/policies/nssi_policies/threshold_nssi.json
@@ -0,0 +1,44 @@
+{
+ "Threshold_{{ service_name }}":{
+ "metadata":{
+ "policy-id":"Threshold_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "geography":[
+
+ ],
+ "identity":"Threshold_{{ service_name }}",
+ "resources":[
+ "{{ service_name }}"
+ ],
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "thresholdProperties":[
+ {
+ "attribute":"latency",
+ "operator":"lte",
+ "threshold":{
+ "get_param":"latency"
+ },
+ "unit":"ms"
+ },
+ {
+ "attribute":"reliability",
+ "operator":"gte",
+ "threshold":{
+ "get_param":"reliability"
+ },
+ "unit":""
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+} \ No newline at end of file
diff --git a/examples/policies/nssi_policies/vnf_nssi.json b/examples/policies/nssi_policies/vnf_nssi.json
new file mode 100644
index 0000000..fd54b7b
--- /dev/null
+++ b/examples/policies/nssi_policies/vnf_nssi.json
@@ -0,0 +1,37 @@
+{
+ "vnfPolicy_{{ service_name }}":{
+ "metadata":{
+ "policy-id":"vnfPolicy_{{ service_name }}",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_{{ service_name }}",
+ "resources":[
+ "{{ service_name }}"
+ ],
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "{{ service_name }}"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "modelInvariantId":{"get_param": "model_invariant_id"},
+ "modelVersionId":{"get_param": "model_version_id"},
+ "service-function":"shared",
+ "service-role":"nssi"
+ },
+ "inventoryProvider":"aai",
+ "inventoryType":"nssi",
+ "unique":"true"
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+} \ No newline at end of file
diff --git a/examples/policies/nst_policies/attribute_policy_nst.json b/examples/policies/nst_policies/attribute_policy_nst.json
new file mode 100644
index 0000000..da2e5fe
--- /dev/null
+++ b/examples/policies/nst_policies/attribute_policy_nst.json
@@ -0,0 +1,41 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "topology_template": {
+ "policies": [
+{
+ "Threshold_nst": {
+ "metadata": {
+ "policy-id": "Threshold_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "nst_Threshold",
+ "resources": [
+ "nst"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ],
+ "thresholdProperties": [
+ {
+ "attribute": "latency",
+ "operator": "lte",
+ "threshold": {
+ "get_param": "latency"
+ },
+ "unit": "ms"
+ }
+ ]
+ },
+ "type": "onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version": "1.0.0",
+ "version": "1.0.0"
+ }
+}
+ ]
+ }
+}
diff --git a/examples/policies/nst_policies/optimization_policy_nst.json b/examples/policies/nst_policies/optimization_policy_nst.json
new file mode 100644
index 0000000..09737ad
--- /dev/null
+++ b/examples/policies/nst_policies/optimization_policy_nst.json
@@ -0,0 +1,44 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "topology_template": {
+ "policies": [
+{
+ "nst_minimize_latency": {
+ "metadata": {
+ "policy-id": "nst_minimize_latency",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "latency",
+ "demand": "nst"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "nst"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
+ ]
+ }
+}
diff --git a/examples/policies/nst_policies/query_policy_nst.json b/examples/policies/nst_policies/query_policy_nst.json
new file mode 100644
index 0000000..2ce441b
--- /dev/null
+++ b/examples/policies/nst_policies/query_policy_nst.json
@@ -0,0 +1,38 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "topology_template": {
+ "policies": [
+{
+ "queryPolicy_nst": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "queryPolicy_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ],
+ "geography": [],
+ "identity": "queryPolicy_nst",
+ "queryProperties": [
+ {
+ "attribute": "latency",
+ "attribute_location": "latency"
+ },
+ {
+ "attribute": "areaTrafficCapDL",
+ "attribute_location": "areaTrafficCapDL"
+ }
+ ]
+ }
+ }
+}
+ ]
+ }
+}
diff --git a/examples/policies/nst_policies/vnf_policy_nst.json b/examples/policies/nst_policies/vnf_policy_nst.json
new file mode 100644
index 0000000..422030c
--- /dev/null
+++ b/examples/policies/nst_policies/vnf_policy_nst.json
@@ -0,0 +1,41 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "topology_template": {
+ "policies": [
+{
+ "vnfPolicy_nst": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "vnfPolicy_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "resources": [
+ "nst"
+ ],
+ "services": [
+ "nst"
+ ],
+ "identity": "vnf_nst",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "inventoryType": "nst",
+ "unique": "true",
+ "attributes": {
+ "model-role": "NST"
+ }
+ }
+ ]
+ }
+ }
+}
+ ]
+ }
+}
diff --git a/examples/policies/policy_types/optimization_v2.json b/examples/policies/policy_types/optimization_v2.json
new file mode 100644
index 0000000..ea5ca6f
--- /dev/null
+++ b/examples/policies/policy_types/optimization_v2.json
@@ -0,0 +1,61 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "policy_types": {
+ "onap.policies.optimization.resource.OptimizationPolicy": {
+ "derived_from": "onap.policies.optimization.Resource",
+ "version": "2.0.0",
+ "name": "onap.policies.optimization.resource.OptimizationPolicy",
+ "properties": {
+ "goal": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "string",
+ "constraints": [
+ {
+ "valid_values": [
+ "minimize",
+ "maximize"
+ ]
+ }
+ ]
+ }
+ },
+ "operation_function": {
+ "type": "policy.data.operation_function_properties",
+ "required": true
+ }
+ }
+ }
+ },
+ "data_types": {
+ "policy.data.operation_function_properties": {
+ "derived_from": "tosca.nodes.Root",
+ "properties": {
+ "operands": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "map"
+ }
+ },
+ "operator": {
+ "type": "string",
+ "required": true,
+ "entry_schema": {
+ "type": "string",
+ "constraints": [
+ {
+ "valid_values": [
+ "sum",
+ "min",
+ "max"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/examples/policies/policy_types/threshold.json b/examples/policies/policy_types/threshold.json
new file mode 100644
index 0000000..60c73fa
--- /dev/null
+++ b/examples/policies/policy_types/threshold.json
@@ -0,0 +1,56 @@
+{
+ "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+ "policy_types": {
+ "onap.policies.optimization.resource.ThresholdPolicy": {
+ "derived_from": "onap.policies.optimization.Resource",
+ "version": "1.0.0",
+ "properties": {
+ "applicableResources": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "string",
+ "constraints": [
+ {
+ "valid_values": [
+ "any",
+ "all"
+ ]
+ }
+ ]
+ }
+ },
+ "thresholdProperties": {
+ "type": "list",
+ "required": true,
+ "entry_schema": {
+ "type": "policy.data.thresholdProperties_properties"
+ }
+ }
+ }
+ }
+ },
+ "data_types": {
+ "policy.data.thresholdProperties_properties": {
+ "derived_from": "tosca.nodes.Root",
+ "properties": {
+ "attribute": {
+ "type": "string",
+ "required": true
+ },
+ "operator": {
+ "type": "string",
+ "required": true
+ },
+ "threshold": {
+ "type": "float",
+ "required": true
+ },
+ "unit": {
+ "type": "string",
+ "required": false
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/examples/policies/policy_utils.py b/examples/policies/policy_utils.py
new file mode 100644
index 0000000..0c1b595
--- /dev/null
+++ b/examples/policies/policy_utils.py
@@ -0,0 +1,192 @@
+from jinja2 import Template
+import json
+import os
+import requests
+import sys
+
+BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+
+HEADERS = {'Content-Type': 'application/json'}
+AUTH = requests.auth.HTTPBasicAuth('healthcheck', 'zb!XztG34')
+
+
+def get_tosca_policy(policy):
+ pol = json.loads(policy)
+ tosca_policy = {
+ 'tosca_definitions_version': 'tosca_simple_yaml_1_1_0',
+ 'topology_template': {
+ 'policies': [pol]
+ }
+ }
+ return json.dumps(tosca_policy)
+
+def gen_policy(template_dir, gen_dir, filename, jinja_args):
+ with open(os.path.join(template_dir, filename), 'r') as file:
+ contents = file.read()
+ tm = Template(contents)
+ gen = tm.render(jinja_args)
+ tosca_policy = get_tosca_policy(gen)
+ with open(os.path.join(gen_dir, filename), 'w') as file:
+ file.write(tosca_policy)
+
+def create_and_push_policies(policy_dir):
+ for filename in os.listdir(policy_dir):
+ if filename.endswith('.json'):
+ with open(os.path.join(policy_dir, filename), 'r') as file:
+ data = json.loads(file.read())
+ metadata = create_policy(data)
+ if metadata:
+ push_policy(metadata)
+
+def delete_policies(policy_dir):
+ for filename in os.listdir(policy_dir):
+ if filename.endswith('.json'):
+ with open(os.path.join(policy_dir, filename), 'r') as file:
+ data = json.loads(file.read())
+ policy_id = list(data['topology_template']['policies'][0].keys())[0]
+ undeploy_policy(policy_id)
+ metadata = delete_policy(data)
+
+def create_policy(data):
+ policy = data['topology_template']['policies'][0]
+ content = policy[list(policy.keys())[0]]
+ policy_type = content['type']
+ type_version = content['type_version']
+ policy_url = "https://policy-api:6969"
+ path = '/policy/api/v1/policytypes/{}/versions/{}/policies'.format(policy_type, type_version)
+ url = policy_url + path
+ try:
+ response = requests.post(url, headers=HEADERS, auth=AUTH, data=json.dumps(data), verify=False)
+ except Exception as e:
+ print(str(e))
+ return None
+ if response.status_code == 200:
+ print('Policy {} created'.format(content['metadata']['policy-id']))
+ return content['metadata']
+ else:
+ print(response.content)
+ return None
+
+def push_policy(metadata):
+ data = {'policies': [metadata]}
+ policy_url = "https://policy-pap:6969"
+ path = '/policy/pap/v1/pdps/policies'
+ url = policy_url + path
+ try:
+ response = requests.post(url, headers=HEADERS, auth=AUTH, data=json.dumps(data), verify=False)
+ except Exception as e:
+ print(str(e))
+ print("Cannot push policy {}".format(metadata['policy-id']))
+ if response.status_code == 200:
+ print("Policy {} pushed".format(metadata['policy-id']))
+ else:
+ print(response.content)
+
+def undeploy_policy(policy_id):
+ policy_url = "https://policy-pap:6969"
+ path = '/policy/pap/v1/pdps/policies/{}'.format(policy_id)
+ url = policy_url + path
+ try:
+ response = requests.delete(url, headers=HEADERS, auth=AUTH, verify=False)
+ except Exception as e:
+ print(str(e))
+ print("Cannot undeploy policy {}".format(policy_id))
+ if response.status_code == 200:
+ print("Policy {} undeployed".format(policy_id))
+ else:
+ print(response.content)
+
+def delete_policy(data):
+ policy = data['topology_template']['policies'][0]
+ content = policy[list(policy.keys())[0]]
+ policy_type = content['type']
+ type_version = content['type_version']
+ policy_id = content['metadata']['policy-id']
+ version = content['version']
+ policy_url = "https://policy-api:6969"
+ path = '/policy/api/v1/policytypes/{}/versions/{}/policies/{}/versions/{}'.format(policy_type, type_version, policy_id, version)
+ url = policy_url + path
+ try:
+ response = requests.delete(url, headers=HEADERS, auth=AUTH, data=json.dumps(data), verify=False)
+ except Exception as e:
+ print(str(e))
+ return None
+ if response.status_code == 200:
+ print('Policy {} deleted'.format(content['metadata']['policy-id']))
+ return content['metadata']
+ else:
+ print(response.content)
+ return None
+
+def generate_nssi_policies(jinja_args):
+ template_dir = BASE_DIR + 'nssi_policies'
+ gen_dir = BASE_DIR + 'gen_nssi_policies'
+
+ if not os.path.exists(gen_dir):
+ os.mkdir(gen_dir)
+
+ for filename in os.listdir(template_dir):
+ if filename.endswith('.json'):
+ gen_policy(template_dir, gen_dir, filename, jinja_args)
+
+def generate_nsi_policies(jinja_args):
+ template_dir = BASE_DIR + 'nsi_policies'
+ gen_dir = BASE_DIR + 'gen_nsi_policies'
+
+ if not os.path.exists(gen_dir):
+ os.mkdir(gen_dir)
+
+ for filename in os.listdir(template_dir):
+ if filename.endswith('.json'):
+ gen_policy(template_dir, gen_dir, filename, jinja_args)
+
+def create_policy_types(policy_dir):
+ for filename in os.listdir(policy_dir):
+ if filename.endswith('.json'):
+ with open(os.path.join(policy_dir, filename), 'r') as file:
+ data = json.loads(file.read())
+ create_policy_type(data)
+
+def create_policy_type(data):
+ policy_url = "https://policy-api:6969"
+ path = '/policy/api/v1/policytypes'
+ url = policy_url + path
+ try:
+ response = requests.post(url, headers=HEADERS, auth=AUTH, data=json.dumps(data), verify=False)
+ except Exception as e:
+ print(str(e))
+ return None
+ if response.status_code == 200:
+ print('Policy type created')
+ else:
+ print(response.content)
+ return None
+
+
+action = sys.argv[1]
+
+if action == "generate_nssi_policies":
+ jinja_args = {
+ 'service_name': sys.argv[2],
+ 'goal': sys.argv[3],
+ 'attribute': sys.argv[4]
+ }
+ generate_nssi_policies(jinja_args)
+
+elif action == "create_and_push_policies":
+ policy_dir = sys.argv[2]
+ create_and_push_policies(policy_dir)
+
+elif action == "delete_policies":
+ policy_dir = sys.argv[2]
+ delete_policies(policy_dir)
+
+elif action == "generate_nsi_policies":
+ jinja_args = {
+ 'service_name': sys.argv[2]
+ }
+ generate_nsi_policies(jinja_args)
+
+elif action == "create_policy_types":
+ policy_dir = sys.argv[2]
+ create_policy_types(policy_dir) \ No newline at end of file
diff --git a/examples/policies/requirements.txt b/examples/policies/requirements.txt
new file mode 100644
index 0000000..1c579e7
--- /dev/null
+++ b/examples/policies/requirements.txt
@@ -0,0 +1 @@
+jinja2 \ No newline at end of file
diff --git a/osdf/__init__.py b/osdf/__init__.py
index c33639e..8036d89 100755
--- a/osdf/__init__.py
+++ b/osdf/__init__.py
@@ -20,11 +20,12 @@
from jinja2 import Template
-
end_point_auth_mapping = { # map a URL endpoint to auth group
"cmscheduler": "CMScheduler",
"placement": "Placement",
- "pci": "PCIOpt"
+ "pci": "PCIOpt",
+ "optmodel": "OptEngine",
+ "optengine": "OptEngine"
}
userid_suffix, passwd_suffix = "Username", "Password"
diff --git a/osdf/adapters/aaf/aaf_authentication.py b/osdf/adapters/aaf/aaf_authentication.py
index 26eac29..b9aa510 100644
--- a/osdf/adapters/aaf/aaf_authentication.py
+++ b/osdf/adapters/aaf/aaf_authentication.py
@@ -17,12 +17,14 @@
#
import base64
-import re
-from datetime import datetime, timedelta
+from datetime import datetime
+from datetime import timedelta
from flask import request
+import re
from osdf.config.base import osdf_config
-from osdf.logging.osdf_logging import error_log, debug_log
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
from osdf.utils.interfaces import RestClient
AUTHZ_PERMS_USER = '{}/authz/perms/user/{}'
@@ -43,7 +45,6 @@ def authenticate(uid, passwd):
return has_valid_role(perms)
except Exception as exp:
error_log.error("Error Authenticating the user {} : {}: ".format(uid, exp))
- pass
return False
@@ -57,27 +58,38 @@ else return false
def has_valid_role(perms):
aaf_user_roles = deploy_config['aaf_user_roles']
+ aaf_roles = get_role_list(perms)
+
for roles in aaf_user_roles:
path_perm = roles.split(':')
uri = path_perm[0]
- role = path_perm[1].split('|')[0]
- if re.search(uri, request.path) and perms:
- roles = perms.get('roles')
- if roles:
- perm_list = roles.get('perm')
- for p in perm_list:
- if role == p['type']:
- return True
+ perm = path_perm[1].split('|')
+ p = (perm[0], perm[1], perm[2].split()[0])
+ if re.search(uri, request.path) and p in aaf_roles:
+ return True
return False
+
"""
-Make the remote aaf api call if user is not in the cache.
+Build a list of roles tuples from the AAF response.
-Return the perms
"""
+
+
+def get_role_list(perms):
+ role_list = []
+ if perms:
+ roles = perms.get('roles')
+ if roles:
+ perm = roles.get('perm', [])
+ for p in perm:
+ role_list.append((p['type'], p['instance'], p['action']))
+ return role_list
+
+
def get_aaf_permissions(uid, passwd):
key = base64.b64encode(bytes("{}_{}".format(uid, passwd), "ascii"))
- time_delta = timedelta(hours=deploy_config.get('aaf_cache_expiry_hrs', 3))
+ time_delta = timedelta(minutes=deploy_config.get('aaf_cache_expiry_mins', 5))
perms = perm_cache.get(key)
@@ -91,8 +103,8 @@ def get_aaf_permissions(uid, passwd):
def remote_api(passwd, uid):
- headers = {"Accept": "application/Users+xml;q=1.0;charset=utf-8;version=2.0,text/xml;q=1.0;version=2.0",
- "Accept": "application/Users+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*/*;q=1.0"}
+ headers = {"Accept": "application/Users+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,"
+ "*/*;q=1.0"}
url = AUTHZ_PERMS_USER.format(deploy_config['aaf_url'], uid)
rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug,
req_id='aaf_user_id')
diff --git a/osdf/adapters/aaf/sms.py b/osdf/adapters/aaf/sms.py
index 9c7af51..031fee4 100644
--- a/osdf/adapters/aaf/sms.py
+++ b/osdf/adapters/aaf/sms.py
@@ -1,6 +1,7 @@
#
# -------------------------------------------------------------------------
# Copyright (c) 2018 Intel Corporation Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,9 +22,12 @@
from onapsmsclient import Client
-import osdf.config.loader as config_loader
+import osdf.config.base as cfg_base
from osdf.config.base import osdf_config
+import osdf.config.credentials as creds
+import osdf.config.loader as config_loader
from osdf.logging.osdf_logging import debug_log
+from osdf.utils import cipherUtils
config_spec = {
"preload_secrets": "config/preload_secrets.yaml"
@@ -31,9 +35,12 @@ config_spec = {
def preload_secrets():
- """ This is intended to load the secrets required for testing Application
- Actual deployment will have a preload script. Make sure the config is
- in sync"""
+ """preload_secrets()
+
+ This is intended to load the secrets required for testing Application
+ Actual deployment will have a preload script. Make sure the config is
+ in sync
+ """
preload_config = config_loader.load_config_file(
config_spec.get("preload_secrets"))
domain = preload_config.get("domain")
@@ -41,6 +48,9 @@ def preload_secrets():
sms_url = config["aaf_sms_url"]
timeout = config["aaf_sms_timeout"]
cacert = config["aaf_ca_certs"]
+ if not sms_url:
+ debug_log.debug("SMS Disabled")
+ return
sms_client = Client(url=sms_url, timeout=timeout, cacert=cacert)
domain_uuid = sms_client.createDomain(domain)
debug_log.debug(
@@ -60,58 +70,80 @@ def retrieve_secrets():
timeout = config["aaf_sms_timeout"]
cacert = config["aaf_ca_certs"]
domain = config["secret_domain"]
- sms_client = Client(url=sms_url, timeout=timeout, cacert=cacert)
- secrets = sms_client.getSecretNames(domain)
- for secret in secrets:
- values = sms_client.getSecret(domain, secret)
- secret_dict[secret] = values
- debug_log.debug("Secret Dictionary Retrieval Success")
+ if sms_url:
+ sms_client = Client(url=sms_url, timeout=timeout, cacert=cacert)
+ secrets = sms_client.getSecretNames(domain)
+ for secret in secrets:
+ values = sms_client.getSecret(domain, secret)
+ secret_dict[secret] = values
+ debug_log.debug("Secret Dictionary Retrieval Success")
+ else:
+ debug_log.debug("SMS Disabled. Secrets not loaded")
return secret_dict
def load_secrets():
config = osdf_config.deployment
secret_dict = retrieve_secrets()
- config['soUsername'] = secret_dict['so']['UserName']
- config['soPassword'] = secret_dict['so']['Password']
- config['conductorUsername'] = secret_dict['conductor']['UserName']
- config['conductorPassword'] = secret_dict['conductor']['Password']
- config['policyPlatformUsername'] = secret_dict['policyPlatform']['UserName']
- config['policyPlatformPassword'] = secret_dict['policyPlatform']['Password']
- config['policyClientUsername'] = secret_dict['policyClient']['UserName']
- config['policyClientPassword'] = secret_dict['policyClient']['Password']
- config['messageReaderAafUserId'] = secret_dict['dmaap']['UserName']
- config['messageReaderAafPassword'] = secret_dict['dmaap']['Password']
- config['sdcUsername'] = secret_dict['sdc']['UserName']
- config['sdcPassword'] = secret_dict['sdc']['Password']
- config['osdfPlacementUsername'] = secret_dict['osdfPlacement']['UserName']
- config['osdfPlacementPassword'] = secret_dict['osdfPlacement']['Password']
- config['osdfPlacementSOUsername'] = secret_dict['osdfPlacementSO']['UserName']
- config['osdfPlacementSOPassword'] = secret_dict['osdfPlacementSO']['Password']
- config['osdfPlacementVFCUsername'] = secret_dict['osdfPlacementVFC']['UserName']
- config['osdfPlacementVFCPassword'] = secret_dict['osdfPlacementVFC']['Password']
- config['osdfCMSchedulerUsername'] = secret_dict['osdfCMScheduler']['UserName']
- config['osdfCMSchedulerPassword'] = secret_dict['osdfCMScheduler']['Password']
- config['configDbUserName'] = secret_dict['configDb']['UserName']
- config['configDbPassword'] = secret_dict['configDb']['Password']
- config['pciHMSUsername'] = secret_dict['pciHMS']['UserName']
- config['pciHMSPassword'] = secret_dict['pciHMS']['Password']
- config['osdfPCIOptUsername'] = secret_dict['osdfPCIOpt']['UserName']
- config['osdfPCIOptPassword'] = secret_dict['osdfPCIOpt']['Password']
+ if secret_dict:
+ config['soUsername'] = secret_dict['so']['UserName']
+ config['soPassword'] = decrypt_pass(secret_dict['so']['Password'])
+ config['conductorUsername'] = secret_dict['conductor']['UserName']
+ config['conductorPassword'] = decrypt_pass(secret_dict['conductor']['Password'])
+ config['policyPlatformUsername'] = secret_dict['policyPlatform']['UserName']
+ config['policyPlatformPassword'] = decrypt_pass(secret_dict['policyPlatform']['Password'])
+ config['policyClientUsername'] = secret_dict['policyPlatform']['UserName']
+ config['policyClientPassword'] = decrypt_pass(secret_dict['policyPlatform']['Password'])
+ config['messageReaderAafUserId'] = secret_dict['dmaap']['UserName']
+ config['messageReaderAafPassword'] = decrypt_pass(secret_dict['dmaap']['Password'])
+ config['sdcUsername'] = secret_dict['sdc']['UserName']
+ config['sdcPassword'] = decrypt_pass(secret_dict['sdc']['Password'])
+ config['osdfPlacementUsername'] = secret_dict['osdfPlacement']['UserName']
+ config['osdfPlacementPassword'] = decrypt_pass(secret_dict['osdfPlacement']['Password'])
+ config['osdfPlacementSOUsername'] = secret_dict['osdfPlacementSO']['UserName']
+ config['osdfPlacementSOPassword'] = decrypt_pass(secret_dict['osdfPlacementSO']['Password'])
+ config['osdfPlacementVFCUsername'] = secret_dict['osdfPlacementVFC']['UserName']
+ config['osdfPlacementVFCPassword'] = decrypt_pass(secret_dict['osdfPlacementVFC']['Password'])
+ config['osdfCMSchedulerUsername'] = secret_dict['osdfCMScheduler']['UserName']
+ config['osdfCMSchedulerPassword'] = decrypt_pass(secret_dict['osdfCMScheduler']['Password'])
+ config['configDbUserName'] = secret_dict['configDb']['UserName']
+ config['configDbPassword'] = decrypt_pass(secret_dict['configDb']['Password'])
+ config['pciHMSUsername'] = secret_dict['pciHMS']['UserName']
+ config['pciHMSPassword'] = decrypt_pass(secret_dict['pciHMS']['Password'])
+ config['osdfPCIOptUsername'] = secret_dict['osdfPCIOpt']['UserName']
+ config['osdfPCIOptPassword'] = decrypt_pass(secret_dict['osdfPCIOpt']['Password'])
+ config['osdfOptEngineUsername'] = secret_dict['osdfOptEngine']['UserName']
+ config['osdfOptEnginePassword'] = decrypt_pass(secret_dict['osdfOptEngine']['Password'])
+ cfg_base.http_basic_auth_credentials = creds.load_credentials(osdf_config)
+ cfg_base.dmaap_creds = creds.dmaap_creds()
+
+
+def decrypt_pass(passwd):
+ config = osdf_config.deployment
+ if not config.get('appkey') or passwd == '' or passwd == 'NA':
+ return passwd
+ else:
+ return cipherUtils.AESCipher.get_instance().decrypt(passwd)
def delete_secrets():
- """ This is intended to delete the secrets for a clean initialization for
- testing Application. Actual deployment will have a preload script.
- Make sure the config is in sync"""
+ """delete_secrets()
+
+ This is intended to delete the secrets for a clean initialization for
+ testing Application. Actual deployment will have a preload script.
+ Make sure the config is in sync
+ """
config = osdf_config.deployment
sms_url = config["aaf_sms_url"]
timeout = config["aaf_sms_timeout"]
cacert = config["aaf_ca_certs"]
domain = config["secret_domain"]
- sms_client = Client(url=sms_url, timeout=timeout, cacert=cacert)
- ret_val = sms_client.deleteDomain(domain)
- debug_log.debug("Clean up complete")
+ if sms_url:
+ sms_client = Client(url=sms_url, timeout=timeout, cacert=cacert)
+ ret_val = sms_client.deleteDomain(domain)
+ debug_log.debug("Clean up complete")
+ else:
+ debug_log.debug("SMS Disabled. Secrets delete skipped")
return ret_val
diff --git a/osdf/adapters/aai/_init_.py b/osdf/adapters/aai/_init_.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/osdf/adapters/aai/_init_.py
diff --git a/osdf/adapters/aai/fetch_aai_data.py b/osdf/adapters/aai/fetch_aai_data.py
new file mode 100644
index 0000000..170d5e5
--- /dev/null
+++ b/osdf/adapters/aai/fetch_aai_data.py
@@ -0,0 +1,90 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import requests
+from requests.auth import HTTPBasicAuth
+from requests import RequestException
+
+from osdf.logging.osdf_logging import debug_log
+
+AAI_HEADERS = {
+ "X-TransactionId": "9999",
+ "X-FromAppId": "OOF",
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+}
+
+AUTH = HTTPBasicAuth("AAI", "AAI")
+
+
+class AAIException(Exception):
+ pass
+
+
+def get_aai_data(request_json, osdf_config):
+
+ """Get the response from AAI
+
+ :param request_json: requestjson
+ :param osdf_config: configuration specific to OSDF app
+ :return:response body from AAI
+ """
+
+ nxi_id = request_json["NxIId"]
+ config = osdf_config.deployment
+ aai_url = config["aaiUrl"]
+ aai_req_url = aai_url + config["aaiServiceInstanceUrl"] + nxi_id + "?depth=2"
+
+ try:
+ debug_log.debug("aai request: {}".format(aai_req_url))
+ response = requests.get(aai_req_url, headers=AAI_HEADERS, auth=AUTH, verify=False)
+ debug_log.debug("aai response: {}".format(response.json()))
+ except RequestException as e:
+ raise AAIException("Request exception was encountered {}".format(e))
+
+ if response.status_code == 200:
+ return response.json()
+ else:
+ raise AAIException("Error response recieved from AAI for the request {}".format(aai_req_url))
+
+
+def execute_dsl_query(query, format, osdf_config):
+ """Get the response from AAI
+
+ :param query: dsl query to be executed
+ :param format format of the output
+ :param osdf_config: configuration specific to OSDF app
+ :return:response body from AAI
+ """
+ config = osdf_config.deployment
+ dsl_url = config["aaiUrl"] + config["dslQueryPath"] + format
+
+ data = json.dumps({'dsl': query})
+ debug_log.debug("aai dsl request: {}".format(data))
+ try:
+ response = requests.put(dsl_url, data=data, headers=AAI_HEADERS, auth=AUTH, verify=False)
+ debug_log.debug("aai dsl response: {}".format(response))
+ except RequestException as ex:
+ raise AAIException("Request exception was encountered {}".format(ex))
+
+ if response.status_code == 200:
+ return response.json()
+ else:
+ raise AAIException("Response code other than 200 from AAI: {} {}".format(response.status_code,
+ response.content))
diff --git a/osdf/optimizers/licenseopt/__init__.py b/osdf/adapters/conductor/__init__.py
index 4b25e5b..6156206 100644
--- a/osdf/optimizers/licenseopt/__init__.py
+++ b/osdf/adapters/conductor/__init__.py
@@ -14,4 +14,4 @@
# limitations under the License.
#
# -------------------------------------------------------------------------
-#
+# \ No newline at end of file
diff --git a/osdf/adapters/conductor/api_builder.py b/osdf/adapters/conductor/api_builder.py
new file mode 100644
index 0000000..f3b0798
--- /dev/null
+++ b/osdf/adapters/conductor/api_builder.py
@@ -0,0 +1,123 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from jinja2 import Template
+import json
+
+import osdf.adapters.conductor.translation as tr
+from osdf.adapters.policy.utils import group_policies_gen
+from osdf.utils.programming_utils import list_flatten
+
+
+def _build_parameters(group_policies, service_info, request_parameters):
+ """Function prepares parameters section for has request
+
+ :param group_policies: filtered policies
+ :param service_info: service info
+ :param request_parameters: request parameters
+ :return:
+ """
+ initial_params = tr.get_opt_query_data(request_parameters,
+ group_policies['onap.policies.optimization.service.QueryPolicy'])
+ params = dict()
+ params.update({"REQUIRED_MEM": initial_params.pop("requiredMemory", "")})
+ params.update({"REQUIRED_DISK": initial_params.pop("requiredDisk", "")})
+ params.update({"customer_lat": initial_params.pop("customerLatitude", 0.0)})
+ params.update({"customer_long": initial_params.pop("customerLongitude", 0.0)})
+ params.update({"service_name": service_info.get('serviceName', "")})
+ params.update({"service_id": service_info.get('serviceInstanceId', "")})
+
+ for key, val in initial_params.items():
+ if val and val != "":
+ params.update({key: val})
+ return params
+
+
+def conductor_api_builder(req_info, demands, request_parameters, service_info,
+ template_fields, flat_policies: list, local_config,
+ template="osdf/adapters/conductor/templates/conductor_interface.json"):
+ """Build an OSDF southbound API call for HAS-Conductor/Placement optimization
+
+ :param req_info: parameter data received from a client
+ :param demands: list of demands
+ :param request_parameters: request parameters
+ :param service_info: service info object
+ :param template_fields: Fields that has to be passed to the template to render
+ :param flat_policies: policy data received from the policy platform (flat policies)
+ :param template: template to generate southbound API call to conductor
+ :param local_config: local configuration file with pointers for
+ the service specific information
+ :return: json to be sent to Conductor/placement optimization
+ """
+
+ templ = Template(open(template).read())
+ gp = group_policies_gen(flat_policies, local_config)
+ demand_name_list = []
+ for demand in demands:
+ demand_name_list.append(demand['resourceModuleName'].lower())
+ demand_list = tr.gen_demands(demands, gp['onap.policies.optimization.resource.VnfPolicy'])
+ attribute_policy_list = tr.gen_attribute_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.AttributePolicy'])
+
+ distance_to_location_policy_list = tr.gen_distance_to_location_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.DistancePolicy'])
+ inventory_policy_list = tr.gen_inventory_group_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.InventoryGroupPolicy'])
+ resource_instance_policy_list = tr.gen_resource_instance_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.ResourceInstancePolicy'])
+ resource_region_policy_list = tr.gen_resource_region_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.ResourceRegionPolicy'])
+ zone_policy_list = tr.gen_zone_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.AffinityPolicy'])
+ optimization_policy_list = tr.gen_optimization_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.OptimizationPolicy'])
+ reservation_policy_list = tr.gen_reservation_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.InstanceReservationPolicy'])
+ capacity_policy_list = tr.gen_capacity_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.Vim_fit'])
+ hpa_policy_list = tr.gen_hpa_policy(
+ demand_name_list, gp['onap.policies.optimization.resource.HpaPolicy'])
+ threshold_policy_list = tr.gen_threshold_policy(demand_name_list,
+ gp['onap.policies.optimization.resource.'
+ 'ThresholdPolicy'])
+ aggregation_policy_list = tr.gen_aggregation_policy(demand_name_list,
+ gp['onap.policies.optimization.resource.'
+ 'AggregationPolicy'])
+ req_params_dict = _build_parameters(gp, service_info, request_parameters)
+ conductor_policies = [attribute_policy_list, distance_to_location_policy_list,
+ inventory_policy_list, resource_instance_policy_list,
+ resource_region_policy_list, zone_policy_list, reservation_policy_list,
+ capacity_policy_list, hpa_policy_list, threshold_policy_list, aggregation_policy_list]
+ filtered_policies = [x for x in conductor_policies if len(x) > 0]
+ policy_groups = list_flatten(filtered_policies)
+ request_type = req_info.get('requestType', None)
+ rendered_req = templ.render(
+ requestType=request_type,
+ demand_list=demand_list,
+ policy_groups=policy_groups,
+ optimization_policies=optimization_policy_list,
+ name=req_info['requestId'],
+ timeout=req_info['timeout'],
+ limit=req_info['numSolutions'],
+ request_params=req_params_dict,
+ location_enabled=template_fields.get('location_enabled'),
+ version=template_fields.get('version'),
+ json=json)
+ json_payload = json.dumps(json.loads(rendered_req)) # need this because template's JSON is ugly!
+ return json_payload
diff --git a/osdf/adapters/conductor/conductor.py b/osdf/adapters/conductor/conductor.py
new file mode 100644
index 0000000..49c123d
--- /dev/null
+++ b/osdf/adapters/conductor/conductor.py
@@ -0,0 +1,120 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+from requests import RequestException
+import time
+
+from osdf.adapters.conductor.api_builder import conductor_api_builder
+from osdf.logging.osdf_logging import debug_log
+from osdf.operation.exceptions import BusinessException
+from osdf.utils.interfaces import RestClient
+
+
+def request(req_info, demands, request_parameters, service_info, template_fields,
+ osdf_config, flat_policies):
+ config = osdf_config.deployment
+ local_config = osdf_config.core
+ uid, passwd = config['conductorUsername'], config['conductorPassword']
+ conductor_url = config['conductorUrl']
+ req_id = req_info["requestId"]
+ transaction_id = req_info['transactionId']
+ headers = dict(transaction_id=transaction_id)
+ placement_ver_enabled = config.get('placementVersioningEnabled', False)
+
+ if placement_ver_enabled:
+ cond_minor_version = config.get('conductorMinorVersion', None)
+ if cond_minor_version is not None:
+ x_minor_version = str(cond_minor_version)
+ headers.update({'X-MinorVersion': x_minor_version})
+ debug_log.debug("Versions set in HTTP header to "
+ "conductor: X-MinorVersion: {} ".format(x_minor_version))
+
+ max_retries = config.get('conductorMaxRetries', 30)
+ ping_wait_time = config.get('conductorPingWaitTime', 60)
+
+ rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug,
+ headers=headers)
+ conductor_req_json_str = conductor_api_builder(req_info, demands, request_parameters,
+ service_info, template_fields, flat_policies,
+ local_config)
+ conductor_req_json = json.loads(conductor_req_json_str)
+
+ debug_log.debug("Sending first Conductor request for request_id {}".format(req_id))
+
+ resp, raw_resp = initial_request_to_conductor(rc, conductor_url, conductor_req_json)
+ # Very crude way of keeping track of time.
+ # We are not counting initial request time, first call back, or time for HTTP request
+ total_time, ctr = 0, 2
+ client_timeout = req_info['timeout']
+ configured_timeout = max_retries * ping_wait_time
+ max_timeout = min(client_timeout, configured_timeout)
+
+ while True: # keep requesting conductor till we get a result or we run out of time
+ if resp is not None:
+ if resp["plans"][0].get("status") in ["error"]:
+ raise RequestException(response=raw_resp, request=raw_resp.request)
+
+ if resp["plans"][0].get("status") in ["done", "not found", "solved"]:
+ return resp
+ new_url = resp['plans'][0]['links'][0][0]['href'] # TODO(krishna): check why a list of lists
+
+ if total_time >= max_timeout:
+ raise BusinessException("Conductor could not provide a solution within {} seconds,"
+ "this transaction is timing out".format(max_timeout))
+ time.sleep(ping_wait_time)
+ ctr += 1
+ debug_log.debug("Attempt number {} url {}; prior status={}"
+ .format(ctr, new_url, resp['plans'][0]['status']))
+ total_time += ping_wait_time
+
+ try:
+ raw_resp = rc.request(new_url, raw_response=True)
+ resp = raw_resp.json()
+ except RequestException as e:
+ debug_log.debug("Conductor attempt {} for request_id {} has failed because {}"
+ .format(ctr, req_id, str(e)))
+
+
+def initial_request_to_conductor(rc, conductor_url, conductor_req_json):
+ """First steps in the request-redirect chain in making a call to Conductor
+
+ :param rc: REST client object for calling conductor
+ :param conductor_url: conductor's base URL to submit a placement request
+ :param conductor_req_json: request json object to send to Conductor
+ :return: URL to check for follow up (similar to redirects);
+ we keep checking these till we get a result/error
+ """
+ debug_log.debug("Payload to Conductor: {}".format(json.dumps(conductor_req_json)))
+ raw_resp = rc.request(url=conductor_url, raw_response=True, method="POST",
+ json=conductor_req_json)
+ resp = raw_resp.json()
+ if resp["status"] != "template":
+ raise RequestException(response=raw_resp, request=raw_resp.request)
+ time.sleep(10) # 10 seconds wait time to avoid being too quick!
+ plan_url = resp["links"][0][0]["href"]
+ debug_log.debug("Attempting to read the plan from "
+ "the conductor provided url {}".format(plan_url))
+ raw_resp = rc.request(raw_response=True,
+ url=plan_url)
+ resp = raw_resp.json()
+
+ if resp["plans"][0]["status"] in ["error"]:
+ raise RequestException(response=raw_resp, request=raw_resp.request)
+ return resp, raw_resp # now the caller of this will handle further follow-ups
diff --git a/osdf/templates/conductor_interface.json b/osdf/adapters/conductor/templates/conductor_interface.json
index d2258a0..c0e28dc 100755
--- a/osdf/templates/conductor_interface.json
+++ b/osdf/adapters/conductor/templates/conductor_interface.json
@@ -1,39 +1,41 @@
-{
- "name": "{{ name }}",
- "files": {},
- "timeout": {{ timeout }},
- "limit": {{ limit }},
- "template": {
- "homing_template_version": "2017-10-10",
- "parameters": {
- "service_name": "{{ service_name }}",
- "service_id": "{{ service_id }}",
- "customer_lat": {{ latitude }},
- "customer_long": {{ longitude }}
- },
- "locations": {
- "customer_loc": {
- "latitude": { "get_param": "customer_lat" },
- "longitude": { "get_param": "customer_long" }
- }
- },
- "demands": {{ json.dumps(demand_list) }},
- {% set comma_main = joiner(",") %}
- "constraints": {
- {% set comma=joiner(",") %}
- {% for elem in policy_groups %} {{ comma() }}
- {% for key, value in elem.items() %}
- "{{key}}": {{ json.dumps(value) }}
- {% endfor %}
- {% endfor %}
- },
- "optimization": {
- {% set comma=joiner(",") %}
- {% for elem in optimization_policies %} {{ comma() }}
- {% for key, value in elem.items() %}
- "{{key}}": {{ json.dumps(value) }}
- {% endfor %}
- {% endfor %}
- }
- }
-} \ No newline at end of file
+{
+ "name": "{{ name }}",
+ "files": {},
+ "timeout": {{ timeout }},
+ "num_solution": "{{ limit }}",
+ "template": {
+ "homing_template_version": "{{ version }}",
+ "parameters": {
+ {% set comma=joiner(",") %}
+ {% for key, value in request_params.items() %} {{ comma() }}
+ "{{key}}": {{ json.dumps(value) }}
+ {% endfor %}
+ },
+ {% if location_enabled %}
+ "locations": {
+ "customer_loc": {
+ "latitude": { "get_param": "customer_lat" },
+ "longitude": { "get_param": "customer_long" }
+ }
+ },
+ {% endif %}
+ "demands": {{ json.dumps(demand_list) }},
+ {% set comma_main = joiner(",") %}
+ "constraints": {
+ {% set comma=joiner(",") %}
+ {% for elem in policy_groups %} {{ comma() }}
+ {% for key, value in elem.items() %}
+ "{{key}}": {{ json.dumps(value) }}
+ {% endfor %}
+ {% endfor %}
+ },
+ "optimization": {
+ {% set comma=joiner(",") %}
+ {% for elem in optimization_policies %} {{ comma() }}
+ {% for key, value in elem.items() %}
+ "{{key}}": {{ json.dumps(value) }} {{ ", " if not loop.last }}
+ {% endfor %}
+ {% endfor %}
+ }
+ }
+}
diff --git a/osdf/adapters/conductor/translation.py b/osdf/adapters/conductor/translation.py
new file mode 100644
index 0000000..f44f27f
--- /dev/null
+++ b/osdf/adapters/conductor/translation.py
@@ -0,0 +1,376 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+import copy
+import json
+import re
+import yaml
+
+from osdf.utils.programming_utils import dot_notation
+
+policy_config_mapping = yaml.safe_load(open('config/has_config.yaml')).get('policy_config_mapping')
+
+CONSTRAINT_TYPE_MAP = {"onap.policies.optimization.resource.AttributePolicy": "attribute",
+ "onap.policies.optimization.resource.DistancePolicy": "distance_to_location",
+ "onap.policies.optimization.resource.InventoryGroupPolicy": "inventory_group",
+ "onap.policies.optimization.resource.ResourceInstancePolicy": "instance_fit",
+ "onap.policies.optimization.resource.ResourceRegionPolicy": "region_fit",
+ "onap.policies.optimization.resource.AffinityPolicy": "zone",
+ "onap.policies.optimization.resource.InstanceReservationPolicy":
+ "instance_reservation",
+ "onap.policies.optimization.resource.Vim_fit": "vim_fit",
+ "onap.policies.optimization.resource.HpaPolicy": "hpa",
+ "onap.policies.optimization.resource.ThresholdPolicy": "threshold",
+ "onap.policies.optimization.resource.AggregationPolicy": "aggregation"
+ }
+
+
+def get_opt_query_data(request_parameters, policies):
+ """Fetch service and order specific details from the requestParameters field of a request.
+
+ :param request_parameters: A list of request parameters
+ :param policies: A set of policies
+ :return: A dictionary with service and order-specific attributes.
+ """
+ req_param_dict = {}
+ if request_parameters:
+ for policy in policies:
+ for queryProp in policy[list(policy.keys())[0]]['properties']['queryProperties']:
+ attr_val = queryProp['value'] if 'value' in queryProp and queryProp['value'] != "" \
+ else dot_notation(request_parameters, queryProp['attribute_location'])
+ if attr_val is not None:
+ req_param_dict.update({queryProp['attribute']: attr_val})
+ return req_param_dict
+
+
+def gen_optimization_policy(vnf_list, optimization_policy):
+ """Generate optimization policy details to pass to Conductor
+
+ :param vnf_list: List of vnf's to used in placement request
+ :param optimization_policy: optimization objective policy information provided in the incoming request
+ :return: List of optimization objective policies in a format required by Conductor
+ """
+ if len(optimization_policy) == 1:
+ policy = optimization_policy[0]
+ policy_content = policy[list(policy.keys())[0]]
+ if policy_content['type_version'] == '2.0.0':
+ properties = policy_content['properties']
+ objective = {'goal': properties['goal'],
+ 'operation_function': properties['operation_function']}
+ return [objective]
+
+ optimization_policy_list = []
+ for policy in optimization_policy:
+ content = policy[list(policy.keys())[0]]['properties']
+ parameter_list = []
+ parameters = ["cloud_version", "hpa_score"]
+
+ for attr in content['objectiveParameter']['parameterAttributes']:
+ parameter = attr['parameter'] if attr['parameter'] in parameters else attr['parameter'] + "_between"
+ default, vnfs = get_matching_vnfs(attr['resources'], vnf_list)
+ for vnf in vnfs:
+ value = [vnf] if attr['parameter'] in parameters else [attr['customerLocationInfo'], vnf]
+ parameter_list.append({
+ attr['operator']: [attr['weight'], {parameter: value}]
+ })
+
+ optimization_policy_list.append({
+ content['objective']: {content['objectiveParameter']['operator']: parameter_list}
+ })
+ return optimization_policy_list
+
+
+def get_matching_vnfs(resources, vnf_list, match_type="intersection"):
+ """Get a list of matching VNFs from the list of resources
+
+ :param resources:
+ :param vnf_list: List of vnfs to used in placement request
+ :param match_type: "intersection" or "all" or "any" (any => send all_vnfs if there is any intersection)
+ :return: List of matching VNFs
+ """
+ # Check if it is a default policy
+ default = True if resources == [] else False
+ resources_lcase = [x.lower() for x in resources] if not default else [x.lower() for x in vnf_list]
+ if match_type == "all": # don't bother with any comparisons
+ return default, resources if set(resources_lcase) <= set(vnf_list) else None
+ common_vnfs = set(vnf_list) & set(resources_lcase) if not default else set(vnf_list)
+ common_resources = [x for x in resources if x.lower() in common_vnfs] if not default else list(common_vnfs)
+ if match_type == "intersection": # specifically requested intersection
+ return default, list(common_resources)
+ return default, resources if common_vnfs else None # "any" match => all resources to be returned
+
+
+def gen_policy_instance(vnf_list, resource_policy, match_type="intersection", rtype=None):
+ """Generate a list of policies
+
+ :param vnf_list: List of vnf's to used in placement request
+ :param resource_policy: policy for this specific resource
+ :param match_type: How to match the vnf_names with the vnf_list (intersection or "any")
+ intersection => return intersection; "any" implies return all vnf_names if intersection is not null
+ :param rtype: resource type (e.g. resourceRegionProperty or resourceInstanceProperty)
+ None => no controller information added to the policy specification to Conductor
+ :return: resource policy list in a format required by Conductor
+ """
+ resource_policy_list = []
+ related_policies = []
+ for policy in resource_policy:
+ pc = policy[list(policy.keys())[0]]
+ default, demands = get_matching_vnfs(pc['properties']['resources'], vnf_list, match_type=match_type)
+ resource = {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']), 'demands': demands}}
+
+ if rtype:
+ resource[pc['properties']['identity']]['properties'] = {'controller': pc[rtype]['controller'],
+ 'request': json.loads(pc[rtype]['request'])}
+ if demands and len(demands) != 0:
+ # The default policy shall not override the specific policy that already appended
+ if default:
+ for d in demands:
+ resource_repeated = True \
+ if {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']),
+ 'demands': d}} in resource_policy_list else False
+ if resource_repeated:
+ continue
+ else:
+ resource_policy_list.append(
+ {pc['properties']['identity']: {'type': CONSTRAINT_TYPE_MAP.get(pc['type']),
+ 'demands': d}})
+ policy[list(policy.keys())[0]]['properties']['resources'] = d
+ related_policies.append(policy)
+ # Need to override the default policies, here delete the outdated policy stored in the db
+ if resource in resource_policy_list:
+ for pc in related_policies:
+ if pc[list(pc.keys()[0])]['properties']['resources'] == resource:
+ related_policies.remove(pc)
+ resource_policy_list.remove(resource)
+ related_policies.append(policy)
+ resource_policy_list.append(resource)
+
+ return resource_policy_list, related_policies
+
+
+def gen_resource_instance_policy(vnf_list, resource_instance_policy):
+ """Get policies governing resource instances in order to populate the Conductor API call"""
+ cur_policies, _ = gen_policy_instance(vnf_list, resource_instance_policy, rtype='resourceInstanceProperty')
+ return cur_policies
+
+
+def gen_resource_region_policy(vnf_list, resource_region_policy):
+ """Get policies governing resource region in order to populate the Conductor API call"""
+ cur_policies, _ = gen_policy_instance(vnf_list, resource_region_policy, rtype='resourceRegionProperty')
+ return cur_policies
+
+
+def gen_inventory_group_policy(vnf_list, inventory_group_policy):
+ """Get policies governing inventory group in order to populate the Conductor API call"""
+ cur_policies, _ = gen_policy_instance(vnf_list, inventory_group_policy, rtype=None)
+ return cur_policies
+
+
+def gen_reservation_policy(vnf_list, reservation_policy):
+ """Get policies governing resource instances in order to populate the Conductor API call"""
+ cur_policies, _ = gen_policy_instance(vnf_list, reservation_policy, rtype='instanceReservationProperty')
+ return cur_policies
+
+
+def gen_distance_to_location_policy(vnf_list, distance_to_location_policy):
+ """Get policies governing distance-to-location for VNFs in order to populate the Conductor API call"""
+ cur_policies, related_policies = gen_policy_instance(vnf_list, distance_to_location_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
+ properties = p_main[list(p_main.keys())[0]]['properties']['distanceProperties']
+ pcp_d = properties['distance']
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = {
+ 'distance': pcp_d['operator'] + " " + pcp_d['value'].lower() + " " + pcp_d['unit'].lower(),
+ 'location': properties['locationInfo']
+ }
+ return cur_policies
+
+
+def gen_attribute_policy(vnf_list, attribute_policy):
+ """Get policies governing attributes of VNFs in order to populate the Conductor API call"""
+ cur_policies, related_policies = gen_policy_instance(vnf_list, attribute_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
+ properties = p_main[list(p_main.keys())[0]]['properties']['attributeProperties']
+ attribute_mapping = policy_config_mapping['filtering_attributes'] # wanted attributes and mapping
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = {
+ 'evaluate': dict((attribute_mapping[k], properties.get(k)
+ if k != "cloudRegion" else gen_cloud_region(properties))
+ for k in attribute_mapping.keys())
+ }
+ return cur_policies # cur_policies gets updated in place...
+
+
+def gen_zone_policy(vnf_list, zone_policy):
+ """Get zone policies in order to populate the Conductor API call"""
+ cur_policies, related_policies = gen_policy_instance(vnf_list, zone_policy, match_type="all", rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
+ pmz = p_main[list(p_main.keys())[0]]['properties']['affinityProperties']
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = \
+ {'category': pmz['category'], 'qualifier': pmz['qualifier']}
+ return cur_policies
+
+
+def gen_capacity_policy(vnf_list, capacity_policy):
+ """Get zone policies in order to populate the Conductor API call"""
+ cur_policies, related_policies = gen_policy_instance(vnf_list, capacity_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
+ pmz = p_main[list(p_main.keys())[0]]['properties']['capacityProperty']
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = \
+ {"controller": pmz['controller'], 'request': json.loads(pmz['request'])}
+ return cur_policies
+
+
+def gen_hpa_policy(vnf_list, hpa_policy):
+ """Get zone policies in order to populate the Conductor API call"""
+ cur_policies, related_policies = gen_policy_instance(vnf_list, hpa_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = \
+ {'evaluate': p_main[list(p_main.keys())[0]]['properties']['flavorFeatures']}
+ return cur_policies
+
+
+def gen_threshold_policy(vnf_list, threshold_policy):
+ cur_policies, related_policies = gen_policy_instance(vnf_list, threshold_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies):
+ pmz = p_main[list(p_main.keys())[0]]['properties']['thresholdProperties']
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = {'evaluate': pmz}
+ return cur_policies
+
+
+def gen_aggregation_policy(vnf_list, cross_policy):
+ cur_policies, related_policies = gen_policy_instance(vnf_list, cross_policy, rtype=None)
+ for p_new, p_main in zip(cur_policies, related_policies):
+ pmz = p_main[list(p_main.keys())[0]]['properties']['aggregationProperties']
+ p_new[p_main[list(p_main.keys())[0]]['properties']['identity']]['properties'] = {'evaluate': pmz}
+ return cur_policies
+
+
+def get_augmented_policy_attributes(policy_property, demand):
+ """Get policy attributes and augment them using policy_config_mapping and demand information"""
+ attributes = copy.copy(policy_property['attributes'])
+ remapping = policy_config_mapping['remapping']
+ extra = dict((x, demand['resourceModelInfo'][remapping[x]]) for x in attributes if x in remapping)
+ attributes.update(extra)
+ return attributes
+
+
+def get_candidates_demands(demand):
+ """Get demands related to candidates; e.g. excluded/required"""
+ res = {}
+ for k, v in policy_config_mapping['candidates'].items():
+ if k not in demand:
+ continue
+ res[v] = [{'inventory_type': x['identifierType'], 'candidate_id': x['identifiers']} for x in demand[k]]
+ return res
+
+
+def get_policy_properties(demand, policies):
+ """Get policy_properties for cases where there is a match with the demand"""
+ for policy in policies:
+ policy_demands = set([x.lower() for x in policy[list(policy.keys())[0]]['properties']['resources']])
+ if policy_demands and demand['resourceModuleName'].lower() not in policy_demands:
+ continue # no match for this policy
+ elif policy_demands == set(): # Append resource name for default policy
+ policy[list(policy.keys())[0]]['properties'].update(resources=list(demand.get('resourceModuleName')))
+ for policy_property in policy[list(policy.keys())[0]]['properties']['vnfProperties']:
+ yield policy_property
+
+
+def get_demand_properties(demand, policies):
+ """Get list demand properties objects (named tuples) from policy"""
+ demand_properties = []
+ for policy_property in get_policy_properties(demand, policies):
+ prop = dict(inventory_provider=policy_property['inventoryProvider'],
+ inventory_type=policy_property['inventoryType'],
+ service_type=demand.get('serviceResourceId', ''),
+ service_resource_id=demand.get('serviceResourceId', ''))
+ policy_property_mapping = {'filtering_attributes': 'attributes',
+ 'passthrough_attributes': 'passthroughAttributes',
+ 'default_attributes': 'defaultAttributes'}
+
+ prop.update({'unique': policy_property['unique']} if 'unique' in policy_property and
+ policy_property['unique'] else {})
+ prop['filtering_attributes'] = dict()
+ for key, value in policy_property_mapping.items():
+ get_demand_attributes(prop, policy_property, key, value)
+
+ prop['filtering_attributes'].update({'global-customer-id': policy_property['customerId']}
+ if 'customerId' in policy_property and policy_property['customerId']
+ else {})
+ prop['filtering_attributes'].update({'model-invariant-id': demand['resourceModelInfo']['modelInvariantId']}
+ if 'modelInvariantId' in demand['resourceModelInfo']
+ and demand['resourceModelInfo']['modelInvariantId'] else {})
+ prop['filtering_attributes'].update({'model-version-id': demand['resourceModelInfo']['modelVersionId']}
+ if 'modelVersionId' in demand['resourceModelInfo']
+ and demand['resourceModelInfo']['modelVersionId'] else {})
+ prop['filtering_attributes'].update({'equipment-role': policy_property['equipmentRole']}
+ if 'equipmentRole' in policy_property and policy_property['equipmentRole']
+ else {})
+ prop.update(get_candidates_demands(demand))
+ demand_properties.append(prop)
+ return demand_properties
+
+
+def get_demand_attributes(prop, policy_property, attribute_type, key):
+ if policy_property.get(key):
+ prop[attribute_type] = dict()
+ for attr_key, attr_val in policy_property[key].items():
+ update_converted_attribute(attr_key, attr_val, prop, attribute_type)
+
+
+def update_converted_attribute(attr_key, attr_val, properties, attribute_type):
+ """Updates dictonary of attributes with one specified in the arguments.
+
+ Automatically translates key namr from camelCase to hyphens
+ :param attribute_type: attribute section name
+ :param attr_key: key of the attribute
+ :param attr_val: value of the attribute
+ :param properties: dictionary with attributes to update
+ :return:
+ """
+ if attr_val:
+ remapping = policy_config_mapping[attribute_type]
+ if remapping.get(attr_key):
+ key_value = remapping.get(attr_key)
+ else:
+ key_value = re.sub('(.)([A-Z][a-z]+)', r'\1-\2', attr_key)
+ key_value = re.sub('([a-z0-9])([A-Z])', r'\1-\2', key_value).lower()
+ properties[attribute_type].update({key_value: attr_val})
+
+
+def gen_demands(demands, vnf_policies):
+ """Generate list of demands based on request and VNF policies
+
+ :param demands: A List of demands
+ :param vnf_policies: Policies associated with demand resources
+ (e.g. from grouped_policies['vnfPolicy'])
+ :return: list of demand parameters to populate the Conductor API call
+ """
+ demand_dictionary = {}
+ for demand in demands:
+ prop = get_demand_properties(demand, vnf_policies)
+ if len(prop) > 0:
+ demand_dictionary.update({demand['resourceModuleName']: prop})
+ return demand_dictionary
+
+
+def gen_cloud_region(property):
+ prop = {"cloud_region_attributes": dict()}
+ if 'cloudRegion' in property:
+ for k, v in property['cloudRegion'].items():
+ update_converted_attribute(k, v, prop, 'cloud_region_attributes')
+ return prop["cloud_region_attributes"]
diff --git a/osdf/adapters/dcae/des.py b/osdf/adapters/dcae/des.py
new file mode 100644
index 0000000..57cb128
--- /dev/null
+++ b/osdf/adapters/dcae/des.py
@@ -0,0 +1,47 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import requests
+
+from osdf.config.base import osdf_config
+from osdf.utils.interfaces import RestClient
+
+
+class DESException(Exception):
+ pass
+
+
+def extract_data(service_id, request_data):
+ """Extracts data from the data lake via DES.
+
+ param: service_id: kpi data identifier
+ param: request_data: data to send
+ param: osdf_config: osdf config to retrieve api info
+ """
+
+ config = osdf_config.deployment
+ user, password = config['desUsername'], config['desPassword']
+ headers = config["desHeaders"]
+ req_url = config["desUrl"] + config["desApiPath"] + service_id
+ rc = RestClient(userid=user, passwd=password, url=req_url, headers=headers, method="POST")
+
+ try:
+ response_json = rc.request(data=request_data)
+ return response_json.get("result")
+ except requests.RequestException as e:
+ raise DESException("Request exception was encountered {}".format(e))
diff --git a/osdf/adapters/dcae/message_router.py b/osdf/adapters/dcae/message_router.py
index caf04a4..0968812 100755
--- a/osdf/adapters/dcae/message_router.py
+++ b/osdf/adapters/dcae/message_router.py
@@ -17,8 +17,10 @@
#
import requests
-from osdf.utils.data_types import list_like
+
from osdf.operation.exceptions import MessageBusConfigurationException
+from osdf.utils.data_types import list_like
+from osdf.utils.interfaces import RestClient
class MessageRouterClient(object):
@@ -27,7 +29,8 @@ class MessageRouterClient(object):
consumer_group_id=':',
timeout_ms=15000, fetch_limit=1000,
userid_passwd=':'):
- """
+ """Class initializer
+
:param dmaap_url: protocol, host and port; can also be a list of URLs
(e.g. https://dmaap-host.onapdemo.onap.org:3905/events/org.onap.dmaap.MULTICLOUD.URGENT),
can also be a list of such URLs
@@ -44,14 +47,14 @@ class MessageRouterClient(object):
self.topic_urls = [dmaap_url] if not list_like(dmaap_url) else dmaap_url
self.timeout_ms = timeout_ms
self.fetch_limit = fetch_limit
- userid, passwd = userid_passwd.split(':')
- self.auth = (userid, passwd) if userid and passwd else None
+ self.userid, self.passwd = userid_passwd.split(':')
consumer_group, consumer_id = consumer_group_id.split(':')
self.consumer_group = consumer_group
self.consumer_id = consumer_id
def get(self, outputjson=True):
"""Fetch messages from message router (DMaaP or UEB)
+
:param outputjson: (optional, specifies if response is expected to be in json format), ignored for "POST"
:return: response as a json object (if outputjson is True) or as a string
"""
@@ -61,7 +64,7 @@ class MessageRouterClient(object):
for url in urls[:-1]:
try:
return self.http_request(method='GET', url=url, outputjson=outputjson)
- except:
+ except Exception:
pass
return self.http_request(method='GET', url=urls[-1], outputjson=outputjson)
@@ -69,13 +72,13 @@ class MessageRouterClient(object):
for url in self.topic_urls[:-1]:
try:
return self.http_request(method='POST', url=url, inputjson=inputjson, msg=msg)
- except:
+ except Exception:
pass
return self.http_request(method='POST', url=self.topic_urls[-1], inputjson=inputjson, msg=msg)
def http_request(self, url, method, inputjson=True, outputjson=True, msg=None, **kwargs):
- """
- Perform the actual URL request (GET or POST), and do error handling
+ """Perform the actual URL request (GET or POST), and do error handling
+
:param url: full URL (including topic, limit, timeout, etc.)
:param method: GET or POST
:param inputjson: Specify whether input is in json format (valid only for POST)
@@ -83,9 +86,15 @@ class MessageRouterClient(object):
:param msg: content to be posted (valid only for POST)
:return: response as a json object (if outputjson or POST) or as a string; None if error
"""
- res = requests.request(url=url, method=method, auth=self.auth, **kwargs)
- if res.status_code == requests.codes.ok:
- return res.json() if outputjson or method == "POST" else res.content
- else:
- raise Exception("HTTP Response Error: code {}; headers:{}, content: {}".format(
- res.status_code, res.headers, res.content))
+
+ rc = RestClient(userid=self.userid, passwd=self.passwd, url=url, method=method)
+ try:
+ res = rc.request(raw_response=True, data=msg, **kwargs)
+ if res.status_code == requests.codes.ok:
+ return res.json() if outputjson or method == "POST" else res.content
+ else:
+ raise Exception("HTTP Response Error: code {}; headers:{}, content: {}".format(
+ res.status_code, res.headers, res.content))
+
+ except requests.RequestException as ex:
+ raise Exception("Request Exception occurred {}".format(str(ex)))
diff --git a/osdf/adapters/local_data/local_policies.py b/osdf/adapters/local_data/local_policies.py
index 6e49388..dc6837a 100644
--- a/osdf/adapters/local_data/local_policies.py
+++ b/osdf/adapters/local_data/local_policies.py
@@ -19,7 +19,7 @@
import json
import os
import re
-
+from osdf.logging.osdf_logging import debug_log
def get_local_policies(local_policy_folder, local_policy_list, policy_id_list=None):
"""
@@ -32,6 +32,7 @@ def get_local_policies(local_policy_folder, local_policy_list, policy_id_list=No
:param policy_id_list: list of policies to get (if unspecified or None, get all)
:return: get policies
"""
+ debug_log.debug("Policy folder: {}, local_list {}, policy id list {}".format(local_policy_folder, local_policy_list, policy_id_list))
policies = []
if policy_id_list:
for policy_id in policy_id_list:
diff --git a/osdf/adapters/policy/interface.py b/osdf/adapters/policy/interface.py
index 95bfacc..6799c6b 100644
--- a/osdf/adapters/policy/interface.py
+++ b/osdf/adapters/policy/interface.py
@@ -1,4 +1,4 @@
- # -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
# Copyright (c) 2015-2017 AT&T Intellectual Property
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,23 @@
#
import base64
-import itertools
import json
-
-
+import os
from requests import RequestException
-from osdf.operation.exceptions import BusinessException
+import uuid
+import yaml
+
from osdf.adapters.local_data.local_policies import get_local_policies
-from osdf.adapters.policy.utils import policy_name_as_regex, retrieve_node
-from osdf.utils.programming_utils import list_flatten, dot_notation
+from osdf.adapters.policy.utils import policy_name_as_regex
from osdf.config.base import osdf_config
-from osdf.logging.osdf_logging import audit_log, MH, metrics_log, debug_log
+from osdf.logging.osdf_logging import audit_log
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import metrics_log
+from osdf.logging.osdf_logging import MH
+from osdf.operation.exceptions import BusinessException
from osdf.utils.interfaces import RestClient
+from osdf.utils.programming_utils import dot_notation
+from osdf.utils.programming_utils import list_flatten
def get_by_name(rest_client, policy_name_list, wildcards=True):
@@ -46,7 +51,8 @@ def get_by_name(rest_client, policy_name_list, wildcards=True):
def get_by_scope(rest_client, req, config_local, type_service):
- """ Get policies by scopes as defined in the configuration file.
+ """Get policies by scopes as defined in the configuration file.
+
:param rest_client: a rest client object to make a call.
:param req: an optimization request.
:param config_local: application configuration file.
@@ -55,28 +61,39 @@ def get_by_scope(rest_client, req, config_local, type_service):
"""
scope_policies = []
references = config_local.get('references', {})
- pscope = config_local.get('policy_info', {}).get(type_service, {}).get('policy_scope', {})
- service_name = dot_notation(req, references.get('service_name', {}).get('value', None))
- primary_scope = pscope['{}_scope'.format(service_name.lower() if pscope.get(service_name + "_scope", None)
- else "default")]
- for sec_scope in pscope.get('secondary_scopes', []):
- policies, scope_fields = [], []
- for field in sec_scope:
- scope_fields.extend([get_scope_fields(field, references, req, list_flatten(scope_policies))
- if 'get_param' in field else field])
- scope_fields = set(list_flatten(scope_fields))
- scope_fields = set([x.lower() for x in scope_fields])
- for scope in scope_fields:
- policies.extend(policy_api_call(rest_client, primary_scope, scope))
- scope_policies.append([policy for policy in policies
- if scope_fields <= set(json.loads(policy['config'])['content']['policyScope'])])
+ pscope = config_local.get('policy_info', {}).get(type_service, {}).get('policy_scope', [])
+ scope_fields = {}
+ policies = {}
+ for scopes in pscope:
+ for key in scopes.keys():
+ for field in scopes[key]:
+ scope_fields[key] = list_flatten([get_scope_fields(field, references, req, policies)
+ if 'get_param' in field else field])
+ if scope_fields.get('resources') and len(scope_fields['resources']) > 1:
+ for s in scope_fields['resources']:
+ scope_fields['resources'] = [s]
+ policies.update(policy_api_call(rest_client, scope_fields).get('policies', {}))
+ else:
+ policies.update(policy_api_call(rest_client, scope_fields).get('policies', {}))
+ for policyName in policies.keys():
+ keys = scope_fields.keys() & policies[policyName]['properties'].keys()
+ policy = {}
+ policy[policyName] = policies[policyName]
+ for k in keys:
+ if set(policies.get(policyName, {}).get('properties', {}).get(k)) >= set(scope_fields[k]) \
+ and policy not in scope_policies:
+ scope_policies.append(policy)
+
return scope_policies
-def get_scope_fields(field, references, req, policy_info):
- """ Retrieve the values for scope fields from a request and policies as per the configuration
- and references defined in a configuration file. If the value of a scope field missing in a request or
+def get_scope_fields(field, references, req, policies):
+ """Retrieve the values for scope fields from a request and policies
+
+ They are derived as per the configuration and references defined in a
+ configuration file. If the value of a scope field missing in a request or
policies, throw an exception since correct policies cannot be retrieved.
+
:param field: details on a scope field from a configuration file.
:param references: references defined in a configuration file.
:param req: an optimization request.
@@ -92,9 +109,9 @@ def get_scope_fields(field, references, req, policy_info):
raise BusinessException("Field {} is missing a value in a request".format(ref_value.split('.')[-1]))
else:
scope_fields = []
- for policy in policy_info:
- policy_content = json.loads(policy.get('config', "{}"))
- if policy_content.get('content', {}).get('policyType', "invalid_policy") == ref_source:
+ for policyName in policies.keys():
+ policy_content = policies.get(policyName)
+ if policy_content.get('type', "invalid_policy") == ref_source:
scope_fields.append(dot_notation(policy_content, ref_value))
scope_values = list_flatten(scope_fields)
if len(scope_values) > 0:
@@ -103,31 +120,35 @@ def get_scope_fields(field, references, req, policy_info):
ref_value.split('.')[-1], ref_source))
-def policy_api_call(rest_client, primary_scope, scope_field):
- """ Makes a getConfig API call to the policy system to retrieve policies matching a scope.
- :param rest_client: rest client object to make a call
- :param primary_scope: the primary scope of policies, which is a folder in the policy system
- where policies are stored.
- :param scope_field: the secondary scope of policies, which is a collection of domain values.
- :return: a list of policies matching both primary and secondary scopes.
+def policy_api_call(rest_client, scope_fields):
+ """Makes the api call to policy and return the response if policies are present
+
+ :param rest_client: rest client to make a call
+ :param scope_fields: a collection of scopes to be used for filtering
+ :return: a list of policies matching all filters
"""
- api_call_body = {"policyName": "{}.*".format(primary_scope),
- "configAttributes": {"policyScope": "{}".format(scope_field)}}
- return rest_client.request(json=api_call_body)
+ api_call_body = {"ONAPName": "OOF",
+ "ONAPComponent": "OOF_Component",
+ "ONAPInstance": "OOF_Component_Instance",
+ "action": "optimize",
+ "resource": scope_fields}
+ response = rest_client.request(json=api_call_body)
+ if not response.get("policies"):
+ raise Exception("Policies not found for the scope {}".format(scope_fields))
+ return response
def remote_api(req_json, osdf_config, service_type="placement"):
"""Make a request to policy and return response -- it accounts for multiple requests that be needed
+
:param req_json: policy request object (can have multiple policy names)
:param osdf_config: main config that will have credential information
:param service_type: the type of service to call: "placement", "scheduling"
:return: all related policies and provStatus retrieved from Subscriber policy
"""
config = osdf_config.deployment
+ headers = {"Content-type": "application/json"}
uid, passwd = config['policyPlatformUsername'], config['policyPlatformPassword']
- pcuid, pcpasswd = config['policyClientUsername'], config['policyClientPassword']
- headers = {"ClientAuth": base64.b64encode(bytes("{}:{}".format(pcuid, pcpasswd), "ascii"))}
- headers.update({'Environment': config['policyPlatformEnv']})
url = config['policyPlatformUrl']
rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug)
@@ -139,17 +160,17 @@ def remote_api(req_json, osdf_config, service_type="placement"):
policies = get_by_scope(rc, req_json, osdf_config.core, service_type)
formatted_policies = []
- for x in itertools.chain(*policies):
- if x['config'] is None:
- raise BusinessException("Config not found for policy with name %s" % x['policyName'])
+ for x in policies:
+ if x[list(x.keys())[0]].get('properties') is None:
+ raise BusinessException("Properties not found for policy with name %s" % x[list(x.keys()[0])])
else:
- formatted_policies.append(json.loads(x['config']))
+ formatted_policies.append(x)
return formatted_policies
def local_policies_location(req_json, osdf_config, service_type):
- """
- Get folder and list of policy_files if "local policies" option is enabled
+ """Get folder and list of policy_files if "local policies" option is enabled
+
:param service_type: placement supported for now, but can be any other service
:return: a tuple (folder, file_list) or None
"""
@@ -157,17 +178,20 @@ def local_policies_location(req_json, osdf_config, service_type):
if lp.get('global_disabled'):
return None # short-circuit to disable all local policies
if lp.get('local_{}_policies_enabled'.format(service_type)):
+ debug_log.debug('Loading local policies for service type: {}'.format(service_type))
if service_type == "scheduling":
return lp.get('{}_policy_dir'.format(service_type)), lp.get('{}_policy_files'.format(service_type))
else:
- service_name = req_json['serviceInfo']['serviceName'] # TODO: data_mapping.get_service_type(model_name)
+ service_name = req_json['serviceInfo']['serviceName']
+ debug_log.debug('Loading local policies for service name: {}'.format(service_name))
return lp.get('{}_policy_dir_{}'.format(service_type, service_name.lower())), \
- lp.get('{}_policy_files_{}'.format(service_type, service_name.lower()))
+ lp.get('{}_policy_files_{}'.format(service_type, service_name.lower()))
return None
def get_policies(request_json, service_type):
"""Validate the request and get relevant policies
+
:param request_json: Request object
:param service_type: the type of service to call: "placement", "scheduling"
:return: policies associated with this request and provStatus retrieved from Subscriber policy
@@ -178,6 +202,8 @@ def get_policies(request_json, service_type):
local_info = local_policies_location(request_json, osdf_config, service_type)
if local_info: # tuple containing location and list of files
+ if local_info[0] is None or local_info[1] is None:
+ raise ValueError("Error fetching local policy info")
to_filter = None
if osdf_config.core['policy_info'][service_type]['policy_fetch'] == "by_name":
to_filter = request_json[service_type + "Info"]['policyId']
@@ -186,3 +212,31 @@ def get_policies(request_json, service_type):
policies = remote_api(request_json, osdf_config, service_type)
return policies
+
+
+def upload_policy_models():
+ """Upload all the policy models reside in the folder"""
+ requestId = uuid.uuid4()
+ config = osdf_config.deployment
+ model_path = config['pathPolicyModelUpload']
+ uid, passwd = config['policyPlatformUsername'], config['policyPlatformPassword']
+ pcuid, pcpasswd = config['policyClientUsername'], config['policyClientPassword']
+ headers = {"ClientAuth": base64.b64encode(bytes("{}:{}".format(pcuid, pcpasswd), "ascii"))}
+ headers.update({'Environment': config['policyPlatformEnv']})
+ headers.update({'X-ONAP-RequestID': requestId})
+ url = config['policyPlatformUrlModelUpload']
+ rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug)
+
+ for file in os.listdir(model_path):
+ if not file.endswith(".yaml"):
+ continue
+ with open(file) as f:
+ file_converted = json.dumps(yaml.load(f))
+ response = rc.request(json=file_converted, ok_codes=(200))
+ if not response:
+ success = False
+ audit_log.warn("Policy model %s uploading failed!" % file)
+ if not success:
+ return "Policy model uploading success!"
+ else:
+ return "Policy model uploading not success!"
diff --git a/osdf/adapters/policy/utils.py b/osdf/adapters/policy/utils.py
index 2f873af..79047eb 100644
--- a/osdf/adapters/policy/utils.py
+++ b/osdf/adapters/policy/utils.py
@@ -33,11 +33,11 @@ def group_policies_gen(flat_policies, config):
"""
filtered_policies = defaultdict(list)
policy_name = []
- policies = [x for x in flat_policies if x['content'].get('policyType')] # drop ones without 'policy_type'
+ policies = [x for x in flat_policies if x[list(x.keys())[0]]["type"]] # drop ones without 'type'
priority = config.get('policy_info', {}).get('prioritization_attributes', {})
aggregated_policies = dict()
for plc in policies:
- attrs = [dot_notation(plc, dot_path) for key in priority.keys() for dot_path in priority[key]]
+ attrs = [dot_notation(plc[list(plc.keys())[0]], dot_path) for key in priority.keys() for dot_path in priority[key]]
attrs_list = [x if isinstance(x, list) else [x] for x in attrs]
attributes = [list_flatten(x) if isinstance(x, list) else x for x in attrs_list]
for y in itertools.product(*attributes):
@@ -45,12 +45,12 @@ def group_policies_gen(flat_policies, config):
aggregated_policies[y].append(plc)
for key in aggregated_policies.keys():
- aggregated_policies[key].sort(key=lambda x: x['priority'], reverse=True)
+ #aggregated_policies[key].sort(key=lambda x: x['priority'], reverse=True)
prioritized_policy = aggregated_policies[key][0]
- if prioritized_policy['policyName'] not in policy_name:
+ if list(prioritized_policy.keys())[0] not in policy_name:
# TODO: Check logic here... should policy appear only once across all groups?
- filtered_policies[prioritized_policy['content']['policyType']].append(prioritized_policy)
- policy_name.append(prioritized_policy['policyName'])
+ filtered_policies[prioritized_policy[list(prioritized_policy.keys())[0]]['type']].append(prioritized_policy)
+ policy_name.append(list(prioritized_policy.keys())[0])
return filtered_policies
diff --git a/osdf/apps/__init__.py b/osdf/apps/__init__.py
new file mode 100644
index 0000000..370bc06
--- /dev/null
+++ b/osdf/apps/__init__.py
@@ -0,0 +1,2 @@
+import yaml
+yaml.warnings({'YAMLLoadWarning': False}) \ No newline at end of file
diff --git a/osdf/apps/baseapp.py b/osdf/apps/baseapp.py
new file mode 100644
index 0000000..1ad7556
--- /dev/null
+++ b/osdf/apps/baseapp.py
@@ -0,0 +1,222 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2017 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+"""
+OSDF Manager Main Flask Application
+"""
+
+import json
+from optparse import OptionParser
+import ssl
+import sys
+import time
+import traceback
+
+from flask import Flask
+from flask import g
+from flask import request
+from flask import Response
+from onaplogging.mdcContext import MDC
+from requests import RequestException
+from schematics.exceptions import DataError
+
+import osdf.adapters.aaf.sms as sms
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import audit_log
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.operation.error_handling import internal_error_message
+from osdf.operation.error_handling import request_exception_to_json_body
+from osdf.operation.exceptions import BusinessException
+import osdf.operation.responses
+from osdf.utils.mdc_utils import clear_mdc
+from osdf.utils.mdc_utils import get_request_id
+from osdf.utils.mdc_utils import populate_default_mdc
+from osdf.utils.mdc_utils import populate_mdc
+from osdf.utils.mdc_utils import set_error_details
+
+ERROR_TEMPLATE = osdf.ERROR_TEMPLATE
+
+app = Flask(__name__)
+
+BAD_CLIENT_REQUEST_MESSAGE = 'Client sent an invalid request'
+
+
+@app.errorhandler(BusinessException)
+def handle_business_exception(e):
+ """An exception explicitly raised due to some business rule
+
+ """
+ error_log.error("Synchronous error for request id {} {}"
+ .format(g.request_id, traceback.format_exc()))
+ err_msg = ERROR_TEMPLATE.render(description=str(e))
+ response = Response(err_msg, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(RequestException)
+def handle_request_exception(e):
+ """Returns a detailed synchronous message to the calling client when osdf fails due to a remote call to another system
+
+ """
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+ err_msg = request_exception_to_json_body(e)
+ response = Response(err_msg, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(DataError)
+def handle_data_error(e):
+ """Returns a detailed message to the calling client when the initial synchronous message is invalid
+
+ """
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+
+ body_dictionary = {
+ "serviceException": {
+ "text": BAD_CLIENT_REQUEST_MESSAGE,
+ "exceptionMessage": str(e.errors),
+ "errorType": "InvalidClientRequest"
+ }
+ }
+
+ body_as_json = json.dumps(body_dictionary)
+ response = Response(body_as_json, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.before_request
+def log_request():
+ clear_mdc()
+ if request.content_type and 'json' in request.content_type:
+ populate_mdc(request)
+ g.request_id = get_request_id(request.get_json())
+ log_message(json.dumps(request.get_json()), "INPROGRESS", 'ENTRY')
+ else:
+ populate_default_mdc(request)
+ log_message('', "INPROGRESS", 'ENTRY')
+
+
+@app.after_request
+def log_response(response):
+ log_response_data(response)
+ return response
+
+
+def log_response_data(response):
+ status_value = ''
+ try:
+ status_value = map_status_value(response)
+ log_message(response.get_data(as_text=True), status_value, 'EXIT')
+ except Exception:
+ try:
+ set_default_audit_mdc(request, status_value, 'EXIT')
+ audit_log.info(response.get_data(as_text=True))
+ except Exception:
+ set_error_details(300, 'Internal Error')
+ error_log.error("Error logging the response data due to {}".format(traceback.format_exc()))
+
+
+def set_default_audit_mdc(request, status_value, p_marker):
+ MDC.put('partnerName', 'internal')
+ MDC.put('serviceName', request.path)
+ MDC.put('statusCode', status_value)
+ MDC.put('requestID', 'internal')
+ MDC.put('timer', int((time.process_time() - g.request_start) * 1000))
+ MDC.put('customField1', p_marker)
+
+
+def log_message(message, status_value, p_marker='INVOKE'):
+ MDC.put('statusCode', status_value)
+ MDC.put('customField1', p_marker)
+ MDC.put('timer', int((time.process_time() - g.request_start) * 1000))
+ audit_log.info(message)
+
+
+def map_status_value(response):
+ if 200 <= response.status_code < 300:
+ status_value = "COMPLETE"
+ else:
+ status_value = "ERROR"
+ return status_value
+
+
+@app.errorhandler(500)
+def internal_failure(error):
+ """Returned when unexpected coding errors occur during initial synchronous processing
+
+ """
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+ response = Response(internal_error_message, content_type='application/json; charset=utf-8')
+ response.status_code = 500
+ return response
+
+
+def get_options(argv):
+ program_version_string = '%%prog %s' % "v1.0"
+ program_longdesc = ""
+ program_license = ""
+
+ parser = OptionParser(version=program_version_string, epilog=program_longdesc, description=program_license)
+ parser.add_option("-l", "--local", dest="local", help="run locally", action="store_true", default=False)
+ parser.add_option("-t", "--devtest", dest="devtest", help="run in dev/test environment", action="store_true",
+ default=False)
+ parser.add_option("-d", "--debughost", dest="debughost",
+ help="IP Address of host running debug server", default='')
+ parser.add_option("-p", "--debugport", dest="debugport",
+ help="Port number of debug server", type=int, default=5678)
+ opts, args = parser.parse_args(argv)
+
+ if opts.debughost:
+ debug_log.debug('pydevd.settrace({}, port={})'.format(opts.debughost, opts.debugport))
+ # pydevd.settrace(opts.debughost, port=opts.debugport)
+ return opts
+
+
+def build_ssl_context():
+ ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+ ssl_context.set_ciphers('ECDHE-RSA-AES128-SHA256:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH')
+ ssl_context.load_cert_chain(sys_conf['ssl_context'][0], sys_conf['ssl_context'][1])
+ return ssl_context
+
+
+def run_app():
+ global sys_conf
+ sys_conf = osdf_config['core']['osdf_system']
+ ports = sys_conf['osdf_ports']
+ internal_port, external_port = ports['internal'], ports['external']
+ local_host = sys_conf['osdf_ip_default']
+ common_app_opts = dict(host=local_host, threaded=True, use_reloader=False)
+ ssl_opts = sys_conf.get('ssl_context')
+ if ssl_opts:
+ common_app_opts.update({'ssl_context': build_ssl_context()})
+ opts = get_options(sys.argv)
+ # Load secrets from SMS
+ sms.load_secrets()
+ if not opts.local and not opts.devtest: # normal deployment
+ app.run(port=internal_port, debug=False, **common_app_opts)
+ else:
+ port = internal_port if opts.local else external_port
+ app.run(port=port, debug=True, **common_app_opts)
+
+
+if __name__ == "__main__":
+ run_app()
diff --git a/osdf/cmd/encryptionUtil.py b/osdf/cmd/encryptionUtil.py
new file mode 100644
index 0000000..6c0cae2
--- /dev/null
+++ b/osdf/cmd/encryptionUtil.py
@@ -0,0 +1,50 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2015-2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+import sys
+from osdf.utils import cipherUtils
+
+
+def main():
+
+ if len(sys.argv) != 4:
+ print("Invalid input - usage --> (options(encrypt/decrypt) input-value with-key)")
+ return
+
+ enc_dec = sys.argv[1]
+ valid_option_values = ['encrypt', 'decrypt']
+ if enc_dec not in valid_option_values:
+ print("Invalid input - usage --> (options(encrypt/decrypt) input-value with-key)")
+ print("Option value can only be one of {}".format(valid_option_values))
+ print("You entered '{}'".format(enc_dec))
+ return
+
+ input_string = sys.argv[2]
+ with_key = sys.argv[3]
+
+ print("You've requested '{}' to be '{}ed' using key '{}'".format(input_string, enc_dec, with_key))
+ print("You can always perform the reverse operation (encrypt/decrypt) using the same key"
+ "to be certain you get the same results back'")
+
+ util = cipherUtils.AESCipher.get_instance(with_key)
+ if enc_dec.lower() == 'encrypt':
+ result = util.encrypt(input_string)
+ else:
+ result = util.decrypt(input_string)
+
+ print("Your resultt: {}".format(result)) \ No newline at end of file
diff --git a/osdf/config/__init__.py b/osdf/config/__init__.py
index 86156a1..e32d44e 100644
--- a/osdf/config/__init__.py
+++ b/osdf/config/__init__.py
@@ -27,6 +27,6 @@ class CoreConfig(metaclass=MetaSingleton):
def get_core_config(self, config_file=None):
if self.core_config is None:
- self.core_config = yaml.load(open(config_file))
+ self.core_config = yaml.safe_load(open(config_file))
return self.core_config
diff --git a/osdf/config/base.py b/osdf/config/base.py
index fbe9315..be693cb 100644
--- a/osdf/config/base.py
+++ b/osdf/config/base.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,16 +18,21 @@
#
import os
-
+from osdf.config.consulconfig import call_consul_kv
import osdf.config.credentials as creds
import osdf.config.loader as config_loader
from osdf.utils.programming_utils import DotDict
+from threading import Thread
config_spec = {
"deployment": os.environ.get("OSDF_CONFIG_FILE", "config/osdf_config.yaml"),
"core": "config/common_config.yaml"
}
+slicing_spec = "config/slicing_config.yaml"
+
+slice_config = config_loader.load_config_file(slicing_spec)
+
osdf_config = DotDict(config_loader.all_configs(**config_spec))
http_basic_auth_credentials = creds.load_credentials(osdf_config)
@@ -34,3 +40,10 @@ http_basic_auth_credentials = creds.load_credentials(osdf_config)
dmaap_creds = creds.dmaap_creds()
creds_prefixes = {"so": "so", "cm": "cmPortal", "pcih": "pciHMS"}
+
+osdf_config_deployment = osdf_config.deployment
+
+
+if osdf_config.deployment.get('activateConsulConfig'):
+ consulthread = Thread(target=call_consul_kv, args=(osdf_config,))
+ consulthread.start()
diff --git a/osdf/config/consulconfig.py b/osdf/config/consulconfig.py
new file mode 100644
index 0000000..fc5b3fe
--- /dev/null
+++ b/osdf/config/consulconfig.py
@@ -0,0 +1,52 @@
+from consul.base import Timeout
+from consul.tornado import Consul
+import json
+from osdf.logging.osdf_logging import debug_log
+from tornado.gen import coroutine
+from tornado.ioloop import IOLoop
+
+
+class Config(object):
+ def __init__(self, loop, osdf_final_config):
+ self.config = osdf_final_config
+ osdf_config = self.config['osdf_config']
+ self.consul = Consul(host=osdf_config['consulHost'], port=osdf_config['consulPort'],
+ scheme=osdf_config['consulScheme'], verify=osdf_config['consulVerify'],
+ cert=osdf_config['consulCert'])
+ result = json.dumps(self.config)
+ self.consul.kv.put("osdfconfiguration", result)
+ loop.add_callback(self.watch)
+
+ @coroutine
+ def watch(self):
+ index = None
+ while True:
+ try:
+ index, data = yield self.consul.kv.get('osdfconfiguration', index=index)
+ if data is not None:
+ self.update_config(data)
+ except Timeout:
+ pass
+ except Exception as e:
+ debug_log.debug('Exception Encountered {}'.format(e))
+
+ def update_config(self, data):
+ new_config = json.loads(data['Value'].decode('utf-8'))
+ osdf_deployment = new_config['osdf_config']
+ osdf_core = new_config['common_config']
+ self.config['osdf_config'].update(osdf_deployment)
+ self.config['common_config'].update(osdf_core)
+ debug_log.debug("updated config {}".format(new_config))
+ debug_log.debug("value changed")
+
+
+def call_consul_kv(osdf_config):
+ osdf_final_config = {
+ 'osdf_config': osdf_config.deployment,
+ 'common_config': osdf_config.core
+ }
+ io_loop = IOLoop()
+ io_loop.make_current()
+ IOLoop.current(instance=False)
+ _ = Config(io_loop, osdf_final_config)
+ io_loop.start()
diff --git a/osdf/config/loader.py b/osdf/config/loader.py
index 7cb363a..dca0033 100644
--- a/osdf/config/loader.py
+++ b/osdf/config/loader.py
@@ -31,7 +31,7 @@ def load_config_file(config_file: str, child_name="dockerConfiguration") -> dict
with open(config_file, 'r') as fid:
res = {}
if config_file.endswith(".yaml"):
- res = yaml.load(fid)
+ res = yaml.safe_load(fid)
elif config_file.endswith(".json") or config_file.endswith("json"):
res = json.load(fid)
return res.get(child_name, res) if child_name else res
diff --git a/osdf/logging/__init__.py b/osdf/logging/__init__.py
index 4b25e5b..df7613d 100644
--- a/osdf/logging/__init__.py
+++ b/osdf/logging/__init__.py
@@ -15,3 +15,7 @@
#
# -------------------------------------------------------------------------
#
+
+import yaml
+
+yaml.warnings({'YAMLLoadWarning': False})
diff --git a/osdf/logging/monkey.py b/osdf/logging/monkey.py
new file mode 100644
index 0000000..f6041bc
--- /dev/null
+++ b/osdf/logging/monkey.py
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+
+__all__ = ["patch_all"]
+
+from onaplogging.logWatchDog import patch_loggingYaml
+
+from osdf.logging.oof_mdc_context import patch_logging_mdc
+
+
+def patch_all(mdc=True, yaml=True):
+ """monkey patch osdf logging to enable mdc
+
+ """
+ if mdc is True:
+ patch_logging_mdc()
+
+ if yaml is True:
+ patch_loggingYaml()
diff --git a/osdf/logging/onap_common_v1/CommonLogger.py b/osdf/logging/onap_common_v1/CommonLogger.py
deleted file mode 100755
index 6572d6f..0000000
--- a/osdf/logging/onap_common_v1/CommonLogger.py
+++ /dev/null
@@ -1,900 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-"""ONAP Common Logging library in Python."""
-
-#!/usr/bin/python
-# -*- indent-tabs-mode: nil -*- vi: set expandtab:
-
-
-from __future__ import print_function
-import os, sys, getopt, logging, logging.handlers, time, re, uuid, socket, threading
-
-class CommonLogger:
- """ONAP Common Logging object.
-
- Public methods:
- __init__
- setFields
- debug
- info
- warn
- error
- fatal
- """
-
- UnknownFile = -1
- ErrorFile = 0
- DebugFile = 1
- AuditFile = 2
- MetricsFile = 3
- DateFmt = '%Y-%m-%dT%H:%M:%S'
- verbose = False
-
- def __init__(self, configFile, logKey, **kwargs):
- """Construct a Common Logger for one Log File.
-
- Arguments:
- configFile -- configuration filename.
- logKey -- the keyword in configFile that identifies the log filename.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages,
- one of CommonLogger.ErrorFile, CommonLogger.DebugFile,
- CommonLogger.AuditFile and CommonLogger.MetricsFile, or
- one of the strings "error", "debug", "audit" or "metrics".
- May also be set in the config file using a field named
- <logKey>Style (where <logKey> is the value of the logKey
- parameter). The keyword value overrides the value in the
- config file.
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._monitorFlag = False
-
- # Get configuration parameters
- self._logKey = str(logKey)
- self._configFile = str(configFile)
- self._rotateMethod = 'time'
- self._timeRotateIntervalType = 'midnight'
- self._timeRotateInterval = 1
- self._sizeMaxBytes = 0
- self._sizeRotateMode = 'a'
- self._socketHost = None
- self._socketPort = 0
- self._typeLogger = 'filelogger'
- self._backupCount = 6
- self._logLevelThreshold = self._intLogLevel('')
- self._logFile = None
- self._begTime = None
- self._begMsec = 0
- self._fields = {}
- self._fields["style"] = CommonLogger.UnknownFile
- try:
- self._configFileModified = os.path.getmtime(self._configFile)
- for line in open(self._configFile):
- line = line.split('#',1)[0] # remove comments
- if '=' in line:
- key, value = [x.strip() for x in line.split('=',1)]
- if key == 'rotateMethod' and value.lower() in ['time', 'size', 'none']:
- self._rotateMethod = value.lower()
- elif key == 'timeRotateIntervalType' and value in ['S', 'M', 'H', 'D', 'W0', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'midnight']:
- self._timeRotateIntervalType = value
- elif key == 'timeRotateInterval' and int( value ) > 0:
- self._timeRotateInterval = int( value )
- elif key == 'sizeMaxBytes' and int( value ) >= 0:
- self._sizeMaxBytes = int( value )
- elif key == 'sizeRotateMode' and value in ['a']:
- self._sizeRotateMode = value
- elif key == 'backupCount' and int( value ) >= 0:
- self._backupCount = int( value )
- elif key == self._logKey + 'SocketHost':
- self._socketHost = value
- elif key == self._logKey + 'SocketPort' and int( value ) == 0:
- self._socketPort = int( value )
- elif key == self._logKey + 'LogType' and value.lower() in ['filelogger', 'stdoutlogger', 'stderrlogger', 'socketlogger', 'nulllogger']:
- self._typeLogger = value.lower()
- elif key == self._logKey + 'LogLevel':
- self._logLevelThreshold = self._intLogLevel(value.upper())
- elif key == self._logKey + 'Style':
- self._fields["style"] = value
- elif key == self._logKey:
- self._logFile = value
- except Exception as x:
- print("exception reading '%s' configuration file: %s" %(self._configFile, str(x)), file=sys.stderr)
- sys.exit(2)
- except:
- print("exception reading '%s' configuration file" %(self._configFile), file=sys.stderr)
- sys.exit(2)
-
- if self._logFile is None:
- print('configuration file %s is missing definition %s for log file' %(self._configFile, self._logKey), file=sys.stderr)
- sys.exit(2)
-
-
- # initialize default log fields
- # timestamp will automatically be generated
- for key in ['style', 'requestID', 'serviceInstanceID', 'threadID', 'serverName', 'serviceName', 'instanceUUID', \
- 'severity', 'serverIPAddress', 'server', 'IPAddress', 'className', 'timer', \
- 'partnerName', 'targetEntity', 'targetServiceName', 'statusCode', 'responseCode', \
- 'responseDescription', 'processKey', 'targetVirtualEntity', 'customField1', \
- 'customField2', 'customField3', 'customField4', 'errorCategory', 'errorCode', \
- 'errorDescription' ]:
- if key in kwargs and kwargs[key] != None:
- self._fields[key] = kwargs[key]
-
- self._resetStyleField()
-
- # Set up logger
- self._logLock = threading.Lock()
- with self._logLock:
- self._logger = logging.getLogger(self._logKey)
- self._logger.propagate = False
- self._createLogger()
-
- self._defaultServerInfo()
-
- # spawn a thread to monitor configFile for logLevel and logFile changes
- self._monitorFlag = True
- self._monitorThread = threading.Thread(target=self._monitorConfigFile, args=())
- self._monitorThread.daemon = True
- self._monitorThread.start()
-
-
- def _createLogger(self):
- if self._typeLogger == 'filelogger':
- self._mkdir_p(self._logFile)
- if self._rotateMethod == 'time':
- self._logHandler = logging.handlers.TimedRotatingFileHandler(self._logFile, \
- when=self._timeRotateIntervalType, interval=self._timeRotateInterval, \
- backupCount=self._backupCount, encoding=None, delay=False, utc=True)
- elif self._rotateMethod == 'size':
- self._logHandler = logging.handlers.RotatingFileHandler(self._logFile, \
- mode=self._sizeRotateMode, maxBytes=self._sizeMaxBytes, \
- backupCount=self._backupCount, encoding=None, delay=False)
-
- else:
- self._logHandler = logging.handlers.WatchedFileHandler(self._logFile, \
- mode=self._sizeRotateMode, \
- encoding=None, delay=False)
- elif self._typeLogger == 'stderrlogger':
- self._logHandler = logging.handlers.StreamHandler(sys.stderr)
- elif self._typeLogger == 'stdoutlogger':
- self._logHandler = logging.handlers.StreamHandler(sys.stdout)
- elif self._typeLogger == 'socketlogger':
- self._logHandler = logging.handlers.SocketHandler(self._socketHost, self._socketPort)
- elif self._typeLogger == 'nulllogger':
- self._logHandler = logging.handlers.NullHandler()
-
- if self._fields["style"] == CommonLogger.AuditFile or self._fields["style"] == CommonLogger.MetricsFile:
- self._logFormatter = logging.Formatter(fmt='%(begtime)s,%(begmsecs)03d+00:00|%(endtime)s,%(endmsecs)03d+00:00|%(message)s', datefmt=CommonLogger.DateFmt)
- else:
- self._logFormatter = logging.Formatter(fmt='%(asctime)s,%(msecs)03d+00:00|%(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
- self._logFormatter.converter = time.gmtime
- self._logHandler.setFormatter(self._logFormatter)
- self._logger.addHandler(self._logHandler)
-
- def _resetStyleField(self):
- styleFields = ["error", "debug", "audit", "metrics"]
- if self._fields['style'] in styleFields:
- self._fields['style'] = styleFields.index(self._fields['style'])
-
- def __del__(self):
- if self._monitorFlag == False:
- return
-
- self._monitorFlag = False
-
- if self._monitorThread is not None and self._monitorThread.is_alive():
- self._monitorThread.join()
-
- self._monitorThread = None
-
-
- def _defaultServerInfo(self):
-
- # If not set or purposely set = None, then set default
- if self._fields.get('server') is None:
- try:
- self._fields['server'] = socket.getfqdn()
- except Exception as err:
- try:
- self._fields['server'] = socket.gethostname()
- except Exception as err:
- self._fields['server'] = ""
-
- # If not set or purposely set = None, then set default
- if self._fields.get('serverIPAddress') is None:
- try:
- self._fields['serverIPAddress'] = socket.gethostbyname(self._fields['server'])
- except Exception as err:
- self._fields['serverIPAddress'] = ""
-
-
- def _monitorConfigFile(self):
- while self._monitorFlag:
- try:
- fileTime = os.path.getmtime(self._configFile)
- if fileTime > self._configFileModified:
- self._configFileModified = fileTime
- ReopenLogFile = False
- logFile = self._logFile
- with open(self._configFile) as fp:
- for line in fp:
- line = line.split('#',1)[0] # remove comments
- if '=' in line:
- key, value = [x.strip() for x in line.split('=',1)]
- if key == 'rotateMethod' and value.lower() in ['time', 'size', 'none'] and self._rotateMethod != value:
- self._rotateMethod = value.lower()
- ReopenLogFile = True
- elif key == 'timeRotateIntervalType' and value in ['S', 'M', 'H', 'D', 'W0', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'midnight']:
- self._timeRotateIntervalType = value
- ReopenLogFile = True
- elif key == 'timeRotateInterval' and int( value ) > 0:
- self._timeRotateInterval = int( value )
- ReopenLogFile = True
- elif key == 'sizeMaxBytes' and int( value ) >= 0:
- self._sizeMaxBytes = int( value )
- ReopenLogFile = True
- elif key == 'sizeRotateMode' and value in ['a']:
- self._sizeRotateMode = value
- ReopenLogFile = True
- elif key == 'backupCount' and int( value ) >= 0:
- self._backupCount = int( value )
- ReopenLogFile = True
- elif key == self._logKey + 'SocketHost' and self._socketHost != value:
- self._socketHost = value
- ReopenLogFile = True
- elif key == self._logKey + 'SocketPort' and self._socketPort > 0 and self._socketPort != int( value ):
- self._socketPort = int( value )
- ReopenLogFile = True
- elif key == self._logKey + 'LogLevel' and self._logLevelThreshold != self._intLogLevel( value.upper() ):
- self._logLevelThreshold = self._intLogLevel(value.upper())
- elif key == self._logKey + 'LogType' and self._typeLogger != value and value.lower() in ['filelogger', 'stdoutlogger', 'stderrlogger', 'socketlogger', 'nulllogger']:
- self._typeLogger = value.lower()
- ReopenLogFile = True
- elif key == self._logKey + 'Style':
- self._fields["style"] = value
- self._resetStyleField()
- elif key == self._logKey and self._logFile != value:
- logFile = value
- ReopenLogFile = True
- if ReopenLogFile:
- with self._logLock:
- self._logger.removeHandler(self._logHandler)
- self._logFile = logFile
- self._createLogger()
- except Exception as err:
- pass
-
- time.sleep(5)
-
-
- def setFields(self, **kwargs):
- """Set default values for log fields.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- for key in ['style', 'requestID', 'serviceInstanceID', 'threadID', 'serverName', 'serviceName', 'instanceUUID', \
- 'severity', 'serverIPAddress', 'server', 'IPAddress', 'className', 'timer', \
- 'partnerName', 'targetEntity', 'targetServiceName', 'statusCode', 'responseCode', \
- 'responseDescription', 'processKey', 'targetVirtualEntity', 'customField1', \
- 'customField2', 'customField3', 'customField4', 'errorCategory', 'errorCode', \
- 'errorDescription' ]:
- if key in kwargs:
- if kwargs[key] != None:
- self._fields[key] = kwargs[key]
- elif key in self._fields:
- del self._fields[key]
-
- self._defaultServerInfo()
-
-
- def debug(self, message, **kwargs):
- """Write a DEBUG level message to the log file.
-
- Arguments:
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._log('DEBUG', message, errorCategory = 'DEBUG', **kwargs)
-
- def info(self, message, **kwargs):
- """Write an INFO level message to the log file.
-
- Arguments:
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._log('INFO', message, errorCategory = 'INFO', **kwargs)
-
- def warn(self, message, **kwargs):
- """Write a WARN level message to the log file.
-
- Arguments:
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._log('WARN', message, errorCategory = 'WARN', **kwargs)
-
- def error(self, message, **kwargs):
- """Write an ERROR level message to the log file.
-
- Arguments:
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._log('ERROR', message, errorCategory = 'ERROR', **kwargs)
-
- def fatal(self, message, **kwargs):
- """Write a FATAL level message to the log file.
-
- Arguments:
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- self._log('FATAL', message, errorCategory = 'FATAL', **kwargs)
-
- def _log(self, logLevel, message, **kwargs):
- """Write a message to the log file.
-
- Arguments:
- logLevel -- value ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', ...) for the log record.
- message -- value for the last log record field.
-
- Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
- style -- the log file format (style) to use when writing log messages
- requestID (dame) -- optional default value for this log record field.
- serviceInstanceID (am) -- optional default value for this log record field.
- threadID (am) -- optional default value for this log record field.
- serverName (am) -- optional default value for this log record field.
- serviceName (am) -- optional default value for this log record field.
- instanceUUID (am) -- optional default value for this log record field.
- severity (am) -- optional default value for this log record field.
- serverIPAddress (am) -- optional default value for this log record field.
- server (am) -- optional default value for this log record field.
- IPAddress (am) -- optional default value for this log record field.
- className (am) -- optional default value for this log record field.
- timer (am) -- (ElapsedTime) optional default value for this log record field.
- partnerName (ame) -- optional default value for this log record field.
- targetEntity (me) -- optional default value for this log record field.
- targetServiceName (me) -- optional default value for this log record field.
- statusCode (am) -- optional default value for this log record field.
- responseCode (am) -- optional default value for this log record field.
- responseDescription (am) -- optional default value for this log record field.
- processKey (am) -- optional default value for this log record field.
- targetVirtualEntity (m) -- optional default value for this log record field.
- customField1 (am) -- optional default value for this log record field.
- customField2 (am) -- optional default value for this log record field.
- customField3 (am) -- optional default value for this log record field.
- customField4 (am) -- optional default value for this log record field.
- errorCategory (e) -- optional default value for this log record field.
- errorCode (e) -- optional default value for this log record field.
- errorDescription (e) -- optional default value for this log record field.
-
- Note: the pipe '|' character is not allowed in any log record field.
- """
-
- # timestamp will automatically be inserted
- style = int(self._getVal('style', '', **kwargs))
- requestID = self._getVal('requestID', '', **kwargs)
- serviceInstanceID = self._getVal('serviceInstanceID', '', **kwargs)
- threadID = self._getVal('threadID', threading.currentThread().getName(), **kwargs)
- serverName = self._getVal('serverName', '', **kwargs)
- serviceName = self._getVal('serviceName', '', **kwargs)
- instanceUUID = self._getVal('instanceUUID', '', **kwargs)
- upperLogLevel = self._noSep(logLevel.upper())
- severity = self._getVal('severity', '', **kwargs)
- serverIPAddress = self._getVal('serverIPAddress', '', **kwargs)
- server = self._getVal('server', '', **kwargs)
- IPAddress = self._getVal('IPAddress', '', **kwargs)
- className = self._getVal('className', '', **kwargs)
- timer = self._getVal('timer', '', **kwargs)
- partnerName = self._getVal('partnerName', '', **kwargs)
- targetEntity = self._getVal('targetEntity', '', **kwargs)
- targetServiceName = self._getVal('targetServiceName', '', **kwargs)
- statusCode = self._getVal('statusCode', '', **kwargs)
- responseCode = self._getVal('responseCode', '', **kwargs)
- responseDescription = self._noSep(self._getVal('responseDescription', '', **kwargs))
- processKey = self._getVal('processKey', '', **kwargs)
- targetVirtualEntity = self._getVal('targetVirtualEntity', '', **kwargs)
- customField1 = self._getVal('customField1', '', **kwargs)
- customField2 = self._getVal('customField2', '', **kwargs)
- customField3 = self._getVal('customField3', '', **kwargs)
- customField4 = self._getVal('customField4', '', **kwargs)
- errorCategory = self._getVal('errorCategory', '', **kwargs)
- errorCode = self._getVal('errorCode', '', **kwargs)
- errorDescription = self._noSep(self._getVal('errorDescription', '', **kwargs))
-
- detailMessage = self._noSep(message)
- if bool(re.match(r" *$", detailMessage)):
- return # don't log empty messages
-
- useLevel = self._intLogLevel(upperLogLevel)
- if CommonLogger.verbose: print("logger STYLE=%s" % style)
- if useLevel < self._logLevelThreshold:
- if CommonLogger.verbose: print("skipping because of level")
- pass
- else:
- with self._logLock:
- if style == CommonLogger.ErrorFile:
- if CommonLogger.verbose: print("using CommonLogger.ErrorFile")
- self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
- %(requestID, threadID, serviceName, partnerName, targetEntity, targetServiceName,
- errorCategory, errorCode, errorDescription, detailMessage))
- elif style == CommonLogger.DebugFile:
- if CommonLogger.verbose: print("using CommonLogger.DebugFile")
- self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
- %(requestID, threadID, serverName, serviceName, instanceUUID, upperLogLevel,
- severity, serverIPAddress, server, IPAddress, className, timer, detailMessage))
- elif style == CommonLogger.AuditFile:
- if CommonLogger.verbose: print("using CommonLogger.AuditFile")
- endAuditTime, endAuditMsec = self._getTime()
- if self._begTime is not None:
- d = { 'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endAuditTime, 'endmsecs': endAuditMsec }
- else:
- d = { 'begtime': endAuditTime, 'begmsecs': endAuditMsec, 'endtime': endAuditTime, 'endmsecs': endAuditMsec }
- self._begTime = None
- unused = ""
- self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
- %(requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
- statusCode, responseCode, responseDescription, instanceUUID, upperLogLevel,
- severity, serverIPAddress, timer, server, IPAddress, className, unused,
- processKey, customField1, customField2, customField3, customField4, detailMessage), extra=d)
- elif style == CommonLogger.MetricsFile:
- if CommonLogger.verbose: print("using CommonLogger.MetricsFile")
- endMetricsTime, endMetricsMsec = self._getTime()
- if self._begTime is not None:
- d = { 'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endMetricsTime, 'endmsecs': endMetricsMsec }
- else:
- d = { 'begtime': endMetricsTime, 'begmsecs': endMetricsMsec, 'endtime': endMetricsTime, 'endmsecs': endMetricsMsec }
- self._begTime = None
- unused = ""
- self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
- %(requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
- targetEntity, targetServiceName, statusCode, responseCode, responseDescription,
- instanceUUID, upperLogLevel, severity, serverIPAddress, timer, server, IPAddress,
- className, unused, processKey, targetVirtualEntity, customField1, customField2,
- customField3, customField4, detailMessage), extra=d)
- else:
- print("!!!!!!!!!!!!!!!! style not set: %s" % self._fields["style"])
-
- def _getTime(self):
- ct = time.time()
- lt = time.localtime(ct)
- return (time.strftime(CommonLogger.DateFmt, lt), (ct - int(ct)) * 1000)
-
- def setStartRecordEvent(self):
- """
- Set the start time to be saved for both audit and metrics records
- """
- self._begTime, self._begMsec = self._getTime()
-
- def _getVal(self, key, default, **kwargs):
- val = self._fields.get(key)
- if key in kwargs: val = kwargs[key]
- if val is None: val = default
- return self._noSep(val)
-
- def _noSep(self, message):
- if message is None: return ''
- return re.sub(r'[\|\n]', ' ', str(message))
-
- def _intLogLevel(self, logLevel):
- if logLevel == 'FATAL': useLevel = 50
- elif logLevel == 'ERROR': useLevel = 40
- elif logLevel == 'WARN': useLevel = 30
- elif logLevel == 'INFO': useLevel = 20
- elif logLevel == 'DEBUG': useLevel = 10
- else: useLevel = 0
- return useLevel
-
- def _mkdir_p(self, filename):
- """Create missing directories from a full filename path like mkdir -p"""
-
- if filename is None:
- return
-
- folder=os.path.dirname(filename)
-
- if folder == "":
- return
-
- if not os.path.exists(folder):
- try:
- os.makedirs(folder)
- except OSError as err:
- print("error number %d creating %s directory to hold %s logfile: %s" %(err.errno, err.filename, filename, err.strerror), file=sys.stderr)
- sys.exit(2)
- except Exception as err:
- print("error creating %s directory to hold %s logfile: %s" %(folder, filename, str(err)), file=sys.stderr)
- sys.exit(2)
-
-def __checkTime1(line):
- format = r'[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9][0-9][0-9][+]00:00[|]'
- format = r'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}[+]00:00[|]'
- m = re.match(format, line)
- if not m:
- print("ERROR: time string did not match proper time format, %s" %line)
- print("\t: format=%s" % format)
- return 1
- return 0
-
-def __checkTime2(line, different):
- format = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:([0-9][0-9]),([0-9][0-9][0-9])[+]00:00[|][0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:([0-9][0-9]),([0-9][0-9][0-9])[+]00:00[|]'
- format = r'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}),([0-9]{3})[+]00:00[|][0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}),([0-9]{3})[+]00:00[|]'
- m = re.match(format, line)
- if not m:
- print("ERROR: time strings did not match proper time format, %s" %line)
- print("\t: format=%s" % format)
- return 1
- second1 = int(m.group(1))
- msec1 = int(m.group(2))
- second2 = int(m.group(3))
- msec2 = int(m.group(4))
- if second1 > second2: second2 += 60
- t1 = second1 * 1000 + msec1
- t2 = second2 * 1000 + msec2
- diff = t2 - t1
- # print("t1=%d (%d,%d) t2=%d (%d,%d), diff = %d" % (t1, second1, msec1, t2, second2, msec2, diff))
- if different:
- if diff < 500:
- print("ERROR: times did not differ enough: %s" % line)
- return 1
- else:
- if diff > 10:
- print("ERROR: times were too far apart: %s" % line)
- return 1
- return 0
-
-def __checkLog(logfile, numLines, numFields):
- lineCount = 0
- errorCount = 0
- with open(logfile, "r") as fp:
- for line in fp:
- # print("saw line %s" % line)
- lineCount += 1
- c = line.count('|')
- if c != numFields:
- print("ERROR: wrong number of fields. Expected %d, got %d: %s" % (numFields, c, line))
- errorCount += 1
- if re.search("should not appear", line):
- print("ERROR: a line appeared that should not have appeared, %s" % line)
- errorCount += 1
- elif re.search("single time", line):
- errorCount += __checkTime1(line)
- elif re.search("time should be the same", line):
- errorCount += __checkTime2(line, different=False)
- elif re.search("time should be different", line):
- errorCount += __checkTime2(line, different=True)
- else:
- print("ERROR: an unknown message appeared, %s" % line)
- errorCount += 1
-
- if lineCount != numLines:
- print("ERROR: expected %d lines, but got %d lines" % (numLines, lineCount))
- errorCount += 1
- return errorCount
-
-if __name__ == "__main__":
- import os, argparse
- parser = argparse.ArgumentParser(description="test the CommonLogger functions")
- parser.add_argument("-k", "--keeplogs", help="Keep the log files after finishing the tests", action="store_true")
- parser.add_argument("-v", "--verbose", help="Print debugging messages", action="store_true")
- args = parser.parse_args()
-
- spid = str(os.getpid())
- if args.keeplogs:
- spid = ""
- logcfg = "/tmp/cl.log" + spid + ".cfg"
- errorLog = "/tmp/cl.error" + spid + ".log"
- metricsLog = "/tmp/cl.metrics" + spid + ".log"
- auditLog = "/tmp/cl.audit" + spid + ".log"
- debugLog = "/tmp/cl.debug" + spid + ".log"
- if args.verbose: CommonLogger.verbose = True
-
- import atexit
- def cleanupTmps():
- for f in [ logcfg, errorLog, metricsLog, auditLog, debugLog ]:
- try:
- os.remove(f)
- except:
- pass
- if not args.keeplogs:
- atexit.register(cleanupTmps)
-
- with open(logcfg, "w") as o:
- o.write("error = " + errorLog + "\n" +
- "errorLogLevel = WARN\n" +
- "metrics = " + metricsLog + "\n" +
- "metricsLogLevel = INFO\n" +
- "audit = " + auditLog + "\n" +
- "auditLogLevel = INFO\n" +
- "debug = " + debugLog + "\n" +
- "debugLogLevel = DEBUG\n")
-
- import uuid
- instanceUUID = uuid.uuid1()
- serviceName = "testharness"
- errorLogger = CommonLogger(logcfg, "error", style=CommonLogger.ErrorFile, instanceUUID=instanceUUID, serviceName=serviceName)
- debugLogger = CommonLogger(logcfg, "debug", style=CommonLogger.DebugFile, instanceUUID=instanceUUID, serviceName=serviceName)
- auditLogger = CommonLogger(logcfg, "audit", style=CommonLogger.AuditFile, instanceUUID=instanceUUID, serviceName=serviceName)
- metricsLogger = CommonLogger(logcfg, "metrics", style=CommonLogger.MetricsFile, instanceUUID=instanceUUID, serviceName=serviceName)
-
- testsRun = 0
- errorCount = 0
- errorLogger.debug("error calling debug (should not appear)")
- errorLogger.info("error calling info (should not appear)")
- errorLogger.warn("error calling warn (single time)")
- errorLogger.error("error calling error (single time)")
- errorLogger.setStartRecordEvent()
- time.sleep(1)
- errorLogger.fatal("error calling fatal, after setStartRecordEvent and sleep (start should be ignored, single time)")
- testsRun += 6
- errorCount += __checkLog(errorLog, 3, 10)
-
- auditLogger.debug("audit calling debug (should not appear)")
- auditLogger.info("audit calling info (time should be the same)")
- auditLogger.warn("audit calling warn (time should be the same)")
- auditLogger.error("audit calling error (time should be the same)")
- auditLogger.setStartRecordEvent()
- time.sleep(1)
- auditLogger.fatal("audit calling fatal, after setStartRecordEvent and sleep, time should be different)")
- testsRun += 6
- errorCount += __checkLog(auditLog, 4, 25)
-
- debugLogger.debug("debug calling debug (single time)")
- debugLogger.info("debug calling info (single time)")
- debugLogger.warn("debug calling warn (single time)")
- debugLogger.setStartRecordEvent()
- time.sleep(1)
- debugLogger.error("debug calling error, after SetStartRecordEvent and sleep (start should be ignored, single time)")
- debugLogger.fatal("debug calling fatal (single time)")
- errorCount += __checkLog(debugLog, 5, 13)
- testsRun += 6
-
- metricsLogger.debug("metrics calling debug (should not appear)")
- metricsLogger.info("metrics calling info (time should be the same)")
- metricsLogger.warn("metrics calling warn (time should be the same)")
- metricsLogger.setStartRecordEvent()
- time.sleep(1)
- metricsLogger.error("metrics calling error, after SetStartRecordEvent and sleep, time should be different")
- metricsLogger.fatal("metrics calling fatal (time should be the same)")
- testsRun += 6
- errorCount += __checkLog(metricsLog, 4, 28)
-
- print("%d tests run, %d errors found" % (testsRun, errorCount))
diff --git a/osdf/logging/onap_common_v1/CommonLogger_test.config b/osdf/logging/onap_common_v1/CommonLogger_test.config
deleted file mode 100755
index 584fb5e..0000000
--- a/osdf/logging/onap_common_v1/CommonLogger_test.config
+++ /dev/null
@@ -1,58 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-# You may change this file while your program is running and CommonLogger will automatically reconfigure accordingly.
-# Changing these parameters may leave old log files lying around.
-
-
-#--- Parameters that apply to all logs
-#
-# rotateMethod: time, size, stdout, stderr, none
-#... Note: the following two parameters apply only when rotateMethod=time
-# timeRotateIntervalType: S, M, H, D, W0 - W6, or midnight (seconds, minutes, hours, days, weekday (0=Monday), or midnight UTC)
-# timeRotateInterval: >= 1 (1 means every timeRotateIntervalType, 2 every other, 3 every third, etc.)
-#... Note: the following parameter applies only when rotateMethod=size
-# sizeMaxBytes: >= 0 (0 means no limit, else maximum filesize in Bytes)
-# backupCount: >= 0 (Number of rotated backup files to retain. If rotateMethod=time, 0 retains *all* backups. If rotateMethod=size, 0 retains *no* backups.)
-#
-rotateMethod = time
-timeRotateIntervalType = midnight
-timeRotateInterval = 1
-sizeMaxBytes = 0
-backupCount = 6
-
-
-#--- Parameters that define log filenames and their initial LogLevel threshold
-#... Note: CommonLogger will exit if your process does not have permission to write to the file.
-#
-
-error = /opt/logs/oof/error.log
-errorLogLevel = WARN
-errorStyle = error
-
-metrics = /opt/logs/oof/metrics.log
-metricsLogLevel = INFO
-metricsStyle = metrics
-
-audit = /opt/logs/oof/audit.log
-auditLogLevel = INFO
-auditStyle = audit
-
-debug = /opt/logs/oof/debug.log
-debugLogLevel = DEBUG
-debugStyle = debug
diff --git a/osdf/logging/onap_common_v1/CommonLogger_testing.py b/osdf/logging/onap_common_v1/CommonLogger_testing.py
deleted file mode 100755
index 43e0ec3..0000000
--- a/osdf/logging/onap_common_v1/CommonLogger_testing.py
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/python
-
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-"""
-Test the ONAP Common Logging library in Python.
-CommonLogger_test.py
-"""
-
-
-from __future__ import print_function # for the example code below parsing command line options
-import os, sys, getopt # for the example code below parsing command line options
-
-from osdf.logging.onap_common_v1.CommonLogger import CommonLogger # all that is needed to import the CommonLogger library
-
-import uuid # to create UUIDs for our log records
-import time # to create elapsed time for our log records
-
-
-#----- A client might want to allow specifying the configFile as a command line option
-usage="usage: %s [ -c <configFile> ]" % ( os.path.basename(__file__) )
-try:
- opts, args = getopt.getopt(sys.argv[1:], "c:")
-except getopt.GetoptError:
- print(usage, file=sys.stderr)
- sys.exit(2)
-
-configFile = "CommonLogger_test.config"
-for opt, arg in opts:
- if opt == "-c":
- configFile = arg
- else:
- print(usage, file=sys.stderr)
- sys.exit(2)
-
-
-#----- Instantiate the loggers
-
-# The client's top-level program (e.g., vPRO.py) can create a unique identifier UUID to differentiate between multiple instances of itself.
-instanceUUID = uuid.uuid1()
-
-# The client should identify its ONAP component -- and if applicable -- its ONAP sub-component
-serviceName = "DCAE/vPRO"
-
-# Instantiate using a configuration file with a key specifying the log file name and set fields' default values
-errorLog = CommonLogger.CommonLogger(configFile, "error", instanceUUID=instanceUUID, serviceName=serviceName)
-metricsLog = CommonLogger.CommonLogger(configFile, "metrics", instanceUUID=instanceUUID, serviceName=serviceName)
-auditLog = CommonLogger.CommonLogger(configFile, "audit", instanceUUID=instanceUUID, serviceName=serviceName)
-debugLog = CommonLogger.CommonLogger(configFile, "debug", instanceUUID=instanceUUID, serviceName=serviceName)
-
-
-#----- use the loggers
-
-# both metrics and audit logs can have an event starting time. This only affects the next log message.
-metricsLog.setStartRecordEvent()
-auditLog.setStartRecordEvent()
-
-# Simple log messages
-debugLog.debug("a DEBUG message for the debug log")
-metricsLog.info("an INFO message for the metrics log")
-auditLog.info("an INFO message for the audit log")
-errorLog.warn("a WARN message for the error log")
-errorLog.error("an ERROR message for the error log")
-errorLog.fatal("a FATAL message for the error log")
-
-
-# Can override any of the other fields when writing each log record
-debugLog.debug("demonstrating overriding all fields with atypical values", requestID="2", serviceInstanceID="3", threadID="4", serverName="5", serviceName="6", instanceUUID="7", severity="9", serverIPAddress="10", server="11", IPAddress="12", className="13", timer="14")
-
-
-# The is an example of an interaction between two ONAP components:
-
-# vPRO generates Closed Loop RESTful API requests to App-C, knowing this information:
-requestClient = "netman@localdcae.att.com:~/vPRO_trinity/vPRO.py:905" # uniquely identifies the requester
-requestTime = "2015-08-20 20:57:14.463426" # unique ID of the request within the requester's scope
-request = "Restart"
-
-# Form the value for Common Logging's requestID field:
-requestID = requestClient + "+" + requestTime # vPRO will use this as the unique requestID
-# requestID = uuid.uuid1() # other services might generate a UUID as their requestID
-
-# Form the value for Common Logging's serviceName field when an interaction between two ONAP components:
-ourONAP = serviceName
-peerONAP = "App-C"
-operation = request
-interaction = ourONAP + ":" + peerONAP + "." + operation
-
-# Let's calculate and report elapsed times
-start = time.time()
-
-# Log the request
-auditLog.info("Requesting %s to %s" %(peerONAP, operation), requestID=requestID, serviceName=interaction)
-
-# Wait for first response
-time.sleep(1) # simulate processing the action, e.g., waiting for response from App-C
-
-# Form the value for Common Logging's serviceName field when an interaction between two ONAP components:
-operation = 'PENDING'
-interaction = peerONAP + ":" + ourONAP + "." + operation
-
-# Log the response with elapsed time
-ms = int(round(1000 * (time.time() - start))) # Calculate elapsed time in ms
-auditLog.info("%s acknowledged receiving request for %s" %(peerONAP, operation), requestID=requestID, serviceName=interaction, timer=ms)
-
-# Wait for next response
-time.sleep(1) # simulate processing the action, e.g., waiting for response from App-C
-
-# Form the value for Common Logging's serviceName field when an interaction between two ONAP components:
-operation = 'SUCCESS'
-interaction = peerONAP + ":" + ourONAP + "." + operation
-
-# Log the response with elapsed time
-ms = int(round(1000 * (time.time() - start))) # Calculate elapsed time in ms
-auditLog.info("%s finished %s" %(peerONAP, operation), requestID=requestID, serviceName=interaction, timer=ms)
-
-
-# Can change the fields' default values for a logger after instantiation if desired
-debugLog.setFields(serviceName="DCAE", threadID='thread-2')
-
-# Then subsequent logging will have the new default field values
-debugLog.info("Something happened")
-debugLog.warn("Something happened again")
-
-
-# Unset (set=None) a field so the Common Logger will use the default value
-debugLog.info("threadID should be default", threadID=None)
-debugLog.setFields(threadID=None)
-debugLog.info("threadID should be default")
diff --git a/osdf/logging/onap_common_v1/README.md b/osdf/logging/onap_common_v1/README.md
deleted file mode 100755
index 596cd7f..0000000
--- a/osdf/logging/onap_common_v1/README.md
+++ /dev/null
@@ -1,214 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-# Common Logging Wrapper for Python
-
-* CommonLogger.py is the module (library) to import
-* CommonLogger_test.config is an example configuration file used by CommonLogger_test.py
-* CommonLogger_test.py is an example of how to import and use the CommonLogger module
-
-## Configuration File
-
-Configure common logging for a python application in a configuration file.
-In the file, put key = value assignments
-
-* defining the filename for each log file you will create, such as
-'error=/path/error.log', 'metrics=/path/metrics.log', 'audit=/path/audit.log',
-and 'debug=/path/debug.log'.
-The name used (shown here as 'error', 'metrics', etc.) is chosen in the program, allowing a single configuration file to be
-used by numerous different programs.
-(It will be referred to below as &lt;logKey&gt;.)
-* defining the style of the log messages to be produced,
-using &lt;logKey&gt; suffixed with 'Style', as in 'errorStyle=', and one of the
-words 'error', 'metrics', 'audit' and 'debug'.
-* defining the minimum level of log messages to be retained in a log file,
-using &lt;logKey&gt; suffixed with 'LogLevel', as in 'errorLogLevel=WARN'.
-The levels are DEBUG, INFO, WARN, ERROR, and FATAL.
-So specifying WARN will retain only WARN, ERROR, and FATAL level
-log messages, while specifying DEBUG will retain all levels of log messages:
-DEBUG, INFO, WARN, ERROR, and FATAL.
-
-Comments may be included on any line following a '#' character.
-
-Common logging monitors the configuration file so if the file is edited
-and any its values change, then common logging will implement the changes
-in the running application.
-This enables operations to change log levels or even log filenames without
-interrupting the running application.
-
-By default, log files are rotated daily at midnight UTC, retaining 6 backup versions by default.
-
-Other strategies can be specified within the configuration file using the keywords:
-
-* rotateMethod = one of 'time', 'size', and 'none' (case insensitive)
-
-If rotateMethod is 'time', the following keywords apply:
-* backupCount = Number of rotated backup files to retain, >= 0. 0 retains *all* backups.
-* timeRotateIntervalType = one of 'S', 'M', 'H', 'D', 'W0', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'midnight'
-(seconds, minutes, hours, days, weekday (0=Monday), or midnight UTC)
-* timeRotateInterval = number of seconds/minutes/hours/days between rotations. (Ignored for W#.)
-
-If rotateMethod is 'size', the following keywords apply:
-* backupCount = Number of rotated backup files to retain, >= 0. 0 retains *no* backups.
-* sizeMaxBytes = maximum number of bytes allowed in the file before rotation
-* sizeRotateMode = for now, this defaults to 'a' and may only be specified as 'a'.
-It is passed to the underlying Python Logging methods.
-
-
-Besides logging to a file, it is also possible to send log messages elsewhere,
-using &lt;logKey&gt; suffixed with 'LogType'.
-You can set &lt;logKey&gt;LogType to any of 'filelogger', 'stdoutlogger', 'stderrlogger', 'socketlogger' orlogger 'null' (case insensitive).
-
-* 'filelogger' is the default specifying logging to a file.
-* 'stdoutlogger' and 'stderrlogger' send the output to the corresponding output streams.
-* 'socketlogger' will send the output to the corresponding socket host.
-* 'nulllogger' turns off logging.
-
-If &lt;logKey&gt;LogType is 'socket', the following keywords apply:
-* &lt;logKey&gt;SocketHost = FQDN or IP address for a host to sent the logs to
-* &lt;logKey&gt;SocketPort = the port (> 0) to open on that host
-
-This is an example configuration file:
-
- error = /var/log/DCAE/vPRO/error.log
- errorLogLevel = WARN
- errorStyle = error
-
- metrics = /var/log/DCAE/vPRO/metrics.log
- metricsLogLevel = INFO
- metricsStyle = metrics
-
- audit = /var/log/DCAE/vPRO/audit.log
- auditLogLevel = INFO
- auditStyle = audit
-
- debug = /var/log/DCAE/vPRO/debug.log
- debugLogLevel = DEBUG
- debugStyle = debug
-
-## Coding Python Applications to Produce ONAP Common Logging
-
-A python application uses common logging by importing the CommonLogger
-module, instantiating a CommonLogger object for each log file, and then
-invoking each object's debug, info, warn, error, or fatal methods to log
-messages to the file. There are four styles of logging:
-error/info logs, debug logs, audit logs, and metrics logs.
-The difference between the types of logs is in the list of fields that
-are printed out.
-
-### Importing the CommonLogger Module
-
-Importing the CommonLogger module is typical:
-
- sys.path.append("/opt/app/dcae-commonlogging/python")
- import CommonLogger
-
-### Creating a CommonLogger object:
-
-When creating a CommonLogger object, three arguments are required:
-
-1. The configuration filename.
-2. The keyword name in the configuration file that
-defines the log filename and parameters controlling rotation of the logfiles.
-(This is the &lt;logKey&gt; referred to above.)
-3. The keyword arguments for style and to set default values for the log record fields.
-
-The style of the log (one of CommonLoger.DebugFile, CommonLogger.AuditFile,
-CommonLogger.MetricsFile and CommonLogger.ErrorFile), must be specified either
-in the configuration file (e.g., errorStyle=error or metricsStyle=metrics) or
-using a style= keyword and one of the values: CommonLoger.DebugFile,
-CommonLogger.AuditFile, CommonLogger.MetricsFile and CommonLogger.ErrorFile.
-
-Keyword arguments for log record fields are as follows.
-The annotation indicates whether the field is included in
-(d) debug logs, (a) audit logs, (m) metrics logs, and (e) error logs.
-
-* requestID (dame)
-* serviceInstanceID (am)
-* threadID (am)
-* serverName (am)
-* serviceName (am)
-* instanceUUID (am)
-* severity (am)
-* serverIPAddress (am)
-* server (am)
-* IPAddress (am)
-* className (am)
-* timer (am)
-* partnerName (ame)
-* targetEntity (me)
-* targetServiceName (me)
-* statusCode (am)
-* responseCode (am)
-* responseDescription (am)
-* processKey (am)
-* targetVirtualEntity (m)
-* customField1 (am)
-* customField2 (am)
-* customField3 (am)
-* customField4 (am)
-* errorCategory (e)
-* errorCode (e)
-* errorDescription (e)
-
-Sample code:
-
- """ The style can be specified here or in the config file using errorStyle. """
- errorLog = CommonLogger.CommonLogger("my.config", "error", style=CommonLogger.ErrorFile, serviceName="DCAE/vPRO")
- infoLog = CommonLogger.CommonLogger("my.config", "info", serviceName="DCAE/vPRO")
-
-### Setting default values for fields:
-
-The object's setFields method allows keyword arguments changing default values for the log record fields.
-
- errorLog.setFields(serviceName="DCAE/vPRO", threadID="thread-2")
-
-### Calling Methods
-
-The object's debug(), info(), warn(), error(), and fatal() methods require a detailMessage argument
-(which can be a zero-length string) and allow the keyword arguments for setting log record field
-values for just that one message.
-Any newlines or '|' characters in the message will be changed to a single space.
-
- infoLog.info("Something benign happened.")
- errorLog.fatal("Something very bad happened.", threadID="thread-4")
-
-### Output
-
-Note that no field may contain the '|' (pipe) field separation character, as that
-character is used as the separator between fields.
-Here is a possible example of a produced log record:
-
- 2015-10-12T15:56:43,182+00:00|netman@localdcae.att.com:~/vPRO_trinity/vPRO.py:905+2015-08-20 20:57:14.463426||||DCAE/vPRO:App-C.Restart|d4d5fc66-70f9-11e5-b0b1-005056866a82|INFO||135.16.76.33|mtvpro01dev1.dev.att.com|||1001|Finished Restart
- 2016-12-09T23:06:02,314+00:00||MainThread|DCAE/vPRO|||||||a FATAL message for the error log
-
-### Example Code
-
-The main within CommonLogger.py contains a regression test of the CommonLogger methods.
-
-CommonLogger_test.py contains a complete demonstration of a python application
-using the python CommonLogging wrapper module, including creating UUIDs,
-setting default log field values, and timing operations.
-
-## Upgrading from Previous Versions of CommonLogger
-
-The current version of CommonLogger is 99% compatible with earlier versions of CommonLogger.
-The key change, due to update ONAP logging requirements, is the choice to use different lists
-of fields in different types of log files.
-This required adding a mandatory "style" to be given, which we chose to do using either a
-new keyword in the configuration file, or using a new parameter keyword when creating the logger.
diff --git a/osdf/logging/oof_mdc_context.py b/osdf/logging/oof_mdc_context.py
new file mode 100644
index 0000000..9c9b52c
--- /dev/null
+++ b/osdf/logging/oof_mdc_context.py
@@ -0,0 +1,170 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import logging
+import re
+import sys
+
+from onaplogging.marker import Marker
+from onaplogging.marker import MARKER_TAG
+from onaplogging.mdcContext import _replace_func_name
+from onaplogging.mdcContext import fetchkeys
+from onaplogging.mdcContext import findCaller as fc
+from onaplogging.mdcContext import MDC
+
+from osdf.utils.mdc_utils import set_error_details
+
+
+def findCaller(self, stack_info=False, stacklevel=1):
+ """replacing onaplogging.mdcContext with this method to work with py3.8
+
+ """
+ return fc(stack_info)
+
+
+def mdc_mapper():
+ """Convert the MDC dict into comma separated, name=value string
+
+ :return: string format
+ """
+ return ','.join(f'{k}={v}' for (k, v) in MDC.result().items() if k not in ['customField2'])
+
+
+@fetchkeys
+def info(self, msg, *args, **kwargs):
+ """Wrapper method for log.info is called
+
+ """
+ if self.isEnabledFor(logging.INFO):
+ MDC.put('customField2', mdc_mapper())
+ self._log(logging.INFO, no_sep(msg), args, **kwargs)
+
+
+@fetchkeys
+def debug(self, msg, *args, **kwargs):
+ """Wrapper method for log.debug is called
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ if self.isEnabledFor(logging.DEBUG):
+ self._log(logging.DEBUG, no_sep(msg), args, **kwargs)
+
+
+@fetchkeys
+def warning(self, msg, *args, **kwargs):
+ """Wrapper method for log.warning is called
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ if self.isEnabledFor(logging.WARNING):
+ self._log(logging.WARNING, no_sep(msg), args, **kwargs)
+
+
+@fetchkeys
+def exception(self, msg, *args, **kwargs):
+ """Wrapper method for log.exception is called
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ kwargs['exc_info'] = 1
+ self.error(no_sep(msg), *args, **kwargs)
+
+
+@fetchkeys
+def critical(self, msg, *args, **kwargs):
+ """Wrapper method for log.critical
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ if self.isEnabledFor(logging.CRITICAL):
+ self._log(logging.CRITICAL, no_sep(msg), args, **kwargs)
+
+
+@fetchkeys
+def error(self, msg, *args, **kwargs):
+ """Wrapper method for log.error is called
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ if self.isEnabledFor(logging.ERROR):
+ if not MDC.get('errorCode'):
+ set_error_details(400, 'Internal Error')
+ MDC.put('customField2', mdc_mapper())
+ self._log(logging.ERROR, no_sep(msg), args, **kwargs)
+
+
+@fetchkeys
+def log(self, level, msg, *args, **kwargs):
+ """Wrapper method for log.log is called
+
+ msg: log message
+ args: logging args
+ kwargs: all the optional args
+ """
+ if not isinstance(level, int):
+ if logging.raiseExceptions:
+ raise TypeError("level must be an integer")
+ else:
+ return
+
+ if self.isEnabledFor(level):
+ self._log(level, no_sep(msg), args, **kwargs)
+
+
+def handle(self, record):
+ """Wrapper method for log.handle is called
+
+ """
+ c_marker = getattr(self, MARKER_TAG, None)
+
+ if isinstance(c_marker, Marker):
+ setattr(record, MARKER_TAG, c_marker)
+
+ if (not self.disabled) and self.filter(record):
+ self.callHandlers(record)
+
+
+def no_sep(message):
+ """This method will remove newline, | from the message
+
+ """
+ if message is None:
+ return ''
+ return re.sub(r'[\|\n]', ' ', str(message))
+
+
+def patch_logging_mdc():
+ """The patch to add MDC ability in logging Record instance at runtime
+
+ """
+ local_module = sys.modules[__name__]
+ for attr in dir(logging.Logger):
+ if attr in _replace_func_name:
+ new_func = getattr(local_module, attr, None)
+ if new_func:
+ setattr(logging.Logger, attr, new_func)
diff --git a/osdf/logging/oof_mdc_formatter.py b/osdf/logging/oof_mdc_formatter.py
new file mode 100644
index 0000000..6272a18
--- /dev/null
+++ b/osdf/logging/oof_mdc_formatter.py
@@ -0,0 +1,51 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import time
+
+from onaplogging.colorFormatter import RESET
+from onaplogging.mdcformatter import MDCFormatter
+
+
+class OOFMDCFormatter(MDCFormatter):
+ """ONAP MDC formatter
+
+ """
+
+ def __init__(self, fmt=None, mdcfmt=None,
+ datefmt=None, colorfmt=None, style="%"):
+ super().__init__(fmt, mdcfmt, datefmt, colorfmt, style)
+ self.converter = time.gmtime
+
+ def _replaceStr(self, keys):
+ """overriding the default behavior
+
+ keys: keys that needs to be substituted
+
+ """
+ fmt = self._mdcFmt
+ for i in keys:
+ fmt = fmt.replace(i, i)
+
+ return fmt
+
+ def format(self, record):
+ """Removing the color format end of line character.
+
+ """
+ return super(OOFMDCFormatter, self).format(record).replace(RESET, '')
diff --git a/osdf/logging/osdf_logging.py b/osdf/logging/osdf_logging.py
index a54d426..7ebaa99 100755
--- a/osdf/logging/osdf_logging.py
+++ b/osdf/logging/osdf_logging.py
@@ -15,38 +15,23 @@
#
# -------------------------------------------------------------------------
#
-
+import logging
+from logging import config
+import os
import traceback
-import uuid
-from .onap_common_v1.CommonLogger import CommonLogger
-from osdf.utils.programming_utils import MetaSingleton
+import yaml
+from osdf.logging import monkey
+from osdf.utils.programming_utils import MetaSingleton
-def log_handlers_pre_onap(config_file="config/onap_logging_common_v1.config",
- service_name="OOF_OSDF"):
- """
- Convenience handlers for logging to different log files
-
- :param config_file: configuration file (properties file) that specifies log location, rotation, etc.
- :param service_name: name for this service
- :return: dictionary of log objects: "error", "metrics", "audit", "debug"
-
- We can use the returned values as follows:
- X["error"].fatal("a FATAL message for the error log")
- X["error"].error("an ERROR message for the error log")
- X["error"].warn("a WARN message for the error log")
- X["audit"].info("an INFO message for the audit log")
- X["metrics"].info("an INFO message for the metrics log")
- X["debug"].debug("a DEBUG message for the debug log")
- """
- main_params = dict(instanceUUID=uuid.uuid1(), serviceName=service_name, configFile=config_file)
- return dict((x, CommonLogger(logKey=x, **main_params))
- for x in ["error", "metrics", "audit", "debug"])
+BASE_DIR = os.path.dirname(__file__)
+LOGGING_FILE = os.path.join(BASE_DIR, '..', '..', 'config', 'log.yml')
def format_exception(err, prefix=None):
"""Format operation for use with ecomp logging
+
:param err: exception object
:param prefix: prefix string message
:return: formatted exception (via repr(traceback.format_tb(err.__traceback__))
@@ -56,188 +41,279 @@ def format_exception(err, prefix=None):
return exception_desc if not prefix else prefix + ": " + exception_desc
-class OOF_OSDFLogMessageHelper(metaclass=MetaSingleton):
+def create_log_dirs():
+ with open(LOGGING_FILE, 'r') as fid:
+ yaml_config = yaml.full_load(fid)
+ for key in yaml_config['handlers']:
+ a = yaml_config['handlers'][key]
+ if a.get('filename'):
+ os.makedirs(os.path.dirname(a['filename']), exist_ok=True)
+
+
+class OOFOSDFLogMessageHelper(metaclass=MetaSingleton):
"""Provides loggers as a singleton (otherwise, we end up with duplicate messages).
+
Provides error_log, metric_log, audit_log, and debug_log (in that order)
+
Additionally can provide specific log handlers too
"""
log_handlers = None
default_levels = ["error", "metrics", "audit", "debug"]
- def _setup_handlers(self, log_version="pre_onap", config_file=None, service_name=None):
- """return error_log, metrics_log, audit_log, debug_log"""
- if self.log_handlers is None:
- params = {}
- params.update({"config_file": config_file} if config_file else {})
- params.update({"service_name": service_name} if service_name else {})
-
- if log_version == "pre_onap":
- self.log_handlers = log_handlers_pre_onap(**params)
-
- def get_handlers(self, levels=None, log_version="pre_onap", config_file=None, service_name=None):
+ def get_handlers(self, levels=None):
"""Return ONAP-compliant log handlers for different levels. Each "level" ends up in a different log file
+
with a prefix of that level.
For example: error_log, metrics_log, audit_log, debug_log in that order
+
:param levels: None or list of levels subset of self.default_levels (["error", "metrics", "audit", "debug"])
- :param log_version: Currently only pre_onap is supported
- :param config_file: Logging configuration file for ONAP compliant logging
- :param service_name: Name of the service
+
:return: list of log_handlers in the order of levels requested.
if levels is None: we return handlers for self.default_levels
if levels is ["error", "audit"], we return log handlers for that.
"""
- self._setup_handlers(log_version="pre_onap", config_file=config_file, service_name=service_name)
+ create_log_dirs()
+ monkey.patch_all()
+ config.yamlConfig(filepath=LOGGING_FILE, watchDog=False)
wanted_levels = self.default_levels if levels is None else levels
- return [self.log_handlers.get(x) for x in wanted_levels]
+ return [logging.getLogger(x) for x in wanted_levels]
-class OOF_OSDFLogMessageFormatter(object):
+class OOFOSDFLogMessageFormatter(object):
@staticmethod
def accepted_valid_request(req_id, request):
+ """valid request message formatter
+
+ """
return "Accepted valid request for ID: {} for endpoint: {}".format(
req_id, request.url)
@staticmethod
def invalid_request(req_id, err):
+ """invalid request message formatter
+
+ """
return "Invalid request for request ID: {}; cause: {}".format(
req_id, format_exception(err))
@staticmethod
def invalid_response(req_id, err):
+ """invalid response message formatter
+
+ """
return "Invalid response for request ID: {}; cause: {}".format(
req_id, format_exception(err))
@staticmethod
def malformed_request(request, err):
+ """Malformed request message formatter
+
+ """
return "Malformed request for URL {}, from {}; cause: {}".format(
request.url, request.remote_address, format_exception(err))
@staticmethod
def malformed_response(response, client, err):
+ """Malformed response message formatter
+
+ """
return "Malformed response {} for client {}; cause: {}".format(
response, client, format_exception(err))
@staticmethod
def need_policies(req_id):
+ """Policies needed message formatter
+
+ """
return "Policies required but found no policies for request ID: {}".format(req_id)
@staticmethod
def policy_service_error(url, req_id, err):
+ """policy service error message formatter
+
+ """
return "Unable to call policy for {} for request ID: {}; cause: {}".format(
url, req_id, format_exception(err))
@staticmethod
def requesting_url(url, req_id):
+ """Message formatter for requesting url
+
+ """
return "Making a call to URL {} for request ID: {}".format(url, req_id)
@staticmethod
def requesting(service_name, req_id):
+ """Message formatter for requesting a service
+
+ """
return "Making a call to service {} for request ID: {}".format(service_name, req_id)
@staticmethod
def error_requesting(service_name, req_id, err):
+ """Message formatter on error requesting a service
+
+ """
return "Error while requesting service {} for request ID: {}; cause: {}".format(
service_name, req_id, format_exception(err))
@staticmethod
def calling_back(req_id, callback_url):
+ """Message formatter when a callback url is invoked
+
+ """
return "Posting result to callback URL for request ID: {}; callback URL={}".format(
req_id, callback_url)
@staticmethod
def calling_back_with_body(req_id, callback_url, body):
+ """Message formatter when a callback url with body is invoked
+
+ """
return "Posting result to callback URL for request ID: {}; callback URL={} body={}".format(
req_id, callback_url, body)
@staticmethod
def error_calling_back(req_id, callback_url, err):
+ """Message formatter on an error while posting result to callback url
+
+ """
return "Error while posting result to callback URL {} for request ID: {}; cause: {}".format(
req_id, callback_url, format_exception(err))
@staticmethod
def received_request(url, remote_addr, json_body):
+ """Message when a call is received
+
+ """
return "Received a call to {} from {} {}".format(url, remote_addr, json_body)
@staticmethod
def new_worker_thread(req_id, extra_msg=""):
+ """Message on invoking a new worker thread
+
+ """
res = "Initiating new worker thread for request ID: {}".format(req_id)
return res + extra_msg
@staticmethod
def inside_worker_thread(req_id, extra_msg=""):
+ """Message when inside a worker thread
+
+ """
res = "Inside worker thread for request ID: {}".format(req_id)
return res + extra_msg
@staticmethod
def processing(req_id, desc):
+ """Processing a request
+
+ """
return "Processing request ID: {} -- {}".format(req_id, desc)
@staticmethod
def processed(req_id, desc):
+ """Processed the request
+
+ """
return "Processed request ID: {} -- {}".format(req_id, desc)
@staticmethod
def error_while_processing(req_id, desc, err):
+ """Error while processing the request
+
+ """
return "Error while processing request ID: {} -- {}; cause: {}".format(
req_id, desc, format_exception(err))
@staticmethod
def creating_local_env(req_id):
+ """Creating a local environment
+
+ """
return "Creating local environment request ID: {}".format(
req_id)
@staticmethod
def error_local_env(req_id, desc, err):
+ """Error creating a local env
+
+ """
return "Error while creating local environment for request ID: {} -- {}; cause: {}".format(
req_id, desc, err.__traceback__)
@staticmethod
def inside_new_thread(req_id, extra_msg=""):
+ """Inside a new thread
+
+ """
res = "Spinning up a new thread for request ID: {}".format(req_id)
return res + " " + extra_msg
@staticmethod
def error_response_posting(req_id, desc, err):
+ """Error while posting a response
+
+ """
return "Error while posting a response for a request ID: {} -- {}; cause: {}".format(
req_id, desc, err.__traceback__)
@staticmethod
def received_http_response(resp):
+ """Received a http response
+
+ """
return "Received response [code: {}, headers: {}, data: {}]".format(
resp.status_code, resp.headers, resp.__dict__)
@staticmethod
def sending_response(req_id, desc):
+ """sending a response
+
+ """
return "Response is sent for request ID: {} -- {}".format(
req_id, desc)
@staticmethod
def listening_response(req_id, desc):
+ """Resposne is sent for a request ID
+
+ """
return "Response is sent for request ID: {} -- {}".format(
req_id, desc)
@staticmethod
def items_received(item_num, item_type, desc="Received"):
+ """Items received
+
+ """
return "{} {} {}".format(desc, item_num, item_type)
@staticmethod
def items_sent(item_num, item_type, desc="Published"):
+ """items published
+
+ """
return "{} {} {}".format(desc, item_num, item_type)
-MH = OOF_OSDFLogMessageFormatter
-error_log, metrics_log, audit_log, debug_log = OOF_OSDFLogMessageHelper().get_handlers()
+MH = OOFOSDFLogMessageFormatter
+
+error_log, metrics_log, audit_log, debug_log = OOFOSDFLogMessageHelper().get_handlers()
def warn_audit_error(msg):
- """Log the message to error_log.warn and audit_log.warn"""
+ """Log the message to error_log.warn and audit_log.warn
+
+ """
log_message_multi(msg, audit_log.warn, error_log.warn)
def log_message_multi(msg, *logger_methods):
"""Log the msg to multiple loggers
+
:param msg: message to log
:param logger_methods: e.g. error_log.warn, audit_log.warn, etc.
"""
diff --git a/osdf/models/policy/placement/tosca/affinityPolicy-v20180326.yml b/osdf/models/policy/placement/tosca/affinityPolicy-v20181031.yml
index 4db64db..89a3e9d 100644
--- a/osdf/models/policy/placement/tosca/affinityPolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/affinityPolicy-v20181031.yml
@@ -19,7 +19,7 @@ node_types:
type: string
consraints:
- valid_values:
- - affinityPolicy
+ - zone
identity:
type: string
required: true
diff --git a/osdf/models/policy/placement/tosca/distancePolicy-v20180326.yml b/osdf/models/policy/placement/tosca/distancePolicy-v20181031.yml
index 53d15dd..9c3bd29 100644
--- a/osdf/models/policy/placement/tosca/distancePolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/distancePolicy-v20181031.yml
@@ -19,7 +19,7 @@ node_types:
type: string
consraints:
- valid_values:
- - distancePolicy
+ - distance_to_location
identity:
type: string
required: true
diff --git a/osdf/models/policy/placement/tosca/hpaPolicy-v20180326.yml b/osdf/models/policy/placement/tosca/hpaPolicy-v20181031.yml
index 293cb63..374f752 100644
--- a/osdf/models/policy/placement/tosca/hpaPolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/hpaPolicy-v20181031.yml
@@ -19,10 +19,12 @@ node_types:
type: string
consraints:
- valid_values:
- - hpaPolicy
- resource:
- type: string
+ - hpa
+ resources:
+ type: list
required: true
+ entry_schema:
+ type: string
identity:
type: string
required: true
@@ -30,7 +32,7 @@ node_types:
type: list
required: true
entry_schema:
- - type: policy.data.flavorFeatures_properties
+ type:policy.data.flavorFeatures_properties
data_types:
policy.data.flavorFeatures_properties:
derived_from: tosca.nodes.Root
@@ -78,7 +80,7 @@ data_types:
required: true
score:
type: string
- required: true
+ required: false
architecture:
type: string
required: true
@@ -122,4 +124,4 @@ data_types:
- subset
unit:
type: string
- required: true
+ required: false
diff --git a/osdf/models/policy/placement/tosca/optimizationPolicy-v20180326.yml b/osdf/models/policy/placement/tosca/optimizationPolicy-v20181031.yml
index 0a3b94f..40678c3 100644
--- a/osdf/models/policy/placement/tosca/optimizationPolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/optimizationPolicy-v20181031.yml
@@ -19,7 +19,7 @@ node_types:
type: string
consraints:
- valid_values:
- - optimizationPolicy
+ - placement_optimization
identity:
type: string
required: true
@@ -32,11 +32,11 @@ node_types:
- valid_values:
- minimize
- maximize
- objectiveParameters:
- type: policy.data.objectiveParameters_properties
+ objectiveParameter:
+ type: policy.data.objectiveParameter_properties
required: true
data_types:
- policy.data.objectiveParameters_properties:
+ policy.data.objectiveParameter_properties:
derived_from: tosca.nodes.Root
properties:
parameterAttributes:
@@ -62,7 +62,7 @@ data_types:
resources:
type: string
required: true
- customerLocation:
+ customerLocationInfo:
type: string
required: true
parameter:
diff --git a/osdf/models/policy/placement/tosca/queryPolicy-v20180326.yml b/osdf/models/policy/placement/tosca/queryPolicy-v20181031.yml
index 2488769..09824db 100644
--- a/osdf/models/policy/placement/tosca/queryPolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/queryPolicy-v20181031.yml
@@ -19,7 +19,7 @@ node_types:
type: string
consraints:
- valid_values:
- - queryPolicy
+ - request_param_query
identity:
type: string
required: true
@@ -27,7 +27,7 @@ node_types:
type: list
required: true
entry_schema:
- - type: policy.data.queryProperties_properties
+ type:policy.data.queryProperties_properties
data_types:
policy.data.queryProperties_properties:
derived_from: tosca.nodes.Root
diff --git a/osdf/models/policy/placement/tosca/vnfPolicy-v20180326.yml b/osdf/models/policy/placement/tosca/vnfPolicy-v20181031.yml
index 3880cea..8eaf178 100644
--- a/osdf/models/policy/placement/tosca/vnfPolicy-v20180326.yml
+++ b/osdf/models/policy/placement/tosca/vnfPolicy-v20181031.yml
@@ -41,7 +41,7 @@ node_types:
type: list
required: true
entry_schema:
- - type: policy.data.vnfProperties_properties
+ type:policy.data.vnfProperties_properties
data_types:
policy.data.vnfProperties_properties:
derived_from: tosca.nodes.Root
@@ -66,3 +66,20 @@ data_types:
customerId:
type: string
required: true
+ unique:
+ type: string
+ required: false
+ attributes:
+ type: list
+ required: false
+ entry_schema:
+ type:policy.data.vnfProperties_filteringAttributes
+ passthroughAttributes:
+ type: list
+ required: false
+ entry_schema:
+ type:policy.data.vnfProperties_passthroughAttributes
+ policy.data.vnfProperties_filteringAttributes:
+ derived_from: tosca.nodes.Root
+ policy.data.vnfProperties_passthroughAttributes:
+ derived_from: tosca.nodes.Root
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AffinityPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AffinityPolicy.yaml
new file mode 100644
index 0000000..3fb8525
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AffinityPolicy.yaml
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.AffinityPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ affinityProperties:
+ type: policy.data.affinityProperties_properties
+ required: true
+data_types:
+ policy.data.affinityProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ qualifier:
+ type: string
+ constraints:
+ - valid_values:
+ - same
+ - different
+ category:
+ type: string
+ required: true \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AggregationPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AggregationPolicy.yaml
new file mode 100644
index 0000000..1e3c813
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.AggregationPolicy.yaml
@@ -0,0 +1,42 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.AggregationPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ aggregationProperties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.aggregationProperties_properties
+data_types:
+ policy.data.aggregationProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ attribute:
+ type: string
+ required: true
+ operator:
+ type: string
+ required: true
+ threshold:
+ type: policy.data.thresh_properties
+ required: true
+ unit:
+ type: string
+ required: false
+ function:
+ type: string
+ required: true
+ policy.data.thresh_properties:
+ derived_from: tosca.nodes.Root
+
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.DistancePolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.DistancePolicy.yaml
new file mode 100644
index 0000000..196ba9e
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.DistancePolicy.yaml
@@ -0,0 +1,56 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.DistancePolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ distanceProperties:
+ type: policy.data.distanceProperties_properties
+ required: true
+data_types:
+ policy.data.distanceProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ locationInfo:
+ type: string
+ required: true
+ distance:
+ type: policy.data.distance_properties
+ required: true
+ entry_schema:
+ type: policy.data.distance_properties
+ policy.data.distance_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ value:
+ type: string
+ required: true
+ operator:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - <
+ - <=
+ - '>'
+ - '>='
+ - =
+ unit:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - km \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.HpaPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.HpaPolicy.yaml
new file mode 100644
index 0000000..fe7b864
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.HpaPolicy.yaml
@@ -0,0 +1,103 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.HpaPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ flavorFeatures:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.flavorFeatures_properties
+data_types:
+ policy.data.flavorFeatures_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ id:
+ type: string
+ required: true
+ type:
+ type: string
+ required: true
+ directives:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.directives_properties
+ flavorProperties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.flavorProperties_properties
+ policy.data.directives_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ type:
+ type: string
+ attributes:
+ type: list
+ entry_schema:
+ type: policy.data.directives_attributes_properties
+ policy.data.directives_attributes_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ attribute_name:
+ type: string
+ attribute_value:
+ type: string
+ policy.data.flavorProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ hpa-feature:
+ type: string
+ required: true
+ mandatory:
+ type: string
+ required: true
+ score:
+ type: string
+ required: false
+ architecture:
+ type: string
+ required: true
+ hpa-version:
+ type: string
+ required: true
+ directives:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.directives_properties
+ hpa-feature-attributes:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.hpa-feature-attributes_properties
+ policy.data.hpa-feature-attributes_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ hpa-attribute-key:
+ type: string
+ required: true
+ hpa-attribute-value:
+ type: string
+ required: true
+ operator:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - <
+ - <=
+ - '>'
+ - '>='
+ - =
+ - '!='
+ - any
+ - all
+ - subset
+ unit:
+ type: string
+ required: false
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.OptimizationPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.OptimizationPolicy.yaml
new file mode 100644
index 0000000..fae050b
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.OptimizationPolicy.yaml
@@ -0,0 +1,66 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.OptimizationPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ objective:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - minimize
+ - maximize
+ objectiveParameter:
+ type: policy.data.objectiveParameter_properties
+ required: true
+data_types:
+ policy.data.objectiveParameter_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ parameterAttributes:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.parameterAttributes_properties
+ operator:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - '*'
+ - +
+ - '-'
+ - /
+ - '%'
+ policy.data.parameterAttributes_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ resources:
+ type: string
+ required: true
+ customerLocationInfo:
+ type: string
+ required: true
+ parameter:
+ type: string
+ required: true
+ weight:
+ type: string
+ required: true
+ operator:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - '*'
+ - +
+ - '-'
+ - /
+ - '%' \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.PciPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.PciPolicy.yaml
new file mode 100644
index 0000000..021cff9
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.PciPolicy.yaml
@@ -0,0 +1,30 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.PciPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ pciProperties:
+ type: list
+ required: false
+ entry_schema:
+ type: policy.data.pciProperties_properties
+data_types:
+ policy.data.pciProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ algoCategory:
+ type: string
+ required: false
+ pciOptmizationAlgoName:
+ type: string
+ required: false
+ pciOptimizationNwConstraint:
+ type: string
+ required: false
+ pciOptimizationPriority:
+ type: string
+ required: false
+ pciOptimizationTimeConstraint:
+ type: string
+ required: false \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.ThresholdPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.ThresholdPolicy.yaml
new file mode 100644
index 0000000..ab400dd
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.ThresholdPolicy.yaml
@@ -0,0 +1,37 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.ThresholdPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ thresholdProperties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.thresholdProperties_properties
+data_types:
+ policy.data.thresholdProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ attribute:
+ type: string
+ required: true
+ operator:
+ type: string
+ required: true
+ threshold:
+ type: float
+ required: true
+ unit:
+ type: string
+ required: false
+
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.Vim_fit.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.Vim_fit.yaml
new file mode 100644
index 0000000..6ba2ae1
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.Vim_fit.yaml
@@ -0,0 +1,28 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.Vim_fit:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ capacityProperties:
+ type: policy.data.capacityProperties_properties
+ required: true
+data_types:
+ policy.data.capacityProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ controller:
+ type: string
+ required: true
+ request:
+ type: string
+ required: true \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.VnfPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.VnfPolicy.yaml
new file mode 100644
index 0000000..1c7d3b6
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.resource.VnfPolicy.yaml
@@ -0,0 +1,44 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.resource.VnfPolicy:
+ derived_from: onap.policies.optimization.Resource
+ version: 1.0.0
+ properties:
+ applicableResources:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - any
+ - all
+ vnfProperties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.vnfProperties_properties
+data_types:
+ policy.data.vnfProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ inventoryProvider:
+ type: string
+ required: true
+ serviceType:
+ type: string
+ required: true
+ inventoryType:
+ type: list
+ required: true
+ entry_schema:
+ type: string
+ constraints:
+ - valid_values:
+ - serviceInstanceId
+ - vnfName
+ - cloudRegionId
+ - vimId
+ customerId:
+ type: string
+ required: true \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.QueryPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.QueryPolicy.yaml
new file mode 100644
index 0000000..2a615ab
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.QueryPolicy.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.service.QueryPolicy:
+ derived_from: onap.policies.optimization.Service
+ version: 1.0.0
+ properties:
+ queryProperties:
+ type: list
+ required: true
+ entry_schema:
+ type: policy.data.queryProperties_properties
+data_types:
+ policy.data.queryProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ attribute:
+ type: string
+ required: true
+ value:
+ type: string
+ required: true
+ attribute_location:
+ type: string
+ required: true \ No newline at end of file
diff --git a/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.SubscriberPolicy.yaml b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.SubscriberPolicy.yaml
new file mode 100644
index 0000000..60da742
--- /dev/null
+++ b/osdf/models/policy/placement/tosca_upload/onap.policies.optimization.service.SubscriberPolicy.yaml
@@ -0,0 +1,34 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.optimization.service.SubscriberPolicy:
+ derived_from: onap.policies.optimization.Service
+ version: 1.0.0
+ properties:
+ subscriberProperties:
+ type: policy.data.subscriberProperties_properties
+ required: true
+data_types:
+ policy.data.subscriberProperties_properties:
+ derived_from: tosca.nodes.Root
+ properties:
+ subscriberName:
+ type: list
+ required: true
+ metadata:
+ contextProvider: true
+ entry_schema:
+ type: string
+ subscriberRole:
+ type: list
+ required: true
+ metadata:
+ contextMatchable: scope
+ entry_schema:
+ type: string
+ provStatus:
+ type: list
+ required: true
+ metadata:
+ contextAttribute: true
+ entry_schema:
+ type: string \ No newline at end of file
diff --git a/osdf/optimizers/pciopt/solver/optimizer.py b/osdf/optimizers/pciopt/solver/optimizer.py
deleted file mode 100644
index e9fcb0d..0000000
--- a/osdf/optimizers/pciopt/solver/optimizer.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import itertools
-
-import os
-import pymzn
-
-from osdf.logging.osdf_logging import debug_log
-from .pci_utils import get_id
-
-BASE_DIR = os.path.dirname(__file__)
-MZN_FILE_NAME = os.path.join(BASE_DIR, 'no_conflicts_no_confusion.mzn')
-
-
-def pci_optimize(cell_id, network_cell_info, cell_info_list):
- debug_log.debug("Cell ID {} ".format(cell_id))
- dzn_data = {}
- dzn_data['NUM_NODES'] = len(cell_info_list)
- dzn_data['NUM_PCIS'] = len(cell_info_list)
-
- conflict_edges = get_conflict_edges(cell_id, network_cell_info)
-
- dzn_data['NUM_CONFLICT_EDGES'] = len(conflict_edges)
- dzn_data['CONFLICT_EDGES'] = conflict_edges
-
- confusion_edges = get_confusion_edges(cell_id, network_cell_info)
-
- dzn_data['NUM_CONFUSION_EDGES'] = len(confusion_edges)
- dzn_data['CONFUSION_EDGES'] = confusion_edges
-
- return solve(dzn_data)
-
-def solve(dzn_data):
- return pymzn.minizinc(MZN_FILE_NAME, data=dzn_data)
-
-
-def get_conflict_edges(cell_id, network_cell_info):
- conflict_edges = []
- for cell in network_cell_info['cell_list']:
-
- if cell_id == cell['cell_id']:
- add_to_conflict_edges(network_cell_info, cell, conflict_edges)
- return conflict_edges
-
-
-def add_to_conflict_edges(network_cell_info, cell, conflict_edges):
- cell_id = cell['cell_id']
- for nbr in cell.get('nbr_list', []):
- conflict_edges.append([get_id(network_cell_info, cell_id), get_id(network_cell_info, nbr['cellId'])])
-
-
-
-def get_confusion_edges(cell_id, network_cell_info):
- confusion_edges = []
- for cell in network_cell_info['cell_list']:
- if cell_id == cell['cell_id']:
- return add_to_confusion_edges(network_cell_info, cell)
- return confusion_edges
-
-
-def add_to_confusion_edges(network_cell_info, cell):
- cell_id = cell['cell_id']
- nbr_list = []
- for nbr in cell.get('nbr_list', []):
- nbr_list.append(get_id(network_cell_info, nbr['cellId']))
- return [list(elem) for elem in list(itertools.combinations(nbr_list, 2))]
diff --git a/osdf/optimizers/placementopt/conductor/api_builder.py b/osdf/optimizers/placementopt/conductor/api_builder.py
deleted file mode 100644
index e841f48..0000000
--- a/osdf/optimizers/placementopt/conductor/api_builder.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import json
-
-from jinja2 import Template
-
-import osdf.optimizers.placementopt.conductor.translation as tr
-from osdf.adapters.policy.utils import group_policies_gen
-from osdf.utils.programming_utils import list_flatten
-
-
-def conductor_api_builder(request_json, flat_policies: list, local_config,
- template="osdf/templates/conductor_interface.json"):
- """Build an OSDF southbound API call for HAS-Conductor/Placement optimization
- :param request_json: parameter data received from a client
- :param flat_policies: policy data received from the policy platform (flat policies)
- :param template: template to generate southbound API call to conductor
- :param local_config: local configuration file with pointers for the service specific information
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: json to be sent to Conductor/placement optimization
- """
- templ = Template(open(template).read())
- gp = group_policies_gen(flat_policies, local_config)
- demand_vnf_name_list = []
-
- for placementDemand in request_json['placementInfo']['placementDemands']:
- demand_vnf_name_list.append(placementDemand['resourceModuleName'].lower())
- demand_list = tr.gen_demands(request_json, gp['vnfPolicy'])
- attribute_policy_list = tr.gen_attribute_policy(demand_vnf_name_list, gp['attribute'])
- distance_to_location_policy_list = tr.gen_distance_to_location_policy(
- demand_vnf_name_list, gp['distance_to_location'])
- inventory_policy_list = tr.gen_inventory_group_policy(demand_vnf_name_list, gp['inventory_group'])
- resource_instance_policy_list = tr.gen_resource_instance_policy(
- demand_vnf_name_list, gp['instance_fit'])
- resource_region_policy_list = tr.gen_resource_region_policy(demand_vnf_name_list, gp['region_fit'])
- zone_policy_list = tr.gen_zone_policy(demand_vnf_name_list, gp['zone'])
- optimization_policy_list = tr.gen_optimization_policy(demand_vnf_name_list, gp['placementOptimization'])
- reservation_policy_list = tr.gen_reservation_policy(demand_vnf_name_list, gp['instance_reservation'])
- capacity_policy_list = tr.gen_capacity_policy(demand_vnf_name_list, gp['vim_fit'])
- hpa_policy_list = tr.gen_hpa_policy(demand_vnf_name_list, gp['hpa'])
- req_params_dict = tr.get_opt_query_data(request_json, gp['optimizationQueryPolicy'])
- conductor_policies = [attribute_policy_list, distance_to_location_policy_list, inventory_policy_list,
- resource_instance_policy_list, resource_region_policy_list, zone_policy_list,
- reservation_policy_list, capacity_policy_list, hpa_policy_list]
- filtered_policies = [x for x in conductor_policies if len(x) > 0]
- policy_groups = list_flatten(filtered_policies)
- req_info = request_json['requestInfo']
- request_type = req_info.get('requestType', None)
- rendered_req = templ.render(
- requestType=request_type,
- demand_list=demand_list,
- policy_groups=policy_groups,
- optimization_policies=optimization_policy_list,
- name=req_info['requestId'],
- timeout=req_info['timeout'],
- limit=req_info['numSolutions'],
- service_type=request_json['serviceInfo']['serviceName'],
- service_id=request_json['serviceInfo']['serviceInstanceId'],
- latitude=req_params_dict.get("customerLatitude", 0.0),
- longitude=req_params_dict.get("customerLongitude", 0.0),
- json=json)
- json_payload = json.dumps(json.loads(rendered_req)) # need this because template's JSON is ugly!
- return json_payload
diff --git a/osdf/optimizers/placementopt/conductor/conductor.py b/osdf/optimizers/placementopt/conductor/conductor.py
deleted file mode 100755
index 357efd1..0000000
--- a/osdf/optimizers/placementopt/conductor/conductor.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-"""
-This application generates conductor API calls using the information received from SO and Policy platform.
-"""
-
-import json
-import time
-
-from jinja2 import Template
-from requests import RequestException
-
-from osdf.logging.osdf_logging import debug_log
-from osdf.optimizers.placementopt.conductor.api_builder import conductor_api_builder
-from osdf.utils.interfaces import RestClient
-from osdf.operation.exceptions import BusinessException
-
-
-def request(req_object, osdf_config, flat_policies):
- """
- Process a placement request from a Client (build Conductor API call, make the call, return result)
- :param req_object: Request parameters from the client
- :param osdf_config: Configuration specific to SNIRO application (core + deployment)
- :param flat_policies: policies related to placement (fetched based on request)
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: response from Conductor (accounting for redirects from Conductor service
- """
- config = osdf_config.deployment
- local_config = osdf_config.core
- uid, passwd = config['conductorUsername'], config['conductorPassword']
- conductor_url = config['conductorUrl']
- req_id = req_object['requestInfo']['requestId']
- transaction_id = req_object['requestInfo']['transactionId']
- headers = dict(transaction_id=transaction_id)
- placement_ver_enabled = config.get('placementVersioningEnabled', False)
-
- if placement_ver_enabled:
- cond_minor_version = config.get('conductorMinorVersion', None)
- if cond_minor_version is not None:
- x_minor_version = str(cond_minor_version)
- headers.update({'X-MinorVersion': x_minor_version})
- debug_log.debug("Versions set in HTTP header to conductor: X-MinorVersion: {} ".format(x_minor_version))
-
- max_retries = config.get('conductorMaxRetries', 30)
- ping_wait_time = config.get('conductorPingWaitTime', 60)
-
- rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
- conductor_req_json_str = conductor_api_builder(req_object, flat_policies, local_config)
- conductor_req_json = json.loads(conductor_req_json_str)
-
- debug_log.debug("Sending first Conductor request for request_id {}".format(req_id))
- resp, raw_resp = initial_request_to_conductor(rc, conductor_url, conductor_req_json)
- # Very crude way of keeping track of time.
- # We are not counting initial request time, first call back, or time for HTTP request
- total_time, ctr = 0, 2
- client_timeout = req_object['requestInfo']['timeout']
- configured_timeout = max_retries * ping_wait_time
- max_timeout = min(client_timeout, configured_timeout)
-
- while True: # keep requesting conductor till we get a result or we run out of time
- if resp is not None:
- if resp["plans"][0].get("status") in ["error"]:
- raise RequestException(response=raw_resp, request=raw_resp.request)
-
- if resp["plans"][0].get("status") in ["done", "not found"]:
- if resp["plans"][0].get("recommendations"):
- return conductor_response_processor(resp, raw_resp, req_id)
- else: # "solved" but no solutions found
- return conductor_no_solution_processor(resp, raw_resp, req_id)
- new_url = resp['plans'][0]['links'][0][0]['href'] # TODO: check why a list of lists
-
- if total_time >= max_timeout:
- raise BusinessException("Conductor could not provide a solution within {} seconds,"
- "this transaction is timing out".format(max_timeout))
- time.sleep(ping_wait_time)
- ctr += 1
- debug_log.debug("Attempt number {} url {}; prior status={}".format(ctr, new_url, resp['plans'][0]['status']))
- total_time += ping_wait_time
-
- try:
- raw_resp = rc.request(new_url, raw_response=True)
- resp = raw_resp.json()
- except RequestException as e:
- debug_log.debug("Conductor attempt {} for request_id {} has failed because {}".format(ctr, req_id, str(e)))
-
-
-def initial_request_to_conductor(rc, conductor_url, conductor_req_json):
- """First steps in the request-redirect chain in making a call to Conductor
- :param rc: REST client object for calling conductor
- :param conductor_url: conductor's base URL to submit a placement request
- :param conductor_req_json: request json object to send to Conductor
- :return: URL to check for follow up (similar to redirects); we keep checking these till we get a result/error
- """
- debug_log.debug("Payload to Conductor: {}".format(json.dumps(conductor_req_json)))
- raw_resp = rc.request(url=conductor_url, raw_response=True, method="POST", json=conductor_req_json)
- resp = raw_resp.json()
- if resp["status"] != "template":
- raise RequestException(response=raw_resp, request=raw_resp.request)
- time.sleep(10) # 10 seconds wait time to avoid being too quick!
- plan_url = resp["links"][0][0]["href"]
- debug_log.debug("Attempting to read the plan from the conductor provided url {}".format(plan_url))
- raw_resp = rc.request(raw_response=True, url=plan_url) # TODO: check why a list of lists for links
- resp = raw_resp.json()
-
- if resp["plans"][0]["status"] in ["error"]:
- raise RequestException(response=raw_resp, request=raw_resp.request)
- return resp, raw_resp # now the caller of this will handle further follow-ups
-
-
-def conductor_response_processor(conductor_response, raw_response, req_id):
- """Build a response object to be sent to client's callback URL from Conductor's response
- This includes Conductor's placement optimization response, and required ASDC license artifacts
-
- :param conductor_response: JSON response from Conductor
- :param raw_response: Raw HTTP response corresponding to above
- :param req_id: Id of a request
- :return: JSON object that can be sent to the client's callback URL
- """
- composite_solutions = []
- name_map = {"physical-location-id": "cloudClli", "host_id": "vnfHostName",
- "cloud_version": "cloudVersion", "cloud_owner": "cloudOwner",
- "cloud": "cloudRegionId", "service": "serviceInstanceId", "is_rehome": "isRehome",
- "location_id": "locationId", "location_type": "locationType", "directives": "oof_directives"}
- for reco in conductor_response['plans'][0]['recommendations']:
- for resource in reco.keys():
- c = reco[resource]['candidate']
- solution = {
- 'resourceModuleName': resource,
- 'serviceResourceId': reco[resource].get('service_resource_id', ""),
- 'solution': {"identifierType": name_map.get(c['inventory_type'], c['inventory_type']),
- 'identifiers': [c['candidate_id']],
- 'cloudOwner': c.get('cloud_owner', "")},
- 'assignmentInfo': []
- }
- for key, value in c.items():
- if key in ["location_id", "location_type", "is_rehome", "host_id"]:
- try:
- solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
- except KeyError:
- debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info".format(key))
-
- for key, value in reco[resource]['attributes'].items():
- try:
- solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
- except KeyError:
- debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info".format(key))
- composite_solutions.append(solution)
-
- request_status = "completed" if conductor_response['plans'][0]['status'] == "done" \
- else conductor_response['plans'][0]['status']
- transaction_id = raw_response.headers.get('transaction_id', "")
- status_message = conductor_response.get('plans')[0].get('message', "")
-
- solution_info = {}
- if composite_solutions:
- solution_info.setdefault('placementSolutions', [])
- solution_info['placementSolutions'].append(composite_solutions)
-
- resp = {
- "transactionId": transaction_id,
- "requestId": req_id,
- "requestStatus": request_status,
- "statusMessage": status_message,
- "solutions": solution_info
- }
- return resp
-
-
-def conductor_no_solution_processor(conductor_response, raw_response, request_id,
- template_placement_response="templates/plc_opt_response.jsont"):
- """Build a response object to be sent to client's callback URL from Conductor's response
- This is for case where no solution is found
-
- :param conductor_response: JSON response from Conductor
- :param raw_response: Raw HTTP response corresponding to above
- :param request_id: request Id associated with the client request (same as conductor response's "name")
- :param template_placement_response: the template for generating response to client (plc_opt_response.jsont)
- :return: JSON object that can be sent to the client's callback URL
- """
- status_message = conductor_response["plans"][0].get("message")
- templ = Template(open(template_placement_response).read())
- return json.loads(templ.render(composite_solutions=[], requestId=request_id, license_solutions=[],
- transactionId=raw_response.headers.get('transaction_id', ""),
- requestStatus="completed", statusMessage=status_message, json=json))
-
-
diff --git a/osdf/optimizers/placementopt/conductor/remote_opt_processor.py b/osdf/optimizers/placementopt/conductor/remote_opt_processor.py
deleted file mode 100644
index 614eca3..0000000
--- a/osdf/optimizers/placementopt/conductor/remote_opt_processor.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-from requests import RequestException
-
-import traceback
-from osdf.operation.error_handling import build_json_error_body
-from osdf.logging.osdf_logging import metrics_log, MH, error_log
-from osdf.optimizers.placementopt.conductor import conductor
-from osdf.optimizers.licenseopt.simple_license_allocation import license_optim
-from osdf.utils.interfaces import get_rest_client
-
-
-def process_placement_opt(request_json, policies, osdf_config):
- """Perform the work for placement optimization (e.g. call SDC artifact and make conductor request)
- NOTE: there is scope to make the requests to policy asynchronous to speed up overall performance
- :param request_json: json content from original request
- :param policies: flattened policies corresponding to this request
- :param osdf_config: configuration specific to OSDF app
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: None, but make a POST to callback URL
- """
-
- try:
- rc = get_rest_client(request_json, service="so")
- req_id = request_json["requestInfo"]["requestId"]
- transaction_id = request_json['requestInfo']['transactionId']
-
- metrics_log.info(MH.inside_worker_thread(req_id))
- license_info = None
- if request_json.get('licenseInfo', {}).get('licenseDemands'):
- license_info = license_optim(request_json)
-
- # Conductor only handles placement, only call Conductor if placementDemands exist
- if request_json.get('placementInfo', {}).get('placementDemands'):
- metrics_log.info(MH.requesting("placement/conductor", req_id))
- placement_response = conductor.request(request_json, osdf_config, policies)
- if license_info: # Attach license solution if it exists
- placement_response['solutionInfo']['licenseInfo'] = license_info
- else: # License selection only scenario
- placement_response = {
- "transactionId": transaction_id,
- "requestId": req_id,
- "requestStatus": "completed",
- "statusMessage": "License selection completed successfully",
- "solutionInfo": {"licenseInfo": license_info}
- }
- except Exception as err:
- error_log.error("Error for {} {}".format(req_id, traceback.format_exc()))
-
- try:
- body = build_json_error_body(err)
- metrics_log.info(MH.sending_response(req_id, "ERROR"))
- rc.request(json=body, noresponse=True)
- except RequestException:
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
- return
-
- try:
- metrics_log.info(MH.calling_back_with_body(req_id, rc.url,placement_response))
- rc.request(json=placement_response, noresponse=True)
- except RequestException : # can't do much here but log it and move on
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
-
diff --git a/osdf/optimizers/placementopt/conductor/translation.py b/osdf/optimizers/placementopt/conductor/translation.py
deleted file mode 100644
index d856a22..0000000
--- a/osdf/optimizers/placementopt/conductor/translation.py
+++ /dev/null
@@ -1,254 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-import copy
-import json
-import yaml
-
-from osdf.utils.data_conversion import text_to_symbol
-from osdf.utils.programming_utils import dot_notation
-
-policy_config_mapping = yaml.load(open('config/has_config.yaml')).get('policy_config_mapping')
-
-
-def get_opt_query_data(req_json, policies):
- """
- Fetch service and order specific details from the requestParameters field of a request.
- :param req_json: a request file
- :param policies: A set of policies
- :return: A dictionary with service and order-specific attributes.
- """
- req_param_dict = {}
- if 'requestParameters' in req_json["placementInfo"]:
- req_params = req_json["placementInfo"]["requestParameters"]
- for policy in policies:
- for queryProp in policy['content']['queryProperties']:
- attr_val = queryProp['value'] if 'value' in queryProp and queryProp['value'] != "" \
- else dot_notation(req_params, queryProp['attribute_location'])
- if attr_val is not None:
- req_param_dict.update({queryProp['attribute']: attr_val})
- return req_param_dict
-
-
-def gen_optimization_policy(vnf_list, optimization_policy):
- """Generate optimization policy details to pass to Conductor
- :param vnf_list: List of vnf's to used in placement request
- :param optimization_policy: optimization objective policy information provided in the incoming request
- :return: List of optimization objective policies in a format required by Conductor
- """
- optimization_policy_list = []
- for policy in optimization_policy:
- content = policy['content']
- parameter_list = []
- parameters = ["cloud_version", "hpa_score"]
-
- for attr in content['objectiveParameter']['parameterAttributes']:
- parameter = attr['parameter'] if attr['parameter'] in parameters else attr['parameter']+"_between"
- vnfs = get_matching_vnfs(attr['resources'], vnf_list)
- for vnf in vnfs:
- value = [vnf] if attr['parameter'] in parameters else [attr['customerLocationInfo'], vnf]
- parameter_list.append({
- attr['operator']: [attr['weight'], {parameter: value}]
- })
-
- optimization_policy_list.append({
- content['objective']: {content['objectiveParameter']['operator']: parameter_list }
- })
- return optimization_policy_list
-
-
-def get_matching_vnfs(resources, vnf_list, match_type="intersection"):
- """Get a list of matching VNFs from the list of resources
- :param resources:
- :param vnf_list: List of vnfs to used in placement request
- :param match_type: "intersection" or "all" or "any" (any => send all_vnfs if there is any intersection)
- :return: List of matching VNFs
- """
- resources_lcase = [x.lower() for x in resources]
- if match_type == "all": # don't bother with any comparisons
- return resources if set(resources_lcase) <= set(vnf_list) else None
- common_vnfs = set(vnf_list) & set(resources_lcase)
- common_resources = [x for x in resources if x.lower() in common_vnfs]
- if match_type == "intersection": # specifically requested intersection
- return list(common_resources)
- return resources if common_vnfs else None # "any" match => all resources to be returned
-
-
-def gen_policy_instance(vnf_list, resource_policy, match_type="intersection", rtype=None):
- """Generate a list of policies
- :param vnf_list: List of vnf's to used in placement request
- :param resource_policy: policy for this specific resource
- :param match_type: How to match the vnf_names with the vnf_list (intersection or "any")
- intersection => return intersection; "any" implies return all vnf_names if intersection is not null
- :param rtype: resource type (e.g. resourceRegionProperty or resourceInstanceProperty)
- None => no controller information added to the policy specification to Conductor
- :return: resource policy list in a format required by Conductor
- """
- resource_policy_list = []
- related_policies = []
- for policy in resource_policy:
- pc = policy['content']
- demands = get_matching_vnfs(pc['resources'], vnf_list, match_type=match_type)
- resource = {pc['identity']: {'type': pc['policyType'], 'demands': demands}}
-
- if rtype:
- resource[pc['identity']]['properties'] = {'controller': pc[rtype]['controller'],
- 'request': json.loads(pc[rtype]['request'])}
- if demands and len(demands) != 0:
- resource_policy_list.append(resource)
- related_policies.append(policy)
- return resource_policy_list, related_policies
-
-
-def gen_resource_instance_policy(vnf_list, resource_instance_policy):
- """Get policies governing resource instances in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, resource_instance_policy, rtype='resourceInstanceProperty')
- return cur_policies
-
-
-def gen_resource_region_policy(vnf_list, resource_region_policy):
- """Get policies governing resource region in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, resource_region_policy, rtype='resourceRegionProperty')
- return cur_policies
-
-
-def gen_inventory_group_policy(vnf_list, inventory_group_policy):
- """Get policies governing inventory group in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, inventory_group_policy, rtype=None)
- return cur_policies
-
-
-def gen_reservation_policy(vnf_list, reservation_policy):
- """Get policies governing resource instances in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, reservation_policy, rtype='instanceReservationProperty')
- return cur_policies
-
-
-def gen_distance_to_location_policy(vnf_list, distance_to_location_policy):
- """Get policies governing distance-to-location for VNFs in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, distance_to_location_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- properties = p_main['content']['distanceProperties']
- pcp_d = properties['distance']
- p_new[p_main['content']['identity']]['properties'] = {
- 'distance': pcp_d['operator'] + " " + pcp_d['value'].lower() + " " + pcp_d['unit'].lower(),
- 'location': properties['locationInfo']
- }
- return cur_policies
-
-
-def gen_attribute_policy(vnf_list, attribute_policy):
- """Get policies governing attributes of VNFs in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, attribute_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- properties = p_main['content']['cloudAttributeProperty']
- attribute_mapping = policy_config_mapping['attributes'] # wanted attributes and mapping
- p_new[p_main['content']['identity']]['properties'] = {
- 'evaluate': dict((k, properties.get(attribute_mapping.get(k))) for k in attribute_mapping.keys())
- }
- return cur_policies # cur_policies gets updated in place...
-
-
-def gen_zone_policy(vnf_list, zone_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, zone_policy, match_type="all", rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- pmz = p_main['content']['affinityProperty']
- p_new[p_main['content']['identity']]['properties'] = {'category': pmz['category'], 'qualifier': pmz['qualifier']}
- return cur_policies
-
-
-def gen_capacity_policy(vnf_list, capacity_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, capacity_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- pmz = p_main['content']['capacityProperty']
- p_new[p_main['content']['identity']]['properties'] = \
- {"controller": pmz['controller'], 'request': json.loads(pmz['request'])}
- return cur_policies
-
-
-def gen_hpa_policy(vnf_list, hpa_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, hpa_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- p_new[p_main['content']['identity']]['properties'] = {'evaluate': p_main['content']['flavorFeatures']}
- return cur_policies
-
-
-def get_augmented_policy_attributes(policy_property, demand):
- """Get policy attributes and augment them using policy_config_mapping and demand information"""
- attributes = copy.copy(policy_property['attributes'])
- remapping = policy_config_mapping['remapping']
- extra = dict((x, demand['resourceModelInfo'][remapping[x]]) for x in attributes if x in remapping)
- attributes.update(extra)
- return attributes
-
-
-def get_candidates_demands(demand):
- """Get demands related to candidates; e.g. excluded/required"""
- res = {}
- for k, v in policy_config_mapping['candidates'].items():
- if k not in demand:
- continue
- res[v] = [{'inventory_type': x['candidateType'], 'candidate_id': x['candidates']} for x in demand[k]]
- return res
-
-
-def get_policy_properties(demand, policies):
- """Get policy_properties for cases where there is a match with the demand"""
- for policy in policies:
- policy_demands = set([x.lower() for x in policy['content'].get('resources', [])])
- if demand['resourceModuleName'].lower() not in policy_demands:
- continue # no match for this policy
- for policy_property in policy['content']['vnfProperties']:
- yield policy_property
-
-
-def get_demand_properties(demand, policies):
- """Get list demand properties objects (named tuples) from policy"""
- demand_properties = []
- for policy_property in get_policy_properties(demand, policies):
- prop = dict(inventory_provider=policy_property['inventoryProvider'],
- inventory_type=policy_property['inventoryType'],
- service_type=demand['serviceResourceId'])
- prop['attributes'] = dict()
- prop['attributes'].update({'global-customer-id': policy_property['customerId']}
- if policy_property['customerId'] else {})
- prop['attributes'].update({'model-invariant-id': demand['resourceModelInfo']['modelInvariantId']}
- if demand['resourceModelInfo']['modelInvariantId'] else {})
- prop['attributes'].update({'model-version-id': demand['resourceModelInfo']['modelVersionId']}
- if demand['resourceModelInfo']['modelVersionId'] else {})
- prop['attributes'].update({'equipment-role': policy_property['equipmentRole']}
- if policy_property['equipmentRole'] else {})
- prop.update(get_candidates_demands(demand))
- demand_properties.append(prop)
- return demand_properties
-
-
-def gen_demands(req_json, vnf_policies):
- """Generate list of demands based on request and VNF policies
- :param req_json: Request object from the client (e.g. MSO)
- :param vnf_policies: Policies associated with demand resources (e.g. from grouped_policies['vnfPolicy'])
- :return: list of demand parameters to populate the Conductor API call
- """
- demand_dictionary = {}
- for demand in req_json['placementInfo']['placementDemands']:
- prop = get_demand_properties(demand, vnf_policies)
- if len(prop) > 0:
- demand_dictionary.update({demand['resourceModuleName']: prop})
- return demand_dictionary
diff --git a/osdf/optimizers/routeopt/simple_route_opt.py b/osdf/optimizers/routeopt/simple_route_opt.py
deleted file mode 100644
index 060e1ed..0000000
--- a/osdf/optimizers/routeopt/simple_route_opt.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 Huawei Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import requests
-from requests.auth import HTTPBasicAuth
-
-
-class RouteOpt:
-
- """
- This values will need to deleted..
- only added for the debug purpose
- """
- # DNS server and standard port of AAI..
- # TODO: read the port from the configuration and add to DNS
- aai_host = "https://aai.api.simpledemo.onap.org:8443"
- aai_headers = {
- "X-TransactionId": "9999",
- "X-FromAppId": "OOF",
- "Accept": "application/json",
- "Content-Type": "application/json",
- "Real-Time": "true"
- }
-
- def isCrossONAPLink(self, logical_link):
- """
- This method checks if cross link is cross onap
- :param logical_link:
- :return:
- """
- for relationship in logical_link["relationship-list"]["relationship"]:
- if relationship["related-to"] == "ext-aai-network":
- return True
- return False
-
- def getRoute(self, request):
- """
- This method checks
- :param logical_link:
- :return:
- """
-
- src_access_node_id = request["srcPort"]["src-access-node-id"]
- dst_access_node_id = request["dstPort"]["dst-access-node-id"]
-
-
- ingress_p_interface = None
- egress_p_interface = None
-
- # for the case of request_json for same domain, return the same node with destination update
- if src_access_node_id == dst_access_node_id:
- data = '{'\
- '"vpns":['\
- '{'\
- '"access-topology-id": "' + request["srcPort"]["src-access-topology-id"] + '",'\
- '"access-client-id": "' + request["srcPort"]["src-access-client-id"] + '",'\
- '"access-provider-id": "' + request["srcPort"]["src-access-provider-id"]+ '",'\
- '"access-node-id": "' + request["srcPort"]["src-access-node-id"]+ '",'\
- '"src-access-ltp-id": "' + request["srcPort"]["src-access-ltp-id"]+ '",'\
- '"dst-access-ltp-id": "' + request["dstPort"]["dst-access-ltp-id"] +'"'\
- '}'\
- ']'\
- '}'
- return data
- else:
- logical_links = self.get_logical_links()
-
- # take the logical link where both the p-interface in same onap
- if logical_links != None:
- for logical_link in logical_links.get("logical-link"):
- if not self.isCrossONAPLink(logical_link):
- # link is in local ONAP
- for relationship in logical_link["relationship-list"]["relationship"]:
- if relationship["related-to"] == "p-interface":
- if src_access_node_id in relationship["related-link"]:
- i_interface = relationship["related-link"].split("/")[-1]
- ingress_p_interface = i_interface.split("-")[-1]
- if dst_access_node_id in relationship["related-link"]:
- e_interface = relationship["related-link"].split("/")[-1]
- egress_p_interface = e_interface.split("-")[-1]
- data = '{'\
- '"vpns":['\
- '{'\
- '"access-topology-id": "' + request["srcPort"]["src-access-topology-id"] + '",'\
- '"access-client-id": "' + request["srcPort"]["src-access-client-id"] + '",'\
- '"access-provider-id": "' + request["srcPort"]["src-access-provider-id"]+ '",'\
- '"access-node-id": "' + request["srcPort"]["src-access-node-id"]+ '",'\
- '"src-access-ltp-id": "' + request["srcPort"]["src-access-ltp-id"]+ '",'\
- '"dst-access-ltp-id": "' + ingress_p_interface +'"'\
- '},'\
- '{' \
- '"access-topology-id": "' + request["dstPort"]["dst-access-topology-id"] + '",' \
- '"access-topology-id": "' + request["dstPort"]["dst-access-topology-id"]+ '",' \
- '"access-provider-id": "' + request["dstPort"]["dst-access-provider-id"]+ '",' \
- '"access-node-id": "' + request["dstPort"]["dst-access-node-id"]+ '",' \
- '"src-access-ltp-id": "' + egress_p_interface + '",' \
- '"dst-access-ltp-id": "' + request["dstPort"]["dst-access-ltp-id"] + '"' \
- '}'\
- ']'\
- '}'
- return data
-
-
- def get_pinterface(self, url):
- """
- This method returns details for p interface
- :return: details of p interface
- """
- aai_req_url = self.aai_host + url
- response = requests.get(aai_req_url,
- headers=self.aai_headers,
- auth=HTTPBasicAuth("AAI", "AAI"),
- verify=False)
-
- if response.status_code == 200:
- return response.json()
-
-
- def get_logical_links(self):
- """
- This method returns list of all cross ONAP links
- from /aai/v14/network/logical-links?operation-status="Up"
- :return: logical-links[]
- """
- logical_link_url = "/aai/v13/network/logical-links?operational-status=up"
- aai_req_url = self.aai_host + logical_link_url
-
- response = requests.get(aai_req_url,
- headers=self.aai_headers,
- auth=HTTPBasicAuth("AAI", "AAI"),
- verify=False)
-
- logical_links = None
- if response.status_code == 200:
- return response.json() \ No newline at end of file
diff --git a/osdf/utils/cipherUtils.py b/osdf/utils/cipherUtils.py
new file mode 100644
index 0000000..169f1a1
--- /dev/null
+++ b/osdf/utils/cipherUtils.py
@@ -0,0 +1,59 @@
+#
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+
+from Crypto.Cipher import AES
+from osdf.config.base import osdf_config
+from Crypto.Util.Padding import unpad
+from Crypto.Util.Padding import pad
+
+
+class AESCipher(object):
+ __instance = None
+
+ @staticmethod
+ def get_instance(key = None):
+ if AESCipher.__instance is None:
+ print("Creating the singleton instance")
+ AESCipher(key)
+ return AESCipher.__instance
+
+ def __init__(self, key=None):
+ if AESCipher.__instance is not None:
+ raise Exception("This class is a singleton!")
+ else:
+ AESCipher.__instance = self
+
+ self.bs = 32
+ if key is None:
+ key = osdf_config.deployment["appkey"]
+
+ self.key = key.encode()
+
+ def encrypt(self, data):
+ data = data.encode()
+ cipher = AES.new(self.key, AES.MODE_CBC)
+ ciphered_data = cipher.encrypt(pad(data, AES.block_size))
+ enc = (cipher.iv.hex())+(ciphered_data.hex())
+ return enc
+
+ def decrypt(self, enc):
+ iv = bytes.fromhex(enc[:32])
+ ciphered_data = bytes.fromhex(enc[32:])
+ cipher = AES.new(self.key, AES.MODE_CBC, iv=iv)
+ original_data = unpad(cipher.decrypt(ciphered_data), AES.block_size).decode()
+ return original_data
diff --git a/osdf/utils/data_conversion.py b/osdf/utils/data_conversion.py
index 2f678fa..08af3e4 100644
--- a/osdf/utils/data_conversion.py
+++ b/osdf/utils/data_conversion.py
@@ -16,15 +16,16 @@
# -------------------------------------------------------------------------
#
-import itertools
from collections import defaultdict
+import itertools
-from dateutil import tz
from dateutil.parser import parse
+from dateutil import tz
def tuples_to_multi_val_dict(kvw_tuples, colnums=(0, 1)):
"""Given a list of k,v tuples, get a dictionary of the form k -> [v1,v2,...,vn]
+
:param kvw_tuples: list of k,v,w tuples (e.g. [(k1,v1,a1), (k2,v2,a2), (k1,v3,a3), (k1,v4,a4)]
:param colnums: column numbers
:return: a dict of str:set, something like {k1: {v1, v3, v4}, k2: {v2}} or {k1: {a1, a3, a4}, k2: {a2}}
@@ -38,6 +39,7 @@ def tuples_to_multi_val_dict(kvw_tuples, colnums=(0, 1)):
def tuples_to_dict(kvw_tuples, colnums=(0, 1)):
"""Given a list of k,v tuples, get a dictionary of the form k -> v
+
:param kvw_tuples: list of k,v,w tuples (e.g. [(k1,v1,a1), (k2,v2,a2), (k3,v3,a3), (k1,v4,a4)]
:param colnums: column numbers
:return: a dict; something like {k1: v4, k2: v2, k3: v3} (note, k1 is repeated, so last val is retained)
@@ -46,13 +48,17 @@ def tuples_to_dict(kvw_tuples, colnums=(0, 1)):
def utc_time_from_ts(timestamp):
- """Return corresponding UTC timestamp for a given ISO timestamp (or anything that parse accepts)"""
+ """Return corresponding UTC timestamp for a given ISO timestamp (or anything that parse accepts)
+
+ """
return parse(timestamp).astimezone(tz.tzutc()).strftime('%Y-%m-%d %H:%M:%S')
-def list_flatten(l):
- """Flatten a complex nested list of nested lists into a flat list"""
- return itertools.chain(*[list_flatten(j) if isinstance(j, list) else [j] for j in l])
+def list_flatten(_l):
+ """Flatten a complex nested list of nested lists into a flat list
+
+ """
+ return itertools.chain(*[list_flatten(j) if isinstance(j, list) else [j] for j in _l])
text_to_symbol = {
@@ -60,3 +66,10 @@ text_to_symbol = {
'less': "<",
'equal': "="
}
+
+
+def decode_data(data):
+ """Decode bytes to string
+
+ """
+ return data.decode(encoding='utf-8') if isinstance(data, bytes) else data
diff --git a/osdf/utils/file_utils.py b/osdf/utils/file_utils.py
new file mode 100644
index 0000000..b12c17d
--- /dev/null
+++ b/osdf/utils/file_utils.py
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+# File related utilities
+
+import os
+from shutil import rmtree
+
+from osdf.logging.osdf_logging import debug_log
+
+
+def delete_file_folder(p):
+ if not p:
+ return
+ debug_log.debug('Deleting folder/file {}'.format(p))
+ if os.path.isfile(p):
+ os.remove(p)
+ else:
+ rmtree(p, ignore_errors=True)
diff --git a/osdf/utils/interfaces.py b/osdf/utils/interfaces.py
index a869d6d..4fa4730 100644
--- a/osdf/utils/interfaces.py
+++ b/osdf/utils/interfaces.py
@@ -20,12 +20,15 @@ import json
import requests
import yaml
-from osdf.config.base import osdf_config, creds_prefixes
-from osdf.logging.osdf_logging import MH, debug_log
+from osdf.config.base import creds_prefixes
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import MH
def get_rest_client(request_json, service):
"""Get a RestClient based on request_json's callback URL and osdf_config's credentials based on service name
+
:param request_json:
:param service: so or cm
:return: rc -- RestClient
@@ -53,21 +56,23 @@ class RestClient(object):
"""Simple REST Client that supports get/post and basic auth"""
def __init__(self, userid=None, passwd=None, log_func=None, url=None, timeout=None, headers=None,
- method="POST", req_id=None):
+ method="POST", req_id=None, verify=None):
self.auth = (userid, passwd) if userid and passwd else None
self.headers = headers if headers else {}
self.method = method
self.url = url
self.log_func = log_func
- self.timeout = (30, 90) if timeout is None else timeout
+ self.timeout = (30, 120) if timeout is None else timeout
self.req_id = req_id
+ self.verify = verify
def add_headers(self, headers):
self.headers.update(headers)
def request(self, url=None, method=None, asjson=True, ok_codes=(2, ),
raw_response=False, noresponse=False, timeout=None, **kwargs):
- """
+ """Sends http request to the specified url
+
:param url: REST end point to query
:param method: GET or POST (default is None => self.method)
:param asjson: whether the expected response is in json format
@@ -83,16 +88,23 @@ class RestClient(object):
else:
debug_log.debug("Requesting URL: {} for request ID: {}".format(url or self.url, self.req_id))
+ if not url:
+ url = self.url
+ if not self.verify and url.startswith("https"):
+ verify = osdf_config.deployment["aaf_ca_certs"]
+ else:
+ verify = self.verify
+
res = requests.request(url=url or self.url, method=method or self.method,
auth=self.auth, headers=self.headers,
- timeout=timeout or self.timeout, **kwargs)
+ timeout=timeout or self.timeout, verify=verify, **kwargs)
if self.log_func:
self.log_func(MH.received_http_response(res))
res_code = str(res.status_code)
if not any(res_code.startswith(x) for x in map(str, ok_codes)):
- raise res.raise_for_status()
+ raise BaseException(res.raise_for_status())
if raw_response:
return res
diff --git a/osdf/utils/mdc_utils.py b/osdf/utils/mdc_utils.py
new file mode 100644
index 0000000..c74a161
--- /dev/null
+++ b/osdf/utils/mdc_utils.py
@@ -0,0 +1,155 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import socket
+import threading
+import time
+import uuid
+
+from flask import g
+from onaplogging.mdcContext import MDC
+
+EMPTY = "EMPTY"
+
+DATE_FMT = '%Y-%m-%dT%H:%M:%S'
+
+
+def default_server_info():
+ """Populate server & server_ip_address MDC fields
+
+ """
+ # If not set or purposely set = None, then set default
+ if MDC.get('server') is None:
+ try:
+ server = socket.getfqdn()
+ except Exception:
+ try:
+ server = socket.gethostname()
+ except Exception:
+ server = ''
+ MDC.put('server', server)
+ if MDC.get('serverIPAddress') is None:
+ try:
+ server_ip_address = socket.gethostbyname(MDC.get('server'))
+ except Exception:
+ server_ip_address = ""
+ MDC.put('serverIPAddress', server_ip_address)
+
+
+def default_mdc():
+ """Populate default MDC fields
+
+ """
+ MDC.put('instanceUUID', generate_uuid())
+ MDC.put('InvocationID', generate_uuid())
+ MDC.put('serviceName', 'OOF_OSDF')
+ MDC.put('threadID', threading.currentThread().getName())
+ default_server_info()
+ MDC.put('requestID', generate_uuid())
+ MDC.put('partnerName', 'N/A')
+ MDC.put('entryTimestamp', get_time())
+
+
+def mdc_from_json(request_json):
+ """Populate MDC fields given a request in json format
+
+ """
+ if MDC.get("instanceUUID") is None:
+ default_mdc()
+ MDC.put('requestID', get_request_id(request_json))
+ MDC.put('partnerName', get_partner_name(request_json))
+
+
+def populate_default_mdc(request):
+ """Populate default MDC fields given the request
+
+ """
+ if MDC.get("instanceUUID") is None:
+ default_mdc()
+ g.request_start = time.process_time()
+ g.empty_value = "EMPTY"
+ g.request_id = MDC.get("requestID")
+ MDC.put('serviceName', request.path)
+ MDC.put('IPAddress', request.headers.get('X-Forwarded-For', request.remote_addr))
+
+
+def populate_mdc(request):
+ """Populate MDC fields from the request headers
+
+ """
+ populate_default_mdc(request)
+ req_id = request.headers.get('X-ONAP-RequestID', g.empty_value)
+ request_json = request.get_json()
+ if req_id == g.empty_value:
+ req_id = get_request_id(request_json)
+ g.request_id = req_id
+ MDC.put('requestID', req_id)
+ MDC.put('partnerName', get_partner_name(request_json))
+
+
+def get_request_id(request_json):
+ """Get the request_id from the request
+
+ """
+ request_id = request_json['requestInfo'].get('requestId')
+ if not request_id:
+ request_id = request_json['requestInfo'].get('requestID')
+ return request_id
+
+
+def generate_uuid():
+ """Generate an unique uuid
+
+ """
+ return f'{uuid.uuid1()}'
+
+
+def get_partner_name(request_json):
+ """Get the partnerName
+
+ """
+ partner_name = EMPTY
+ if 'requestInfo' in request_json:
+ partner_name = request_json['requestInfo'].get('sourceId', EMPTY)
+ return partner_name
+
+
+def clear_mdc():
+ """Clear MDC
+
+ """
+ MDC.clear()
+
+
+def get_time():
+ """Generate the invocation time string
+
+ The dateformat is %Y-%m-%dT%H:%M:%S.sss
+ """
+ ct = time.time()
+ lt = time.gmtime(ct)
+ msec = int((ct - int(ct)) * 1000)
+ return f'{time.strftime(DATE_FMT, lt)}.{msec:0>3}'
+
+
+def set_error_details(code, desc):
+ """set errorCode and description
+
+ """
+ MDC.put('errorCode', code)
+ MDC.put('errorDescription', desc)
diff --git a/osdf/webapp/appcontroller.py b/osdf/webapp/appcontroller.py
index 3a5385d..5db879a 100644
--- a/osdf/webapp/appcontroller.py
+++ b/osdf/webapp/appcontroller.py
@@ -16,13 +16,16 @@
# -------------------------------------------------------------------------
#
+import json
+
+from flask import Response
from flask import request
from flask_httpauth import HTTPBasicAuth
-from flask import Response
-import json
+
import osdf
-from osdf.config.base import http_basic_auth_credentials, osdf_config
+import osdf.config.base as cfg_base
from osdf.adapters.aaf import aaf_authentication as aaf_auth
+from osdf.config.base import osdf_config
auth_basic = HTTPBasicAuth()
@@ -34,11 +37,15 @@ error_body = {
unauthorized_message = json.dumps(error_body)
+
@auth_basic.get_password
def get_pw(username):
- end_point = request.url.split('/')[-1]
- auth_group = osdf.end_point_auth_mapping.get(end_point)
- return http_basic_auth_credentials[auth_group].get(username) if auth_group else None
+ auth_group = ''
+ for k in osdf.end_point_auth_mapping:
+ if k in request.url:
+ auth_group = osdf.end_point_auth_mapping.get(k)
+ return cfg_base.http_basic_auth_credentials[auth_group].get(username) if auth_group else None
+
@auth_basic.error_handler
def auth_error():
@@ -56,4 +63,3 @@ def verify_pw(username, password):
else:
pw = get_pw(username)
return pw == password
- return False \ No newline at end of file
diff --git a/osdfapp.py b/osdfapp.py
index f43c215..8b672f4 100755
--- a/osdfapp.py
+++ b/osdfapp.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2015-2017 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,82 +21,36 @@
OSDF Manager Main Flask Application
"""
-import sys
-from threading import Thread # for scaling up, may need celery with RabbitMQ or redis
+import json
-from flask import Flask, request, Response, g
+from threading import Thread # for scaling up, may need celery with RabbitMQ or redis
-import osdf
-import pydevd
-import json
-import osdf.adapters.policy.interface
-import osdf.config.credentials
-import osdf.config.loader
-import osdf.operation.error_handling
-import osdf.operation.responses
-import traceback
-from schematics.exceptions import DataError
-from requests import RequestException
-from optparse import OptionParser
+from flask import request, g
+
+from osdf.apps.baseapp import app, run_app
+from apps.nst.models.api.nstSelectionRequest import NSTSelectionAPI
+from apps.nsst.models.api.nsstSelectionRequest import NSSTSelectionAPI
+from apps.pci.models.api.pciOptimizationRequest import PCIOptimizationAPI
+from apps.nst.optimizers.nst_select_processor import NstSelection
+from apps.nsst.optimizers.nsst_select_processor import NsstSelection
+from apps.pci.optimizers.pci_opt_processor import process_pci_optimation
+from apps.placement.models.api.placementRequest import PlacementAPI
+from apps.placement.optimizers.conductor.remote_opt_processor import process_placement_opt
+from apps.route.optimizers.inter_domain_route_opt import InterDomainRouteOpt
+from apps.route.optimizers.simple_route_opt import RouteOpt
+from apps.slice_selection.models.api.nsi_selection_request import NSISelectionAPI
+from apps.slice_selection.models.api.nssi_selection_request import NSSISelectionAPI
+from apps.slice_selection.optimizers.conductor.remote_opt_processor import SliceSelectionOptimizer
from osdf.adapters.policy.interface import get_policies
+from osdf.adapters.policy.interface import upload_policy_models
from osdf.config.base import osdf_config
-from osdf.optimizers.placementopt.conductor.remote_opt_processor import process_placement_opt
-from osdf.webapp.appcontroller import auth_basic
-from osdf.operation.exceptions import BusinessException
-from osdf.operation.error_handling import request_exception_to_json_body, internal_error_message
-from osdf.logging.osdf_logging import MH, audit_log, error_log, debug_log
-from osdf.models.api.placementRequest import PlacementAPI
-from osdf.models.api.pciOptimizationRequest import PCIOptimizationAPI
+from osdf.config.base import slice_config
+from osdf.logging.osdf_logging import MH, audit_log
from osdf.operation.responses import osdf_response_for_request_accept as req_accept
-from osdf.optimizers.routeopt.simple_route_opt import RouteOpt
-from osdf.optimizers.pciopt.pci_opt_processor import process_pci_optimation
from osdf.utils import api_data_utils
-
-ERROR_TEMPLATE = osdf.ERROR_TEMPLATE
-
-app = Flask(__name__)
-
-BAD_CLIENT_REQUEST_MESSAGE = 'Client sent an invalid request'
-
-
-@app.errorhandler(BusinessException)
-def handle_business_exception(e):
- """An exception explicitly raised due to some business rule"""
- error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
- err_msg = ERROR_TEMPLATE.render(description=str(e))
- response = Response(err_msg, content_type='application/json; charset=utf-8')
- response.status_code = 400
- return response
-
-
-@app.errorhandler(RequestException)
-def handle_request_exception(e):
- """Returns a detailed synchronous message to the calling client
- when osdf fails due to a remote call to another system"""
- error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
- err_msg = request_exception_to_json_body(e)
- response = Response(err_msg, content_type='application/json; charset=utf-8')
- response.status_code = 400
- return response
-
-
-@app.errorhandler(DataError)
-def handle_data_error(e):
- """Returns a detailed message to the calling client when the initial synchronous message is invalid"""
- error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
-
- body_dictionary = {
- "serviceException": {
- "text": BAD_CLIENT_REQUEST_MESSAGE,
- "exceptionMessage": str(e.errors),
- "errorType": "InvalidClientRequest"
- }
- }
-
- body_as_json = json.dumps(body_dictionary)
- response = Response(body_as_json, content_type='application/json; charset=utf-8')
- response.status_code = 400
- return response
+from osdf.webapp.appcontroller import auth_basic
+from apps.nxi_termination.optimizers.remote_opt_processor import process_nxi_termination_opt
+from apps.nxi_termination.models.api.nxi_termination_request import NxiTerminationApi
@app.route("/api/oof/v1/healthcheck", methods=["GET"])
@@ -105,6 +60,15 @@ def do_osdf_health_check():
return "OK"
+@app.route("/api/oof/loadmodels/v1", methods=["GET"])
+def do_osdf_load_policies():
+ audit_log.info("Uploading policy models")
+ """Upload policy models"""
+ response = upload_policy_models()
+ audit_log.info(response)
+ return "OK"
+
+
@app.route("/api/oof/v1/placement", methods=["POST"])
@auth_basic.login_required
def do_placement_opt():
@@ -138,79 +102,121 @@ def placement_rest_api():
version_info=api_version_info, request_status="accepted", status_message="")
-@app.route("/api/oof/v1/route", methods=["POST"])
+@app.route("/api/oof/route/v1", methods=["POST"])
def do_route_calc():
"""
Perform the basic route calculations and returnn the vpn-bindings
"""
request_json = request.get_json()
audit_log.info("Calculate Route request received!")
- return RouteOpt().getRoute(request_json)
+ response = RouteOpt().get_route(request_json, osdf_config)
+ return response
+
+
+@app.route("/api/oof/mdons/route/v1", methods=["POST"])
+def do_mdons_route_calc():
+ """
+ Perform the inter domain route calculation
+ """
+ request_json = request.get_json()
+ audit_log.info("Inter Domain Calculation Route request received!")
+ response = InterDomainRouteOpt().get_route(request_json, osdf_config)
+ return response
+
+
+@app.route("/api/oof/v1/selection/nst", methods=["POST"])
+def do_nst_selection():
+ request_json = request.get_json()
+ req_id = request_json['requestInfo']['requestId']
+ audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
+ NSTSelectionAPI(request_json).validate()
+ audit_log.info(MH.new_worker_thread(req_id, "[for NST selection]"))
+ nst_selection = NstSelection(osdf_config, request_json)
+ nst_selection.start()
+ return req_accept(request_id=req_id,
+ transaction_id=request_json['requestInfo']['transactionId'],
+ request_status="accepted", status_message="")
+
+
+@app.route("/api/oof/v1/selection/nsst", methods=["POST"])
+def do_nsst_selection():
+ request_json = request.get_json()
+ req_id = request_json['requestInfo']['requestId']
+ audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
+ NSSTSelectionAPI(request_json).validate()
+ audit_log.info(MH.new_worker_thread(req_id, "[for NSST selection]"))
+ nsst_selection = NsstSelection(osdf_config, request_json)
+ nsst_selection.start()
+ return req_accept(request_id=req_id,
+ transaction_id=request_json['requestInfo']['transactionId'],
+ request_status="accepted", status_message="")
@app.route("/api/oof/v1/pci", methods=["POST"])
+@app.route("/api/oof/pci/v1", methods=["POST"])
@auth_basic.login_required
def do_pci_optimization():
request_json = request.get_json()
+ audit_log.info('request json obtained==>')
+ audit_log.info(request_json)
+
req_id = request_json['requestInfo']['requestId']
+ audit_log.info('requestID obtained==>')
+ audit_log.info(req_id)
+
g.request_id = req_id
audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
PCIOptimizationAPI(request_json).validate()
- #disable policy retrieval
+ # disable policy retrieval
# policies = get_policies(request_json, "pciopt")
audit_log.info(MH.new_worker_thread(req_id, "[for pciopt]"))
t = Thread(target=process_pci_optimation, args=(request_json, osdf_config, None))
t.start()
audit_log.info(MH.accepted_valid_request(req_id, request))
+ audit_log.info('reached upto return')
return req_accept(request_id=req_id,
transaction_id=request_json['requestInfo']['transactionId'],
request_status="accepted", status_message="")
-@app.errorhandler(500)
-def internal_failure(error):
- """Returned when unexpected coding errors occur during initial synchronous processing"""
- error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
- response = Response(internal_error_message, content_type='application/json; charset=utf-8')
- response.status_code = 500
- return response
+@app.route("/api/oof/selection/nsi/v1", methods=["POST"])
+def do_nsi_selection():
+ request_json = request.get_json()
+ req_id = request_json['requestInfo']['requestId']
+ g.request_id = req_id
+ audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
+ NSISelectionAPI(request_json).validate()
+ audit_log.info(MH.new_worker_thread(req_id, "[for NSI selection]"))
+ slice_opt = SliceSelectionOptimizer(osdf_config, slice_config, request_json, 'NSI')
+ slice_opt.start()
+ return req_accept(request_id=req_id,
+ transaction_id=request_json['requestInfo']['transactionId'],
+ request_status="accepted", status_message="")
-def get_options(argv):
- program_version_string = '%%prog %s' % "v1.0"
- program_longdesc = ""
- program_license = ""
- parser = OptionParser(version=program_version_string, epilog=program_longdesc, description=program_license)
- parser.add_option("-l", "--local", dest="local", help="run locally", action="store_true", default=False)
- parser.add_option("-t", "--devtest", dest="devtest", help="run in dev/test environment", action="store_true",
- default=False)
- parser.add_option("-d", "--debughost", dest="debughost", help="IP Address of host running debug server", default='')
- parser.add_option("-p", "--debugport", dest="debugport", help="Port number of debug server", type=int, default=5678)
- opts, args = parser.parse_args(argv)
+@app.route("/api/oof/selection/nssi/v1", methods=["POST"])
+def do_nssi_selection():
+ request_json = request.get_json()
+ req_id = request_json['requestInfo']['requestId']
+ g.request_id = req_id
+ audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
+ NSSISelectionAPI(request_json).validate()
+ audit_log.info(MH.new_worker_thread(req_id, "[for NSSI selection]"))
+ slice_opt = SliceSelectionOptimizer(osdf_config, slice_config, request_json, 'NSSI')
+ slice_opt.start()
+ return req_accept(request_id=req_id,
+ transaction_id=request_json['requestInfo']['transactionId'],
+ request_status="accepted", status_message="")
- if opts.debughost:
- debug_log.debug('pydevd.settrace({}, port={})'.format(opts.debughost, opts.debugport))
- pydevd.settrace(opts.debughost, port=opts.debugport)
- return opts
+
+@app.route("/api/oof/terminate/nxi/v1",methods=["POST"])
+def do_nxi_terminaton():
+ request_json = request.get_json()
+ req_id = request_json['requestInfo']['requestId']
+ g.request_id = req_id
+ audit_log.info(MH.received_request(request.url, request.remote_addr, json.dumps(request_json)))
+ NxiTerminationApi(request_json).validate()
+ return process_nxi_termination_opt(request_json,osdf_config)
if __name__ == "__main__":
-
- sys_conf = osdf_config['core']['osdf_system']
- ports = sys_conf['osdf_ports']
- internal_port, external_port = ports['internal'], ports['external']
-
- local_host = sys_conf['osdf_ip_default']
- common_app_opts = dict(host=local_host, threaded=True, use_reloader=False)
-
- ssl_opts = sys_conf.get('ssl_context')
- if ssl_opts:
- common_app_opts.update({'ssl_context': tuple(ssl_opts)})
-
- opts = get_options(sys.argv)
- # TODO(Dileep): Uncomment once Helm charts to preload secrets available
- # sms.load_secrets()
- if not opts.local and not opts.devtest: # normal deployment
- app.run(port=internal_port, debug=False, **common_app_opts)
- else:
- port = internal_port if opts.local else external_port
- app.run(port=port, debug=True, **common_app_opts)
+ run_app()
diff --git a/osdfapp.sh b/osdfapp.sh
index 0e1846a..7e3284f 100755
--- a/osdfapp.sh
+++ b/osdfapp.sh
@@ -18,14 +18,60 @@
# -------------------------------------------------------------------------
#
+usage() {
+ echo "Usage:"
+ echo " $0 -h Display this help message."
+ echo " $0 -c configfile_path(optional) -x app.py file"
+ exit 0
+}
+
cd $(dirname $0)
# bash ../etc/make-certs.sh # create the https certificates if they are not present
+while getopts ":hc:x:" opt; do
+ case ${opt} in
+ h )
+ usage
+ ;;
+ c )
+ # process option configuration
+ export OSDF_CONFIG_FILE=$OPTARG
+ ;;
+ x )
+ # process executable file
+ export EXEC_FILE=$OPTARG
+ ;;
+ ? )
+ usage
+ ;;
+ : )
+ echo "Invalid Option: -$OPTARG requires an argument" 1>&2
+ exit 1
+ ;;
+ esac
+done
+shift $(( OPTIND - 1 ))
+
+set -e
+
LOGS=logs
mkdir -p $LOGS
-export OSDF_CONFIG_FILE=${1:-/opt/app/config/osdf_config.yaml} # this file may be passed by invoker
-[ ! -e "$OSDF_CONFIG_FILE" ] && unset OSDF_CONFIG_FILE
+#if [ -e /opt/app/ssl_cert/aaf_root_ca.cer ]; then
+# #assuming that this would be an ubuntu vm.
+# cp /opt/app/ssl_cert/aaf_root_ca.cer /usr/local/share/ca-certificates/aafcacert.crt
+# chmod 444 /usr/local/share/ca-certificates/aafcacert.crt
+# update-ca-certificates
+#fi
+
+export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
-python osdfapp.py 2>$LOGS/err.log 1>$LOGS/out.log < /dev/null # running the app
+if [ ! -z "$EXEC_FILE" ]
+then
+ # flask run
+ echo "Running $EXEC_FILE"
+ python $EXEC_FILE # running the app
+else
+ usage
+fi
diff --git a/pom.xml b/pom.xml
index 438e989..bd31f85 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,71 +14,201 @@
License for the specific language governing permissions and limitations
under the License.
-->
-<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>
- <packaging>pom</packaging>
+<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
+http://maven.apache.org/POM/4.0.0 ">
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>pom</packaging>
- <parent>
- <groupId>org.onap.oparent</groupId>
- <artifactId>oparent-python</artifactId>
- <version>1.2.1</version>
- </parent>
+ <parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent-python</artifactId>
+ <version>3.0.0</version>
+ </parent>
- <groupId>org.onap.optf.osdf</groupId>
- <artifactId>optf-osdf</artifactId>
- <name>optf-osdf</name>
- <version>1.2.2-SNAPSHOT</version>
- <description>Optimization Service Design Framework</description>
+ <groupId>org.onap.optf.osdf</groupId>
+ <artifactId>optf-osdf</artifactId>
+ <name>optf-osdf</name>
+ <version>3.0.8-SNAPSHOT</version>
+ <description>Optimization Service Design Framework</description>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <sonar.sources>.</sonar.sources>
- <sonar.junit.reportsPath>xunit-results.xml</sonar.junit.reportsPath>
- <sonar.python.coverage.reportPath>coverage.xml</sonar.python.coverage.reportPath>
- <sonar.language>py</sonar.language>
- <sonar.pluginname>python</sonar.pluginname>
- <sonar.inclusions>**/**.py,osdfapp.py</sonar.inclusions>
- <sonar.exclusions>test/**.py</sonar.exclusions>
- </properties>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <sonar.sources>.</sonar.sources>
+ <sonar.junit.reportsPath>xunit-results.xml</sonar.junit.reportsPath>
+ <sonar.python.coverage.reportPaths>coverage.xml</sonar.python.coverage.reportPaths>
+ <sonar.language>py</sonar.language>
+ <sonar.pluginname>python</sonar.pluginname>
+ <sonar.inclusions>**/**.py,osdfapp.py</sonar.inclusions>
+ <sonar.exclusions>test/**.py,docs/**.py</sonar.exclusions>
+ <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+ <osdf.build.timestamp>${maven.build.timestamp}</osdf.build.timestamp>
+ <osdf.project.version>${project.version}</osdf.project.version>
+ <osdf.docker.repository>nexus3.onap.org:10003</osdf.docker.repository>
+ <osdf.base.image>osdf-base</osdf.base.image>
+ <image.namespace>${osdf.docker.repository}/onap/optf-osdf</image.namespace>
+ <opteng.namespace>${osdf.docker.repository}/onap/optf-opteng</opteng.namespace>
+ </properties>
- <build>
- <plugins>
- <!-- triggers tox test for sonar -->
- <plugin>
- <artifactId>exec-maven-plugin</artifactId>
- <groupId>org.codehaus.mojo</groupId>
- </plugin>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <configuration>
- <appendAssemblyId>false</appendAssemblyId>
- <descriptors>
- <descriptor>assembly.xml</descriptor>
- </descriptors>
- </configuration>
- <executions>
- <execution>
- <id>make-assembly</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
+ <build>
+ <plugins>
+ <!-- triggers tox test for sonar -->
+ <plugin>
+ <artifactId>exec-maven-plugin</artifactId>
+ <groupId>org.codehaus.mojo</groupId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-deploy-plugin</artifactId>
- <version>2.8</version>
- <configuration>
- <retryFailedDeploymentCount>2</retryFailedDeploymentCount>
- </configuration>
- </plugin>
- </plugins>
- </build>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.8</version>
+ <configuration>
+ <retryFailedDeploymentCount>2</retryFailedDeploymentCount>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.groovy.maven</groupId>
+ <artifactId>gmaven-plugin</artifactId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>${project.basedir}/script/TagVersion.groovy</source>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <version>0.26.0</version>
+ <configuration>
+ <verbose>true</verbose>
+ <apiVersion>1.23</apiVersion>
+ <images>
+ <image>
+ <name>${osdf.base.image}</name>
+ <alias>optf-base</alias>
+ <build>
+ <cleanup>true</cleanup>
+ <tags>
+ <tag>latest</tag>
+ </tags>
+
+ <dockerFile>${project.basedir}/docker/osdf-lib-base/Dockerfile</dockerFile>
+ <assembly>
+ <descriptor>${project.basedir}/docker/osdf-lib-base/assembly/osdf-lib-files.xml</descriptor>
+ <name>onap-osdf-tm</name>
+ </assembly>
+ <args>
+ <MVN_ARTIFACT_VERSION>${project.version}</MVN_ARTIFACT_VERSION>
+ <REPO>${project.repo}</REPO>
+ </args>
+ </build>
+ </image>
+ <image>
+ <name>${image.namespace}</name>
+ <alias>optf-osdf</alias>
+ <build>
+ <cleanup>true</cleanup>
+ <tags>
+ <tag>latest</tag>
+ <tag>${project.docker.latesttagtimestamp.version}</tag>
+ <tag>${project.docker.latesttag.version}</tag>
+ </tags>
+
+ <dockerFile>${project.basedir}/docker/osdf/Dockerfile</dockerFile>
+ <assembly>
+ <descriptor>${project.basedir}/docker/osdf/assembly/osdf-files.xml</descriptor>
+ <name>onap-osdf-tm</name>
+ </assembly>
+ <args>
+ <MVN_ARTIFACT_VERSION>${project.version}</MVN_ARTIFACT_VERSION>
+ <REPO>${project.repo}</REPO>
+
+ <!-- plugin cannot handle empty (no proxy) arguments
+ <http_proxy_arg>${docker.http_proxy}</http_proxy_arg>
+ <https_proxy_arg>${docker.https_proxy}</https_proxy_arg>
+ -->
+ </args>
+ </build>
+ </image>
+ <image>
+ <name>${opteng.namespace}</name>
+ <alias>optf-opteng</alias>
+ <build>
+ <cleanup>true</cleanup>
+ <tags>
+ <tag>latest</tag>
+ <tag>${project.docker.latesttagtimestamp.version}</tag>
+ <tag>${project.docker.latesttag.version}</tag>
+ </tags>
+
+ <dockerFile>${project.basedir}/docker/opteng/Dockerfile</dockerFile>
+ <assembly>
+ <descriptor>${project.basedir}/docker/opteng/assembly/osdf-files.xml</descriptor>
+ <name>onap-osdf-tm</name>
+ </assembly>
+ <args>
+ <MVN_ARTIFACT_VERSION>${project.version}</MVN_ARTIFACT_VERSION>
+ <REPO>${project.repo}</REPO>
+
+ <!-- plugin cannot handle empty (no proxy) arguments
+ <http_proxy_arg>${docker.http_proxy}</http_proxy_arg>
+ <https_proxy_arg>${docker.https_proxy}</https_proxy_arg>
+ -->
+ </args>
+ </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>build</goal>
+ <goal>push</goal>
+ </goals>
+ <configuration>
+ <image>${image.namespace}:%l</image>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/releases/1.3.3.yaml b/releases/1.3.3.yaml
new file mode 100644
index 0000000..bcff0af
--- /dev/null
+++ b/releases/1.3.3.yaml
@@ -0,0 +1,6 @@
+distribution_type: 'maven'
+version: '1.3.3'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/97/'
+maven_central_url: 'oss.sonatype.org'
+
diff --git a/releases/1.3.4.yaml b/releases/1.3.4.yaml
new file mode 100644
index 0000000..c7da426
--- /dev/null
+++ b/releases/1.3.4.yaml
@@ -0,0 +1,5 @@
+distribution_type: 'maven'
+version: '1.3.4'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/106/'
+
diff --git a/releases/2.0.0-container.yaml b/releases/2.0.0-container.yaml
new file mode 100644
index 0000000..4f458d2
--- /dev/null
+++ b/releases/2.0.0-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '2.0.0'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/150/'
+ref: 6e84d892b5f8e3a2f90fb36b6c7a642c800c2f9c
+containers:
+ - name: 'optf-osdf'
+ version: '2.0.0-STAGING-20200316T162605Z'
+ - name: 'optf-opteng'
+ version: '2.0.0-STAGING-20200316T162605Z' \ No newline at end of file
diff --git a/releases/2.0.0.yaml b/releases/2.0.0.yaml
new file mode 100644
index 0000000..fee446c
--- /dev/null
+++ b/releases/2.0.0.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '2.0.0'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/329/' \ No newline at end of file
diff --git a/releases/2.0.1-container.yaml b/releases/2.0.1-container.yaml
new file mode 100644
index 0000000..b2fe40c
--- /dev/null
+++ b/releases/2.0.1-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '2.0.1'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/160/'
+ref: fcb37e97e37137d3111924e993e75fdb83c2a0a0
+containers:
+ - name: 'optf-osdf'
+ version: '2.0.1-STAGING-20200325T192323Z'
+ - name: 'optf-opteng'
+ version: '2.0.1-STAGING-20200325T192323Z' \ No newline at end of file
diff --git a/releases/2.0.1.yaml b/releases/2.0.1.yaml
new file mode 100644
index 0000000..86f3f47
--- /dev/null
+++ b/releases/2.0.1.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '2.0.1'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/340/' \ No newline at end of file
diff --git a/releases/2.0.2-container.yaml b/releases/2.0.2-container.yaml
new file mode 100644
index 0000000..9e44d61
--- /dev/null
+++ b/releases/2.0.2-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '2.0.2'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/163/'
+ref: ddac631c097167df890cf6814df301b61a0815c7
+containers:
+ - name: 'optf-osdf'
+ version: '2.0.2-STAGING-20200327T232752Z'
+ - name: 'optf-opteng'
+ version: '2.0.2-STAGING-20200327T232752Z' \ No newline at end of file
diff --git a/releases/2.0.3-container.yaml b/releases/2.0.3-container.yaml
new file mode 100644
index 0000000..30d8603
--- /dev/null
+++ b/releases/2.0.3-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '2.0.3'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/185/'
+ref: d79e6bda8b636d77d51ddb63dcd3d91ddda34d83
+containers:
+ - name: 'optf-osdf'
+ version: '2.0.3-STAGING-20200415T161453Z'
+ - name: 'optf-opteng'
+ version: '2.0.3-STAGING-20200415T161453Z' \ No newline at end of file
diff --git a/releases/2.0.3.yaml b/releases/2.0.3.yaml
new file mode 100644
index 0000000..5a2d322
--- /dev/null
+++ b/releases/2.0.3.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '2.0.3'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/365/' \ No newline at end of file
diff --git a/releases/2.0.4-container.yaml b/releases/2.0.4-container.yaml
new file mode 100644
index 0000000..b792d55
--- /dev/null
+++ b/releases/2.0.4-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '2.0.4'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/222/'
+ref: acb4f63122e205acf0bc4f8649f746bd5bccd486
+containers:
+ - name: 'optf-osdf'
+ version: '2.0.4-STAGING-20200521T185101Z'
+ - name: 'optf-opteng'
+ version: '2.0.4-STAGING-20200521T185101Z' \ No newline at end of file
diff --git a/releases/2.0.4.yaml b/releases/2.0.4.yaml
new file mode 100644
index 0000000..b96f810
--- /dev/null
+++ b/releases/2.0.4.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '2.0.4'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/402/' \ No newline at end of file
diff --git a/releases/3.0.0-container.yaml b/releases/3.0.0-container.yaml
new file mode 100644
index 0000000..fb9e198
--- /dev/null
+++ b/releases/3.0.0-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.0'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/346/'
+ref: c9b6e78051ea314bc7f20d1e273f51c9017e2e5b
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.0-STAGING-20200921T105356Z'
+ - name: 'optf-opteng'
+ version: '3.0.0-STAGING-20200921T105356Z'
diff --git a/releases/3.0.0.yaml b/releases/3.0.0.yaml
new file mode 100644
index 0000000..85993d0
--- /dev/null
+++ b/releases/3.0.0.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '3.0.0'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-stage-master/525/'
diff --git a/releases/3.0.1-container.yaml b/releases/3.0.1-container.yaml
new file mode 100644
index 0000000..f065265
--- /dev/null
+++ b/releases/3.0.1-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.1'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/364/'
+ref: e5a3e67f106f88a1143da7ee2f7248fe8dc1920d
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.1-STAGING-20201008T142633Z'
+ - name: 'optf-opteng'
+ version: '3.0.1-STAGING-20201008T142633Z'
diff --git a/releases/3.0.2-container.yaml b/releases/3.0.2-container.yaml
new file mode 100644
index 0000000..c6f66c3
--- /dev/null
+++ b/releases/3.0.2-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.2'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/404/'
+ref: dbdc2d26632175ab01d345b88ebf02ee8f95454a
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.2-STAGING-20201116T133002Z'
+ - name: 'optf-opteng'
+ version: '3.0.2-STAGING-20201116T133002Z'
diff --git a/releases/3.0.3-container.yaml b/releases/3.0.3-container.yaml
new file mode 100644
index 0000000..268c71c
--- /dev/null
+++ b/releases/3.0.3-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.3'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/504/'
+ref: 818489f9580f62c71ee6d6ad7a9e6e080e4c2107
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.3-STAGING-20210223T072953Z'
+ - name: 'optf-opteng'
+ version: '3.0.3-STAGING-20210223T072953Z'
diff --git a/releases/3.0.4-container.yaml b/releases/3.0.4-container.yaml
new file mode 100644
index 0000000..6c32fb5
--- /dev/null
+++ b/releases/3.0.4-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.4'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/520/'
+ref: e5182a3ed5333c7da2e043a58d8df8d76e7f6e2f
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.4-STAGING-20210310T054208Z'
+ - name: 'optf-opteng'
+ version: '3.0.4-STAGING-20210310T054208Z'
diff --git a/releases/3.0.5-container.yaml b/releases/3.0.5-container.yaml
new file mode 100644
index 0000000..4d58a70
--- /dev/null
+++ b/releases/3.0.5-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.5'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/663/'
+ref: 9f6fccf6a2609fbd2c9e50cb7f27d15b040133bb
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.5-STAGING-20210730T065718Z'
+ - name: 'optf-opteng'
+ version: '3.0.5-STAGING-20210730T065718Z'
diff --git a/releases/3.0.6-container.yaml b/releases/3.0.6-container.yaml
new file mode 100644
index 0000000..0dcd634
--- /dev/null
+++ b/releases/3.0.6-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.6'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/732/'
+ref: 93997d04f30539b8947f3084d2397b34d9d75e27
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.6-STAGING-20211007T114744Z'
+ - name: 'optf-opteng'
+ version: '3.0.6-STAGING-20211007T114744Z'
diff --git a/releases/3.0.7-container.yaml b/releases/3.0.7-container.yaml
new file mode 100644
index 0000000..2dbab8f
--- /dev/null
+++ b/releases/3.0.7-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.7'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/1078/'
+ref: ba5deeadc1eef53a2f44ba92e6ede9026b56bc57
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.7-STAGING-20220922T095920Z'
+ - name: 'optf-opteng'
+ version: '3.0.7-STAGING-20220922T095920Z'
diff --git a/releases/3.0.8-container.yaml b/releases/3.0.8-container.yaml
new file mode 100644
index 0000000..e1969a1
--- /dev/null
+++ b/releases/3.0.8-container.yaml
@@ -0,0 +1,10 @@
+distribution_type: 'container'
+container_release_tag: '3.0.8'
+project: 'optf-osdf'
+log_dir: 'optf-osdf-maven-docker-stage-master/1226/'
+ref: dee386685502c63d64959e0f2324bf52440e9655
+containers:
+ - name: 'optf-osdf'
+ version: '3.0.8-STAGING-20230217T053828Z'
+ - name: 'optf-opteng'
+ version: '3.0.8-STAGING-20230217T053828Z'
diff --git a/requirements-opteng.txt b/requirements-opteng.txt
new file mode 100644
index 0000000..a20435b
--- /dev/null
+++ b/requirements-opteng.txt
@@ -0,0 +1 @@
+mysql-connector-python==8.0.31
diff --git a/requirements-osdf.txt b/requirements-osdf.txt
new file mode 100644
index 0000000..c095258
--- /dev/null
+++ b/requirements-osdf.txt
@@ -0,0 +1 @@
+scikit-learn>=0.22.0 \ No newline at end of file
diff --git a/requirements-sim.txt b/requirements-sim.txt
new file mode 100644
index 0000000..56a8931
--- /dev/null
+++ b/requirements-sim.txt
@@ -0,0 +1,18 @@
+cryptography==3.3.2
+docutils>=0.12
+docopt>=0.6.2
+Flask>=0.11.1
+Flask-HTTPAuth>=3.2.2
+jsonschema>=2.5.1
+lxml>=3.6.4
+python-dateutil>=2.5.3
+PyYAML==5.4.1
+requests>=2.14.2
+schematics>=2.0.0
+onapsmsclient>=0.0.4
+pymzn>=0.18.3
+onappylog>=1.0.9
+pathtools>=0.1.2
+pycryptodome>=3.9.6
+python-consul>=1.1.0
+tornado>=6.1
diff --git a/requirements.txt b/requirements.txt
index 0275ab7..56a8931 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,15 +1,18 @@
+cryptography==3.3.2
docutils>=0.12
docopt>=0.6.2
Flask>=0.11.1
Flask-HTTPAuth>=3.2.2
jsonschema>=2.5.1
lxml>=3.6.4
-nose>=1.3.7
python-dateutil>=2.5.3
-PyYAML>=3.12
+PyYAML==5.4.1
requests>=2.14.2
schematics>=2.0.0
-docopt>=0.6.2
-pydevd>=1.0.0
onapsmsclient>=0.0.4
-pymzn>=0.17.0
+pymzn>=0.18.3
+onappylog>=1.0.9
+pathtools>=0.1.2
+pycryptodome>=3.9.6
+python-consul>=1.1.0
+tornado>=6.1
diff --git a/osdf/optimizers/placementopt/conductor/__init__.py b/runtime/__init__.py
index 4b25e5b..2aa67d8 100644
--- a/osdf/optimizers/placementopt/conductor/__init__.py
+++ b/runtime/__init__.py
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------
-# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (c) 2020 AT&T Intellectual Property
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/runtime/model_api.py b/runtime/model_api.py
new file mode 100644
index 0000000..b0492f2
--- /dev/null
+++ b/runtime/model_api.py
@@ -0,0 +1,221 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import traceback
+
+from flask import Flask
+from flask import g
+from flask import Response
+import mysql.connector
+
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import debug_log
+from osdf.logging.osdf_logging import error_log
+from osdf.operation.exceptions import BusinessException
+from osdf.utils.data_conversion import decode_data
+
+
+def init_db():
+ if is_db_enabled():
+ get_db()
+
+
+def get_db():
+ """Opens a new database connection if there is none yet for the current application context.
+
+ """
+ if not hasattr(g, 'pg'):
+ properties = osdf_config['deployment']
+ host, db_port, db = properties["osdfDatabaseHost"], properties["osdfDatabasePort"], properties.get(
+ "osdfDatabaseSchema")
+ user, password = properties["osdfDatabaseUsername"], properties["osdfDatabasePassword"]
+ g.pg = mysql.connector.connect(host=host, port=db_port, user=user, password=password, database=db)
+ return g.pg
+
+
+def close_db():
+ """Closes the database again at the end of the request.
+
+ """
+ if hasattr(g, 'pg'):
+ g.pg.close()
+
+
+app = Flask(__name__)
+
+
+def create_model_data(model_api):
+ with app.app_context():
+ try:
+ model_info = model_api['modelInfo']
+ model_id = model_info['modelId']
+ debug_log.debug(
+ "persisting model_api {}".format(model_id))
+ connection = get_db()
+ cursor = connection.cursor(buffered=True)
+ query = "SELECT model_id FROM optim_model_data WHERE model_id = %s"
+ values = (model_id,)
+ cursor.execute(query, values)
+ if cursor.fetchone() is None:
+ query = "INSERT INTO optim_model_data (model_id, model_content, description, solver_type) VALUES " \
+ "(%s, %s, %s, %s)"
+ values = (model_id, model_info['modelContent'], model_info.get('description'), model_info['solver'])
+ cursor.execute(query, values)
+ g.pg.commit()
+
+ debug_log.debug("A record successfully inserted for request_id: {}".format(model_id))
+ return retrieve_model_data(model_id)
+ close_db()
+ else:
+ query = "UPDATE optim_model_data SET model_content = %s, description = %s, solver_type = %s where " \
+ "model_id = %s "
+ values = (model_info['modelContent'], model_info.get('description'), model_info['solver'], model_id)
+ cursor.execute(query, values)
+ g.pg.commit()
+
+ return retrieve_model_data(model_id)
+ close_db()
+ except Exception as err:
+ error_log.error("error for request_id: {} - {}".format(model_id, traceback.format_exc()))
+ close_db()
+ raise BusinessException(err)
+
+
+def retrieve_model_data(model_id):
+ status, resp_data = get_model_data(model_id)
+
+ if status == 200:
+ resp = json.dumps(build_model_dict(resp_data))
+ return build_response(resp, status)
+ else:
+ resp = json.dumps({
+ 'modelId': model_id,
+ 'statusMessage': "Error retrieving the model data for model {} due to {}".format(model_id, resp_data)
+ })
+ return build_response(resp, status)
+
+
+def build_model_dict(resp_data, content_needed=True):
+ resp = {'modelId': resp_data[0], 'description': resp_data[2] if resp_data[2] else '',
+ 'solver': resp_data[3]}
+ if content_needed:
+ resp.update({'modelContent': decode_data(resp_data[1])})
+ return resp
+
+
+def build_response(resp, status):
+ response = Response(resp, content_type='application/json; charset=utf-8')
+ response.headers.add('content-length', len(resp))
+ response.status_code = status
+ return response
+
+
+def delete_model_data(model_id):
+ with app.app_context():
+ try:
+ debug_log.debug("deleting model data given model_id = {}".format(model_id))
+ connection = get_db()
+ cursor = connection.cursor(buffered=True)
+ query = "delete from optim_model_data WHERE model_id = %s"
+ values = (model_id,)
+ cursor.execute(query, values)
+ g.pg.commit()
+ close_db()
+ resp = {
+ "statusMessage": "model data for modelId {} deleted".format(model_id)
+ }
+ return build_response(json.dumps(resp), 200)
+ except Exception as err:
+ error_log.error("error deleting model_id: {} - {}".format(model_id, traceback.format_exc()))
+ close_db()
+ raise BusinessException(err)
+
+
+def get_model_data(model_id):
+ with app.app_context():
+ try:
+ debug_log.debug("getting model data given model_id = {}".format(model_id))
+ d = dict()
+ connection = get_db()
+ cursor = connection.cursor(buffered=True)
+ query = "SELECT model_id, model_content, description, " \
+ "solver_type FROM optim_model_data WHERE model_id = %s"
+ values = (model_id,)
+ cursor.execute(query, values)
+ if cursor is None:
+ return 400, "FAILED"
+ else:
+ rows = cursor.fetchone()
+ if rows is not None:
+ index = 0
+ for row in rows:
+ d[index] = row
+ index = index + 1
+ return 200, d
+ else:
+ close_db()
+ return 500, "NOT_FOUND"
+ except Exception:
+ error_log.error("error for request_id: {} - {}".format(model_id, traceback.format_exc()))
+ close_db()
+ return 500, "FAILED"
+
+
+def retrieve_all_models():
+ status, resp_data = get_all_models()
+ model_list = []
+ if status == 200:
+ for r in resp_data:
+ model_list.append(build_model_dict(r, False))
+ resp = json.dumps(model_list)
+ return build_response(resp, status)
+
+ else:
+ resp = json.dumps({
+ 'statusMessage': "Error retrieving all the model data due to {}".format(resp_data)
+ })
+ return build_response(resp, status)
+
+
+def get_all_models():
+ with app.app_context():
+ try:
+ debug_log.debug("getting all model data".format())
+ connection = get_db()
+ cursor = connection.cursor(buffered=True)
+ query = "SELECT model_id, model_content, description, solver_type FROM optim_model_data"
+
+ cursor.execute(query)
+ if cursor is None:
+ return 400, "FAILED"
+ else:
+ rows = cursor.fetchall()
+ if rows is not None:
+ return 200, rows
+ else:
+ close_db()
+ return 500, "NOT_FOUND"
+ except Exception:
+ error_log.error("error for request_id: {}".format(traceback.format_exc()))
+ close_db()
+ return 500, "FAILED"
+
+
+def is_db_enabled():
+ return osdf_config['deployment'].get('isDatabaseEnabled', False)
diff --git a/runtime/models/__init__.py b/runtime/models/__init__.py
new file mode 100644
index 0000000..2aa67d8
--- /dev/null
+++ b/runtime/models/__init__.py
@@ -0,0 +1,17 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
diff --git a/runtime/models/api/__init__.py b/runtime/models/api/__init__.py
new file mode 100644
index 0000000..2aa67d8
--- /dev/null
+++ b/runtime/models/api/__init__.py
@@ -0,0 +1,17 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
diff --git a/runtime/models/api/model_request.py b/runtime/models/api/model_request.py
new file mode 100644
index 0000000..710da4b
--- /dev/null
+++ b/runtime/models/api/model_request.py
@@ -0,0 +1,48 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from schematics.types import StringType
+from schematics.types.compound import ModelType
+
+from osdf.models.api.common import OSDFModel
+
+
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client such as PCI-mS Handler"""
+ transactionId = StringType(required=True)
+ requestID = StringType(required=True)
+ sourceId = StringType(required=True)
+
+
+class OptimModelInfo(OSDFModel):
+ """Optimizer request info details."""
+ # ModelId from the database
+ modelId = StringType()
+ # type of solver (mzn, or-tools, etc.)
+ solver = StringType(required=True)
+ # Description of the model
+ description = StringType()
+ # a large blob string containing the model (which is not that
+ # problematic since models are fairly small).
+ modelContent = StringType()
+
+
+class OptimModelRequestAPI(OSDFModel):
+ """Request for Optimizer API (specific to optimization and additional metadata"""
+ requestInfo = ModelType(RequestInfo, required=True)
+ modelInfo = ModelType(OptimModelInfo, required=True)
diff --git a/runtime/models/api/model_response.py b/runtime/models/api/model_response.py
new file mode 100644
index 0000000..e4a41a5
--- /dev/null
+++ b/runtime/models/api/model_response.py
@@ -0,0 +1,31 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from schematics.types import StringType
+
+from osdf.models.api.common import OSDFModel
+
+
+class OptimModelResponse(OSDFModel):
+ modelId = StringType()
+ # type of solver (mzn, or-tools, etc.)
+ solver = StringType()
+ # a large blob string containing the model
+ modelContent = StringType()
+ # statusMessage
+ statusMessage = StringType()
diff --git a/runtime/models/api/optim_request.py b/runtime/models/api/optim_request.py
new file mode 100644
index 0000000..4a046d2
--- /dev/null
+++ b/runtime/models/api/optim_request.py
@@ -0,0 +1,60 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from schematics.types import BaseType, DictType, StringType, IntType
+from schematics.types.compound import ModelType
+
+from osdf.models.api.common import OSDFModel
+
+"""
+"""
+class RequestInfo(OSDFModel):
+ """Info for northbound request from client """
+ transactionId = StringType(required=True)
+ requestID = StringType(required=True)
+ callbackUrl = StringType()
+ sourceId = StringType(required=True)
+ timeout = IntType()
+
+
+class DataInfo(OSDFModel):
+ """Optimization data info"""
+ text = StringType()
+ json = DictType(BaseType)
+
+
+class OptimInfo(OSDFModel):
+ """Optimizer request info details."""
+ # ModelId from the database, if its not populated,
+ # assume that solverModel will be populated.
+ modelId = StringType()
+ # type of solver (mzn, or-tools, etc.)
+ solver = StringType()
+ # Arguments for solver
+ solverArgs = DictType(BaseType)
+ # NOTE: a large blob string containing the model (which is not that
+ # problematic since models are fairly small).
+ modelContent = StringType()
+ # Data Payload, input data for the solver
+ optData = ModelType(DataInfo)
+
+
+class OptimizationAPI(OSDFModel):
+ """Request for Optimizer API (specific to optimization and additional metadata"""
+ requestInfo = ModelType(RequestInfo, required=True)
+ optimInfo = ModelType(OptimInfo, required=True)
diff --git a/runtime/models/api/optim_response.py b/runtime/models/api/optim_response.py
new file mode 100644
index 0000000..6fd0f6b
--- /dev/null
+++ b/runtime/models/api/optim_response.py
@@ -0,0 +1,30 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from schematics.types import StringType, BaseType
+from schematics.types.compound import DictType
+
+from osdf.models.api.common import OSDFModel
+
+
+class OptimResponse(OSDFModel):
+ transactionId = StringType(required=True)
+ requestID = StringType(required=True)
+ requestStatus = StringType(required=True)
+ statusMessage = StringType()
+ solutions = DictType(BaseType)
diff --git a/runtime/optim_engine.py b/runtime/optim_engine.py
new file mode 100644
index 0000000..b303bbf
--- /dev/null
+++ b/runtime/optim_engine.py
@@ -0,0 +1,80 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from flask import Response
+
+from osdf.operation.exceptions import BusinessException
+from osdf.utils.data_conversion import decode_data
+from runtime.model_api import get_model_data
+from runtime.models.api.optim_request import OptimizationAPI
+from runtime.solvers.mzn.mzn_solver import solve as mzn_solve
+from runtime.solvers.py.py_solver import solve as py_solve
+
+
+def is_valid_optim_request(request_json):
+ # Method to check whether the requestinfo/optimizer value is valid.
+ opt_info = request_json['optimInfo']
+ if not opt_info.get('modelId'):
+ if not opt_info.get('modelContent') or not opt_info.get('solver'):
+ raise BusinessException('modelContent and solver needs to be populated if model_id is not set')
+ if not opt_info.get('optData'):
+ raise BusinessException('optimInfo.optData needs to be populated to solve for a problem')
+
+ return True
+
+
+def validate_request(request_json):
+ OptimizationAPI(request_json).validate()
+ if not is_valid_optim_request(request_json):
+ raise BusinessException('Invalid optim request ')
+ return True
+
+
+def process_request(request_json):
+ response_code, response_message = run_optimizer(request_json)
+ response = Response(response_message, content_type='application/json; charset=utf-8')
+ response.headers.add('content-length', len(response_message))
+ response.status_code = response_code
+ return response
+
+
+def run_optimizer(request_json):
+ validate_request(request_json)
+
+ model_content, solver = get_model_content(request_json)
+
+ if solver == 'mzn':
+ return mzn_solve(request_json, model_content)
+ elif solver == 'py':
+ return py_solve(request_json, model_content)
+ raise BusinessException('Unsupported optimization solver requested {} '.format(solver))
+
+
+def get_model_content(request_json):
+ model_id = request_json['optimInfo'].get('modelId')
+ if model_id:
+ status, data = get_model_data(model_id)
+ if status == 200:
+ model_content = decode_data(data[1])
+ solver = data[3]
+ else:
+ raise BusinessException('model_id [{}] not found in the model database'.format(model_id))
+ else:
+ model_content = request_json['optimInfo']['modelContent']
+ solver = request_json['optimInfo']['solver']
+ return model_content, solver
diff --git a/runtime/solvers/__init__.py b/runtime/solvers/__init__.py
new file mode 100644
index 0000000..2aa67d8
--- /dev/null
+++ b/runtime/solvers/__init__.py
@@ -0,0 +1,17 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
diff --git a/runtime/solvers/mzn/__init__.py b/runtime/solvers/mzn/__init__.py
new file mode 100644
index 0000000..2aa67d8
--- /dev/null
+++ b/runtime/solvers/mzn/__init__.py
@@ -0,0 +1,17 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
diff --git a/runtime/solvers/mzn/mzn_solver.py b/runtime/solvers/mzn/mzn_solver.py
new file mode 100644
index 0000000..f3daa2b
--- /dev/null
+++ b/runtime/solvers/mzn/mzn_solver.py
@@ -0,0 +1,132 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from datetime import datetime
+import json
+
+from pymzn import cbc
+from pymzn import chuffed
+from pymzn import gecode
+from pymzn import minizinc
+from pymzn import or_tools
+from pymzn import Status
+
+from osdf.utils.file_utils import delete_file_folder
+
+error_status_map = {
+ Status.INCOMPLETE: "incomplete",
+ Status.COMPLETE: "complete",
+ Status.UNSATISFIABLE: "unsatisfiable",
+ Status.UNKNOWN: "unknown",
+ Status.UNBOUNDED: "unbounded",
+ Status.UNSATorUNBOUNDED: "unsat_or_unbounded",
+ Status.ERROR: "error"
+}
+
+solver_dict = {
+ 'cbc': cbc,
+ 'geocode': gecode,
+ 'chuffed': chuffed,
+ 'cp': chuffed,
+ 'or_tools': or_tools
+}
+
+
+def map_status(status):
+ return error_status_map.get(status, "failed")
+
+
+def solve(request_json, mzn_content):
+ """Given the request and minizinc content. Translates the json request to the format minizinc understands
+
+ return: returns the optimized solution.
+ """
+ req_info = request_json['requestInfo']
+ opt_info = request_json['optimInfo']
+ try:
+ mzn_solution = mzn_solver(mzn_content, opt_info)
+
+ response = {
+ 'transactionId': req_info['transactionId'],
+ 'requestID': req_info['requestID'],
+ 'requestStatus': 'done',
+ 'statusMessage': map_status(mzn_solution.status),
+ 'solutions': mzn_solution[0] if mzn_solution else {}
+ }
+ return 200, json.dumps(response)
+ except Exception as e:
+ response = {
+ 'transactionId': req_info['transactionId'],
+ 'requestID': req_info['requestID'],
+ 'requestStatus': 'failed',
+ 'statusMessage': 'Failed due to {}'.format(e)
+ }
+ return 400, json.dumps(response)
+
+
+def mzn_solver(mzn_content, opt_info):
+ """Calls the minizinc optimizer.
+
+ """
+ args = opt_info['solverArgs']
+ solver = get_mzn_solver(args.pop('solver'))
+ mzn_opts = dict()
+
+ try:
+ file_name = persist_opt_data(opt_info)
+ mzn_opts.update(args)
+ return minizinc(mzn_content, file_name, **mzn_opts, solver=solver)
+
+ finally:
+ delete_file_folder(file_name)
+
+
+def persist_opt_data(opt_info):
+ """Persist the opt data, if included as part of the request.
+
+ return: file_name path of the optim_data
+ returns None if no optData is part of the request
+ """
+ file_name = None
+ if 'optData' in opt_info:
+ if opt_info['optData'].get('json'):
+ data_content = json.dumps(opt_info['optData']['json'])
+ file_name = '/tmp/optim_engine_{}.json'.format(datetime.timestamp(datetime.now()))
+ persist_data(data_content, file_name)
+ elif opt_info['optData'].get('text'):
+ data_content = opt_info['optData']['text']
+ file_name = '/tmp/optim_engine_{}.dzn'.format(datetime.timestamp(datetime.now()))
+ persist_data(data_content, file_name)
+ return file_name
+
+
+def persist_data(data_content, file_name):
+ """Save the dzn data into a file
+
+ """
+ with open(file_name, "wt") as data:
+ data.write(data_content)
+
+
+def get_mzn_solver(solver):
+ """Returns a solver type object for minizinc optimizers
+
+ solver: solver that is part of the request
+ return: solver mapped object
+ """
+ return solver_dict.get(solver)
diff --git a/runtime/solvers/py/__init__.py b/runtime/solvers/py/__init__.py
new file mode 100644
index 0000000..a8aa582
--- /dev/null
+++ b/runtime/solvers/py/__init__.py
@@ -0,0 +1,17 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+# \ No newline at end of file
diff --git a/runtime/solvers/py/py_solver.py b/runtime/solvers/py/py_solver.py
new file mode 100644
index 0000000..6b200ab
--- /dev/null
+++ b/runtime/solvers/py/py_solver.py
@@ -0,0 +1,92 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import subprocess
+import traceback
+from datetime import datetime
+
+from osdf.logging.osdf_logging import error_log, debug_log
+from osdf.utils.file_utils import delete_file_folder
+
+
+def py_solver(py_content, opt_info):
+ py_file = '/tmp/custom_heuristics_{}.py'.format(datetime.timestamp(datetime.now()))
+ with open(py_file, "wt") as f:
+ f.write(py_content)
+ if opt_info['optData'].get('json'):
+ data_content = json.dumps(opt_info['optData']['json'])
+ input_file = '/tmp/optim_engine_{}.json'.format(datetime.timestamp(datetime.now()))
+ elif opt_info['optData'].get('text'):
+ data_content = opt_info['optData']['text']
+ input_file = '/tmp/optim_engine_{}.txt'.format(datetime.timestamp(datetime.now()))
+ with open(input_file, "wt") as f:
+ f.write(data_content)
+
+ output_file = '/tmp/opteng_output_{}.json'.format(datetime.timestamp(datetime.now()))
+
+ command = ['python', py_file, input_file, output_file]
+
+ try:
+ p = subprocess.run(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+
+ debug_log.debug('Process return code {}'.format(p.returncode))
+ if p.returncode > 0:
+ error_log.error('Process return code {} {}'.format(p.returncode, p.stdout))
+ return 'error', {}
+ with open(output_file) as file:
+ data = file.read()
+ return 'success', json.loads(data)
+
+ except Exception as e:
+ error_log.error("Error running optimizer {}".format(traceback.format_exc()))
+ return 'error', {}
+ finally:
+ cleanup((input_file, output_file, py_file))
+
+
+def cleanup(file_tup):
+ for f in file_tup:
+ try:
+ delete_file_folder(f)
+ except Exception as e:
+ error_log.error("Failed deleting the file {} - {}".format(f, traceback.format_exc()))
+
+
+def solve(request_json, py_content):
+ req_info = request_json['requestInfo']
+ opt_info = request_json['optimInfo']
+ try:
+ status, solution = py_solver(py_content, opt_info)
+
+ response = {
+ 'transactionId': req_info['transactionId'],
+ 'requestID': req_info['requestID'],
+ 'requestStatus': status,
+ 'statusMessage': "completed",
+ 'solutions': solution if solution else {}
+ }
+ return 200, json.dumps(response)
+ except Exception as e:
+ response = {
+ 'transactionId': req_info['transactionId'],
+ 'requestID': req_info['requestID'],
+ 'requestStatus': 'failed',
+ 'statusMessage': 'Failed due to {}'.format(e)
+ }
+ return 400, json.dumps(response)
diff --git a/script/TagVersion.groovy b/script/TagVersion.groovy
new file mode 100644
index 0000000..01bc840
--- /dev/null
+++ b/script/TagVersion.groovy
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP OSDF
+ * ================================================================================
+ * 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.osdf.maven.scripts
+
+println project.properties['osdf.project.version']
+
+def versionTag
+if ( project.properties['osdf.project.version'] != null ) {
+ versionArray = project.properties['osdf.project.version'].split('\\.|-');
+ versionTag = versionArray[0] + '.' + versionArray[1] + '.' + versionArray[2]
+ timestamp = project.properties['osdf.build.timestamp']
+}
+
+if ( project.properties['osdf.project.version'].endsWith("-SNAPSHOT") ) {
+ project.properties['project.docker.latesttag.version']=versionTag + "-SNAPSHOT-latest";
+ project.properties['project.docker.latesttagtimestamp.version']=versionTag + "-SNAPSHOT-"+timestamp;
+ project.properties['project.repo'] = 'snapshots'
+} else {
+ project.properties['project.docker.latesttag.version']=versionTag + "-STAGING-latest";
+ project.properties['project.docker.latesttagtimestamp.version']=versionTag + "-STAGING-"+timestamp;
+ project.properties['project.repo'] = 'releases'
+}
+
+println 'New Tag for docker: ' + project.properties['project.docker.latesttag.version']; \ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..1dffa77
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,53 @@
+# -*- encoding: utf-8 -*-
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+'''Setup'''
+
+import setuptools
+
+setuptools.setup(name='of-osdf',
+ version='1.0',
+ description='Python Distribution Utilities',
+ author='xyz',
+ author_email='xyz@wipro.com',
+ url='https://wiki.onap.org/display/DW/Optimization+Service+Design+Framework',
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Environment :: ONAP',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3'
+ 'Programming Language :: Python :: 3.5'
+ 'Topic :: Communications :: Email',
+ 'Topic :: Office/Business',
+ 'Topic :: Software Development :: Bug Tracking',],
+ keywords=['onap','osdf'],
+ packages=['osdf'],
+ entry_points = {
+ 'console_scripts': [
+ 'cipher-utility = osdf.cmd.encryptionUtil:main',
+ ],
+ 'oslo.config.opts': [
+ 'osdf = osdf.opts:list_opts',
+ ],
+ }
+ )
diff --git a/solverapp.py b/solverapp.py
new file mode 100644
index 0000000..a2df317
--- /dev/null
+++ b/solverapp.py
@@ -0,0 +1,82 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+from flask import request
+from markupsafe import Markup
+
+from osdf.apps.baseapp import app, run_app
+from osdf.logging.osdf_logging import audit_log
+from osdf.webapp.appcontroller import auth_basic
+from runtime.model_api import create_model_data, retrieve_model_data, retrieve_all_models, delete_model_data
+from runtime.models.api.model_request import OptimModelRequestAPI
+from runtime.optim_engine import process_request
+
+
+@app.route("/api/oof/optengine/v1", methods=["POST"])
+@auth_basic.login_required
+def opt_engine_rest_api():
+ """Perform OptimEngine optimization after validating the request
+ """
+ request_json = request.get_json()
+ return process_request(request_json)
+
+
+@app.route("/api/oof/optmodel/v1", methods=["PUT", "POST"])
+@auth_basic.login_required
+def opt_model_create_rest_api():
+ """Perform OptimEngine optimization after validating the request
+ """
+ request_json = request.get_json()
+ OptimModelRequestAPI(request_json).validate()
+ return create_model_data(request_json)
+
+
+@app.route("/api/oof/optmodel/v1/<model_id>", methods=["GET"])
+@auth_basic.login_required
+def opt_get_model_rest_api(model_id):
+ """Retrieve model data
+ """
+ model_id = Markup.escape(model_id)
+ return retrieve_model_data(model_id)
+
+
+@app.route("/api/oof/optmodel/v1", methods=["GET"])
+@auth_basic.login_required
+def opt_get_all_models_rest_api():
+ """Retrieve all models data
+ """
+ return retrieve_all_models()
+
+
+@app.route("/api/oof/optmodel/v1/<model_id>", methods=["DELETE"])
+@auth_basic.login_required
+def opt_delete_model_rest_api(model_id):
+ """Perform OptimEngine optimization after validating the request
+ """
+ return delete_model_data(model_id)
+
+
+@app.route("/api/oof/optengine/healthcheck/v1", methods=["GET"])
+def do_health_check():
+ """Simple health check"""
+ audit_log.info("A OptimEngine health check v1 request is processed!")
+ return "OK"
+
+
+if __name__ == "__main__":
+ run_app()
diff --git a/ssl_certs/oof.crt b/ssl_certs/oof.crt
deleted file mode 100644
index dc61a43..0000000
--- a/ssl_certs/oof.crt
+++ /dev/null
@@ -1,59 +0,0 @@
-Bag Attributes
- localKeyID: F5 64 7B F8 32 67 FD CE 81 5E 0D 13 36 B7 67 35 47 33 B8 9B
- friendlyName: oof@oof.onap.org
-subject=/C=US/O=ONAP/OU=oof@oof.onap.org/OU=OSAAF/CN=oof.api.simpledemo.onap.org
-issuer=/C=US/O=ONAP/OU=OSAAF/CN=intermediateCA_1
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIBHjANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEN
-MAsGA1UECgwET05BUDEOMAwGA1UECwwFT1NBQUYxGTAXBgNVBAMMEGludGVybWVk
-aWF0ZUNBXzEwHhcNMTgwNDI1MTIxMzAxWhcNMTkwNDIwMTIxMzAxWjBtMQswCQYD
-VQQGEwJVUzENMAsGA1UECgwET05BUDEZMBcGA1UECwwQb29mQG9vZi5vbmFwLm9y
-ZzEOMAwGA1UECwwFT1NBQUYxJDAiBgNVBAMMG29vZi5hcGkuc2ltcGxlZGVtby5v
-bmFwLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGpQUtgLXG3
-dVikd/QC2Q24wzeTOeZzbx3PnidNYZT5K0sJ/TdnZF6O/4+9gXQ6AQS2Q8wfQ009
-MQAA5vhUaq5yZ2K+XAtEFGln1TxTFpGu3WDOwQ800Vw18Dk8WidrkzDJv489Bn1f
-SSaPC0IaRB0K1d8BD63ZHgsuEY8lt31DX2wFWJcfN9mxNDzuLTZoLxtxKsedoZKH
-rsOOILwXOhwuunfx40i6RQN/pFX6C2i8dtOA5OwUm9Q1RrZ2Tv1Uf4IURriH6bfZ
-5n50yxTuL22TMYXsF/ohrdgwacuC0aV9ZSGhIZUJPyHVg7+QTBioHmoUJInVKuIx
-kkC4lENbLYUCAwEAAaOB+jCB9zAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG
-wDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRp
-ZmljYXRlMB0GA1UdDgQWBBQwbU5oHU2iYHCoVz4hFCvBW59cdTBUBgNVHSMETTBL
-gBQd5lldG54KOKRipsGF8/PP1vGX6qEwpC4wLDEOMAwGA1UECwwFT1NBQUYxDTAL
-BgNVBAoMBE9OQVAxCzAJBgNVBAYTAlVTggEBMA4GA1UdDwEB/wQEAwIF4DAdBgNV
-HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBADEa
-0VuxoFIygeQTqlizpHNwfApPmlAVSKDTWuEu4rhJs8GT61EuWZQPygXEUHCYmGvJ
-GMwEGGIDGiQqxMqlqng46gksNJbi1ktXr6Du18qW7gziUd84ve8KcecjZru1Sk1e
-UJ/6WEQVE17CHKcnzQZsMDakgP+61VgKbk5NlkeF/Qh4L6/3jY7g+xoXqaId5RT9
-BetmH/cMsj33lxQTs0fcXTbAQd6BX5ug854OJ1mU4ngJnNBdmn9Ow1bB71ohf5Xv
-OEYX8+khjgjlmM0u1hBRL4qViv3y2Gzhpm1M8cETMDj4g0zIJytzIYMxO8XvDPCF
-YmVZHXJDLsCogSOmmh0=
------END CERTIFICATE-----
-Bag Attributes: <No Attributes>
-subject=/C=US/O=ONAP/OU=OSAAF/CN=intermediateCA_1
-issuer=/OU=OSAAF/O=ONAP/C=US
------BEGIN CERTIFICATE-----
-MIIEVDCCAjygAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMQ4wDAYDVQQLDAVPU0FB
-RjENMAsGA1UECgwET05BUDELMAkGA1UEBhMCVVMwHhcNMTgwNDA1MTQxNTQwWhcN
-MTgwNjA0MTQxNTQwWjBHMQswCQYDVQQGEwJVUzENMAsGA1UECgwET05BUDEOMAwG
-A1UECwwFT1NBQUYxGTAXBgNVBAMMEGludGVybWVkaWF0ZUNBXzEwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCY3YPA/YQdz4kaZQzdRzWNjmn33WYAWZ8+
-EIz3PhkEzk7M1q9N7Icx2LvozMj4VH0yGz/HYlliHhw26ZRsjYMSR8zATsXl4oW9
-w9BrjuyvM3w8Ptxe8WbUFF9LJDGyXPeVvcXVo0iyh3QYPWC/AWmomN19MvBFN5vH
-AvEG/7qtonViNfISW9Gr9LpXB0foCmUDBu/lV+SwRGajoCPqdZhZ6/L6/yqDvha2
-wsML/UZXlGhXAedt/xOKmT/dSXx/I0vWBVp6Tq4zu87yCvd+I6Tpa5HjttA2I5EV
-zdHX+JYBPBBcVCyO9YQOYjJuoVDE4D5etY6dEipKG/KZF/rqAoqZAgMBAAGjZjBk
-MB0GA1UdDgQWBBQd5lldG54KOKRipsGF8/PP1vGX6jAfBgNVHSMEGDAWgBRTVTPy
-S+vQUbHBeJrBKDF77+rtSTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAmgeiitBDi/YEqFh2Cqp0VIEqw8hiuV87
-rADQWMK4hv5WXl3KJTjFAnWsYFUKrm6s1jNH16FyGExUQgwggob0Vt+MHiUs36jU
-kyret/uE5qrjz+/J+i2XG6s1oKcDRVD/jU4qBygZWFBMuwl7sz8IEvaYXGM43s96
-Du3UF9E+V3aMppqkGWz6MnrTmANnWAlDAMeifcoexjrpxiKbp8f49HX1UzwFoeEg
-RnVwNqgDWT66yGV6mbNl6FpE/U81RpCRY1ZJDeVTxbqIaG/UPV4hpQ+BEVBDF+cb
-rGsvsNYYpWx5srIQ7WtGKIlaDFbfWPwnHDHegzr8ypAS3KNWULE+QXCbHWtB+b0Y
-WhP/2F6Jjb+ByvJqQoE+nHEYBeUOZUUZC4IuQFNJ5Wy5P0CNXdheiWhdrBmG02Gy
-KMi0FJx6BEoWM2xcdl6bn5j9mhF4TX7zgepNWlgTra4Z8Oz8iqbQk33/s2OKM4ic
-6ZezUYhNp+MuUt4Se+ufNcGV65jnUKeROtWzNLwP+xwglEFlG8aNiAORthd7QJuT
-Ey2cX7H7f38ENQ5YCriUk1nVLO9F66l/rNRzYZgQzRI3IvDW8vyM2TLW2mcZNsaf
-qjFMcCDweV2FRb8eTbmWzzB2/xTVpGzVJqzwgE+U7UtJx5CZS3wPkvXuEgvcg1tY
-m1r4NGYFvLM=
------END CERTIFICATE-----
diff --git a/ssl_certs/oof.crt.pem b/ssl_certs/oof.crt.pem
deleted file mode 100644
index 4c6eb91..0000000
--- a/ssl_certs/oof.crt.pem
+++ /dev/null
@@ -1,25 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIBHjANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJVUzEN
-MAsGA1UECgwET05BUDEOMAwGA1UECwwFT1NBQUYxGTAXBgNVBAMMEGludGVybWVk
-aWF0ZUNBXzEwHhcNMTgwNDI1MTIxMzAxWhcNMTkwNDIwMTIxMzAxWjBtMQswCQYD
-VQQGEwJVUzENMAsGA1UECgwET05BUDEZMBcGA1UECwwQb29mQG9vZi5vbmFwLm9y
-ZzEOMAwGA1UECwwFT1NBQUYxJDAiBgNVBAMMG29vZi5hcGkuc2ltcGxlZGVtby5v
-bmFwLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGpQUtgLXG3
-dVikd/QC2Q24wzeTOeZzbx3PnidNYZT5K0sJ/TdnZF6O/4+9gXQ6AQS2Q8wfQ009
-MQAA5vhUaq5yZ2K+XAtEFGln1TxTFpGu3WDOwQ800Vw18Dk8WidrkzDJv489Bn1f
-SSaPC0IaRB0K1d8BD63ZHgsuEY8lt31DX2wFWJcfN9mxNDzuLTZoLxtxKsedoZKH
-rsOOILwXOhwuunfx40i6RQN/pFX6C2i8dtOA5OwUm9Q1RrZ2Tv1Uf4IURriH6bfZ
-5n50yxTuL22TMYXsF/ohrdgwacuC0aV9ZSGhIZUJPyHVg7+QTBioHmoUJInVKuIx
-kkC4lENbLYUCAwEAAaOB+jCB9zAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG
-wDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRp
-ZmljYXRlMB0GA1UdDgQWBBQwbU5oHU2iYHCoVz4hFCvBW59cdTBUBgNVHSMETTBL
-gBQd5lldG54KOKRipsGF8/PP1vGX6qEwpC4wLDEOMAwGA1UECwwFT1NBQUYxDTAL
-BgNVBAoMBE9OQVAxCzAJBgNVBAYTAlVTggEBMA4GA1UdDwEB/wQEAwIF4DAdBgNV
-HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBADEa
-0VuxoFIygeQTqlizpHNwfApPmlAVSKDTWuEu4rhJs8GT61EuWZQPygXEUHCYmGvJ
-GMwEGGIDGiQqxMqlqng46gksNJbi1ktXr6Du18qW7gziUd84ve8KcecjZru1Sk1e
-UJ/6WEQVE17CHKcnzQZsMDakgP+61VgKbk5NlkeF/Qh4L6/3jY7g+xoXqaId5RT9
-BetmH/cMsj33lxQTs0fcXTbAQd6BX5ug854OJ1mU4ngJnNBdmn9Ow1bB71ohf5Xv
-OEYX8+khjgjlmM0u1hBRL4qViv3y2Gzhpm1M8cETMDj4g0zIJytzIYMxO8XvDPCF
-YmVZHXJDLsCogSOmmh0=
------END CERTIFICATE----- \ No newline at end of file
diff --git a/ssl_certs/oof_new.key b/ssl_certs/oof_new.key
deleted file mode 100644
index b3208c1..0000000
--- a/ssl_certs/oof_new.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA0alBS2Atcbd1WKR39ALZDbjDN5M55nNvHc+eJ01hlPkrSwn9
-N2dkXo7/j72BdDoBBLZDzB9DTT0xAADm+FRqrnJnYr5cC0QUaWfVPFMWka7dYM7B
-DzTRXDXwOTxaJ2uTMMm/jz0GfV9JJo8LQhpEHQrV3wEPrdkeCy4RjyW3fUNfbAVY
-lx832bE0PO4tNmgvG3Eqx52hkoeuw44gvBc6HC66d/HjSLpFA3+kVfoLaLx204Dk
-7BSb1DVGtnZO/VR/ghRGuIfpt9nmfnTLFO4vbZMxhewX+iGt2DBpy4LRpX1lIaEh
-lQk/IdWDv5BMGKgeahQkidUq4jGSQLiUQ1sthQIDAQABAoIBAHeHah1B6MajE/iE
-U4q+sOYcxtcBTYovl1LEkeLQP+jBoUf3mvAiNtud5N8a6BnOE9SO4NoXnLQFRdE9
-snAzGFr6CC0IX8tgdc6eDriEmiJWMgnF9dTohM9wRNMssC03LEQtUNOls/R4BWlB
-NebquJhiHAo2Pa0cUf+HtSUKGLEFVqyGyf/psqw+y38VP5ZVv5BvlPGRsSyExbwD
-uZ7QNC5szL7k1kqsiQ0nRxHBZxTI9gBQr2LKM8TY4TAmFr2JIoFDr9BDZ5GANzGR
-aglyQWERRuNhGDkS9Okn/vfxjhUcuaNciULUyIMt0RT3IlgmgWyWqk75xueaCiMr
-kpFWRWECgYEA72WwP+rqv6gM88kD+zBKcyianW6TYSN6TDBpzX4StcPr32KYqvXW
-CXgUUjfZQduyNrfxxI7C/6fGWT6oj3G7I3dI+GXMQ6TYWUIos0uhL4SBPZa04hKf
-Y3P6PBFGOqv301/mwS5MI2sMOBrpJH/hig0ExXrzM2EAQi7V6adji5kCgYEA4DOg
-NTuLaB0FinHzPCySiujjcAWBsvjhpF+C3g3RMOFC0EKCy3snPnxyLYQENcIueE9r
-9y68pnpqNqFWOJqLINc727cU2+becFfpinGQEnZuC/48FbiDDR2uTv/vd4OT8+ng
-tuNGXbBz/XP9nvjS5t06MDOrOrseBSpo3ZfmBM0CgYEAxQCOgJrl4R/+wKL75rp/
-mbKhQcqb94UFgCsa9iK4bOG0ehid/5ncL+CkAGC7JWoQhtzqVNESgOXk4M4iUiDK
-Wk4wO1EyPbwq2ZELAzjKhNrqq+8YHS4sAeCP3NxuSZv4jfZOY0yhFUhjPsxObV3b
-EQrTkVszRWWem9gE6ol37okCgYEAhEeRb7b5Em2FFmES/N7je1fa0P4+vuS+5OeB
-ZBhM44UUkaGcYAgCaIiuKRKqFTnDhzJ85fNKVQMG5cKdB3qPOcojxAeqI/B8L1Z/
-MTK9qVb8qNDQjJQ3piZr8KpqlF4qjg/giKdhned9F/42lnQCoznFmijyDw3VsYCL
-LKrxiMUCgYAvq51mzXuGRGEJp8QmVBJGfSwIlqB9F5zdkVfWADP6X99MSH0PGpvU
-SJOYO9gQJA31v3AECLUXYjYFlEX4PcAhMCwVONm2AAok0EXIc1UgJrpNkdRIjhJW
-81NkKznllRF7LownV1zoOl9CcIn8u9XoRd1OjRTzU8QTZ1QfLkexoQ==
------END RSA PRIVATE KEY-----
diff --git a/test/adapters/dcae/des_response.json b/test/adapters/dcae/des_response.json
new file mode 100644
index 0000000..c8595eb
--- /dev/null
+++ b/test/adapters/dcae/des_response.json
@@ -0,0 +1,47 @@
+{
+ "result": [
+ {
+ "additionalMeasurements": [
+ {
+ "hashMap":{
+ "networkId":"plmnid1",
+ "InterEnbOutAtt_X2HO":"300",
+ "InterEnbOutSucc_X2HO":"290"
+ },
+ "name":"Chn0004"
+ },
+ {
+ "hashMap":{
+ "InterEnbOutAtt_X2HO":"250",
+ "InterEnbOutSucc_X2HO":"170"
+ },
+ "name":"Chn0001"
+ }
+ ]
+ },
+ {
+ "additionalMeasurements": [
+ {
+ "hashMap":{
+ "networkId":"plmnid1",
+ "InterEnbOutAtt_X2HO":"300",
+ "InterEnbOutSucc_X2HO":"290"
+ },
+ "name":"Chn0004"
+ },
+ {
+ "hashMap":{
+ "InterEnbOutAtt_X2HO":"250",
+ "InterEnbOutSucc_X2HO":"170"
+ },
+ "name":"Chn0001"
+ }
+ ]
+ }
+ ],
+ "request": {
+ "cell_id": "Chn0002",
+ "interval": 2
+ },
+ "result_count": 2
+} \ No newline at end of file
diff --git a/test/adapters/dcae/test_des.py b/test/adapters/dcae/test_des.py
new file mode 100644
index 0000000..6e2520a
--- /dev/null
+++ b/test/adapters/dcae/test_des.py
@@ -0,0 +1,71 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import mock
+from mock import patch
+from requests import RequestException
+from requests.exceptions import HTTPError
+import unittest
+from osdf.adapters.dcae import des
+from osdf.adapters.dcae.des import DESException
+import osdf.config.loader as config_loader
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+
+
+class TestDes(unittest.TestCase):
+
+ def setUp(self):
+ self.config_spec = {
+ "deployment": "config/osdf_config.yaml",
+ "core": "config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ def tearDown(self):
+ pass
+
+ def test_extract_data(self):
+ response_file = 'test/adapters/dcae/des_response.json'
+ response_json = json_from_file(response_file)
+
+ des_config = self.osdf_config.core['PCI']['DES']
+ service_id = des_config['service_id']
+ data = des_config['filter']
+ expected = response_json['result']
+ response = mock.MagicMock()
+ response.status_code = 200
+ response.ok = True
+ response.json.return_value = response_json
+ self.patcher_req = patch('requests.request', return_value=response)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEqual(expected, des.extract_data(service_id, data))
+ self.patcher_req.stop()
+
+ response = mock.MagicMock()
+ response.status_code = 404
+ response.raise_for_status.side_effect = HTTPError("404")
+ self.patcher_req = patch('requests.request', return_value=response)
+ self.Mock_req = self.patcher_req.start()
+ self.assertRaises(DESException, des.extract_data, service_id, data)
+ self.patcher_req.stop()
+
+ self.patcher_req = patch('requests.request', side_effect=RequestException("error"))
+ self.Mock_req = self.patcher_req.start()
+ self.assertRaises(DESException, des.extract_data, service_id, data)
+ self.patcher_req.stop()
diff --git a/test/apps/nxi_termination/_init_.py b/test/apps/nxi_termination/_init_.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/apps/nxi_termination/_init_.py
diff --git a/test/apps/nxi_termination/aai_exception_response.json b/test/apps/nxi_termination/aai_exception_response.json
new file mode 100644
index 0000000..56f61df
--- /dev/null
+++ b/test/apps/nxi_termination/aai_exception_response.json
@@ -0,0 +1,4 @@
+{
+ "status-code": 404,
+ "status-response": "NOT FOUND"
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/aai_response.json b/test/apps/nxi_termination/aai_response.json
new file mode 100644
index 0000000..b7ef43b
--- /dev/null
+++ b/test/apps/nxi_termination/aai_response.json
@@ -0,0 +1,64 @@
+{"service-instance": [{
+ "service-instance-id": "1a636c4d-5e76-427e-bfd6-241a947224b0",
+ "service-instance-name": "nssi_test_0211",
+ "service-type": "embb",
+ "service-role": "nssi",
+ "environment-context": "cn",
+ "model-invariant-id": "21d57d4b-52ad-4d3c-a798-248b5bb9124a",
+ "model-version-id": "bfba363e-e39c-4bd9-a9d5-1371c28f4d22",
+ "resource-version": "1581418601616",
+ "orchestration-status": "active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "service-instance",
+ "relationship-label": "org.onap.relationships.inventory.ComposedOf",
+ "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b518"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "service-instance.service-instance-name",
+ "property-value": "nsi_test_0211"
+ }
+ ]
+ }
+ ]
+ },
+ "slice-profiles": {
+ "slice-profile": [
+ {
+ "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299",
+ "latency": 20,
+ "max-number-of-UEs": 0,
+ "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "ue-mobility-level": "stationary",
+ "resource-sharing-level": "0",
+ "exp-data-rate-UL": 100,
+ "exp-data-rate-DL": 100,
+ "activity-factor": 0,
+ "e2e-latency": 0,
+ "jitter": 0,
+ "survival-time": 0,
+ "exp-data-rate": 0,
+ "payload-size": 0,
+ "traffic-density": 0,
+ "conn-density": 0,
+ "reliability": 99.999,
+ "resource-version": "1581418602494"
+ }
+ ]
+ }
+}]}
diff --git a/test/apps/nxi_termination/exception_response1.json b/test/apps/nxi_termination/exception_response1.json
new file mode 100644
index 0000000..cde603f
--- /dev/null
+++ b/test/apps/nxi_termination/exception_response1.json
@@ -0,0 +1,7 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "failure",
+ "reason": "Error response recieved from AAI for the request"
+
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/failure_relationship_list.json b/test/apps/nxi_termination/failure_relationship_list.json
new file mode 100644
index 0000000..392f4db
--- /dev/null
+++ b/test/apps/nxi_termination/failure_relationship_list.json
@@ -0,0 +1,66 @@
+[
+ {
+ "related-to": "allotted-resource",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "related-link": "/aai/v23/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/d88b6ce6-19be-439d-8553-4f9d6cce0494/allotted-resources/allotted-resource/07138106-f535-413b-b002-40ba24f95937",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "07138106-f535-413b-b002-40ba24f95937"
+ },
+ {
+ "relationship-key": "allotted-resource.id",
+ "relationship-value": "07138106-f535-413b-b002-40ba24f95937"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "allotted-resource.description"
+ },
+ {
+ "property-key": "allotted-resource.allotted-resource-name",
+ "property-value": "Allotted_coe"
+ }
+ ]
+ },
+ {
+ "related-to": "allotted-resource",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "related-link": "/aai/v23/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/d88b6ce6-19be-439d-8553-4f9d6cce0494/allotted-resources/allotted-resource/07138106-f535-413b-b002-40ba24f95937",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ },
+ {
+ "relationship-key": "allotted-resource.id",
+ "relationship-value": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "allotted-resource.description"
+ },
+ {
+ "property-key": "allotted-resource.allotted-resource-name",
+ "property-value": "Allotted_terminate"
+ }
+ ]
+ }
+] \ No newline at end of file
diff --git a/test/apps/nxi_termination/failure_relationship_list2.json b/test/apps/nxi_termination/failure_relationship_list2.json
new file mode 100644
index 0000000..624448a
--- /dev/null
+++ b/test/apps/nxi_termination/failure_relationship_list2.json
@@ -0,0 +1,52 @@
+[
+ {
+ "related-to": "service-instance",
+ "relationship-label": "org.onap.relationships.inventory.ComposedOf",
+ "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b567"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "service-instance.service-instance-name",
+ "property-value": "nsi_test_0211"
+ }
+ ]
+ },
+ {
+ "related-to": "service-instance",
+ "relationship-label": "org.onap.relationships.inventory.ComposedOf",
+ "related-link": "/aai/v16/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/4115d3c8-dd59-45d6-b09d-e756dee9b518",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "4115d3c8-dd59-45d6-b09d-e756dee9b567"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "service-instance.service-instance-name",
+ "property-value": "nsi_test_0211"
+ }
+ ]
+ }
+ ] \ No newline at end of file
diff --git a/test/apps/nxi_termination/failure_service_profiles.json b/test/apps/nxi_termination/failure_service_profiles.json
new file mode 100644
index 0000000..d10a818
--- /dev/null
+++ b/test/apps/nxi_termination/failure_service_profiles.json
@@ -0,0 +1,24 @@
+[
+ {
+ "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c29",
+ "latency": 20,
+ "max-number-of-UEs": 0,
+ "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "ue-mobility-level": "stationary",
+ "resource-sharing-level": "0",
+ "exp-data-rate-UL": 100,
+ "exp-data-rate-DL": 100,
+ "activity-factor": 0,
+ "e2e-latency": 0,
+ "jitter": 0,
+ "survival-time": 0,
+ "exp-data-rate": 0,
+ "payload-size": 0,
+ "traffic-density": 0,
+ "conn-density": 0,
+ "reliability": 99.999,
+ "resource-version": "1581418602494"
+ }
+]
+
+
diff --git a/test/apps/nxi_termination/failure_service_profiles2.json b/test/apps/nxi_termination/failure_service_profiles2.json
new file mode 100644
index 0000000..1740758
--- /dev/null
+++ b/test/apps/nxi_termination/failure_service_profiles2.json
@@ -0,0 +1,42 @@
+[
+ {
+ "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299",
+ "latency": 20,
+ "max-number-of-UEs": 0,
+ "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "ue-mobility-level": "stationary",
+ "resource-sharing-level": "0",
+ "exp-data-rate-UL": 100,
+ "exp-data-rate-DL": 100,
+ "activity-factor": 0,
+ "e2e-latency": 0,
+ "jitter": 0,
+ "survival-time": 0,
+ "exp-data-rate": 0,
+ "payload-size": 0,
+ "traffic-density": 0,
+ "conn-density": 0,
+ "reliability": 99.999,
+ "resource-version": "1581418602494"
+ },
+ {
+ "profile-id": "abcd9f49-4201-4e3a-aac1-b0f27902c299",
+ "latency": 20,
+ "max-number-of-UEs": 0,
+ "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "ue-mobility-level": "stationary",
+ "resource-sharing-level": "0",
+ "exp-data-rate-UL": 100,
+ "exp-data-rate-DL": 100,
+ "activity-factor": 0,
+ "e2e-latency": 0,
+ "jitter": 0,
+ "survival-time": 0,
+ "exp-data-rate": 0,
+ "payload-size": 0,
+ "traffic-density": 0,
+ "conn-density": 0,
+ "reliability": 99.999,
+ "resource-version": "1581418602494"
+ }
+]
diff --git a/test/apps/nxi_termination/invalid_request.json b/test/apps/nxi_termination/invalid_request.json
new file mode 100644
index 0000000..72eafd7
--- /dev/null
+++ b/test/apps/nxi_termination/invalid_request.json
@@ -0,0 +1,17 @@
+{
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5,
+ "addtnlArgs": {
+ "serviceInstanceId":"cdad9f49-4201-4e3a-aac1-b0f27902c299"
+ }
+ },
+ "type":"NST",
+ "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851"
+
+}
diff --git a/test/apps/nxi_termination/nsi_success_output.json b/test/apps/nxi_termination/nsi_success_output.json
new file mode 100644
index 0000000..e25a272
--- /dev/null
+++ b/test/apps/nxi_termination/nsi_success_output.json
@@ -0,0 +1,7 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "success",
+ "terminateResponse": true,
+ "reason": ""
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/nssi_failure_output.json b/test/apps/nxi_termination/nssi_failure_output.json
new file mode 100644
index 0000000..f300c53
--- /dev/null
+++ b/test/apps/nxi_termination/nssi_failure_output.json
@@ -0,0 +1,8 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "success",
+ "terminateResponse": false,
+ "reason": ""
+
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/nssi_termination.json b/test/apps/nxi_termination/nssi_termination.json
new file mode 100644
index 0000000..b4e3711
--- /dev/null
+++ b/test/apps/nxi_termination/nssi_termination.json
@@ -0,0 +1,17 @@
+{
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5,
+ "addtnlArgs": {
+ "serviceInstanceId":"4115d3c8-dd59-45d6-b09d-e756dee9b518"
+ }
+ },
+ "type":"NSSI",
+ "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851"
+
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/nxi_failure_output1.json b/test/apps/nxi_termination/nxi_failure_output1.json
new file mode 100644
index 0000000..4cce5eb
--- /dev/null
+++ b/test/apps/nxi_termination/nxi_failure_output1.json
@@ -0,0 +1,10 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "success",
+ "terminateResponse": false,
+ "reason": ""
+
+}
+
+
diff --git a/test/apps/nxi_termination/nxi_failure_output2.json b/test/apps/nxi_termination/nxi_failure_output2.json
new file mode 100644
index 0000000..f18b73c
--- /dev/null
+++ b/test/apps/nxi_termination/nxi_failure_output2.json
@@ -0,0 +1,7 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "success",
+ "terminateResponse": false,
+ "reason": ""
+} \ No newline at end of file
diff --git a/test/apps/nxi_termination/nxi_termination.json b/test/apps/nxi_termination/nxi_termination.json
new file mode 100644
index 0000000..1e25f2e
--- /dev/null
+++ b/test/apps/nxi_termination/nxi_termination.json
@@ -0,0 +1,17 @@
+{
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5,
+ "addtnlArgs": {
+ "serviceInstanceId":"cdad9f49-4201-4e3a-aac1-b0f27902c299"
+ }
+ },
+ "type":"NSI",
+ "NxIId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "UUID":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "invariantUUID":"d290f1ee-6c54-4b01-90e6-d701748f0851"
+
+}
diff --git a/test/apps/nxi_termination/service_profiles.json b/test/apps/nxi_termination/service_profiles.json
new file mode 100644
index 0000000..899acb4
--- /dev/null
+++ b/test/apps/nxi_termination/service_profiles.json
@@ -0,0 +1,23 @@
+[
+ {
+ "profile-id": "cdad9f49-4201-4e3a-aac1-b0f27902c299",
+ "latency": 20,
+ "max-number-of-UEs": 0,
+ "coverage-area-TA-list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "ue-mobility-level": "stationary",
+ "resource-sharing-level": "0",
+ "exp-data-rate-UL": 100,
+ "exp-data-rate-DL": 100,
+ "activity-factor": 0,
+ "e2e-latency": 0,
+ "jitter": 0,
+ "survival-time": 0,
+ "exp-data-rate": 0,
+ "payload-size": 0,
+ "traffic-density": 0,
+ "conn-density": 0,
+ "reliability": 99.999,
+ "resource-version": "1581418602494"
+ }
+]
+
diff --git a/test/apps/nxi_termination/success_relationship_list.json b/test/apps/nxi_termination/success_relationship_list.json
new file mode 100644
index 0000000..608418d
--- /dev/null
+++ b/test/apps/nxi_termination/success_relationship_list.json
@@ -0,0 +1,34 @@
+[
+ {
+ "related-to": "allotted-resource",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "related-link": "/aai/v23/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/d88b6ce6-19be-439d-8553-4f9d6cce0494/allotted-resources/allotted-resource/07138106-f535-413b-b002-40ba24f95937",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "cdad9f49-4201-4e3a-aac1-b0f27902c299"
+ },
+ {
+ "relationship-key": "allotted-resource.id",
+ "relationship-value": "07138106-f535-413b-b002-40ba24f95937"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "allotted-resource.description"
+ },
+ {
+ "property-key": "allotted-resource.allotted-resource-name",
+ "property-value": "Allotted_coe"
+ }
+ ]
+ }
+] \ No newline at end of file
diff --git a/test/apps/nxi_termination/test_fetch_aai_data.py b/test/apps/nxi_termination/test_fetch_aai_data.py
new file mode 100644
index 0000000..241b24b
--- /dev/null
+++ b/test/apps/nxi_termination/test_fetch_aai_data.py
@@ -0,0 +1,70 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import unittest
+import mock
+from unittest.mock import patch
+from osdf.config.base import osdf_config
+import osdf.config.loader as config_loader
+from osdf.utils.programming_utils import DotDict
+from osdf.utils.interfaces import json_from_file
+from osdf.adapters.aai.fetch_aai_data import get_aai_data,AAIException
+
+class TestRemoteOptProcessor(unittest.TestCase):
+ def setUp(self):
+ self.config_spec = {
+ "deployment": "config/osdf_config.yaml",
+ "core": "config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ def tearDown(self):
+
+ patch.stopall()
+
+
+ def test_get_aai_data(self):
+ main_dir = ""
+ response_file = main_dir + 'test/apps/nxi_termination/aai_response.json'
+ exception_response_file = main_dir + 'test/apps/nxi_termination/aai_exception_response.json'
+ request_file = main_dir + 'test/apps/nxi_termination/nxi_termination.json'
+ response_json = json_from_file(response_file)
+ request_json = json_from_file(request_file)
+ exception_json = json_from_file(exception_response_file)
+ response = mock.MagicMock()
+ response.status_code = 200
+ response.ok = True
+ response.json.return_value = response_json
+ self.patcher_req = patch('requests.get',
+ return_value = response)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(response_json, get_aai_data(request_json,osdf_config))
+ self.patcher_req.stop()
+
+ responsenew=mock.MagicMock()
+ responsenew.status_code=404
+ responsenew.json.return_value = exception_json
+ self.patcher_req = patch('requests.get',
+ return_value=responsenew)
+ self.Mock_req = self.patcher_req.start()
+ self.assertRaises( AAIException,get_aai_data,request_json,osdf_config)
+ self.patcher_req.stop()
+
+
+if __name__ == "__main__":
+ unittest.main() \ No newline at end of file
diff --git a/test/apps/nxi_termination/test_remote_opt_processor_termination.py b/test/apps/nxi_termination/test_remote_opt_processor_termination.py
new file mode 100644
index 0000000..555f2e8
--- /dev/null
+++ b/test/apps/nxi_termination/test_remote_opt_processor_termination.py
@@ -0,0 +1,136 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import unittest
+from unittest.mock import patch
+import osdf.config.loader as config_loader
+import pytest
+from apps.nxi_termination.optimizers.remote_opt_processor import process_nxi_termination_opt
+from osdf.adapters.aai.fetch_aai_data import AAIException
+
+from osdf.config.base import osdf_config
+from osdf.utils.programming_utils import DotDict
+from osdf.utils.interfaces import json_from_file
+
+class TestRemoteOptProcessor(unittest.TestCase):
+ def setUp(self):
+ self.config_spec = {
+ "deployment": "config/osdf_config.yaml",
+ "core": "config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ def tearDown(self):
+
+ patch.stopall()
+
+ def test_process_nxi_termination_opt(self):
+ main_dir = ""
+ request_file = main_dir + 'test/apps/nxi_termination/nxi_termination.json'
+ nssi_request_file=main_dir + 'test/apps/nxi_termination/nssi_termination.json'
+ service_file = main_dir + 'test/apps/nxi_termination/service_profiles.json'
+ failure_service_file = main_dir + 'test/apps/nxi_termination/failure_service_profiles.json'
+ failure_service_file2 = main_dir + 'test/apps/nxi_termination/failure_service_profiles2.json'
+ nsi_success=main_dir + 'test/apps/nxi_termination/nsi_success_output.json'
+ nxi_failure1 = main_dir + 'test/apps/nxi_termination/nxi_failure_output1.json'
+ nxi_failure2 = main_dir + 'test/apps/nxi_termination/nxi_failure_output2.json'
+ nssi_failure = main_dir + 'test/apps/nxi_termination/nssi_failure_output.json'
+ success_rel_file = main_dir + 'test/apps/nxi_termination/success_relationship_list.json'
+ failure_rel_file1 = main_dir + 'test/apps/nxi_termination/failure_relationship_list.json'
+ failure_rel_file2 = main_dir + 'test/apps/nxi_termination/failure_relationship_list2.json'
+ exception_response_file1 = main_dir + 'test/apps/nxi_termination/exception_response1.json'
+ request_json=json_from_file(request_file)
+ nssi_request_json = json_from_file(nssi_request_file)
+ service_profile_json = json_from_file(service_file)
+ failure_service_profile_json = json_from_file(failure_service_file)
+ failure_service_profile_json2 = json_from_file(failure_service_file2)
+ success_rel_json=json_from_file(success_rel_file)
+ failure_rel_json = json_from_file(failure_rel_file1)
+ failure_rel_json2 = json_from_file(failure_rel_file2)
+ success_output_json=json_from_file(nsi_success)
+ nxi_failure_output_json1 = json_from_file(nxi_failure1)
+ nxi_failure_output_json2 = json_from_file(nxi_failure2)
+ nssi_failure_output_json = json_from_file(nssi_failure)
+ exception_response_json1 = json_from_file(exception_response_file1)
+
+ #nsi success scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_allotted_resources', return_value=success_rel_json)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(success_output_json, process_nxi_termination_opt(request_json, osdf_config))
+ self.patcher_req.stop()
+
+ #nsi failure scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_allotted_resources', return_value=failure_rel_json)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(nxi_failure_output_json1, process_nxi_termination_opt(request_json, osdf_config))
+ self.patcher_req.stop()
+
+ request_json["requestInfo"]["addtnlArgs"] = {}
+
+ #nsi success scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_allotted_resources',
+ return_value=[])
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(success_output_json, process_nxi_termination_opt(request_json, osdf_config))
+ self.patcher_req.stop()
+
+ # #
+ # nssi success scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count', return_value=1)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(success_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config))
+ self.patcher_req.stop()
+
+ # nssi failure scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count',
+ return_value=2)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(nssi_failure_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config))
+ self.patcher_req.stop()
+
+ nssi_request_json["requestInfo"]["addtnlArgs"] = {}
+
+ # nssi success scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count',
+ return_value=0)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(success_output_json, process_nxi_termination_opt(nssi_request_json, osdf_config))
+ self.patcher_req.stop()
+
+ # nssi failure scenario
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count',
+ return_value=1)
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals(nxi_failure_output_json2, process_nxi_termination_opt(nssi_request_json, osdf_config))
+ self.patcher_req.stop()
+
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count',
+ side_effect=AAIException("Error response recieved from AAI for the request"))
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals("failure", process_nxi_termination_opt(nssi_request_json, osdf_config).get('requestStatus'))
+ self.patcher_req.stop()
+
+ self.patcher_req = patch('apps.nxi_termination.optimizers.remote_opt_processor.get_resource_count',
+ side_effect=AAIException("Request exception was encountered"))
+ self.Mock_req = self.patcher_req.start()
+ self.assertEquals("failure", process_nxi_termination_opt(nssi_request_json, osdf_config).get('requestStatus'))
+ self.patcher_req.stop()
+
+
+if __name__ == "__main__":
+ unittest.main() \ No newline at end of file
diff --git a/test/apps/pci_optimization/des_result.json b/test/apps/pci_optimization/des_result.json
new file mode 100644
index 0000000..9209acf
--- /dev/null
+++ b/test/apps/pci_optimization/des_result.json
@@ -0,0 +1,18 @@
+[
+ [
+ {
+ "overallHoAtt": 1300
+ },
+ {
+ "overallHoAtt": 550
+ }
+ ],
+ [
+ {
+ "overallHoAtt": 450
+ },
+ {
+ "overallHoAtt": 400
+ }
+ ]
+]
diff --git a/test/apps/pci_optimization/test_ml_model.py b/test/apps/pci_optimization/test_ml_model.py
new file mode 100644
index 0000000..cf0dee5
--- /dev/null
+++ b/test/apps/pci_optimization/test_ml_model.py
@@ -0,0 +1,87 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import copy
+from mock import patch
+import unittest
+from apps.pci.optimizers.solver.ml_model import MlModel
+from osdf.adapters.dcae.des import DESException
+import osdf.config.loader as config_loader
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+
+
+class TestMlModel(unittest.TestCase):
+ def setUp(self):
+ self.config_spec = {
+ "deployment": "config/osdf_config.yaml",
+ "core": "config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ def tearDown(self):
+ pass
+
+ def test_ml_model(self):
+ des_result_file = 'test/apps/pci_optimization/des_result.json'
+ results = json_from_file(des_result_file)
+
+ dzn_data = {
+ 'NUM_NODES': 4,
+ 'NUM_PCIS': 4,
+ 'NUM_NEIGHBORS': 4,
+ 'NEIGHBORS': [],
+ 'NUM_SECOND_LEVEL_NEIGHBORS': 1,
+ 'SECOND_LEVEL_NEIGHBORS': [],
+ 'PCI_UNCHANGEABLE_CELLS': {},
+ 'ORIGINAL_PCIS': []
+ }
+
+ network_cell_info = {
+ 'cell_list': [
+ {
+ 'cell_id': 'Chn0001',
+ 'id': 1,
+ 'nbr_list': []
+ },
+ {
+ 'cell_id': 'Chn0002',
+ 'id': 2,
+ 'nbr_list': []
+ }
+ ]
+ }
+ self.patcher_req = patch('osdf.adapters.dcae.des.extract_data', side_effect=results)
+ self.Mock_req = self.patcher_req.start()
+ mlmodel = MlModel()
+ mlmodel.get_additional_inputs(dzn_data, network_cell_info)
+ self.assertEqual({1}, dzn_data['PCI_UNCHANGEABLE_CELLS'])
+ self.patcher_req.stop()
+
+ dzn_data['PCI_UNCHANGEABLE_CELLS'] = []
+ self.patcher_req = patch('osdf.adapters.dcae.des.extract_data', side_effect=DESException('error'))
+ self.Mock_req = self.patcher_req.start()
+ mlmodel.get_additional_inputs(dzn_data, network_cell_info)
+ self.assertEqual(set() , dzn_data['PCI_UNCHANGEABLE_CELLS'])
+ self.patcher_req.stop()
+
+ self.patcher_req = patch('osdf.adapters.dcae.des.extract_data', return_value=[])
+ self.Mock_req = self.patcher_req.start()
+ mlmodel.get_additional_inputs(dzn_data, network_cell_info)
+ self.assertEqual(set() , dzn_data['PCI_UNCHANGEABLE_CELLS'])
+ self.patcher_req.stop()
diff --git a/test/apps/slice_selection/conductor_error_response.json b/test/apps/slice_selection/conductor_error_response.json
new file mode 100644
index 0000000..95a9750
--- /dev/null
+++ b/test/apps/slice_selection/conductor_error_response.json
@@ -0,0 +1,18 @@
+{
+ "plans": [
+ {
+ "status": "error",
+ "message": "Some error message",
+ "name": "Plan Name 1",
+ "links": [
+ [
+ {
+ "href": "http://conductor:8091/v1/plans/plan_id",
+ "rel": "self"
+ }
+ ]
+ ],
+ "id": "plan_id"
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/new_solution_conductor_response.json b/test/apps/slice_selection/new_solution_conductor_response.json
new file mode 100644
index 0000000..897aa2b
--- /dev/null
+++ b/test/apps/slice_selection/new_solution_conductor_response.json
@@ -0,0 +1,47 @@
+{
+ "plans":[
+ {
+ "status":"done",
+ "id":"plan_id",
+ "name":"Plan Name 1",
+ "links":[
+ [
+ {
+ "href":"http://conductor:8091/v1/plans/plan_id",
+ "rel":"self"
+ }
+ ]
+ ],
+ "recommendations":[
+ {
+ "embb-nst":{
+ "inventory_provider":"generator",
+ "candidate": {
+ "candidate_id":"1a636c4d-5e76-427e-bfd6-241a947224b0",
+ "latency":20,
+ "inventory_provider":"generator",
+ "max_number_of_ues":100,
+ "ue_mobility_level":"stationary",
+ "candidate_type":"slice_profiles",
+ "resource_sharing_level":"shared",
+ "inventory_type":"slice_profiles",
+ "reliability": 99.99,
+ "AN_latency": 10,
+ "AN_ue_mobility_level": "stationary",
+ "AN_max_number_of_ues": 100,
+ "AN_reliability": 99.99,
+ "AN_resource_sharing_level":"shared",
+ "CN_latency": 5,
+ "CN_reliability": 99.99,
+ "CN_resource_sharing_level":"shared",
+ "TN-BH_reliability": 99.99,
+ "TN-BH_latency": 5,
+ "TN-BH_resource_sharing_level":"shared",
+ "cost":1.0
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/new_solution_nsi_response.json b/test/apps/slice_selection/new_solution_nsi_response.json
new file mode 100644
index 0000000..52624b6
--- /dev/null
+++ b/test/apps/slice_selection/new_solution_nsi_response.json
@@ -0,0 +1,35 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "completed",
+ "statusMessage": "",
+ "solutions": [
+ {
+ "existingNSI": false,
+ "newNSISolution": {
+ "sliceProfiles": [
+ {
+ "domainType": "AN",
+ "resourceSharingLevel": "shared",
+ "latency": 10,
+ "reliability": 99.99,
+ "uEMobilityLevel": "stationary",
+ "maxNumberofUEs": 100
+ },
+ {
+ "domainType": "CN",
+ "resourceSharingLevel": "shared",
+ "latency": 5,
+ "reliability": 99.99
+ },
+ {
+ "domainType": "TN-BH",
+ "resourceSharingLevel": "shared",
+ "latency": 5,
+ "reliability": 99.99
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/no_rec.json b/test/apps/slice_selection/no_rec.json
new file mode 100644
index 0000000..855afac
--- /dev/null
+++ b/test/apps/slice_selection/no_rec.json
@@ -0,0 +1,18 @@
+{
+ "plans": [
+ {
+ "id": "d8c07237-5f66-4aa6-871c-a04221d99458",
+ "links": [
+ [
+ {
+ "href": "https://oof-has-api:8091/v1/plans/d8c07237-5f66-4aa6-871c-a04221d99458",
+ "rel": "self"
+ }
+ ]
+ ],
+ "message": "Plan d8c07237-5f66-4aa6-871c-a04221d99458 search failed, no recommendations found by machine dev-oof-has-solver-65d478b6d-ql5fp",
+ "name": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "status": "not found"
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/no_recomm_conductor_response.json b/test/apps/slice_selection/no_recomm_conductor_response.json
new file mode 100644
index 0000000..f23af87
--- /dev/null
+++ b/test/apps/slice_selection/no_recomm_conductor_response.json
@@ -0,0 +1,18 @@
+{
+ "plans":[
+ {
+ "status":"done",
+ "id":"plan_id",
+ "name":"Plan Name 1",
+ "links":[
+ [
+ {
+ "href":"http://conductor:8091/v1/plans/plan_id",
+ "rel":"self"
+ }
+ ]
+ ],
+ "recommendations": []
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/no_recomm_nsi_response.json b/test/apps/slice_selection/no_recomm_nsi_response.json
new file mode 100644
index 0000000..e36a243
--- /dev/null
+++ b/test/apps/slice_selection/no_recomm_nsi_response.json
@@ -0,0 +1,7 @@
+{
+ "requestId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus":"completed",
+ "statusMessage":"",
+ "solutions": []
+}
diff --git a/test/apps/slice_selection/nsi_error_response.json b/test/apps/slice_selection/nsi_error_response.json
new file mode 100644
index 0000000..9dc5300
--- /dev/null
+++ b/test/apps/slice_selection/nsi_error_response.json
@@ -0,0 +1,6 @@
+{
+ "requestId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus":"error",
+ "statusMessage":"Some error message"
+}
diff --git a/test/apps/slice_selection/nsi_request.json b/test/apps/slice_selection/nsi_request.json
new file mode 100644
index 0000000..72b2c8b
--- /dev/null
+++ b/test/apps/slice_selection/nsi_request.json
@@ -0,0 +1,31 @@
+{
+ "serviceProfile": {
+ "latency": 2,
+ "security": "High",
+ "reliability": 99.9999,
+ "trafficDensity": 1,
+ "connDensity": 100000,
+ "expDataRate": 50,
+ "jitter": 1,
+ "survivalTime": 0,
+ "resourceSharingLevel":"shared"
+ },
+ "serviceInfo":{
+ "serviceInstanceId": "209fb01e-60ca-4325-b074-c5ad4e0499f8",
+ "serviceName": ""
+ },
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5
+ },
+ "NSTInfoList": [
+ {
+ "modelInvariantId": "fda3c1e8-7653-4acd-80ef-f5755c1d3859",
+ "modelVersionId": "a6906768-1cae-4e78-acd1-d753ac61f3e8",
+ "modelName": "URLLC_1"
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/nsi_selection_invalid_request.json b/test/apps/slice_selection/nsi_selection_invalid_request.json
new file mode 100644
index 0000000..3ecd1e3
--- /dev/null
+++ b/test/apps/slice_selection/nsi_selection_invalid_request.json
@@ -0,0 +1,80 @@
+{
+ "serviceProfile": {
+ "latency": 2,
+ "security": "High",
+ "reliability": 99.9999,
+ "trafficDensity": 1,
+ "connDensity": 100000,
+ "expDataRate": 50,
+ "jitter": 1,
+ "survivalTime": 0,
+ "resourceSharingLevel":"shared"
+ },
+ "requestInfo": {
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "timeout": 5
+ },
+ "NSSTInfo":[
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa2",
+ "invariantUUID":"2fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-an-nf"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa3",
+ "invariantUUID":"4fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-cn"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa4",
+ "invariantUUID":"5ta85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-fh"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa5",
+ "invariantUUID":"6ya85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-mh"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa7",
+ "invariantUUID":"7ua85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-bh"
+ }
+ ],
+ "preferReuse":true,
+ "subnetCapabilities":[
+ {
+ "domainType":"AN-NF",
+ "capabilityDetails":{
+ "blob":"content"
+ }
+ },
+ {
+ "domainType":"CN",
+ "capabilityDetails":{
+ "blob":"content"
+ }
+ },
+ {
+ "domainType":"TN-FH",
+ "capabilityDetails":{
+ "blob":"content"
+ }
+ },
+ {
+ "domainType":"TN-MH",
+ "capabilityDetails":{
+ "blob":"content"
+ }
+ },
+ {
+ "domainType":"TN-BH",
+ "capabilityDetails":{
+ "blob":"content"
+ }
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/nsi_selection_request.json b/test/apps/slice_selection/nsi_selection_request.json
new file mode 100644
index 0000000..39fb925
--- /dev/null
+++ b/test/apps/slice_selection/nsi_selection_request.json
@@ -0,0 +1,84 @@
+{
+ "serviceProfile":{
+ "latency":5,
+ "security":"High",
+ "reliability":99.999,
+ "resourceSharingLevel":"shared"
+ },
+ "requestInfo":{
+ "transactionId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "callbackHeader":{
+ "blob":"content"
+ },
+ "sourceId":"d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "timeout":5,
+ "numSolutions":1
+ },
+ "NSTInfo":{
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa1",
+ "invariantUUID":"7ua85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-nst"
+ },
+ "NSSTInfo":[
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa2",
+ "invariantUUID":"2fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-an-nf"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa3",
+ "invariantUUID":"4fa85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-cn"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa4",
+ "invariantUUID":"5ta85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-fh"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa5",
+ "invariantUUID":"6ya85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-mh"
+ },
+ {
+ "UUID":"3fa85f64-5717-4562-b3fc-2c963f66afa7",
+ "invariantUUID":"7ua85f64-5717-4562-b3fc-2c963f66afa6",
+ "name":"embb-tn-bh"
+ }
+ ],
+ "preferReuse":false,
+ "subnetCapabilities":[
+ {
+ "domainType":"AN",
+ "capabilityDetails":{
+ "latency": "4",
+ "reliability": "99.9",
+ "maxNumberofUEs": "10",
+ "maxThroughput": "50",
+ "termDensity": "60"
+ }
+ },
+ {
+ "domainType":"CN",
+ "capabilityDetails":{
+ "latency": "3",
+ "reliability": "99.9",
+ "maxNumberofUEs": "10",
+ "maxThroughput": "50",
+ "termDensity": "60"
+ }
+ },
+ {
+ "domainType":"TN-BH",
+ "capabilityDetails":{
+ "latency": "2",
+ "reliability": "99.9",
+ "maxNumberofUEs": "10",
+ "maxThroughput": "50",
+ "termDensity": "60"
+ }
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/nssi_conductor_response.json b/test/apps/slice_selection/nssi_conductor_response.json
new file mode 100644
index 0000000..d2edcf5
--- /dev/null
+++ b/test/apps/slice_selection/nssi_conductor_response.json
@@ -0,0 +1,53 @@
+{
+ "plans":[
+ {
+ "status":"done",
+ "id":"plan_id",
+ "name":"Plan Name 1",
+ "links":[
+ [
+ {
+ "href":"http://conductor:8091/v1/plans/plan_id",
+ "rel":"self"
+ }
+ ]
+ ],
+ "recommendations":[
+ {
+ "embb-cn": {
+ "inventory_provider": "aai",
+ "candidate": {
+ "exp_data_rate": 0,
+ "conn_density": 0,
+ "coverage_area_ta_list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "activity_factor": 0,
+ "cs_availability": null,
+ "candidate_id": "1a636c4d-5e76-427e-bfd6-241a947224b0",
+ "area_traffic_cap_dl": null,
+ "latency": 20,
+ "service_area_dimension": null,
+ "e2e_latency": 0,
+ "area_traffic_cap_ul": null,
+ "inventory_provider": "aai",
+ "exp_data_rate_ul": 100,
+ "max_number_of_ues": 0,
+ "ue_mobility_level": "stationary",
+ "candidate_type": "nssi",
+ "traffic_density": 0,
+ "payload_size": 0,
+ "exp_data_rate_dl": 100,
+ "jitter": 0,
+ "survival_time": 0,
+ "resource_sharing_level": "shared",
+ "inventory_type": "nssi",
+ "reliability": null,
+ "cost": 1.0,
+ "instance_id": "e1041cdc-12da-4f36-b84e-68c380e9cd47",
+ "instance_name": "nssi_test_0211"
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/nssi_error_response.json b/test/apps/slice_selection/nssi_error_response.json
new file mode 100644
index 0000000..70e0596
--- /dev/null
+++ b/test/apps/slice_selection/nssi_error_response.json
@@ -0,0 +1,7 @@
+{
+ "requestId":"r450f1ee-6c54-4b01-90e6-d701748f0851",
+ "transactionId":"t670f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus":"completed",
+ "statusMessage":"",
+ "solutions": []
+}
diff --git a/test/apps/slice_selection/nssi_selection_invalid_request.json b/test/apps/slice_selection/nssi_selection_invalid_request.json
new file mode 100644
index 0000000..57e0184
--- /dev/null
+++ b/test/apps/slice_selection/nssi_selection_invalid_request.json
@@ -0,0 +1,23 @@
+{
+ "sliceProfile": {
+ "blob": "content"
+ },
+ "requestInfo": {
+ "transactionId": "t670f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "r450f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "callbackHeader": {
+ "blob": "content"
+ },
+ "sourceId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "timeout": 5,
+ "numSolutions": 1,
+ "addtnlArgs": {
+ "blob": "content"
+ }
+ },
+ "NSSTInfo": {
+ "UUID": "y7785f64-5717-4562-b3fc-2c963f66afa6",
+ "name": "embb-cn"
+ }
+}
diff --git a/test/apps/slice_selection/nssi_selection_request.json b/test/apps/slice_selection/nssi_selection_request.json
new file mode 100644
index 0000000..61ee563
--- /dev/null
+++ b/test/apps/slice_selection/nssi_selection_request.json
@@ -0,0 +1,27 @@
+{
+ "sliceProfile": {
+ "latency":5,
+ "security":"High",
+ "reliability":99.999,
+ "resourceSharingLevel":"shared"
+ },
+ "requestInfo": {
+ "transactionId": "t670f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestId": "r450f1ee-6c54-4b01-90e6-d701748f0851",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "callbackHeader": {
+ "blob": "content"
+ },
+ "sourceId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "timeout": 5,
+ "numSolutions": 1,
+ "addtnlArgs": {
+ "blob": "content"
+ }
+ },
+ "NSSTInfo": {
+ "UUID": "a7785f64-5717-4562-b3fc-2c963f66afa6",
+ "invariantUUID": "9fh85f64-5717-4562-b3fc-2c963f66afa6",
+ "name": "embb-cn"
+ }
+}
diff --git a/test/apps/slice_selection/shared_solution_conductor_response.json b/test/apps/slice_selection/shared_solution_conductor_response.json
new file mode 100644
index 0000000..a187fef
--- /dev/null
+++ b/test/apps/slice_selection/shared_solution_conductor_response.json
@@ -0,0 +1,53 @@
+{
+ "plans":[
+ {
+ "status":"done",
+ "id":"plan_id",
+ "name":"Plan Name 1",
+ "links":[
+ [
+ {
+ "href":"http://conductor:8091/v1/plans/plan_id",
+ "rel":"self"
+ }
+ ]
+ ],
+ "recommendations":[
+ {
+ "embb-nst": {
+ "inventory_provider": "aai",
+ "candidate": {
+ "exp_data_rate": 0,
+ "conn_density": 0,
+ "coverage_area_ta_list": "[{\"province\":\"??\",\"city\":\"???\",\"county\":\"???\",\"street\":\"?????\"}]",
+ "activity_factor": 0,
+ "cs_availability": null,
+ "candidate_id": "1a636c4d-5e76-427e-bfd6-241a947224b0",
+ "area_traffic_cap_dl": null,
+ "latency": 20,
+ "service_area_dimension": null,
+ "e2e_latency": 0,
+ "area_traffic_cap_ul": null,
+ "inventory_provider": "aai",
+ "exp_data_rate_ul": 100,
+ "max_number_of_ues": 0,
+ "ue_mobility_level": "stationary",
+ "candidate_type": "nsi",
+ "traffic_density": 0,
+ "payload_size": 0,
+ "exp_data_rate_dl": 100,
+ "jitter": 0,
+ "survival_time": 0,
+ "resource_sharing_level": "shared",
+ "inventory_type": "nsi",
+ "reliability": null,
+ "cost": 1.0,
+ "instance_id": "f1041cdc-12da-4f36-b84e-68c380e9cd47",
+ "instance_name": "nsi_test_0211"
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/test/apps/slice_selection/shared_solution_nsi_response.json b/test/apps/slice_selection/shared_solution_nsi_response.json
new file mode 100644
index 0000000..ff83dfc
--- /dev/null
+++ b/test/apps/slice_selection/shared_solution_nsi_response.json
@@ -0,0 +1,17 @@
+{
+ "requestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "completed",
+ "solutions": [
+ {
+ "existingNSI": true,
+ "sharedNSISolution": {
+ "UUID": "3fa85f64-5717-4562-b3fc-2c963f66afa1",
+ "invariantUUID": "7ua85f64-5717-4562-b3fc-2c963f66afa6",
+ "NSIName": "nsi_test_0211",
+ "NSIId": "f1041cdc-12da-4f36-b84e-68c380e9cd47"
+ }
+ }
+ ],
+ "statusMessage": "",
+ "transactionId": "d290f1ee-6c54-4b01-90e6-d701748f0851"
+}
diff --git a/test/apps/slice_selection/shared_solution_nssi_response.json b/test/apps/slice_selection/shared_solution_nssi_response.json
new file mode 100644
index 0000000..f3468a4
--- /dev/null
+++ b/test/apps/slice_selection/shared_solution_nssi_response.json
@@ -0,0 +1,15 @@
+{
+ "requestId": "r450f1ee-6c54-4b01-90e6-d701748f0851",
+ "requestStatus": "completed",
+ "solutions": [
+ {
+ "UUID": "a7785f64-5717-4562-b3fc-2c963f66afa6",
+ "invariantUUID": "9fh85f64-5717-4562-b3fc-2c963f66afa6",
+ "NSSIName": "nssi_test_0211",
+ "NSSIId": "e1041cdc-12da-4f36-b84e-68c380e9cd47"
+
+ }
+ ],
+ "statusMessage": "",
+ "transactionId": "t670f1ee-6c54-4b01-90e6-d701748f0851"
+}
diff --git a/test/apps/slice_selection/slice_policies.txt b/test/apps/slice_selection/slice_policies.txt
new file mode 100644
index 0000000..7eb55de
--- /dev/null
+++ b/test/apps/slice_selection/slice_policies.txt
@@ -0,0 +1,5 @@
+query_policy_nsi.json
+threshold_policy_nsi.json
+vnf_policy_nsi_shared_case.json
+opt_policy_nsi_reuse.json
+
diff --git a/test/apps/slice_selection/subnet_policies.txt b/test/apps/slice_selection/subnet_policies.txt
new file mode 100644
index 0000000..649672d
--- /dev/null
+++ b/test/apps/slice_selection/subnet_policies.txt
@@ -0,0 +1,5 @@
+query_policy_nsi.json
+threshold_policy_nsi.json
+vnf_policy_nssi_shared.json
+opt_policy_nssi.json
+
diff --git a/test/apps/slice_selection/test_remote_opt_processor.py b/test/apps/slice_selection/test_remote_opt_processor.py
new file mode 100644
index 0000000..7c2d191
--- /dev/null
+++ b/test/apps/slice_selection/test_remote_opt_processor.py
@@ -0,0 +1,165 @@
+# -------------------------------------------------------------------------
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import unittest
+from requests import RequestException, Response
+
+from apps.slice_selection.optimizers.conductor.remote_opt_processor import SliceSelectionOptimizer
+from osdf.adapters.local_data import local_policies
+from osdf.utils.interfaces import json_from_file, yaml_from_file
+from osdf.utils.programming_utils import DotDict
+import osdf.config.loader as config_loader
+from mock import patch, MagicMock
+import json
+from osdf.logging.osdf_logging import error_log, debug_log
+from osdf.adapters.policy.interface import get_policies
+
+
+class TestRemoteOptProcessor(unittest.TestCase):
+ def setUp(self):
+ self.config_spec = {
+ "deployment": "config/osdf_config.yaml",
+ "core": "config/common_config.yaml"
+ }
+ slice_spec = "config/slicing_config.yaml"
+ self.slice_config = config_loader.load_config_file(slice_spec)
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+ self.patcher_RestClient = patch(
+ 'osdf.utils.interfaces.RestClient.request', return_value=MagicMock())
+ self.mock_rc = self.patcher_RestClient.start()
+
+ def tearDown(self):
+ patch.stopall()
+
+ def test_process_nsi_selection_opt(self):
+ main_dir = ""
+ request_file = main_dir + 'test/apps/slice_selection/nsi_selection_request.json'
+ not_shared_request_file = main_dir + 'test/apps/slice_selection/not_shared_nsi_request.json'
+ #response files
+ new_solution_response_file = main_dir + 'test/apps/slice_selection/new_solution_nsi_response.json'
+ shared_solution_response_file = main_dir + 'test/apps/slice_selection/shared_solution_nsi_response.json'
+ no_solution_response_file = main_dir + 'test/apps/slice_selection/no_recomm_nsi_response.json'
+ error_response_file = main_dir + 'test/apps/slice_selection/nsi_error_response.json'
+
+ request_json = json_from_file(request_file)
+ new_solution_response_json = json_from_file(new_solution_response_file)
+ shared_solution_response_json = json_from_file(shared_solution_response_file)
+ no_solution_response_json = json_from_file(no_solution_response_file)
+ error_response_json = json_from_file(error_response_file)
+
+ policies_path = main_dir + 'test/policy-local-files/slice-selection-files'
+ slice_policies_file = main_dir + 'test/apps/slice_selection/slice_policies.txt'
+
+ valid_policies_files = local_policies.get_policy_names_from_file(slice_policies_file)
+ policies = [json_from_file(policies_path + '/' + name) for name in valid_policies_files]
+ self.patcher_get_policies = patch('osdf.adapters.policy.interface.remote_api',
+ return_value=policies)
+ self.Mock_get_policies = self.patcher_get_policies.start()
+
+ # new solution
+ new_solution_conductor_response_file = 'test/apps/slice_selection/new_solution_conductor_response.json'
+ new_solution_conductor_response = json_from_file(new_solution_conductor_response_file)
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ return_value=new_solution_conductor_response)
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt = SliceSelectionOptimizer(self.osdf_config, self.slice_config, request_json, 'NSI')
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=new_solution_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ # shared solution
+ request_json['preferReuse'] = True
+ shared_solution_conductor_response_file = 'test/apps/slice_selection/shared_solution_conductor_response.json'
+ shared_solution_conductor_response = json_from_file(shared_solution_conductor_response_file)
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ return_value=shared_solution_conductor_response)
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt = SliceSelectionOptimizer(self.osdf_config, self.slice_config, request_json, 'NSI')
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=shared_solution_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ # no recommendation
+ no_solution_conductor_response_file = 'test/apps/slice_selection/no_rec.json'
+ no_solution_conductor_response = json_from_file(no_solution_conductor_response_file)
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ return_value=no_solution_conductor_response)
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=no_solution_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ # Exception
+ conductor_error_response_file = 'test/apps/slice_selection/conductor_error_response.json'
+ conductor_error_response = json_from_file(conductor_error_response_file)
+
+ response = Response()
+ response._content = json.dumps(conductor_error_response).encode()
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ side_effect=RequestException(response=response))
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=error_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ side_effect=Exception("Some error message"))
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=error_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ def test_process_nssi_selection_opt(self):
+ main_dir = ""
+ request_file = main_dir + 'test/apps/slice_selection/nssi_selection_request.json'
+ # response files
+ shared_solution_response_file = main_dir + 'test/apps/slice_selection/shared_solution_nssi_response.json'
+ error_response_file = main_dir + 'test/apps/slice_selection/nssi_error_response.json'
+
+ request_json = json_from_file(request_file)
+ shared_solution_response_json = json_from_file(shared_solution_response_file)
+ error_response_json = json_from_file(error_response_file)
+
+ policies_path = main_dir + 'test/policy-local-files/slice-selection-files'
+ slice_policies_file = main_dir + 'test/apps/slice_selection/subnet_policies.txt'
+
+ valid_policies_files = local_policies.get_policy_names_from_file(slice_policies_file)
+ policies = [json_from_file(policies_path + '/' + name) for name in valid_policies_files]
+ self.patcher_get_policies = patch('osdf.adapters.policy.interface.remote_api',
+ return_value=policies)
+ self.Mock_get_policies = self.patcher_get_policies.start()
+
+ shared_solution_conductor_response_file = 'test/apps/slice_selection/nssi_conductor_response.json'
+ shared_solution_conductor_response = json_from_file(shared_solution_conductor_response_file)
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ return_value=shared_solution_conductor_response)
+ self.Mock_req = self.patcher_req.start()
+ slice_select_opt = SliceSelectionOptimizer(self.osdf_config, self.slice_config, request_json, 'NSSI')
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=shared_solution_response_json, noresponse=True)
+ self.patcher_req.stop()
+
+ request_json['sliceProfile']['resourceSharingLevel'] = "not-shared"
+ slice_select_opt = SliceSelectionOptimizer(self.osdf_config, self.slice_config, request_json, 'NSSI')
+ slice_select_opt.process_slice_selection_opt()
+ self.mock_rc.assert_called_with(json=error_response_json, noresponse=True)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/test/conductor/test_conductor_calls.py b/test/conductor/test_conductor_calls.py
index 1a96da7..8b4411d 100644
--- a/test/conductor/test_conductor_calls.py
+++ b/test/conductor/test_conductor_calls.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,7 +18,7 @@
#
import unittest
-from osdf.optimizers.placementopt.conductor import conductor
+from osdf.adapters.conductor import conductor
import osdf.config.loader as config_loader
from osdf.utils.interfaces import json_from_file
from osdf.utils.programming_utils import DotDict
@@ -34,6 +35,10 @@ class TestConductorCalls(unittest.TestCase):
self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
self.lp = self.osdf_config.core.get('osdf_temp', {}).get('local_policies', {}
).get('placement_policy_files_vcpe')
+ self.template_fields = {
+ 'location_enabled': True,
+ 'version': '2017-10-10'
+ }
def tearDown(self):
pass
@@ -41,7 +46,22 @@ class TestConductorCalls(unittest.TestCase):
def test_request(self):
req_json = json_from_file("./test/placement-tests/request.json")
policies = pol.get_local_policies("test/policy-local-files/", self.lp)
- conductor.request(req_json, self.osdf_config, policies)
+ req_info = req_json['requestInfo']
+ demands = req_json['placementInfo']['placementDemands']
+ request_parameters = req_json['placementInfo']['requestParameters']
+ service_info = req_json['serviceInfo']
+ conductor.request(req_info, demands, request_parameters, service_info, self.template_fields,
+ self.osdf_config, policies)
+
+ def test_request_vfmod(self):
+ req_json = json_from_file("./test/placement-tests/request_vfmod.json")
+ policies = pol.get_local_policies("test/policy-local-files/", self.lp)
+ req_info = req_json['requestInfo']
+ demands = req_json['placementInfo']['placementDemands']
+ request_parameters = req_json['placementInfo']['requestParameters']
+ service_info = req_json['serviceInfo']
+ conductor.request(req_info, demands, request_parameters, service_info, self.template_fields,
+ self.osdf_config, policies)
if __name__ == "__main__":
diff --git a/test/conductor/test_conductor_translation.py b/test/conductor/test_conductor_translation.py
index 0c7da94..2a600e4 100644
--- a/test/conductor/test_conductor_translation.py
+++ b/test/conductor/test_conductor_translation.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,40 +16,71 @@
#
# -------------------------------------------------------------------------
#
-import mock
import unittest
-from flask import Response
-from mock import patch
from osdf.adapters.local_data import local_policies
-from osdf.optimizers.placementopt.conductor import translation as tr
-from osdf.utils.interfaces import json_from_file, yaml_from_file
+from osdf.adapters.conductor import translation as tr
+from osdf.utils.interfaces import json_from_file
class TestConductorTranslation(unittest.TestCase):
def setUp(self):
- main_dir = ""
- conductor_api_template = main_dir + "osdf/templates/conductor_interface.json"
- parameter_data_file = main_dir + "test/placement-tests/request.json"
- policy_data_path = main_dir + "test/policy-local-files/"
- local_config_file = main_dir + "config/common_config.yaml"
+ self.main_dir = ""
+ self.conductor_api_template = self.main_dir + "osdf/templates/conductor_interface.json"
+ self.local_config_file = self.main_dir + "config/common_config.yaml"
+ policy_data_path = self.main_dir + "test/policy-local-files"
valid_policies_list_file = policy_data_path + '/' + 'meta-valid-policies.txt'
valid_policies_files = local_policies.get_policy_names_from_file(valid_policies_list_file)
+ parameter_data_file = self.main_dir + "test/placement-tests/request.json"
self.request_json = json_from_file(parameter_data_file)
+ parameter_data_file = self.main_dir + "test/placement-tests/request_vfmod.json"
+ self.request_vfmod_json = json_from_file(parameter_data_file)
self.policies = [json_from_file(policy_data_path + '/' + name) for name in valid_policies_files]
+ self.optimization_policies = [json_from_file(policy_data_path + '/'
+ + "slice-selection-files/opt_policy_nsi_reuse.json")]
+
def tearDown(self):
pass
def test_gen_demands(self):
# need to run this only on vnf policies
- vnf_policies = [x for x in self.policies if x["content"]["policyType"] == "vnfPolicy"]
- res = tr.gen_demands(self.request_json, vnf_policies)
+ vnf_policies = [x for x in self.policies if x[list(x.keys())[0]]["type"]
+ == "onap.policies.optimization.VnfPolicy"]
+ res = tr.gen_demands(self.request_json['placementInfo']['placementDemands'], vnf_policies)
+
+ assert res is not None
+
+ def test_gen_vfmod_demands(self):
+ # need to run this only on vnf policies
+ vnf_policies = [x for x in self.policies if x[list(x.keys())[0]]["type"]
+ == "onap.policies.optimization.VnfPolicy"]
+ res = tr.gen_demands(self.request_vfmod_json['placementInfo']['placementDemands'], vnf_policies)
assert res is not None
+ def test_gen_optimization_policy(self):
+ expected = [{
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "creation_cost",
+ "demand": "embb-nst"
+ }
+ }
+ ]
+ }
+ }]
+ self.assertEqual(expected,
+ tr.gen_optimization_policy(self.request_vfmod_json['placementInfo']['placementDemands'],
+ self.optimization_policies))
+
if __name__ == "__main__":
unittest.main()
diff --git a/test/config/common_config.yaml b/test/config/common_config.yaml
index a3ef82e..560d707 100644
--- a/test/config/common_config.yaml
+++ b/test/config/common_config.yaml
@@ -61,4 +61,14 @@ policy_info:
- get_param: subscriber_role
default: # if no explicit service related information is needed
policy_fetch: by_name
- policy_scope: none \ No newline at end of file
+ policy_scope: none
+
+PCI:
+ ML:
+ average_ho_threshold: 10000
+ latest_ho_threshold: 500
+ DES:
+ service_id: ho_metric
+ filter:
+ interval: 10
+ ml_enabled: false
diff --git a/test/config/log.yml b/test/config/log.yml
new file mode 100644
index 0000000..ad0de21
--- /dev/null
+++ b/test/config/log.yml
@@ -0,0 +1,100 @@
+version: 1
+disable_existing_loggers: True
+
+loggers:
+ error:
+ handlers: [error_handler, console_handler]
+ level: "WARN"
+ propagate: True
+ debug:
+ handlers: [debug_handler, console_handler]
+ level: "DEBUG"
+ propagate: True
+ metrics:
+ handlers: [metrics_handler, console_handler]
+ level: "INFO"
+ propagate: True
+ audit:
+ handlers: [audit_handler, console_handler]
+ level: "INFO"
+ propagate: True
+handlers:
+ debug_handler:
+ level: "DEBUG"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/debug.log"
+ formatter: "debugFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ error_handler:
+ level: "WARN"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/error.log"
+ formatter: "errorFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ metrics_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/metrics.log"
+ formatter: "metricsFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ audit_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/audit.log"
+ formatter: "auditFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ console_handler:
+ level: "DEBUG"
+ class: "logging.StreamHandler"
+ formatter: "metricsFormat"
+
+formatters:
+ standard:
+ format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s"
+ debugFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{server}|%(levelname)s|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ errorFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{serviceName}|{partnerName}\
+ |{targetEntity}|{targetServiceName}|%(levelname)s|{errorCode}|{errorDescription}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ auditFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ metricsFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{targetEntity}|{targetServiceName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{TargetVirtualEntity}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ mdcFormat:
+ format: "%(asctime)s.%(msecs)03d+00:00|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s"
+ mdcfmt: "{requestID} {invocationID} {serviceName} {serverIPAddress}"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
diff --git a/test/config/opteng_config.yaml b/test/config/opteng_config.yaml
new file mode 100755
index 0000000..4a7e57d
--- /dev/null
+++ b/test/config/opteng_config.yaml
@@ -0,0 +1,25 @@
+# Policy Platform -- requires Authorization
+policyPlatformUrl: https://policy-xacml-pdp:6969/policy/pdpx/decision/v1 # Policy Dev platform URL
+
+# AAF Authentication config
+is_aaf_enabled: False
+aaf_cache_expiry_mins: 5
+aaf_url: https://aaftest.simpledemo.onap.org:8095
+aaf_user_roles:
+ - '/optmodel:org.onap.oof.access|*|read ALL'
+ - '/optengine:org.onap.oof.access|*|read ALL'
+
+# Secret Management Service from AAF
+aaf_sms_url: https://aaf-sms.onap:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+
+osdfDatabaseHost: localhost
+osdfDatabaseSchema: osdf
+osdfDatabaseUsername: osdf
+osdfDatabasePassword: osdf
+osdfDatabasePort: 3306
+
+#key
+appkey: os35@rrtky400fdntc#001t5 \ No newline at end of file
diff --git a/test/config/osdf_config.yaml b/test/config/osdf_config.yaml
index 495feb1..05d7c6a 100755
--- a/test/config/osdf_config.yaml
+++ b/test/config/osdf_config.yaml
@@ -1,3 +1,15 @@
+placementVersioningEnabled: False
+
+# Placement API latest version numbers to be set in HTTP header
+placementMajorVersion: "1"
+placementMinorVersion: "0"
+placementPatchVersion: "0"
+
+# Placement API default version numbers to be set in HTTP header
+placementDefaultMajorVersion: "1"
+placementDefaultMinorVersion: "0"
+placementDefaultPatchVersion: "0"
+
osdfUserNameForSO: "" # The OSDF Manager username for MSO.
odfPasswordForSO: "" # The OSDF Manager password for MSO.
@@ -10,6 +22,8 @@ conductorUsername: "CONDUCTOR-USER"
conductorPassword: "CONDUCTOR-PASSWD"
conductorPingWaitTime: 60 # seconds to wait before calling the conductor retry URL
conductorMaxRetries: 30 # if we don't get something in 30 minutes, give up
+# versions to be set in HTTP header
+conductorMinorVersion: 0
# Policy Platform -- requires ClientAuth, Authorization, and Environment
policyPlatformUrl: https://POLICY-URL:8081/pdp/getConfig # Policy Dev platform URL
@@ -34,7 +48,51 @@ osdfPlacementUsername: "test"
osdfPlacementPassword: "testpwd"
is_aaf_enabled: False
-aaf_cache_expiry_hrs: 3
+aaf_cache_expiry_mins: 5
aaf_url: https://aaftest.simpledemo.onap.org:8095
aaf_user_roles:
- - /api/oof/v1/placement:org.onap.osdf.access|*|read ALL \ No newline at end of file
+ - '/placement:org.onap.oof.access|*|read ALL'
+ - '/pci:org.onap.oof.access|*|read ALL'
+
+# Secret Management Service from AAF
+aaf_sms_url: https://aaf-sms.onap:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+
+# Credentials for PCIHandler
+pciHMSUsername: "" # pcihandler username for call back.
+pciHMSPassword: "" # pcihandler password for call back.
+
+configClientType: configdb
+
+# config db api
+configDbUrl: http://127.0.0.1:5000/simulated/configdb
+configDbUserName: osdf
+configDbPassword: passwd
+configDbGetCellListUrl: 'getCellList'
+configDbGetNbrListUrl: 'getNbrList'
+
+# Credentials for the OOF PCI Opt service
+osdfPCIOptUsername: PCI-OSDF-USER
+osdfPCIOptPassword: PCI-OSDF-PASSWD
+
+aaiUrl: "https://aai.url:30233"
+aaiServiceInstanceUrl : "/aai/v20/nodes/service-instances/service-instance/"
+
+#DES api
+desUrl: http://des.url:9000
+desApiPath: /datalake/v1/exposure/
+desHeaders:
+ Accept: application/json
+ Content-Type: application/json
+desUsername:
+desPassword:
+
+#consulconfig
+consulHost: '127.0.0.1'
+consulPort: 8500
+consulScheme: 'http'
+consulVerify: True
+consulCert: None
+activateConsulConfig: False \ No newline at end of file
diff --git a/test/configdb/test_configdb_calls.py b/test/configdb/test_configdb_calls.py
index eb799e7..3393991 100644
--- a/test/configdb/test_configdb_calls.py
+++ b/test/configdb/test_configdb_calls.py
@@ -16,7 +16,7 @@
# -------------------------------------------------------------------------
#
-from osdf.optimizers.pciopt.configdb import request
+from apps.pci.optimizers.config_request import request
import osdf.config.loader as config_loader
from osdf.utils.interfaces import json_from_file
from osdf.utils.programming_utils import DotDict
diff --git a/test/functest/scripts/start-simulators.sh b/test/functest/scripts/start-simulators.sh
index a3f3db1..66507d4 100755
--- a/test/functest/scripts/start-simulators.sh
+++ b/test/functest/scripts/start-simulators.sh
@@ -20,7 +20,12 @@
# This script is in osdf/test/functest/scripts/
-SCRIPTDIR=$(dirname $(readlink -f $0))
+if [[ `uname` == "Darwin" ]]
+then
+ SCRIPTDIR=$(dirname $(greadlink -f $0))
+else
+ SCRIPTDIR=$(dirname $(readlink -f $0))
+fi
FUNC_TEST_DIR=$(dirname $SCRIPTDIR)
TEST_DIR=$(dirname $FUNC_TEST_DIR)
OSDF_DIR=$(dirname $TEST_DIR)
diff --git a/test/functest/scripts/stop-simulators.sh b/test/functest/scripts/stop-simulators.sh
index c9dd126..e80a080 100755
--- a/test/functest/scripts/stop-simulators.sh
+++ b/test/functest/scripts/stop-simulators.sh
@@ -23,7 +23,12 @@
# We don't need all the directory names here and the "cd", but it may be needed later on
# Also, it will be a guard against some bad config where the directory doesn't exist
-SCRIPTDIR=$(dirname $(readlink -f $0))
+if [[ `uname` == "Darwin" ]]
+then
+ SCRIPTDIR=$(dirname $(greadlink -f $0))
+else
+ SCRIPTDIR=$(dirname $(readlink -f $0))
+fi
FUNC_TEST_DIR=$(dirname $SCRIPTDIR)
TEST_DIR=$(dirname $FUNC_TEST_DIR)
OSDF_DIR=$(dirname $TEST_DIR)
diff --git a/test/functest/simulators/Dockerfile b/test/functest/simulators/Dockerfile
index 7f6b49f..233503c 100644
--- a/test/functest/simulators/Dockerfile
+++ b/test/functest/simulators/Dockerfile
@@ -17,18 +17,22 @@
# -------------------------------------------------------------------------
#
-FROM ubuntu:16.04
+FROM ubuntu:20.04
+
+ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y \
- && apt-get install -y vim unzip wget libmpfr-dev \
- && apt-get install -y git libqt5printsupport5 build-essential \
- && apt-get install -y python3 python3-setuptools python3-dev \
- && easy_install3 pip \
- && pip install --upgrade virtualenv pip wheel
+ && apt-get install -y --no-install-recommends software-properties-common \
+ curl ca-certificates vim binutils binfmt-support build-essential \
+ python3 python3-setuptools python3-dev \
+ && ln -s /usr/bin/python3.8 /usr/bin/python \
+ && curl -s https://bootstrap.pypa.io/get-pip.py | python \
+ && python -m pip --no-cache-dir install --upgrade pip wheel setuptools \
+ && rm -rf /var/lib/apt/lists/*
-RUN ln -s /usr/bin/python3.5 /usr/bin/python
-ADD requirements.txt /requirements.txt
+COPY requirements.txt /requirements.txt
RUN pip install -r requirements.txt
-ADD sim /sim
+COPY sim /sim
+COPY start_sim.sh /start_sim.sh
-CMD cd /sim && python oof_dependencies_simulators.py > simulator-logs 2>&1 \ No newline at end of file
+CMD ["/start_sim.sh"] \ No newline at end of file
diff --git a/test/functest/simulators/aai/response-payloads/nsi_instance.json b/test/functest/simulators/aai/response-payloads/nsi_instance.json
new file mode 100644
index 0000000..b09d2e4
--- /dev/null
+++ b/test/functest/simulators/aai/response-payloads/nsi_instance.json
@@ -0,0 +1,13 @@
+{
+ "service-instance-id": "9629e36c-a3d9-4aed-8368-f72b8be1cd34",
+ "service-instance-name": "nsi_test_0211",
+ "service-type": "embb",
+ "service-role": "nsi",
+ "environment-context": "cn",
+ "model-invariant-id": "21d57d4b-52ad-4d3c-a798-248b5bb9124a",
+ "model-version-id": "bfba363e-e39c-4bd9-a9d5-1371c28f4d22",
+ "resource-version": "1581418601616",
+ "orchestration-status": "active",
+ "relationship-list": {
+ "relationship": [
+]}}
diff --git a/test/functest/simulators/aai/response-payloads/nsi_instance_with_args.json b/test/functest/simulators/aai/response-payloads/nsi_instance_with_args.json
new file mode 100644
index 0000000..19e5ac1
--- /dev/null
+++ b/test/functest/simulators/aai/response-payloads/nsi_instance_with_args.json
@@ -0,0 +1,45 @@
+{
+ "service-instance-id": "9629e36c-a3d9-4aed-8368-f72b8be1cd34",
+ "service-instance-name": "nsi_test_0211",
+ "service-type": "embb",
+ "service-role": "nsi",
+ "environment-context": "cn",
+ "model-invariant-id": "21d57d4b-52ad-4d3c-a798-248b5bb9124a",
+ "model-version-id": "bfba363e-e39c-4bd9-a9d5-1371c28f4d22",
+ "resource-version": "1581418601616",
+ "orchestration-status": "active",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "allotted-resource",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "related-link": "/aai/v23/business/customers/customer/5GCustomer/service-subscriptions/service-subscription/5G/service-instances/service-instance/d88b6ce6-19be-439d-8553-4f9d6cce0494/allotted-resources/allotted-resource/07138106-f535-413b-b002-40ba24f95937",
+ "relationship-data": [
+ {
+ "relationship-key": "customer.global-customer-id",
+ "relationship-value": "5GCustomer"
+ },
+ {
+ "relationship-key": "service-subscription.service-type",
+ "relationship-value": "5G"
+ },
+ {
+ "relationship-key": "service-instance.service-instance-id",
+ "relationship-value": "cdad9f49-4201-4e3a-aac1-b0f27902c299"
+ },
+ {
+ "relationship-key": "allotted-resource.id",
+ "relationship-value": "07138106-f535-413b-b002-40ba24f95937"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "allotted-resource.description"
+ },
+ {
+ "property-key": "allotted-resource.allotted-resource-name",
+ "property-value": "Allotted_coe"
+ }
+ ]
+ }
+]}}
diff --git a/test/functest/simulators/build_sim_image.sh b/test/functest/simulators/build_sim_image.sh
index c035e9a..561db19 100755
--- a/test/functest/simulators/build_sim_image.sh
+++ b/test/functest/simulators/build_sim_image.sh
@@ -18,13 +18,23 @@
# -------------------------------------------------------------------------
#
-SCRIPTDIR=$(dirname $(readlink -f $0))
+if [[ `uname` == "Darwin" ]]
+then
+ SCRIPTDIR=$(dirname $(greadlink -f $0))
+else
+ SCRIPTDIR=$(dirname $(readlink -f $0))
+fi
+
FUNC_TEST_DIR=$(dirname $SCRIPTDIR)
TEST_DIR=$(dirname $FUNC_TEST_DIR)
SIMULATORS_DIR=$FUNC_TEST_DIR/simulators
OSDF_DIR=$(dirname $TEST_DIR)
DOCKER_DIR=$SIMULATORS_DIR/tmp_docker
+echo "Before Docker Build"
+cat $OSDF_DIR/requirements-sim.txt
+echo $OSDF_DIR
+
mkdir -p $DOCKER_DIR/sim/osdf/policy/response-payloads/pdp-has-vcpe-good
cp $SIMULATORS_DIR/Dockerfile $DOCKER_DIR/.
@@ -32,13 +42,17 @@ cp $SIMULATORS_DIR/Dockerfile $DOCKER_DIR/.
cp -r $OSDF_DIR/osdf $DOCKER_DIR/sim
mkdir -p $DOCKER_DIR/sim/config/
cp $SIMULATORS_DIR/simulated-config/*.yaml $DOCKER_DIR/sim/config/
+cp $SIMULATORS_DIR/simulated-config/*.yml $DOCKER_DIR/sim/config/
cp $SIMULATORS_DIR/simulated-config/*.config $DOCKER_DIR/sim/config/
cp -r $SIMULATORS_DIR/configdb $DOCKER_DIR/sim
cp -r $SIMULATORS_DIR/has-api $DOCKER_DIR/sim
cp -r $SIMULATORS_DIR/policy $DOCKER_DIR/sim
+cp -r $SIMULATORS_DIR/aai $DOCKER_DIR/sim
cp $TEST_DIR/policy-local-files/*.json $DOCKER_DIR/sim/policy/response-payloads/pdp-has-vcpe-good
+cp $TEST_DIR/placement-tests/policy_response.json $DOCKER_DIR/sim/policy/response-payloads/
cp $SIMULATORS_DIR/oof_dependencies_simulators.py $DOCKER_DIR/sim/oof_dependencies_simulators.py
-cp $OSDF_DIR/requirements.txt $DOCKER_DIR
+cp $OSDF_DIR/requirements-sim.txt $DOCKER_DIR/requirements.txt
+cp -r $SIMULATORS_DIR/start_sim.sh $DOCKER_DIR/
cd $DOCKER_DIR
diff --git a/test/functest/simulators/configdb/response-payloads/getCellList-1000.json b/test/functest/simulators/configdb/response-payloads/getCellList-netw1000.json
index df23f6e..df23f6e 100644
--- a/test/functest/simulators/configdb/response-payloads/getCellList-1000.json
+++ b/test/functest/simulators/configdb/response-payloads/getCellList-netw1000.json
diff --git a/test/functest/simulators/configdb/response-payloads/getCellList-netw2000.json b/test/functest/simulators/configdb/response-payloads/getCellList-netw2000.json
new file mode 100644
index 0000000..77cf7db
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getCellList-netw2000.json
@@ -0,0 +1 @@
+["cell20","cell21","cell22","cell23","cell24"] \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell0.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell0.json
index e0986d8..ff291fb 100644
--- a/test/functest/simulators/configdb/response-payloads/getNbrList-cell0.json
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell0.json
@@ -1,10 +1,15 @@
-[
- {
- "cellId": "cell1",
- "pciValue": 1
- },
- {
- "cellId": "cell2",
- "pciValue": 2
- }
-] \ No newline at end of file
+{
+ "cellId": "cell0",
+ "nbrList": [
+ {
+ "targetCellId": "cell1",
+ "pciValue": 1,
+ "ho": true
+ },
+ {
+ "targetCellId": "cell2",
+ "pciValue": 2,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell1.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell1.json
index d6ed353..3c487e8 100644
--- a/test/functest/simulators/configdb/response-payloads/getNbrList-cell1.json
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell1.json
@@ -1,10 +1,15 @@
-[
- {
- "cellId": "cell0",
- "pciValue": 0
- },
- {
- "cellId": "cell2",
- "pciValue": 2
- }
-] \ No newline at end of file
+{
+ "cellId": "cell1",
+ "nbrList": [
+ {
+ "targetCellId": "cell0",
+ "pciValue": 0,
+ "ho": true
+ },
+ {
+ "targetCellId": "cell2",
+ "pciValue": 2,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell2.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell2.json
index 1ea80be..20a8c98 100644
--- a/test/functest/simulators/configdb/response-payloads/getNbrList-cell2.json
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell2.json
@@ -1,10 +1,15 @@
-[
- {
- "cellId": "cell0",
- "pciValue": 0
- },
- {
- "cellId": "cell1",
- "pciValue": 1
- }
-] \ No newline at end of file
+{
+ "cellId": "cell2",
+ "nbrList": [
+ {
+ "targetCellId": "cell0",
+ "pciValue": 0,
+ "ho": true
+ },
+ {
+ "targetCellId": "cell1",
+ "pciValue": 1,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell20.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell20.json
new file mode 100644
index 0000000..d4e754f
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell20.json
@@ -0,0 +1,20 @@
+{
+ "cellId": "cell20",
+ "nbrList": [
+ {
+ "targetCellId": "cell21",
+ "pciValue": 0,
+ "ho": true
+ },
+ {
+ "targetCellId": "cell22",
+ "pciValue": 1,
+ "ho": true
+ },
+ {
+ "targetCellId": "cell23",
+ "pciValue": 2,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell21.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell21.json
new file mode 100644
index 0000000..a1d6f55
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell21.json
@@ -0,0 +1,10 @@
+{
+ "cellId": "cell21",
+ "nbrList": [
+ {
+ "targetCellId": "cell20",
+ "pciValue": 0,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell22.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell22.json
new file mode 100644
index 0000000..9c16aec
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell22.json
@@ -0,0 +1,10 @@
+{
+ "cellId": "cell22",
+ "nbrList": [
+ {
+ "targetCellId": "cell20",
+ "pciValue": 0,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell23.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell23.json
new file mode 100644
index 0000000..ac3bf6f
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell23.json
@@ -0,0 +1,10 @@
+{
+ "cellId": "cell23",
+ "nbrList": [
+ {
+ "targetCellId": "cell24",
+ "pciValue": 0,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/configdb/response-payloads/getNbrList-cell24.json b/test/functest/simulators/configdb/response-payloads/getNbrList-cell24.json
new file mode 100644
index 0000000..f34128e
--- /dev/null
+++ b/test/functest/simulators/configdb/response-payloads/getNbrList-cell24.json
@@ -0,0 +1,10 @@
+{
+ "cellId": "cell24",
+ "nbrList": [
+ {
+ "targetCellId": "cell23",
+ "pciValue": 2,
+ "ho": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/functest/simulators/oof_dependencies_simulators.py b/test/functest/simulators/oof_dependencies_simulators.py
index b7e6cb5..d7b1f04 100755..100644
--- a/test/functest/simulators/oof_dependencies_simulators.py
+++ b/test/functest/simulators/oof_dependencies_simulators.py
@@ -22,6 +22,7 @@ Simulators for dependencies of OSDF (e.g. HAS-API, Policy, SO-callback, etc.)
import glob
import json
import os
+
from flask import Flask, jsonify, request
from osdf.utils.interfaces import json_from_file
@@ -93,22 +94,64 @@ def get_policies(sub_component):
return jsonify(list_json)
-@app.route("/simulated/configdb/getCellList", methods=["GET"])
-def get_cell_list():
+@app.route("/simulated/policy/pdpx/decision/v1", methods=["POST"])
+def get_pdx_policies():
+ """
+ get the pdpx policy
+ """
+ return jsonify(json_from_file("policy/response-payloads/policy_response.json"))
+
+
+@app.route("/simulated/configdb/getCellList/<network_id>/<ts>", methods=["GET"])
+def get_cell_list(network_id, ts):
data, status = get_payload_for_simulated_component('configdb',
- 'getCellList-' + request.args.get('networkId') + '.json')
+ 'getCellList-' + network_id + '.json')
if not status:
return jsonify(data)
return jsonify(data), 503
-@app.route("/simulated/configdb/getNbrList", methods=["GET"])
-def get_nbr_list():
- data, status = get_payload_for_simulated_component('configdb', 'getNbrList-' + request.args.get('cellId') + '.json')
+@app.route("/simulated/configdb/getNbrList/<cell_id>/<ts>", methods=["GET"])
+def get_nbr_list(cell_id, ts):
+ data, status = get_payload_for_simulated_component('configdb', 'getNbrList-' + cell_id + '.json')
if not status:
return jsonify(data)
return jsonify(data), 503
+@app.route("/simulated/aai/v23/nodes/service-instances/service-instance/<service_id>", methods=["GET"])
+def get_aai_instances(service_id):
+ data, status = get_payload_for_simulated_component('aai', 'nsi_instance.json')
+ if not status:
+ return jsonify(data)
+ return jsonify(data), 503
+
+@app.route("/simulated/aai/v23/dsl", methods=["PUT"])
+def dsl_query():
+
+ nssi_query = {"dsl": "service-instance*('service-instance-id','9629e36c-a3d9-4aed-8368-f72b8be1cd34')('workload-context', 'CN') > "
+ "service-instance*('service-role','nsi')"}
+
+ nssi_with_nsi_query = {"dsl": "service-instance*('service-instance-id','9629e36c-a3d9-4aed-8368-f72b8be1cd34')('workload-context', 'CN') > "
+ "service-instance*('service-role','nsi')('service-instance-id',"
+ "'660ca85c-1a0f-4521-a559-65f23e794699')"}
+
+ queries = {
+ "nssi_query": nssi_query,
+ "nssi_with_nsi": nssi_with_nsi_query
+ }
+
+ count = {
+ "nssi_query": 1,
+ "nssi_with_nsi": 2
+ }
+
+ request_body = request.get_json()
+ service_count = 0
+ for query_type, query in queries.items():
+ if request_body == query:
+ service_count = count[query_type]
+ return {'results': [{'service-instance': service_count}]}
+
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json
index 6f0ecb3..2953589 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json
@@ -1,7 +1,7 @@
{
- "service": "zone",
- "policyName": "OSDF_R2.Affinity_vCPE_1",
- "description": "Optimization query policy for vCPE",
+ "service": "affinityPolicy",
+ "policyName": "OSDF_DUBLIN.Affinity_vCPE_1",
+ "description": "Zone policy for vCPE",
"templateVersion": "OpenSource.version.1",
"version": "test1",
"priority": "3",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json
index 2578544..010cf3f 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json
@@ -1,6 +1,6 @@
{
"service": "vim_fit",
- "policyName": "OSDF_R2.Capacity_vGMuxInfra",
+ "policyName": "OSDF_DUBLIN.Capacity_vGMuxInfra",
"description": "Capacity policy for vGMuxInfra",
"templateVersion": "OpenSource.version.1",
"version": "test1",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json
index c1682fa..fedcc4f 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json
@@ -1,6 +1,6 @@
{
"service": "vim_fit",
- "policyName": "OSDF_R2.Capacity_vG_1",
+ "policyName": "OSDF_DUBLIN.Capacity_vG_1",
"description": "Capacity policy for vG",
"templateVersion": "OpenSource.version.1",
"version": "test1",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json
index 61ec500..e3ba83c 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json
@@ -1,6 +1,6 @@
{
- "service": "distance_to_location",
- "policyName": "OSDF_R2.Distance_vGMuxInfra",
+ "service": "distancePolicy",
+ "policyName": "OSDF_DUBLIN.Distance_vGMuxInfra",
"description": "Distance Policy for vGMuxInfra",
"templateVersion": "OpenSource.version.1",
"version": "test1",
@@ -10,13 +10,13 @@
"guard": "False",
"content": {
"distanceProperties": {
- "locationInfo": "customer_location",
+ "locationInfo": "customer_loc",
"distance": { "value": "500", "operator": "<", "unit": "km" }
},
"identity": "distance-vGMuxInfra",
"resources": ["vGMuxInfra"],
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "policyType": "distancePolicy",
+ "policyType": "distance_to_location",
"applicableResources": "any"
}
}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json
index 06c3ada..c498c7a 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json
@@ -1,6 +1,6 @@
{
- "service": "distance_to_location",
- "policyName": "OSDF_R2.Distance_vG_1",
+ "service": "distancePolicy",
+ "policyName": "OSDF_DUBLIN.Distance_vG_1",
"description": "Distance Policy for vG",
"templateVersion": "OpenSource.version.1",
"version": "test1",
@@ -10,13 +10,13 @@
"guard": "False",
"content": {
"distanceProperties": {
- "locationInfo": "customer_location",
+ "locationInfo": "customer_loc",
"distance": { "value": "1500", "operator": "<", "unit": "km" }
},
"identity": "distance-vG",
"resources": ["vG"],
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "policyType": "distancePolicy",
+ "policyType": "distance_to_location",
"applicableResources": "any"
}
}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json
index ab3c586..9b062b0 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json
@@ -1,6 +1,6 @@
{
- "service": "placementOptimization",
- "policyName": "OSDF_R2.Placement_Optimization_1",
+ "service": "optimizationPolicy",
+ "policyName": "OSDF_DUBLIN.Placement_Optimization_1",
"description": "Placement Optimization Policy for vGMuxInfra",
"templateVersion": "OpenSource.version.1",
"version": "test1",
@@ -30,13 +30,26 @@
"parameter": "hpa_score",
"weight": "200",
"operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
}
],
"operator": "sum"
},
"identity": "optimization",
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
- "policyType": "placementOptimization",
+ "policyType": "placement_optimization",
"objective": "minimize"
}
}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json
index 27f49d2..5097964 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json
@@ -1,7 +1,7 @@
{
- "service": "optimizationQueryPolicy",
- "policyName": "OSDF_R2.QueryPolicy_vCPE",
- "description": "Optimization query policy for vCPE",
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.QueryPolicy_vCPE",
+ "description": "Query policy for vCPE",
"templateVersion": "OpenSource.version.1",
"version": "test1",
"priority": "3",
@@ -14,7 +14,7 @@
{"attribute":"customerLongitude", "attribute_location": "customerLongitude"}
],
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
- "policyType": "optimizationQueryPolicy",
+ "policyType": "request_param_query",
"serviceName": "vCPE",
"identity": "vCPE_Query_Policy"
}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json
index 7f1db83..e398f39 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json
@@ -1,10 +1,10 @@
{
- "service": "optimizationQueryPolicy",
- "policyName": "oofBeijing.queryPolicy_vCPE",
- "description": "Optimization query policy for vCPE",
- "templateVersion": "0.0.1",
- "version": "oofBeijing",
- "priority": "5",
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.queryPolicy_vCPE",
+ "description": "Query policy for vCPE",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
"riskType": "test",
"riskLevel": "2",
"guard": "False",
@@ -17,7 +17,8 @@
{"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": 2.2}
],
"serviceName": "vCPE",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG", "optimizationQueryPolicy"],
- "policyType": "optimizationQueryPolicy"
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+ "policyType": "request_param_query",
+ "identity": "vCPE_Query_Policy"
}
}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json
index ce0b7e3..690f5dc 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json
@@ -1,6 +1,6 @@
{
"service": "hpaPolicy",
- "policyName": "OSDF_R2.hpa_policy_vGMuxInfra_1",
+ "policyName": "OSDF_DUBLIN.hpa_policy_vGMuxInfra_1",
"description": "HPA policy for vGMuxInfra",
"templateVersion": "OpenSource.version.1",
"version": "test1",
@@ -9,10 +9,10 @@
"riskLevel": "2",
"guard": "False",
"content": {
- "resources": "vGMuxInfra",
- "identity": "hpaPolicy_vGMuxInfra",
+ "resources": ["vGMuxInfra"],
+ "identity": "hpa-vGMuxInfra",
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "policyType": "hpaPolicy",
+ "policyType": "hpa",
"flavorFeatures": [
{
"id": "vgmux_1",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json
index 5d2499f..b29c67d 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json
@@ -1,6 +1,6 @@
{
"service": "hpaPolicy",
- "policyName": "OSDF_R2.hpa_policy_vG_1",
+ "policyName": "OSDF_DUBLIN.hpa_policy_vG_1",
"description": "HPA policy for vG",
"templateVersion": "OpenSource.version.1",
"version": "test1",
@@ -9,10 +9,10 @@
"riskLevel": "2",
"guard": "False",
"content": {
- "resources": "vG",
- "identity": "hpaPolicy_vG",
+ "resources": ["vG"],
+ "identity": "hpa-vG",
"policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "policyType": "hpaPolicy",
+ "policyType": "hpa",
"flavorFeatures": [
{
"id": "vg_1",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json
index d215078..b047686 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json
@@ -1,6 +1,6 @@
{
"service": "vnfPolicy",
- "policyName": "OSDF_R2.vnfPolicy_vG",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vG",
"description": "vnfPolicy",
"templateVersion": "OpenSource.version.1",
"version": "test1",
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json
index 6849105..45d67f6 100644
--- a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json
+++ b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json
@@ -1,6 +1,6 @@
{
"service": "vnfPolicy",
- "policyName": "OSDF_R2.vnfPolicy_vGMuxInfra",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vGMuxInfra",
"description": "vnfPolicy",
"templateVersion": "OpenSource.version.1",
"version": "test1",
diff --git a/test/functest/simulators/simulated-config/common_config.yaml b/test/functest/simulators/simulated-config/common_config.yaml
index 1a85714..36c639f 100644
--- a/test/functest/simulators/simulated-config/common_config.yaml
+++ b/test/functest/simulators/simulated-config/common_config.yaml
@@ -23,7 +23,7 @@ osdf_temp: # special configuration required for "workarounds" or testing
- hpa_policy_vG_1.json
- vnfPolicy_vG.json
- vnfPolicy_vGMuxInfra.json
- - subscriber_policy.json
+ - subscriber_policy_vCPE.json
service_info:
vCPE:
vcpeHostName: requestParameters.vcpeHostName
@@ -62,3 +62,13 @@ policy_info:
default: # if no explicit service related information is needed
policy_fetch: by_name
policy_scope: none
+
+PCI:
+ ML:
+ average_ho_threshold: 10000
+ latest_ho_threshold: 500
+ DES:
+ service_id: ho_metric
+ filter:
+ interval: 10
+ ml_enabled: false
diff --git a/test/functest/simulators/simulated-config/log.yml b/test/functest/simulators/simulated-config/log.yml
new file mode 100644
index 0000000..ad0de21
--- /dev/null
+++ b/test/functest/simulators/simulated-config/log.yml
@@ -0,0 +1,100 @@
+version: 1
+disable_existing_loggers: True
+
+loggers:
+ error:
+ handlers: [error_handler, console_handler]
+ level: "WARN"
+ propagate: True
+ debug:
+ handlers: [debug_handler, console_handler]
+ level: "DEBUG"
+ propagate: True
+ metrics:
+ handlers: [metrics_handler, console_handler]
+ level: "INFO"
+ propagate: True
+ audit:
+ handlers: [audit_handler, console_handler]
+ level: "INFO"
+ propagate: True
+handlers:
+ debug_handler:
+ level: "DEBUG"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/debug.log"
+ formatter: "debugFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ error_handler:
+ level: "WARN"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/error.log"
+ formatter: "errorFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ metrics_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/metrics.log"
+ formatter: "metricsFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ audit_handler:
+ level: "INFO"
+ class: "logging.handlers.TimedRotatingFileHandler"
+ filename: "logs/audit.log"
+ formatter: "auditFormat"
+ when: midnight
+ interval: 1
+ utc: True
+ delay: False
+ backupCount: 10
+ console_handler:
+ level: "DEBUG"
+ class: "logging.StreamHandler"
+ formatter: "metricsFormat"
+
+formatters:
+ standard:
+ format: "%(asctime)s|||||%(name)s||%(thread)||%(funcName)s||%(levelname)s||%(message)s"
+ debugFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{server}|%(levelname)s|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ errorFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "%(asctime)s.%(msecs)03d+00:00|{requestID}|%(threadName)s|{serviceName}|{partnerName}\
+ |{targetEntity}|{targetServiceName}|%(levelname)s|{errorCode}|{errorDescription}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ auditFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ metricsFormat:
+ format: "%(mdc)s"
+ datefmt: "%Y-%m-%dT%H:%M:%S"
+ mdcfmt: "{entryTimestamp}+00:00|%(asctime)s.%(msecs)03d+00:00|{requestID}|{serviceInstanceID}\
+ |%(threadName)s|{server}|{serviceName}|{partnerName}|{targetEntity}|{targetServiceName}|{statusCode}|{responseCode}|{responseDescription}\
+ |{instanceUUID}|%(levelname)s|{severity}|{serverIPAddress}|{timer}|{server}|{IPAddress}||{unused}\
+ |{processKey}|{TargetVirtualEntity}|{customField1}|{customField2}|{customField3}|{customField4}|%(message)s"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
+ mdcFormat:
+ format: "%(asctime)s.%(msecs)03d+00:00|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s"
+ mdcfmt: "{requestID} {invocationID} {serviceName} {serverIPAddress}"
+ (): osdf.logging.oof_mdc_formatter.OOFMDCFormatter
diff --git a/test/functest/simulators/simulated-config/opteng_config.yaml b/test/functest/simulators/simulated-config/opteng_config.yaml
new file mode 100755
index 0000000..0dfb536
--- /dev/null
+++ b/test/functest/simulators/simulated-config/opteng_config.yaml
@@ -0,0 +1,25 @@
+# Policy Platform -- requires Authorization
+policyPlatformUrl: https://policy-xacml-pdp:6969/policy/pdpx/decision/v1 # Policy Dev platform URL
+
+# AAF Authentication config
+is_aaf_enabled: False
+aaf_cache_expiry_mins: 5
+aaf_url: https://aaftest.simpledemo.onap.org:8095
+aaf_user_roles:
+ - '/optmodel:org.onap.oof.access|*|read ALL'
+ - '/optengine:org.onap.oof.access|*|read ALL'
+
+# Secret Management Service from AAF
+aaf_sms_url: https://aaf-sms.onap:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+
+osdfDatabaseHost: localhost
+osdfDatabaseSchema: osdf
+osdfDatabaseUsername: osdf
+osdfDatabasePassword: osdf
+osdfDatabasePort: 3306
+
+#key
+appkey: os35@rrtky400fdntc#001t5
diff --git a/test/functest/simulators/simulated-config/osdf_config.yaml b/test/functest/simulators/simulated-config/osdf_config.yaml
index dbdcc91..eb02b33 100755
--- a/test/functest/simulators/simulated-config/osdf_config.yaml
+++ b/test/functest/simulators/simulated-config/osdf_config.yaml
@@ -1,3 +1,15 @@
+placementVersioningEnabled: False
+
+# Placement API latest version numbers to be set in HTTP header
+placementMajorVersion: "1"
+placementMinorVersion: "0"
+placementPatchVersion: "0"
+
+# Placement API default version numbers to be set in HTTP header
+placementDefaultMajorVersion: "1"
+placementDefaultMinorVersion: "0"
+placementDefaultPatchVersion: "0"
+
osdfUserNameForSO: "" # The OSDF Manager username for MSO.
odfPasswordForSO: "" # The OSDF Manager password for MSO.
@@ -10,6 +22,8 @@ conductorUsername: "CONDUCTOR-USER"
conductorPassword: "CONDUCTOR-PASSWD"
conductorPingWaitTime: 2 # seconds to wait before calling the conductor retry URL
conductorMaxRetries: 5 # if we don't get something in 30 minutes, give up
+# versions to be set in HTTP header
+conductorMinorVersion: 0
# Policy Platform -- requires ClientAuth, Authorization, and Environment
policyPlatformUrl: http://127.0.0.1:5001/simulated/policy/pdp-has-vcpe-good/pdp/getConfig # Policy Dev platform URL
@@ -33,6 +47,21 @@ osdfPlacementUrl: "http://127.0.0.1:24699/osdf/api/v2/placement"
osdfPlacementUsername: "test"
osdfPlacementPassword: "testpwd"
+# AAF Authentication config
+is_aaf_enabled: False
+aaf_cache_expiry_hrs: 3
+aaf_url: https://aaftest.simpledemo.onap.org:8095
+aaf_user_roles:
+ - /api/oof/v1/placement:org.onap.osdf.access|*|read ALL
+
+# Secret Management Service from AAF
+aaf_sms_url: https://aaf-sms.onap:10443
+aaf_sms_timeout: 30
+secret_domain: osdf
+aaf_ca_certs: ssl_certs/aaf_root_ca.cer
+
+configClientType: configdb
+
# config db api
configDbUrl: http://127.0.0.1:5000/simulated/configdb
configDbUserName: osdf
@@ -44,3 +73,16 @@ configDbGetNbrListUrl: 'getNbrList'
pciHMSUsername: "" # pcihandler username for call back.
pciHMSPassword: "" # pcihandler password for call back.
+aaiUrl: "https://api.url:30233"
+aaiGetLinksUrl: "/aai/v16/network/logical-links"
+aaiGetControllersUrl: /aai/v19/external-system/esr-thirdparty-sdnc-list
+controllerQueryUrl: /aai/v19/query?format=resource
+aaiGetInterDomainLinksUrl: /aai/v19/network/logical-links?link-type=inter-domain&operational-status=up
+
+#consulconfig
+consulHost: '127.0.0.1'
+consulPort: 8500
+consulScheme: 'http'
+consulVerify: True
+consulCert: None
+activateConsulConfig: False
diff --git a/test/functest/simulators/simulated-config/slicing_config.yaml b/test/functest/simulators/simulated-config/slicing_config.yaml
new file mode 100644
index 0000000..179f54a
--- /dev/null
+++ b/test/functest/simulators/simulated-config/slicing_config.yaml
@@ -0,0 +1,96 @@
+app_info:
+ NSI:
+ app_name: slice_selection
+ requirements_field: serviceProfile
+ model_info: NSTInfo
+ NSSI:
+ app_name: subnet_selection
+ requirements_field: sliceProfile
+ model_info: NSSTInfo
+
+attribute_mapping:
+ camel_to_snake:
+ maxBandwidth: max_bandwidth
+ jitter: jitter
+ sST: sst
+ latency: latency
+ resourceSharingLevel: resource_sharing_level
+ uEMobilityLevel: ue_mobility_level
+ maxNumberofUEs: max_number_of_ues
+ dLThptPerUE: dl_thpt_per_ue
+ uLThptPerUE: ul_thpt_per_ue
+ sNSSAI: s_nssai
+ pLMNIdList: plmn_id_list
+ activityFactor: activity_factor
+ coverageAreaTAList: coverage_area_ta_list
+ availability: availability
+ cSAvailabilityTarget: cs_availability_target
+ reliability: reliability
+ cSReliabilityMeanTime: cs_reliability_mean_time
+ dLThptPerSlice: dl_thpt_per_slice
+ expDataRateDL: exp_data_rate_dl
+ uLThptPerSlice: ul_thpt_per_slice
+ expDataRateUL: exp_data_rate_ul
+ maxPktSize: max_pkt_size
+ msgSizeByte: msg_size_byte
+ maxNumberofConns: max_number_of_conns
+ maxNumberofPDUSession: max_number_of_pdu_session
+ termDensity: terminal_density
+ survivalTime: survival_time
+ areaTrafficCapDL: area_traffic_cap_dl
+ areaTrafficCapUL: area_traffic_cap_ul
+ overallUserDensity: overall_user_density
+ transferIntervalTarget: transfer_interval_target
+ expDataRate: exp_data_rate
+ security: security
+ maxThroughput: max_throughput
+ sliceProfileId: slice_profile_id
+ snssaiList: s_nssai_list
+ domainType: domain_type
+ logicInterfaceId: logical_interface_id
+ ipAddress: ip_address
+ nextHopInfo: next_hop_info
+ perfReq: perf_req
+
+ snake_to_camel:
+ max_bandwidth: maxBandwidth
+ jitter: jitter
+ sst: sST
+ latency: latency
+ resource_sharing_level: resourceSharingLevel
+ ue_mobility_level: uEMobilityLevel
+ max_number_of_ues: maxNumberofUEs
+ dl_thpt_per_ue: dLThptPerUE
+ ul_thpt_per_ue: uLThptPerUE
+ s_nssai: sNSSAI
+ plmn_id_list: pLMNIdList
+ activity_factor: activityFactor
+ coverage_area_ta_list: coverageAreaTAList
+ availability: availability
+ cs_availability_target: cSAvailabilityTarget
+ reliability: reliability
+ cs_reliability_mean_time: cSReliabilityMeanTime
+ dl_thpt_per_slice: dLThptPerSlice
+ exp_data_rate_dl: expDataRateDL
+ ul_thpt_per_slice: uLThptPerSlice
+ exp_data_rate_ul: expDataRateUL
+ max_pkt_size: maxPktSize
+ msg_size_byte: msgSizeByte
+ max_number_of_conns: maxNumberofConns
+ max_number_of_pdu_session: maxNumberofPDUSession
+ terminal_density: termDensity
+ survival_time: survivalTime
+ area_traffic_cap_dl: areaTrafficCapDL
+ area_traffic_cap_ul: areaTrafficCapUL
+ overall_user_density: overallUserDensity
+ transfer_interval_target: transferIntervalTarget
+ exp_data_rate: expDataRate
+ security: security
+ max_throughput: maxThroughput
+ slice_profile_id: sliceProfileId
+ s_nssai_list: snssaiList
+ domain_type: domainType
+ logical_interface_id: logicInterfaceId
+ ip_address: ipAddress
+ next_hop_info: nextHopInfo
+ perf_req: perfReq
diff --git a/test/functest/simulators/start_sim.sh b/test/functest/simulators/start_sim.sh
new file mode 100755
index 0000000..f5935da
--- /dev/null
+++ b/test/functest/simulators/start_sim.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+cd /sim
+python oof_dependencies_simulators.py
diff --git a/test/inter_domain_route_opt/bandwidth_attributes.json b/test/inter_domain_route_opt/bandwidth_attributes.json
new file mode 100644
index 0000000..0de7e51
--- /dev/null
+++ b/test/inter_domain_route_opt/bandwidth_attributes.json
@@ -0,0 +1,176 @@
+{
+ "int-1-bw":{
+ "interface-name":"int1",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ },
+ "int-3-bw":{
+ "interface-name":"int3",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ },
+ "int-4-bw":{
+ "interface-name":"int4",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ },
+ "int-5-bw":{
+ "interface-name":"int5",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ },
+ "int-6-bw":{
+ "interface-name":"int6",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ },
+ "int-7-bw":{
+ "interface-name":"int7",
+ "bandwidth-attributes":{
+ "bandwidth-attribute":[
+ {
+ "bwa-id":"bw6",
+ "resource-version":"1596387588545",
+ "available-bandwidth-map":{
+ "available-bandwidth":[
+ {
+ "ab-id":"ab226",
+ "odu-type":"ODU2",
+ "number":1,
+ "resource-version":"1596387588545"
+ },
+ {
+ "ab-id":"ab112",
+ "odu-type":"ODU4",
+ "number":8,
+ "resource-version":"1596387588545"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "resource-version":"1596387588545",
+ "in-maint":false
+ }
+}
diff --git a/test/inter_domain_route_opt/controllers_for_interfaces.json b/test/inter_domain_route_opt/controllers_for_interfaces.json
new file mode 100644
index 0000000..3de47d1
--- /dev/null
+++ b/test/inter_domain_route_opt/controllers_for_interfaces.json
@@ -0,0 +1,62 @@
+{
+ "int-1-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller1",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ },
+ "int-3-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller2",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ },
+ "int-4-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller2",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ },
+ "int-5-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller3",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ },
+ "int-6-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller3",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ },
+ "int-7-cont":{
+ "results":[
+ {
+ "esr-thirdparty-sdnc":{
+ "thirdparty-sdnc-id":"Controller4",
+ "resource-version":"1593421890494"
+ }
+ }
+ ]
+ }
+}
diff --git a/test/inter_domain_route_opt/controllers_list.json b/test/inter_domain_route_opt/controllers_list.json
new file mode 100644
index 0000000..158f530
--- /dev/null
+++ b/test/inter_domain_route_opt/controllers_list.json
@@ -0,0 +1,16 @@
+{
+ "esr-thirdparty-sdnc":[
+ {
+ "thirdparty-sdnc-id":"Controller1"
+ },
+ {
+ "thirdparty-sdnc-id":"Controller2"
+ },
+ {
+ "thirdparty-sdnc-id":"Controller3"
+ },
+ {
+ "thirdparty-sdnc-id":"Controller4"
+ }
+ ]
+}
diff --git a/test/inter_domain_route_opt/get_links.json b/test/inter_domain_route_opt/get_links.json
new file mode 100644
index 0000000..0e70523
--- /dev/null
+++ b/test/inter_domain_route_opt/get_links.json
@@ -0,0 +1,157 @@
+{
+ "logical-link":[
+ {
+ "link-name":"link1",
+ "in-maint":false,
+ "link-type":"inter-domain",
+ "resource-version":"1588952379221",
+ "operational-status":"up",
+ "relationship-list":{
+ "relationship":[
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf1/p-interfaces/p-interface/int1",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf1"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int1"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf2/p-interfaces/p-interface/int3",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf2"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int3"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name":"link2",
+ "in-maint":false,
+ "link-type":"inter-domain",
+ "resource-version":"1588952379221",
+ "operational-status":"up",
+ "relationship-list":{
+ "relationship":[
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf2/p-interfaces/p-interface/int4",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf2"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int4"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf3/p-interfaces/p-interface/int5",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf3"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int5"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name":"link3",
+ "in-maint":false,
+ "link-type":"inter-domain",
+ "resource-version":"1588952379221",
+ "operational-status":"up",
+ "relationship-list":{
+ "relationship":[
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf3/p-interfaces/p-interface/int6",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf3"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int6"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to":"p-interface",
+ "relationship-label":"tosca.relationships.network.LinksTo",
+ "related-link":"/aai/v19/network/pnfs/pnf/pnf4/p-interfaces/p-interface/int7",
+ "relationship-data":[
+ {
+ "relationship-key":"pnf.pnf-name",
+ "relationship-value":"pnf4"
+ },
+ {
+ "relationship-key":"p-interface.interface-name",
+ "relationship-value":"int7"
+ }
+ ],
+ "related-to-property":[
+ {
+ "property-key":"p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/test/inter_domain_route_opt/request.json b/test/inter_domain_route_opt/request.json
new file mode 100644
index 0000000..041a32f
--- /dev/null
+++ b/test/inter_domain_route_opt/request.json
@@ -0,0 +1,30 @@
+{
+ "requestInfo":{
+ "transactionId":"123456",
+ "requestId":"789456",
+ "callbackUrl":"",
+ "callbackHeader": "",
+ "sourceId":"SDNC",
+ "requestType":"create",
+ "numSolutions":1,
+ "optimizers":[
+ "route"
+ ],
+ "timeout":600
+ },
+ "routeInfo":{
+ "routeRequest":{
+ "srcDetails":{
+ "interfaceId":"int19",
+ "nodeId":"pnf1",
+ "controllerId":"Controller1"
+ },
+ "dstDetails":{
+ "interfaceId":"int20",
+ "nodeId":"pnf4",
+ "controllerId":"Controller3"
+ },
+ "serviceRate":"ODU2"
+ }
+ }
+}
diff --git a/test/logging/test_osdf_logging.py b/test/logging/test_osdf_logging.py
index 982ef0b..c8fa3ae 100755
--- a/test/logging/test_osdf_logging.py
+++ b/test/logging/test_osdf_logging.py
@@ -16,13 +16,11 @@
# -------------------------------------------------------------------------
#
import unittest
-import json
-import yaml
+from unittest import mock
from osdf.logging import osdf_logging as L1
-from osdf.logging.osdf_logging import OOF_OSDFLogMessageHelper as MH
-from osdf.logging.osdf_logging import OOF_OSDFLogMessageFormatter as formatter
-from unittest import mock
+from osdf.logging.osdf_logging import OOFOSDFLogMessageFormatter as formatter
+from osdf.logging.osdf_logging import OOFOSDFLogMessageHelper as MH
class TestOSDFLogging(unittest.TestCase):
@@ -45,12 +43,8 @@ class TestOSDFLogging(unittest.TestCase):
self.json_body = mock.MagicMock()
self.F = formatter
- def test_log_handlers_pre_onap(self):
- res = L1.log_handlers_pre_onap()
- assert type(res) == dict
-
def test_format_exception(self):
- res = L1.format_exception(Exception("Some error"))
+ L1.format_exception(Exception("Some error"))
def test_accepted_valid_request(self):
res = formatter.accepted_valid_request(self.req_id, self.request)
@@ -95,7 +89,7 @@ class TestOSDFLogging(unittest.TestCase):
def test_error_calling_back(self):
res = formatter.error_calling_back(self.service_name, self.callback_url, self.err)
assert res.startswith("Error while posting result to callback URL")
-
+
def test_calling_back(self):
res = formatter.calling_back(self.req_id, self.callback_url)
assert res.startswith("Posting result to callback URL")
@@ -168,15 +162,6 @@ class TestOSDFLogging(unittest.TestCase):
"""Log the message to error_log.warn and audit_log.warn"""
L1.warn_audit_error("Some warning message")
- def test_log_message_multi(msg):
- X = L1.log_handlers_pre_onap()
- wanted_methods = [
- X["error"].error, X["error"].warn, X["audit"].info,
- X["metrics"].info, X["debug"].debug, X["error"].fatal
- ]
- L1.log_message_multi("Some log message", *wanted_methods)
-
if __name__ == "__main__":
unittest.main()
-
diff --git a/test/mainapp/test_osdfapp.py b/test/mainapp/test_osdfapp.py
index 7fbe707..e4f12e6 100644
--- a/test/mainapp/test_osdfapp.py
+++ b/test/mainapp/test_osdfapp.py
@@ -15,21 +15,27 @@
#
# -------------------------------------------------------------------------
#
-import osdfapp
+
import unittest
+from unittest import TestCase
+from unittest import mock
+from unittest.mock import patch
-from osdf.operation.exceptions import BusinessException
-from requests import Request, RequestException
+from requests import Request
+from requests import RequestException
from schematics.exceptions import DataError
-from unittest import mock, TestCase
-from unittest.mock import patch
+
+from osdf.apps import baseapp
+from osdf.apps.baseapp import app
+from osdf.operation.exceptions import BusinessException
class TestOSDFApp(TestCase):
def setUp(self):
- self.patcher_g = patch('osdfapp.g', return_value={'request_id':'DUMMY-REQ'})
- self.Mock_g = self.patcher_g.start()
+ with app.app_context():
+ self.patcher_g = patch('osdf.apps.baseapp.g', return_value={'request_id': 'DUMMY-REQ'})
+ self.Mock_g = self.patcher_g.start()
# self.patcher2 = patch('package.module.Class2')
# self.MockClass2 = self.patcher2.start()
@@ -44,31 +50,30 @@ class TestOSDFApp(TestCase):
e.response.content = "Some request exception occurred"
# request().raise_for_status.side_effect = e
return e
-
+
def test_handle_business_exception(self):
e = BusinessException("Business Exception Description")
- resp = osdfapp.handle_business_exception(e)
+ resp = baseapp.handle_business_exception(e)
assert resp.status_code == 400
def test_handle_request_exception(self):
e = self.dummy_request_exception()
- resp = osdfapp.handle_request_exception(e)
+ resp = baseapp.handle_request_exception(e)
assert resp.status_code == 400
def test_handle_data_error(self):
e = DataError({"A1": "A1 Data Error"})
- resp = osdfapp.handle_data_error(e)
+ resp = baseapp.handle_data_error(e)
assert resp.status_code == 400
def test_internal_failure(self):
e = Exception("An Internal Error")
- resp = osdfapp.internal_failure(e)
+ resp = baseapp.internal_failure(e)
assert resp.status_code == 500
def test_get_options_default(self):
- opts = osdfapp.get_options(["PROG"]) # ensure nothing breaks
+ baseapp.get_options(["PROG"]) # ensure nothing breaks
if __name__ == "__main__":
unittest.main()
-
diff --git a/test/optengine-tests/test_modelapi_invalid.json b/test/optengine-tests/test_modelapi_invalid.json
new file mode 100644
index 0000000..a58258e
--- /dev/null
+++ b/test/optengine-tests/test_modelapi_invalid.json
@@ -0,0 +1,13 @@
+{
+ "requestInfo": {
+ "transactinId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt"
+ },
+ "modelInfo": {
+ "modelId": "model2",
+ "solver": "mzn",
+ "description": "graph coloring problem for australia",
+ "modelContent": "int: nc;\r\nvar 1 .. nc: wa; var 1 .. nc: nt; var 1 .. nc: sa; var 1 .. nc: q;\r\nvar 1 .. nc: nsw; var 1 .. nc: v; var 1 .. nc: t;\r\nconstraint wa != nt;\r\nconstraint wa != sa;\r\nconstraint nt != sa;\r\nconstraint nt != q;\r\nconstraint sa != q;\r\nconstraint sa != nsw;\r\nconstraint sa != v;\r\nconstraint q != nsw;\r\nconstraint nsw != v;\r\nsolve satisfy;\r\noutput [\r\n \"wa=\\(wa)\\t nt=\\(nt)\\t sa=\\(sa)\\n\",\r\n \"q=\\(q)\\t nsw=\\(nsw)\\t v=\\(v)\\n\",\r\n \"t=\", show(t), \"\\n\"\r\n];"
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_modelapi_valid.json b/test/optengine-tests/test_modelapi_valid.json
new file mode 100644
index 0000000..1fbca5b
--- /dev/null
+++ b/test/optengine-tests/test_modelapi_valid.json
@@ -0,0 +1,13 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt"
+ },
+ "modelInfo": {
+ "modelId": "model2",
+ "solver": "mzn",
+ "description": "graph coloring problem for australia",
+ "modelContent": "int: nc;\r\nvar 1 .. nc: wa; var 1 .. nc: nt; var 1 .. nc: sa; var 1 .. nc: q;\r\nvar 1 .. nc: nsw; var 1 .. nc: v; var 1 .. nc: t;\r\nconstraint wa != nt;\r\nconstraint wa != sa;\r\nconstraint nt != sa;\r\nconstraint nt != q;\r\nconstraint sa != q;\r\nconstraint sa != nsw;\r\nconstraint sa != v;\r\nconstraint q != nsw;\r\nconstraint nsw != v;\r\nsolve satisfy;\r\noutput [\r\n \"wa=\\(wa)\\t nt=\\(nt)\\t sa=\\(sa)\\n\",\r\n \"q=\\(q)\\t nsw=\\(nsw)\\t v=\\(v)\\n\",\r\n \"t=\", show(t), \"\\n\"\r\n];"
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_invalid.json b/test/optengine-tests/test_optengine_invalid.json
new file mode 100644
index 0000000..9a0267a
--- /dev/null
+++ b/test/optengine-tests/test_optengine_invalid.json
@@ -0,0 +1,18 @@
+{
+ "requestInfo": {
+ "transactioId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "mzn",
+ "solverArgs": {
+ "solver": "geocode"
+ },
+ "modelContent": "int: nc;\r\nvar 1 .. nc: wa; var 1 .. nc: nt; var 1 .. nc: sa; var 1 .. nc: q;\r\nvar 1 .. nc: nsw; var 1 .. nc: v; var 1 .. nc: t;\r\nconstraint wa != nt;\r\nconstraint wa != sa;\r\nconstraint nt != sa;\r\nconstraint nt != q;\r\nconstraint sa != q;\r\nconstraint sa != nsw;\r\nconstraint sa != v;\r\nconstraint q != nsw;\r\nconstraint nsw != v;\r\nsolve satisfy;\r\noutput [\r\n \"wa=\\(wa)\\t nt=\\(nt)\\t sa=\\(sa)\\n\",\r\n \"q=\\(q)\\t nsw=\\(nsw)\\t v=\\(v)\\n\",\r\n \"t=\", show(t), \"\\n\"\r\n];",
+ "optData": {
+ "nc": 3
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_invalid2.json b/test/optengine-tests/test_optengine_invalid2.json
new file mode 100644
index 0000000..23c5a8e
--- /dev/null
+++ b/test/optengine-tests/test_optengine_invalid2.json
@@ -0,0 +1,15 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+
+ "solverArgs": {
+ "solver": "cbc"
+ },
+ "modelContent": "% Baking cakes for the school fete (with data file)\r\n\r\nint: flour; %no. grams of flour available\r\nint: banana; %no. of bananas available\r\nint: sugar; %no. grams of sugar available\r\nint: butter; %no. grams of butter available\r\nint: cocoa; %no. grams of cocoa available\r\n\r\nconstraint assert(flour >= 0,\"Invalid datafile: \" ++\r\n \"Amount of flour should be non-negative\");\r\nconstraint assert(banana >= 0,\"Invalid datafile: \" ++\r\n \"Amount of banana should be non-negative\");\r\nconstraint assert(sugar >= 0,\"Invalid datafile: \" ++\r\n \"Amount of sugar should be non-negative\");\r\nconstraint assert(butter >= 0,\"Invalid datafile: \" ++\r\n \"Amount of butter should be non-negative\");\r\nconstraint assert(cocoa >= 0,\"Invalid datafile: \" ++\r\n \"Amount of cocoa should be non-negative\");\r\n\r\nvar 0..100: b; % no. of banana cakes\r\nvar 0..100: c; % no. of chocolate cakes\r\n\r\n% flour\r\nconstraint 250*b + 200*c <= flour;\r\n% bananas\r\nconstraint 2*b <= banana;\r\n% sugar\r\nconstraint 75*b + 150*c <= sugar;\r\n% butter\r\nconstraint 100*b + 150*c <= butter;\r\n% cocoa\r\nconstraint 75*c <= cocoa;\r\n\r\n% maximize our profit\r\nsolve maximize 400*b + 450*c;\r\n\r\noutput [\"no. of banana cakes = \\(b)\\n\",\r\n \"no. of chocolate cakes = \\(c)\\n\"];"
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_invalid_solver.json b/test/optengine-tests/test_optengine_invalid_solver.json
new file mode 100644
index 0000000..a967c16
--- /dev/null
+++ b/test/optengine-tests/test_optengine_invalid_solver.json
@@ -0,0 +1,15 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "apy",
+ "modelContent": "import sys\r\n\r\nif __name__ == \"__main__\":\r\n print(sys.argv[1],sys.argv[2])\r\n\r\n with open(sys.argv[2], \"wt\") as f:\r\n f.write('{\"hello\":\"world\",\"another\":\"string\"}')\r\n\r\n",
+ "optData": {
+ "text": "flour = 8000; \r\nbanana = 11; \r\nsugar = 3000; \r\nbutter = 1500; \r\ncocoa = 800; "
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_modelId.json b/test/optengine-tests/test_optengine_modelId.json
new file mode 100644
index 0000000..b676d91
--- /dev/null
+++ b/test/optengine-tests/test_optengine_modelId.json
@@ -0,0 +1,19 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "modelId": "test",
+ "solverArgs": {
+ "solver": "geocode"
+ },
+ "optData": {
+ "json": {
+ "nc": 3
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_no_modelid.json b/test/optengine-tests/test_optengine_no_modelid.json
new file mode 100644
index 0000000..9a8c3a4
--- /dev/null
+++ b/test/optengine-tests/test_optengine_no_modelid.json
@@ -0,0 +1,24 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "mzn",
+ "solverArgs": {
+ "solver": "cbc"
+ },
+ "modelContent": "% Baking cakes for the school fete (with data file)\r\n\r\nint: flour; %no. grams of flour available\r\nint: banana; %no. of bananas available\r\nint: sugar; %no. grams of sugar available\r\nint: butter; %no. grams of butter available\r\nint: cocoa; %no. grams of cocoa available\r\n\r\nconstraint assert(flour >= 0,\"Invalid datafile: \" ++\r\n \"Amount of flour should be non-negative\");\r\nconstraint assert(banana >= 0,\"Invalid datafile: \" ++\r\n \"Amount of banana should be non-negative\");\r\nconstraint assert(sugar >= 0,\"Invalid datafile: \" ++\r\n \"Amount of sugar should be non-negative\");\r\nconstraint assert(butter >= 0,\"Invalid datafile: \" ++\r\n \"Amount of butter should be non-negative\");\r\nconstraint assert(cocoa >= 0,\"Invalid datafile: \" ++\r\n \"Amount of cocoa should be non-negative\");\r\n\r\nvar 0..100: b; % no. of banana cakes\r\nvar 0..100: c; % no. of chocolate cakes\r\n\r\n% flour\r\nconstraint 250*b + 200*c <= flour;\r\n% bananas\r\nconstraint 2*b <= banana;\r\n% sugar\r\nconstraint 75*b + 150*c <= sugar;\r\n% butter\r\nconstraint 100*b + 150*c <= butter;\r\n% cocoa\r\nconstraint 75*c <= cocoa;\r\n\r\n% maximize our profit\r\nsolve maximize 400*b + 450*c;\r\n\r\noutput [\"no. of banana cakes = \\(b)\\n\",\r\n \"no. of chocolate cakes = \\(c)\\n\"];",
+ "optData": {
+ "json": {
+ "flour": 4000,
+ "banana": 6,
+ "sugar": 2000,
+ "butter": 500,
+ "cocoa": 500
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_no_optdata.json b/test/optengine-tests/test_optengine_no_optdata.json
new file mode 100644
index 0000000..f6645c8
--- /dev/null
+++ b/test/optengine-tests/test_optengine_no_optdata.json
@@ -0,0 +1,15 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "mzn",
+ "solverArgs": {
+ "solver": "geocode"
+ },
+ "modelContent": "int: nc;\r\nvar 1 .. nc: wa; var 1 .. nc: nt; var 1 .. nc: sa; var 1 .. nc: q;\r\nvar 1 .. nc: nsw; var 1 .. nc: v; var 1 .. nc: t;\r\nconstraint wa != nt;\r\nconstraint wa != sa;\r\nconstraint nt != sa;\r\nconstraint nt != q;\r\nconstraint sa != q;\r\nconstraint sa != nsw;\r\nconstraint sa != v;\r\nconstraint q != nsw;\r\nconstraint nsw != v;\r\nsolve satisfy;\r\noutput [\r\n \"wa=\\(wa)\\t nt=\\(nt)\\t sa=\\(sa)\\n\",\r\n \"q=\\(q)\\t nsw=\\(nsw)\\t v=\\(v)\\n\",\r\n \"t=\", show(t), \"\\n\"\r\n];"
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_solverid.json b/test/optengine-tests/test_optengine_solverid.json
new file mode 100644
index 0000000..bfd446c
--- /dev/null
+++ b/test/optengine-tests/test_optengine_solverid.json
@@ -0,0 +1,15 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "py",
+ "modelContent": "import sys\r\n\r\nif __name__ == \"__main__\":\r\n print(sys.argv[1],sys.argv[2])\r\n\r\n with open(sys.argv[2], \"wt\") as f:\r\n f.write('{\"hello\":\"world\",\"another\":\"string\"}')\r\n\r\n",
+ "optData": {
+ "text": "flour = 8000; \r\nbanana = 11; \r\nsugar = 3000; \r\nbutter = 1500; \r\ncocoa = 800; "
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_optengine_valid.json b/test/optengine-tests/test_optengine_valid.json
new file mode 100644
index 0000000..8de2b71
--- /dev/null
+++ b/test/optengine-tests/test_optengine_valid.json
@@ -0,0 +1,20 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "mzn",
+ "solverArgs": {
+ "solver": "geocode"
+ },
+ "modelContent": "int: nc;\r\nvar 1 .. nc: wa; var 1 .. nc: nt; var 1 .. nc: sa; var 1 .. nc: q;\r\nvar 1 .. nc: nsw; var 1 .. nc: v; var 1 .. nc: t;\r\nconstraint wa != nt;\r\nconstraint wa != sa;\r\nconstraint nt != sa;\r\nconstraint nt != q;\r\nconstraint sa != q;\r\nconstraint sa != nsw;\r\nconstraint sa != v;\r\nconstraint q != nsw;\r\nconstraint nsw != v;\r\nsolve satisfy;\r\noutput [\r\n \"wa=\\(wa)\\t nt=\\(nt)\\t sa=\\(sa)\\n\",\r\n \"q=\\(q)\\t nsw=\\(nsw)\\t v=\\(v)\\n\",\r\n \"t=\", show(t), \"\\n\"\r\n];",
+ "optData": {
+ "json": {
+ "nc": 3
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/optengine-tests/test_py_optengine_valid.json b/test/optengine-tests/test_py_optengine_valid.json
new file mode 100644
index 0000000..bfd446c
--- /dev/null
+++ b/test/optengine-tests/test_py_optengine_valid.json
@@ -0,0 +1,15 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestID": "yyy-yyy-yyyy",
+ "sourceId": "cmopt",
+ "timeout": 600
+ },
+ "optimInfo": {
+ "solver": "py",
+ "modelContent": "import sys\r\n\r\nif __name__ == \"__main__\":\r\n print(sys.argv[1],sys.argv[2])\r\n\r\n with open(sys.argv[2], \"wt\") as f:\r\n f.write('{\"hello\":\"world\",\"another\":\"string\"}')\r\n\r\n",
+ "optData": {
+ "text": "flour = 8000; \r\nbanana = 11; \r\nsugar = 3000; \r\nbutter = 1500; \r\ncocoa = 800; "
+ }
+ }
+} \ No newline at end of file
diff --git a/test/osdf/utils/test_interfaces.py b/test/osdf/utils/test_interfaces.py
index cdb3d7a..8d66e16 100644
--- a/test/osdf/utils/test_interfaces.py
+++ b/test/osdf/utils/test_interfaces.py
@@ -16,12 +16,13 @@
# -------------------------------------------------------------------------
#
import requests
-import unittest
-
from requests.models import Response
-from osdf.utils.interfaces import RestClient, get_rest_client
+import unittest
from unittest.mock import patch
+from osdf.utils.interfaces import get_rest_client
+from osdf.utils.interfaces import RestClient
+
m1 = Response()
m1._content = b'{"msg": "OK"}'
@@ -39,7 +40,7 @@ class TestOsdfUtilsInterfaces(unittest.TestCase):
def test_rc_request(self, mock_good_response):
rc = RestClient()
rc.add_headers({})
- rc.request(req_id="testReq")
+ rc.request(url="http://localhost", req_id="testReq")
@patch('requests.request', return_value=mock_good_response)
def test_rc_request_v1(self, mock_good_response):
@@ -53,7 +54,7 @@ class TestOsdfUtilsInterfaces(unittest.TestCase):
def test_rc_request_v2(self, mock_bad_response):
rc = RestClient()
try:
- rc.request()
+ rc.request(url="http://localhost")
except requests.RequestException:
return
raise Exception("Allows bad requests instead of raising exception")
@@ -66,4 +67,3 @@ class TestOsdfUtilsInterfaces(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
-
diff --git a/test/pci-optimization-tests/fixed_pci.json b/test/pci-optimization-tests/fixed_pci.json
new file mode 100644
index 0000000..0038d04
--- /dev/null
+++ b/test/pci-optimization-tests/fixed_pci.json
@@ -0,0 +1,42 @@
+{
+
+ "requestInfo": {
+
+ "transactionId": "xxx-xxx-xxxx",
+
+ "requestId": "yyy-yyy-yyyy",
+
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl/",
+
+ "sourceId": "SO",
+
+ "requestType": "create",
+
+ "numSolutions": 1,
+
+ "optimizers": [
+
+ "pci-anr"
+
+ ],
+
+ "timeout": 600
+
+ },
+
+ "cellInfo": {
+
+ "networkId": "netw2000",
+
+ "cellIdList": [
+
+ "cell0"
+
+ ],
+
+ "fixedPCICells": ["cell21","cell22"],
+ "anrInputList": [{"cellId": "cell20", "removeableNeighbors" :["cell23"]}],
+ "trigger": "NbrListChange"
+ }
+
+}
diff --git a/test/pci-optimization-tests/pci_anr_request.json b/test/pci-optimization-tests/pci_anr_request.json
new file mode 100644
index 0000000..34e2409
--- /dev/null
+++ b/test/pci-optimization-tests/pci_anr_request.json
@@ -0,0 +1,29 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestId": "yyy-yyy-yyyy",
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl/",
+ "sourceId": "SO",
+ "requestType": "create",
+ "numSolutions": 1,
+ "optimizers": [
+ "pci-anr"
+ ],
+ "timeout": 600
+ },
+ "cellInfo": {
+ "networkId": "netw2000",
+ "cellIdList": [
+ "cell20"
+ ]
+ },
+ "anrInputList": [
+ {
+ "cellId": "cell20",
+ "removeableNeighbors": [
+ "cell23"
+ ]
+ }
+ ],
+ "trigger": "NbrListChange"
+} \ No newline at end of file
diff --git a/test/pci-optimization-tests/request.json b/test/pci-optimization-tests/request.json
index 7ec9ab5..a8eb4f6 100644
--- a/test/pci-optimization-tests/request.json
+++ b/test/pci-optimization-tests/request.json
@@ -7,14 +7,14 @@
"requestType": "create",
"numSolutions": 1,
"optimizers": [
- "placement"
+ "pci"
],
"timeout": 600
},
"cellInfo": {
- "networkId": "1000",
+ "networkId": "netw1000",
"cellIdList": [
"cell0"
]
}
-} \ No newline at end of file
+}
diff --git a/test/placement-tests/policy_response.json b/test/placement-tests/policy_response.json
index 8de8537..a257ecc 100644
--- a/test/placement-tests/policy_response.json
+++ b/test/placement-tests/policy_response.json
@@ -1,182 +1,694 @@
-[
{
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"SubscriberPolicy\",\"policyName\":\"oofBeijing.SubscriberPolicy_v1\",\"description\":\"Subscriber Policy\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"1\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"subscriber\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"subscriberpolicy\",\"subscriber_x\",\"subscriber_y\"],\"properties\":{\"subscriberName\":[\"subscriber_x\",\"subscriber_y\"],\"subscriberRole\":[\"PVT Homing\"],\"provStatus\":[\"CAPPED\"]},\"policyType\":\"SubscriberPolicy\"}}",
- "policyName": "oofBeijing.Config_MS_SubscriberPolicy_v1.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "SubscriberPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"hpaPolicy\",\"policyName\":\"oofBeijing.hpaPolicy_vGMuxInfra\",\"description\":\"HPA policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"1.0\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"resources\":\"vGMuxInfra\",\"identity\":\"hpaPolicy_vGMuxInfra\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"hpaPolicy\",\"flavorFeatures\":[{\"flavorLabel\":\"flavor_label_vm_01\",\"flavorProperties\":[{\"hpa-feature\":\"cpuTopology\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numCpusockets\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpusockets\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"4\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"8\",\"operator\":\"<=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"ovsDpdk\",\"mandatory\":\"False\",\"score\":\"3\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"dataProcessingAccelerationLibrary\",\"hpa-attribute-value\":\"ovsDpdk_version\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"cpuInstructionSetExtensions\",\"mandatory\":\"True\",\"architecture\":\"INTEL-64\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"instructionSetExtensions\",\"hpa-attribute-value\":[\"<CPUINST>\",\"<CPUINST>\"],\"operator\":\"ALL\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_02\",\"flavorProperties\":[{\"hpa-feature\":\"cpuPinningy\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"logicalCpuThreadPinningPolicy\",\"hpa-attribute-value\":\"<CPUTHREADPOLICY>\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"logicalCpuPinningPolicy\",\"hpa-attribute-value\":\"<CPUPOLICY>\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"localStorage\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"diskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"ephemeralDiskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"swapMemSize\",\"hpa-attribute-value\":\"16\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"pcie\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"pciCount\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciVendorId\",\"hpa-attribute-value\":\"8086\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciDeviceId\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"functionType\",\"hpa-attribute-value\":\"<PCITYPEVALUE>\",\"operator\":\"=\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_03\",\"flavorProperties\":[{\"hpa-feature\":\"numa\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numaNodes\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaCpu-0\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-0\",\"hpa-attribute-value\":\"2048\",\"operator\":\"=\",\"unit\":\"MB\"},{\"hpa-attribute-key\":\"numaCpu-1\",\"hpa-attribute-value\":\"4\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-1\",\"value\":\"4096\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"hugePages\",\"mandatory\":\"False\",\"score\":\"7\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"memoryPageSize\",\"hpa-attribute-value\":\"<MEMORYPAGESIZE>\",\"operator\":\"=\",\"unit\":\"\"}]}]}]}}",
- "policyName": "oofBeijing.Config_MS_hpaPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "hpaPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vG\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vG\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"international\",\"ip\",\"vG\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vG\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
- "policyName": "oofBeijing.Config_MS_vnfPolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "VnfPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vGMuxInfra\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vGMuxInfra\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vGMuxInfra\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
- "policyName": "oofBeijing.Config_MS_vnfPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "VnfPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vG\",\"description\":\"Distance Policy for vG\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"1500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vG\",\"resources\":[\"vG\"],\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vG\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
- "policyName": "oofBeijing.Config_MS_distancePolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "distancePolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vG\", \"description\": \"Capacity policy for vG\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vG\", \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vG\", \"vim_fit\"], \"resources\": [\"vG\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
- "policyName": "oofBeijing.Config_MS_capacityPolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "capacityPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"optimizationQueryPolicy\", \"policyName\": \"oofBeijing.queryPolicy_vcpe\", \"description\": \"Optimization query policy for vcpe\", \"templateVersion\": \"0.0.1\", \"version\": \"oofBeijing\", \"priority\": \"3\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"queryProperties\": [{\"attribute\": \"locationId\", \"attribute_location\": \"customerLocation\", \"value\": \"\"}, {\"attribute\": \"id\", \"attribute_location\": \"vpnInfo.vpnId\", \"value\": \"\"}, {\"attribute\": \"upstreamBW\", \"attribute_location\": \"vpnInfo.upstreamBW\", \"value\": \"\"}, {\"attribute\": \"customerLatitude\", \"attribute_location\": \"customerLatitude\", \"value\": 32.89748}, {\"attribute\": \"customerLongitude\", \"attribute_location\": \"customerLongitude\", \"value\": -97.040443}], \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vGMuxInfra\", \"vG\", \"optimizationQueryPolicy\"], \"policyType\": \"optimizationQueryPolicy\"}}",
- "policyName": "oofBeijing.Config_MS_queryPolicy_vcpe.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "optimizationQueryPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"PlacementOptimizationPolicy\",\"policyName\":\"oofBeijing.PlacementOptimizationPolicy_vGMuxInfra\",\"description\":\"Placement Optimization Policy for vGMuxInfra\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"5\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"objectiveParameter\":{\"parameterAttributes\":[{\"resource\":[\"vGMuxInfra\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"},{\"resource\":[\"vG\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"}],\"operator\":\"sum\"},\"identity\":\"optimization\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\",\"vG\"],\"policyType\":\"placementOptimization\",\"objective\":\"minimize\"}}",
- "policyName": "oofBeijing.Config_MS_PlacementOptimizationPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "PlacementOptimizationPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vGMuxInfra\",\"description\":\"Distance Policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vGMuxInfra\",\"resources\":[\"vGMuxInfra\"],\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
- "policyName": "oofBeijing.Config_MS_distancePolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "distancePolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vGMuxInfra\", \"description\": \"Capacity policy for vGMuxInfra\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vGMuxInfra\", \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vGMuxInfra\", \"vim_fit\"], \"resources\": [\"vGMuxInfra\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
- "policyName": "oofBeijing.Config_MS_capacityPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "capacityPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
+ "policies": {
+ "OSDF_FRANKFURT.SubscriberPolicy_v1": {
+ "type": "onap.policies.optimization.SubscriberPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.SubscriberPolicy_v1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "identity": "subscriber_vCPE",
+ "properties": {
+ "subscriberName": [
+ "subscriber_x",
+ "subscriber_y"
+ ],
+ "subscriberRole": [
+ "PVT Homing"
+ ],
+ "provStatus": [
+ "CAPPED"
+ ]
+ }
+ }
+ },
+ "OSDF_FRANKFURT.vnfPolicy_vG": {
+ "type": "onap.policies.optimization.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vG",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vG",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
+ }
+ },
+ "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra": {
+ "type": "onap.policies.optimization.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vGMuxInfra",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "vGMuxInfra-xx",
+ "inventoryType": "service",
+ "customerId": "SDN-ETHERNET-INTERNET",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
+ }
+ },
+ "OSDF_FRANKFURT.Distance_vG_1": {
+ "type": "onap.policies.optimization.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vG",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "1500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
+ },
+ "OSDF_FRANKFURT.Distance_vGMuxInfra": {
+ "type": "onap.policies.optimization.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vGMuxInfra",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
+ },
+ "OSDF_FRANKFURT.Placement_optimization_1": {
+ "type": "onap.policies.optimization.OptimizationPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Placement_optimization_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG",
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "optimization",
+ "objective": "minimize",
+ "objectiveParameter": {
+ "parameterAttributes": [
+ {
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vG"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vG"
+ ],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vFW"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vFW"
+ ],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ }
+ ],
+ "operator": "sum"
+ }
+ }
+ },
+ "OSDF_FRANKFURT.queryPolicy_vCPE": {
+ "type": "onap.policies.optimization.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_vCPE",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra",
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vCPE_Query_Policy",
+ "queryProperties": [
+ {
+ "attribute": "customerLatitude",
+ "attribute_location": "customerLatitude"
+ },
+ {
+ "attribute": "customerLongitude",
+ "attribute_location": "customerLongitude"
+ }
+ ]
+ }
+ },
+ "OSDF_FRANKFURT.hpa_policy_vG_1": {
+ "type": "onap.policies.optimization.HpaPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.hpa_policy_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "hpa-vG",
+ "flavorFeatures": [
+ {
+ "id": "vg_1",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_01",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "cpuTopology",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "2",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "4",
+ "operator": "<=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "2",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "4",
+ "operator": "<=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "4",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "8",
+ "operator": "<=",
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": true,
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "ovsDpdk",
+ "mandatory": false,
+ "score": 3,
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "dataProcessingAccelerationLibrary",
+ "hpa-attribute-value": "ovsDpdk_version",
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "cpuInstructionSetExtensions",
+ "mandatory": true,
+ "architecture": "INTEL-64",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": [
+ "<CPUINST>",
+ "<CPUINST>"
+ ],
+ "operator": [
+ "ALL"
+ ],
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_2",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_02",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "cpuPinningy",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "logicalCpuThreadPinningPolicy",
+ "hpa-attribute-value": "<CPUTHREADPOLICY>",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "logicalCpuPinningPolicy",
+ "hpa-attribute-value": "<CPUPOLICY>",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": "GB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "localStorage",
+ "mandatory": "False",
+ "score": "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "diskSize",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": "GB"
+ },
+ {
+ "hpa-attribute-key": "ephemeralDiskSize",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": "GB"
+ },
+ {
+ "hpa-attribute-key": "swapMemSize",
+ "hpa-attribute-value": "16",
+ "operator": "=",
+ "unit": "MB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "pciePassthrough",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "pciCount",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "pciVendorId",
+ "hpa-attribute-value": "8086",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "pciDeviceId",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_03",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "numa",
+ "mandatory": "False",
+ "score": "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numaNodes",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaCpu-0",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaMem-0",
+ "hpa-attribute-value": "2048",
+ "operator": "=",
+ "unit": "MB"
+ },
+ {
+ "hpa-attribute-key": "numaCpu-1",
+ "hpa-attribute-value": "4",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaMem-1",
+ "value": "4096",
+ "operator": "=",
+ "unit": "MB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": "GB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "hugePages",
+ "mandatory": "False",
+ "score": "7",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "memoryPageSize",
+ "hpa-attribute-value": "<MEMORYPAGESIZE>",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "OSDF_FRANKFURT.Capacity_vG_1": {
+ "type": "onap.policies.optimization.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vG",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
+ }
+ },
+ "OSDF_FRANKFURT.Capacity_vGMuxInfra": {
+ "type": "onap.policies.optimization.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vGMuxInfra",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
+ }
+ }
+ }
}
-] \ No newline at end of file
diff --git a/test/placement-tests/policy_response2.json b/test/placement-tests/policy_response2.json
index 2cd6dcb..15ddbe1 100644
--- a/test/placement-tests/policy_response2.json
+++ b/test/placement-tests/policy_response2.json
@@ -1,182 +1,705 @@
-[
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"SubscriberPolicy\",\"policyName\":\"oofBeijing.SubscriberPolicy_v1\",\"description\":\"Subscriber Policy\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"1\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"subscriber\",\"policyScope\":[\"vCPE\",\"PVT Homing\",\"SubscriberPolicy\",\"subscriber_x\",\"subscriber_y\"],\"properties\":{\"subscriberName\":[\"subscriber_x\",\"subscriber_y\"],\"subscriberRole\":[\"PVT Homing\"],\"provStatus\":[\"CAPPED\"]},\"policyType\":\"SubscriberPolicy\"}}",
- "policyName": "oofBeijing.Config_MS_SubscriberPolicy_v1.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "SubscriberPolicy",
- "uuid": "",
- "Location": ""
+{
+ "policies": {
+ "OSDF_FRANKFURT.SubscriberPolicy_v1": {
+ "type": "onap.policies.optimization.SubscriberPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.SubscriberPolicy_v1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "identity": "subscriber_vCPE",
+ "properties": {
+ "subscriberName": [
+ "subscriber_x",
+ "subscriber_y"
+ ],
+ "subscriberRole": [
+ "PVT Homing"
+ ],
+ "provStatus": [
+ "CAPPED"
+ ]
+ }
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"hpaPolicy\",\"policyName\":\"oofBeijing.hpaPolicy_vGMuxInfra\",\"description\":\"HPA policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"1.0\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"resources\":\"vGMuxInfra\",\"identity\":\"hpaPolicy_vGMuxInfra\",\"policyScope\":[\"vCPE\",\"PVT Homing\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"hpaPolicy\",\"flavorFeatures\":[{\"flavorLabel\":\"flavor_label_vm_01\",\"flavorProperties\":[{\"hpa-feature\":\"cpuTopology\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numCpuSockets\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuSockets\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"4\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"8\",\"operator\":\"<=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"ovsDpdk\",\"mandatory\":\"False\",\"score\":\"3\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"dataProcessingAccelerationLibrary\",\"hpa-attribute-value\":\"ovsDpdk_version\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"cpuInstructionSetExtensions\",\"mandatory\":\"True\",\"architecture\":\"INTEL-64\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"instructionSetExtensions\",\"hpa-attribute-value\":[\"<CPUINST>\",\"<CPUINST>\"],\"operator\":\"ALL\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_02\",\"flavorProperties\":[{\"hpa-feature\":\"cpuPinningy\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"logicalCpuThreadPinningPolicy\",\"hpa-attribute-value\":\"<CPUTHREADPOLICY>\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"logicalCpuPinningPolicy\",\"hpa-attribute-value\":\"<CPUPOLICY>\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"localStorage\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"diskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"ephemeralDiskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"swapMemSize\",\"hpa-attribute-value\":\"16\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"pcie\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"pciCount\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciVendorId\",\"hpa-attribute-value\":\"8086\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciDeviceId\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"functionType\",\"hpa-attribute-value\":\"<PCITYPEVALUE>\",\"operator\":\"=\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_03\",\"flavorProperties\":[{\"hpa-feature\":\"numa\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numaNodes\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaCpu-0\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-0\",\"hpa-attribute-value\":\"2048\",\"operator\":\"=\",\"unit\":\"MB\"},{\"hpa-attribute-key\":\"numaCpu-1\",\"hpa-attribute-value\":\"4\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-1\",\"value\":\"4096\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"hugePages\",\"mandatory\":\"False\",\"score\":\"7\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"memoryPageSize\",\"hpa-attribute-value\":\"<MEMORYPAGESIZE>\",\"operator\":\"=\",\"unit\":\"\"}]}]}]}}",
- "policyName": "oofBeijing.Config_MS_hpaPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "hpaPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.vnfPolicy_vG": {
+ "type": "onap.policies.optimization.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vG",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vG",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vG\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vG\",\"policyScope\":[\"vCPE\",\"INTERNATIONAL\",\"ip\",\"vG\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vG\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
- "policyName": "oofBeijing.Config_MS_vnfPolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "VnfPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra": {
+ "type": "onap.policies.optimization.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vGMuxInfra",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "vGMuxInfra-xx",
+ "inventoryType": "service",
+ "customerId": "SDN-ETHERNET-INTERNET",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vGMuxInfra\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vGMuxInfra\",\"policyScope\":[\"vCPE\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vGMuxInfra\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
- "policyName": "oofBeijing.Config_MS_vnfPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "VnfPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.Distance_vG_1": {
+ "type": "onap.policies.optimization.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vG",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "1500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vG\",\"description\":\"Distance Policy for vG\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"1500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vG\",\"resources\":[\"vG\"],\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vG\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
- "policyName": "oofBeijing.Config_MS_distancePolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "distancePolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.Distance_vGMuxInfra": {
+ "type": "onap.policies.optimization.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vGMuxInfra",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vG\", \"description\": \"Capacity policy for vG\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vG\", \"policyScope\": [\"VCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vG\", \"vim_fit\"], \"resources\": [\"vG\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
- "policyName": "oofBeijing.Config_MS_capacityPolicy_vG.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "capacityPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.Placement_optimization_1": {
+ "type": "onap.policies.optimization.OptimizationPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Placement_optimization_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG",
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "optimization",
+ "objective": "minimize",
+ "objectiveParameter": {
+ "parameterAttributes": [
+ {
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vG"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vG"
+ ],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vFW"
+ ],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": [
+ "vFW"
+ ],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ }
+ ],
+ "operator": "sum"
+ }
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"optimizationQueryPolicy\", \"policyName\": \"oofBeijing.queryPolicy_vCPE\", \"description\": \"Optimization query policy for vCPE\", \"templateVersion\": \"0.0.1\", \"version\": \"oofBeijing\", \"priority\": \"3\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"queryProperties\": [{\"attribute\": \"locationId\", \"attribute_location\": \"customerLocation\", \"value\": \"\"}, {\"attribute\": \"id\", \"attribute_location\": \"vpnInfo.vpnId\", \"value\": \"\"}, {\"attribute\": \"upstreamBW\", \"attribute_location\": \"vpnInfo.upstreamBW\", \"value\": \"\"}, {\"attribute\": \"customerLatitude\", \"attribute_location\": \"customerLatitude\", \"value\": 32.89748}, {\"attribute\": \"customerLongitude\", \"attribute_location\": \"customerLongitude\", \"value\": -97.040443}], \"policyScope\": [\"vCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vGMuxInfra\", \"vG\", \"optimizationQueryPolicy\"], \"policyType\": \"optimizationQueryPolicy\"}}",
- "policyName": "oofBeijing.Config_MS_queryPolicy_vCPE.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "optimizationQueryPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.queryPolicy_vCPE": {
+ "type": "onap.policies.optimization.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_vCPE",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra",
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vCPE_Query_Policy",
+ "queryProperties": [
+ {
+ "attribute": "customerLatitude",
+ "attribute_location": "customerLatitude"
+ },
+ {
+ "attribute": "customerLongitude",
+ "attribute_location": "customerLongitude"
+ }
+ ]
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"PlacementOptimizationPolicy\",\"policyName\":\"oofBeijing.PlacementOptimizationPolicy_vGMuxInfra\",\"description\":\"Placement Optimization Policy for vGMuxInfra\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"5\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"objectiveParameter\":{\"parameterAttributes\":[{\"resource\":[\"vGMuxInfra\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"},{\"resource\":[\"vG\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"}],\"operator\":\"sum\"},\"identity\":\"optimization\",\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\",\"vG\"],\"policyType\":\"placementOptimization\",\"objective\":\"minimize\"}}",
- "policyName": "oofBeijing.Config_MS_PlacementOptimizationPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "PlacementOptimizationPolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.hpa_policy_vG_1": {
+ "type": "onap.policies.optimization.HpaPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.hpa_policy_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "hpa-vG",
+ "flavorFeatures": [
+ {
+ "id": "vg_1",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_01",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "cpuTopology",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "2",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuSockets",
+ "hpa-attribute-value": "4",
+ "operator": "<=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "2",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuCores",
+ "hpa-attribute-value": "4",
+ "operator": "<=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "4",
+ "operator": ">=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numCpuThreads",
+ "hpa-attribute-value": "8",
+ "operator": "<=",
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": true,
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "ovsDpdk",
+ "mandatory": false,
+ "score": 3,
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "dataProcessingAccelerationLibrary",
+ "hpa-attribute-value": "ovsDpdk_version",
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "cpuInstructionSetExtensions",
+ "mandatory": true,
+ "architecture": "INTEL-64",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": [
+ "<CPUINST>",
+ "<CPUINST>"
+ ],
+ "operator": [
+ "ALL"
+ ],
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_2",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_02",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "cpuPinningy",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "logicalCpuThreadPinningPolicy",
+ "hpa-attribute-value": "<CPUTHREADPOLICY>",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "logicalCpuPinningPolicy",
+ "hpa-attribute-value": "<CPUPOLICY>",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": "GB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "localStorage",
+ "mandatory": "False",
+ "score": "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "diskSize",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": "GB"
+ },
+ {
+ "hpa-attribute-key": "ephemeralDiskSize",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": "GB"
+ },
+ {
+ "hpa-attribute-key": "swapMemSize",
+ "hpa-attribute-value": "16",
+ "operator": "=",
+ "unit": "MB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "pciePassthrough",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "pciCount",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "pciVendorId",
+ "hpa-attribute-value": "8086",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "pciDeviceId",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_03",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "numa",
+ "mandatory": "False",
+ "score": "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numaNodes",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaCpu-0",
+ "hpa-attribute-value": "2",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaMem-0",
+ "hpa-attribute-value": "2048",
+ "operator": "=",
+ "unit": "MB"
+ },
+ {
+ "hpa-attribute-key": "numaCpu-1",
+ "hpa-attribute-value": "4",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "numaMem-1",
+ "value": "4096",
+ "operator": "=",
+ "unit": "MB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": "6",
+ "operator": "=",
+ "unit": "GB"
+ }
+ ]
+ },
+ {
+ "hpa-feature": "hugePages",
+ "mandatory": "False",
+ "score": "7",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {
+ "hpa-attribute-key": "memoryPageSize",
+ "hpa-attribute-value": "<MEMORYPAGESIZE>",
+ "operator": "=",
+ "unit": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vGMuxInfra\",\"description\":\"Distance Policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vGMuxInfra\",\"resources\":[\"vGMuxInfra\"],\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
- "policyName": "oofBeijing.Config_MS_distancePolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "distancePolicy",
- "uuid": "",
- "Location": ""
+ "OSDF_FRANKFURT.Capacity_vG_1": {
+ "type": "onap.policies.optimization.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vG",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
+ }
},
- "responseAttributes": { },
- "property": null
- },
- {
- "policyConfigMessage": "Config Retrieved! ",
- "policyConfigStatus": "CONFIG_RETRIEVED",
- "type": "JSON",
- "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vGMuxInfra\", \"description\": \"Capacity policy for vGMuxInfra\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vGMuxInfra\", \"policyScope\": [\"VCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vGMuxInfra\", \"vim_fit\"], \"resources\": [\"vGMuxInfra\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
- "policyName": "oofBeijing.Config_MS_capacityPolicy_vGMuxInfra.1.xml",
- "policyVersion": "1",
- "matchingConditions": {
- "ECOMPName": "SNIRO-Placement",
- "ONAPName": "SNIRO-Placement",
- "ConfigName": "",
- "service": "capacityPolicy",
- "uuid": "",
- "Location": ""
- },
- "responseAttributes": { },
- "property": null
+ "OSDF_FRANKFURT.Capacity_vGMuxInfra": {
+ "type": "onap.policies.optimization.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "PVT Homing"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vGMuxInfra",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
+ }
+ }
}
-] \ No newline at end of file
+}
+
diff --git a/test/placement-tests/policy_response2_old_format.json b/test/placement-tests/policy_response2_old_format.json
new file mode 100644
index 0000000..2cd6dcb
--- /dev/null
+++ b/test/placement-tests/policy_response2_old_format.json
@@ -0,0 +1,182 @@
+[
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"SubscriberPolicy\",\"policyName\":\"oofBeijing.SubscriberPolicy_v1\",\"description\":\"Subscriber Policy\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"1\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"subscriber\",\"policyScope\":[\"vCPE\",\"PVT Homing\",\"SubscriberPolicy\",\"subscriber_x\",\"subscriber_y\"],\"properties\":{\"subscriberName\":[\"subscriber_x\",\"subscriber_y\"],\"subscriberRole\":[\"PVT Homing\"],\"provStatus\":[\"CAPPED\"]},\"policyType\":\"SubscriberPolicy\"}}",
+ "policyName": "oofBeijing.Config_MS_SubscriberPolicy_v1.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "SubscriberPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"hpaPolicy\",\"policyName\":\"oofBeijing.hpaPolicy_vGMuxInfra\",\"description\":\"HPA policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"1.0\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"resources\":\"vGMuxInfra\",\"identity\":\"hpaPolicy_vGMuxInfra\",\"policyScope\":[\"vCPE\",\"PVT Homing\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"hpaPolicy\",\"flavorFeatures\":[{\"flavorLabel\":\"flavor_label_vm_01\",\"flavorProperties\":[{\"hpa-feature\":\"cpuTopology\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numCpuSockets\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuSockets\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"4\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"8\",\"operator\":\"<=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"ovsDpdk\",\"mandatory\":\"False\",\"score\":\"3\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"dataProcessingAccelerationLibrary\",\"hpa-attribute-value\":\"ovsDpdk_version\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"cpuInstructionSetExtensions\",\"mandatory\":\"True\",\"architecture\":\"INTEL-64\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"instructionSetExtensions\",\"hpa-attribute-value\":[\"<CPUINST>\",\"<CPUINST>\"],\"operator\":\"ALL\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_02\",\"flavorProperties\":[{\"hpa-feature\":\"cpuPinningy\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"logicalCpuThreadPinningPolicy\",\"hpa-attribute-value\":\"<CPUTHREADPOLICY>\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"logicalCpuPinningPolicy\",\"hpa-attribute-value\":\"<CPUPOLICY>\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"localStorage\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"diskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"ephemeralDiskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"swapMemSize\",\"hpa-attribute-value\":\"16\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"pcie\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"pciCount\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciVendorId\",\"hpa-attribute-value\":\"8086\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciDeviceId\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"functionType\",\"hpa-attribute-value\":\"<PCITYPEVALUE>\",\"operator\":\"=\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_03\",\"flavorProperties\":[{\"hpa-feature\":\"numa\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numaNodes\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaCpu-0\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-0\",\"hpa-attribute-value\":\"2048\",\"operator\":\"=\",\"unit\":\"MB\"},{\"hpa-attribute-key\":\"numaCpu-1\",\"hpa-attribute-value\":\"4\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-1\",\"value\":\"4096\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"hugePages\",\"mandatory\":\"False\",\"score\":\"7\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"memoryPageSize\",\"hpa-attribute-value\":\"<MEMORYPAGESIZE>\",\"operator\":\"=\",\"unit\":\"\"}]}]}]}}",
+ "policyName": "oofBeijing.Config_MS_hpaPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "hpaPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vG\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vG\",\"policyScope\":[\"vCPE\",\"INTERNATIONAL\",\"ip\",\"vG\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vG\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
+ "policyName": "oofBeijing.Config_MS_vnfPolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "VnfPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vGMuxInfra\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vGMuxInfra\",\"policyScope\":[\"vCPE\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vGMuxInfra\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
+ "policyName": "oofBeijing.Config_MS_vnfPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "VnfPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vG\",\"description\":\"Distance Policy for vG\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"1500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vG\",\"resources\":[\"vG\"],\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vG\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
+ "policyName": "oofBeijing.Config_MS_distancePolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "distancePolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vG\", \"description\": \"Capacity policy for vG\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vG\", \"policyScope\": [\"VCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vG\", \"vim_fit\"], \"resources\": [\"vG\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
+ "policyName": "oofBeijing.Config_MS_capacityPolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "capacityPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"optimizationQueryPolicy\", \"policyName\": \"oofBeijing.queryPolicy_vCPE\", \"description\": \"Optimization query policy for vCPE\", \"templateVersion\": \"0.0.1\", \"version\": \"oofBeijing\", \"priority\": \"3\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"queryProperties\": [{\"attribute\": \"locationId\", \"attribute_location\": \"customerLocation\", \"value\": \"\"}, {\"attribute\": \"id\", \"attribute_location\": \"vpnInfo.vpnId\", \"value\": \"\"}, {\"attribute\": \"upstreamBW\", \"attribute_location\": \"vpnInfo.upstreamBW\", \"value\": \"\"}, {\"attribute\": \"customerLatitude\", \"attribute_location\": \"customerLatitude\", \"value\": 32.89748}, {\"attribute\": \"customerLongitude\", \"attribute_location\": \"customerLongitude\", \"value\": -97.040443}], \"policyScope\": [\"vCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vGMuxInfra\", \"vG\", \"optimizationQueryPolicy\"], \"policyType\": \"optimizationQueryPolicy\"}}",
+ "policyName": "oofBeijing.Config_MS_queryPolicy_vCPE.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "optimizationQueryPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"PlacementOptimizationPolicy\",\"policyName\":\"oofBeijing.PlacementOptimizationPolicy_vGMuxInfra\",\"description\":\"Placement Optimization Policy for vGMuxInfra\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"5\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"objectiveParameter\":{\"parameterAttributes\":[{\"resource\":[\"vGMuxInfra\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"},{\"resource\":[\"vG\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"}],\"operator\":\"sum\"},\"identity\":\"optimization\",\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\",\"vG\"],\"policyType\":\"placementOptimization\",\"objective\":\"minimize\"}}",
+ "policyName": "oofBeijing.Config_MS_PlacementOptimizationPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "PlacementOptimizationPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vGMuxInfra\",\"description\":\"Distance Policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vGMuxInfra\",\"resources\":[\"vGMuxInfra\"],\"policyScope\":[\"vCPE\",\"US\",\"INTERNATIONAL\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
+ "policyName": "oofBeijing.Config_MS_distancePolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "distancePolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vGMuxInfra\", \"description\": \"Capacity policy for vGMuxInfra\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vGMuxInfra\", \"policyScope\": [\"VCPE\",\"US\", \"INTERNATIONAL\", \"ip\", \"vGMuxInfra\", \"vim_fit\"], \"resources\": [\"vGMuxInfra\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
+ "policyName": "oofBeijing.Config_MS_capacityPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "capacityPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ }
+] \ No newline at end of file
diff --git a/test/placement-tests/policy_response_old_format.json b/test/placement-tests/policy_response_old_format.json
new file mode 100644
index 0000000..8de8537
--- /dev/null
+++ b/test/placement-tests/policy_response_old_format.json
@@ -0,0 +1,182 @@
+[
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"SubscriberPolicy\",\"policyName\":\"oofBeijing.SubscriberPolicy_v1\",\"description\":\"Subscriber Policy\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"1\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"subscriber\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"subscriberpolicy\",\"subscriber_x\",\"subscriber_y\"],\"properties\":{\"subscriberName\":[\"subscriber_x\",\"subscriber_y\"],\"subscriberRole\":[\"PVT Homing\"],\"provStatus\":[\"CAPPED\"]},\"policyType\":\"SubscriberPolicy\"}}",
+ "policyName": "oofBeijing.Config_MS_SubscriberPolicy_v1.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "SubscriberPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"hpaPolicy\",\"policyName\":\"oofBeijing.hpaPolicy_vGMuxInfra\",\"description\":\"HPA policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"1.0\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"resources\":\"vGMuxInfra\",\"identity\":\"hpaPolicy_vGMuxInfra\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"hpaPolicy\",\"flavorFeatures\":[{\"flavorLabel\":\"flavor_label_vm_01\",\"flavorProperties\":[{\"hpa-feature\":\"cpuTopology\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numCpusockets\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpusockets\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"2\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuCores\",\"hpa-attribute-value\":\"4\",\"operator\":\"<=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"4\",\"operator\":\">=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numCpuThreads\",\"hpa-attribute-value\":\"8\",\"operator\":\"<=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"ovsDpdk\",\"mandatory\":\"False\",\"score\":\"3\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"dataProcessingAccelerationLibrary\",\"hpa-attribute-value\":\"ovsDpdk_version\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"cpuInstructionSetExtensions\",\"mandatory\":\"True\",\"architecture\":\"INTEL-64\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"instructionSetExtensions\",\"hpa-attribute-value\":[\"<CPUINST>\",\"<CPUINST>\"],\"operator\":\"ALL\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_02\",\"flavorProperties\":[{\"hpa-feature\":\"cpuPinningy\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"logicalCpuThreadPinningPolicy\",\"hpa-attribute-value\":\"<CPUTHREADPOLICY>\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"logicalCpuPinningPolicy\",\"hpa-attribute-value\":\"<CPUPOLICY>\",\"operator\":\"=\",\"unit\":\"\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"localStorage\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"diskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"ephemeralDiskSize\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"GB\"},{\"hpa-attribute-key\":\"swapMemSize\",\"hpa-attribute-value\":\"16\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"pcie\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"pciCount\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciVendorId\",\"hpa-attribute-value\":\"8086\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"pciDeviceId\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"functionType\",\"hpa-attribute-value\":\"<PCITYPEVALUE>\",\"operator\":\"=\",\"unit\":\"\"}]}]},{\"flavorLabel\":\"flavor_label_vm_03\",\"flavorProperties\":[{\"hpa-feature\":\"numa\",\"mandatory\":\"False\",\"score\":\"5\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numaNodes\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaCpu-0\",\"hpa-attribute-value\":\"2\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-0\",\"hpa-attribute-value\":\"2048\",\"operator\":\"=\",\"unit\":\"MB\"},{\"hpa-attribute-key\":\"numaCpu-1\",\"hpa-attribute-value\":\"4\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"numaMem-1\",\"value\":\"4096\",\"operator\":\"=\",\"unit\":\"MB\"}]},{\"hpa-feature\":\"basicCapabilities\",\"mandatory\":\"True\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"numVirtualCpu\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"\"},{\"hpa-attribute-key\":\"virtualMemSize\",\"hpa-attribute-value\":\"6\",\"operator\":\"=\",\"unit\":\"GB\"}]},{\"hpa-feature\":\"hugePages\",\"mandatory\":\"False\",\"score\":\"7\",\"architecture\":\"generic\",\"hpa-feature-attributes\":[{\"hpa-attribute-key\":\"memoryPageSize\",\"hpa-attribute-value\":\"<MEMORYPAGESIZE>\",\"operator\":\"=\",\"unit\":\"\"}]}]}]}}",
+ "policyName": "oofBeijing.Config_MS_hpaPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "hpaPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vG\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vG\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"international\",\"ip\",\"vG\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vG\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
+ "policyName": "oofBeijing.Config_MS_vnfPolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "VnfPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"VnfPolicy\",\"policyName\":\"oofBeijing.vnfPolicy_vGMuxInfra\",\"description\":\"vnfPolicy\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"6\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vnf_vGMuxInfra\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"vnf_policy\",\"resources\":[\"vGMuxInfra\"],\"applicableResources\":\"any\",\"vnfProperties\":[{\"inventoryProvider\":\"aai\",\"serviceType\":\"\",\"inventoryType\":\"cloud\",\"customerId\":\"\"},{\"inventoryProvider\":\"multicloud\",\"serviceType\":\"HNGATEWAY\",\"inventoryType\":\"service\",\"customerId\":\"21014aa2-526b-11e6-beb8-9e71128cae77\"}]}}",
+ "policyName": "oofBeijing.Config_MS_vnfPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "VnfPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vG\",\"description\":\"Distance Policy for vG\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"1500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vG\",\"resources\":[\"vG\"],\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vG\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
+ "policyName": "oofBeijing.Config_MS_distancePolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "distancePolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vG\", \"description\": \"Capacity policy for vG\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vG\", \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vG\", \"vim_fit\"], \"resources\": [\"vG\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
+ "policyName": "oofBeijing.Config_MS_capacityPolicy_vG.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "capacityPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"optimizationQueryPolicy\", \"policyName\": \"oofBeijing.queryPolicy_vcpe\", \"description\": \"Optimization query policy for vcpe\", \"templateVersion\": \"0.0.1\", \"version\": \"oofBeijing\", \"priority\": \"3\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"queryProperties\": [{\"attribute\": \"locationId\", \"attribute_location\": \"customerLocation\", \"value\": \"\"}, {\"attribute\": \"id\", \"attribute_location\": \"vpnInfo.vpnId\", \"value\": \"\"}, {\"attribute\": \"upstreamBW\", \"attribute_location\": \"vpnInfo.upstreamBW\", \"value\": \"\"}, {\"attribute\": \"customerLatitude\", \"attribute_location\": \"customerLatitude\", \"value\": 32.89748}, {\"attribute\": \"customerLongitude\", \"attribute_location\": \"customerLongitude\", \"value\": -97.040443}], \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vGMuxInfra\", \"vG\", \"optimizationQueryPolicy\"], \"policyType\": \"optimizationQueryPolicy\"}}",
+ "policyName": "oofBeijing.Config_MS_queryPolicy_vcpe.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "optimizationQueryPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"PlacementOptimizationPolicy\",\"policyName\":\"oofBeijing.PlacementOptimizationPolicy_vGMuxInfra\",\"description\":\"Placement Optimization Policy for vGMuxInfra\",\"templateVersion\":\"1702.03\",\"version\":\"oofBeijing\",\"priority\":\"5\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"objectiveParameter\":{\"parameterAttributes\":[{\"resource\":[\"vGMuxInfra\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"},{\"resource\":[\"vG\"],\"customerLocationInfo\":\"customer_loc\",\"parameter\":\"distance\",\"weight\":\"1\",\"operator\":\"product\"}],\"operator\":\"sum\"},\"identity\":\"optimization\",\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\",\"vG\"],\"policyType\":\"placementOptimization\",\"objective\":\"minimize\"}}",
+ "policyName": "oofBeijing.Config_MS_PlacementOptimizationPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "PlacementOptimizationPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\":\"distancePolicy\",\"policyName\":\"oofBeijing.distancePolicy_vGMuxInfra\",\"description\":\"Distance Policy for vGMuxInfra\",\"templateVersion\":\"0.0.1\",\"version\":\"oofBeijing\",\"priority\":\"3\",\"riskType\":\"test\",\"riskLevel\":\"2\",\"guard\":\"False\",\"content\":{\"distanceProperties\":{\"locationInfo\":\"customer_location\",\"distance\":{\"value\":\"500\",\"operator\":\"<\",\"unit\":\"km\"}},\"identity\":\"distance-vGMuxInfra\",\"resources\":[\"vGMuxInfra\"],\"policyScope\":[\"vcpe\",\"PVT Homing\",\"us\",\"international\",\"ip\",\"vGMuxInfra\"],\"policyType\":\"distancePolicy\",\"applicableResources\":\"any\"}}",
+ "policyName": "oofBeijing.Config_MS_distancePolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "distancePolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ },
+ {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ "config": "{\"service\": \"capacityPolicy\", \"policyName\": \"oofBeijing.capacityPolicy_vGMuxInfra\", \"description\": \"Capacity policy for vGMuxInfra\", \"templateVersion\": \"1702.03\", \"version\": \"oofBeijing\", \"priority\": \"5\", \"riskType\": \"test\", \"riskLevel\": \"2\", \"guard\": \"False\", \"content\": {\"identity\": \"capacity_vGMuxInfra\", \"policyScope\": [\"vcpe\", \"PVT Homing\",\"us\", \"international\", \"ip\", \"vGMuxInfra\", \"vim_fit\"], \"resources\": [\"vGMuxInfra\"], \"capacityProperty\": {\"controller\": \"multicloud\", \"request\": \"{\\\"vCPU\\\": 10, \\\"Memory\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_MEM\\\"}, \\\"unit\\\": \\\"GB\\\"}, \\\"Storage\\\": {\\\"quantity\\\": {\\\"get_param\\\": \\\"REQUIRED_DISK\\\", \\\"unit\\\": \\\"GB\\\"}}}\"}, \"policyType\": \"vim_fit\", \"applicableResources\": \"any\"}}",
+ "policyName": "oofBeijing.Config_MS_capacityPolicy_vGMuxInfra.1.xml",
+ "policyVersion": "1",
+ "matchingConditions": {
+ "ECOMPName": "SNIRO-Placement",
+ "ONAPName": "SNIRO-Placement",
+ "ConfigName": "",
+ "service": "capacityPolicy",
+ "uuid": "",
+ "Location": ""
+ },
+ "responseAttributes": { },
+ "property": null
+ }
+] \ No newline at end of file
diff --git a/test/placement-tests/request_placement_vfmod.json b/test/placement-tests/request_placement_vfmod.json
new file mode 100644
index 0000000..4b2b852
--- /dev/null
+++ b/test/placement-tests/request_placement_vfmod.json
@@ -0,0 +1,113 @@
+{
+ "name": "de4f04e3-0a65-470b-9d07-8ea6c2fb3e10",
+ "files": {},
+ "timeout": 1200,
+ "num_solution": "100",
+ "template": {
+ "homing_template_version": "2017-10-10",
+ "parameters": {
+ "REQUIRED_MEM": "",
+ "REQUIRED_DISK": "",
+ "customer_lat": 1.1,
+ "customer_long": 2.2,
+ "service_name": "vFW_TD",
+ "service_id": "3e8d118c-10ca-4b4b-b3db-089b5e9e6a1c",
+ "chosen_region": "RegionOne"
+ },
+ "locations": {
+ "customer_loc": {
+ "latitude": {
+ "get_param": "customer_lat"
+ },
+ "longitude": {
+ "get_param": "customer_long"
+ }
+ }
+ },
+ "demands": {
+ "vFW-SINK": [
+ {
+ "inventory_provider": "aai",
+ "inventory_type": "vfmodule",
+ "service_type": "vFW-SINK-XX",
+ "service_resource_id": "vFW-SINK-XX",
+ "filtering_attributes": {
+ "global-customer-id": {
+ "get_param": "chosen_customer_id"
+ },
+ "model-invariant-id": "e7227847-dea6-4374-abca-4561b070fe7d",
+ "model-version-id": "763731df-84fd-494b-b824-01fc59a5ff2d",
+ "orchestration-status": [
+ "active"
+ ],
+ "prov-status": "ACTIVE",
+ "cloud-region-id": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthrough_attributes": {
+ "td-role": "destination"
+ },
+ "excluded_candidates": [
+ {
+ "inventory_type": "vfmodule",
+ "candidate_id": [
+ "e765d576-8755-4145-8536-0bb6d9b1dc9a"
+ ]
+ }
+ ]
+ }
+ ],
+ "vPGN": [
+ {
+ "inventory_provider": "aai",
+ "inventory_type": "vfmodule",
+ "service_type": "vPGN-XX",
+ "service_resource_id": "vPGN-XX",
+ "unique": "False",
+ "filtering_attributes": {
+ "global-customer-id": {
+ "get_param": "chosen_customer_id"
+ },
+ "model-invariant-id": "762472ef-5284-4daa-ab32-3e7bee2ec355",
+ "model-version-id": "e02a7e5c-9d27-4360-ab7c-73bb83b07e3b",
+ "orchestration-status": [
+ "active"
+ ],
+ "prov-status": "ACTIVE",
+ "cloud-region-id": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthrough_attributes": {
+ "td-role": "anchor"
+ }
+ }
+ ]
+ },
+ "constraints": {
+ "affinity_vFW_TD": {
+ "type": "zone",
+ "demands": [
+ "vFW-SINK",
+ "vPGN"
+ ],
+ "properties": {
+ "category": "region",
+ "qualifier": "same"
+ }
+ }
+ },
+ "optimization": {
+ "minimize": {
+ "sum": []
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/placement-tests/request_vfmod.json b/test/placement-tests/request_vfmod.json
new file mode 100644
index 0000000..1a8a462
--- /dev/null
+++ b/test/placement-tests/request_vfmod.json
@@ -0,0 +1,57 @@
+{
+ "requestInfo": {
+ "transactionId": "e576c75e-7536-4145-a1c0-d60b65bb1bb8",
+ "requestId": "de4f04e3-0a65-470b-9d07-8ea6c2fb3e10",
+ "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+ "sourceId": "SO",
+ "requestType": "create",
+ "numSolutions": "100",
+ "optimizers": [
+ "placement"
+ ],
+ "timeout": 1200
+ },
+ "placementInfo": {
+ "requestParameters": {
+ "chosenRegion": "RegionOne"
+ },
+ "subscriberInfo": {
+ "globalSubscriberId": "dbc2c763-6383-42d6-880a-b7d5c5bc84d9",
+ "subscriberName": "oof-so-chm"
+ },
+ "placementDemands": [
+ {
+ "resourceModuleName": "vFW-SINK",
+ "serviceResourceId": "vFW-SINK-XX",
+ "resourceModelInfo": {
+ "modelInvariantId": "e7227847-dea6-4374-abca-4561b070fe7d",
+ "modelVersionId": "763731df-84fd-494b-b824-01fc59a5ff2d"
+ },
+ "excludedCandidates": [
+ {
+ "identifierType": "vfmodule",
+ "identifiers": [
+ "e765d576-8755-4145-8536-0bb6d9b1dc9a"
+ ]
+ }
+ ]
+ },
+ {
+ "resourceModuleName": "vPGN",
+ "serviceResourceId": "vPGN-XX",
+ "resourceModelInfo": {
+ "modelInvariantId": "762472ef-5284-4daa-ab32-3e7bee2ec355",
+ "modelVersionId": "e02a7e5c-9d27-4360-ab7c-73bb83b07e3b"
+ }
+ }
+ ]
+ },
+ "serviceInfo": {
+ "serviceInstanceId": "3e8d118c-10ca-4b4b-b3db-089b5e9e6a1c",
+ "serviceName": "vFW_TD",
+ "modelInfo": {
+ "modelInvariantId": "TD-invariantId",
+ "modelVersionId": "TD-versionId"
+ }
+ }
+} \ No newline at end of file
diff --git a/test/placement-tests/response_vfmod.json b/test/placement-tests/response_vfmod.json
new file mode 100644
index 0000000..06e40de
--- /dev/null
+++ b/test/placement-tests/response_vfmod.json
@@ -0,0 +1,229 @@
+{
+ "transactionId": "",
+ "requestStatus": "completed",
+ "solutions": {
+ "placementSolutions": [
+ [{
+ "assignmentInfo": [{
+ "key": "locationType",
+ "value": "att_aic"
+ }, {
+ "key": "vnfHostName",
+ "value": "vFW-FW-MC"
+ }, {
+ "key": "locationId",
+ "value": "RegionOne"
+ }, {
+ "key": "isRehome",
+ "value": "false"
+ }, {
+ "key": "nf-name",
+ "value": "vFW-FW-MC"
+ }, {
+ "key": "vnf-type",
+ "value": "5G_EVE_Demo/5G_EVE_FW 0"
+ }, {
+ "key": "ipv6-oam-address",
+ "value": ""
+ }, {
+ "key": "ipv4-oam-address",
+ "value": "oam_network_zb4J"
+ }, {
+ "key": "vservers",
+ "value": [{
+ "vserver-id": "4a61b075-5ae0-4cfe-b213-27d3647a0578",
+ "l-interfaces": [{
+ "macaddr": "fa:16:3e:4a:00:56",
+ "interface-name": "vnf-snk-r1-t1-mc-vfw_private_3_port-tntiamoj2res",
+ "ipv4-addresses": ["10.100.100.1"],
+ "ipv6-addresses": [],
+ "interface-id": "ff27775b-a2b7-4e6e-8f71-6a5a5e6020cd",
+ "network-name": "",
+ "network-id": "59763a33-3296-4dc8-9ee6-2bdcd63322fc"
+ }, {
+ "macaddr": "fa:16:3e:a1:e8:c9",
+ "interface-name": "vnf-snk-r1-t1-mc-vfw_private_2_port-hiay5zan4da6",
+ "ipv4-addresses": ["10.0.110.1"],
+ "ipv6-addresses": [],
+ "interface-id": "0bb0bb92-a4d1-4104-b491-e469949f60a3",
+ "network-name": "",
+ "network-id": "cdb4bc25-2412-4b77-bbd5-791a02f8776d"
+ }, {
+ "macaddr": "fa:16:3e:45:e2:16",
+ "interface-name": "vnf-snk-r1-t1-mc-vfw_private_0_port-7xlr5kjvsmk6",
+ "ipv4-addresses": ["192.168.10.100"],
+ "ipv6-addresses": [],
+ "interface-id": "f0291365-6070-4baa-8470-8775bed7c2c4",
+ "network-name": "",
+ "network-id": "932ac514-639a-45b2-b1a3-4c5bb708b5c1"
+ }, {
+ "macaddr": "fa:16:3e:2f:0b:2f",
+ "interface-name": "vnf-snk-r1-t1-mc-vfw_private_1_port-khio4swt2vy3",
+ "ipv4-addresses": ["192.168.20.100"],
+ "ipv6-addresses": [],
+ "interface-id": "5ba290b0-0833-4008-acda-be1878b9ae0c",
+ "network-name": "",
+ "network-id": "bd64a2b0-0bdd-45b4-b755-65d5ebe1cee0"
+ }],
+ "vserver-name": "vfw-vfw-1-dt"
+ }, {
+ "vserver-id": "cf51eeab-8f75-4635-a01c-9f4bbd1e146e",
+ "l-interfaces": [{
+ "macaddr": "fa:16:3e:23:82:d7",
+ "interface-name": "vnf-snk-r1-t1-mc-vsn_private_2_port-spbtqjnybz5g",
+ "ipv4-addresses": ["10.100.100.3"],
+ "ipv6-addresses": [],
+ "interface-id": "1b3fd313-cde3-4df6-8ea8-bf4ae28e7e03",
+ "network-name": "",
+ "network-id": "59763a33-3296-4dc8-9ee6-2bdcd63322fc"
+ }, {
+ "macaddr": "fa:16:3e:fc:bd:16",
+ "interface-name": "vnf-snk-r1-t1-mc-vsn_private_1_port-spqyrticfqan",
+ "ipv4-addresses": ["10.0.110.3"],
+ "ipv6-addresses": [],
+ "interface-id": "1b33d675-f351-4766-8669-7314f774d52c",
+ "network-name": "",
+ "network-id": "cdb4bc25-2412-4b77-bbd5-791a02f8776d"
+ }, {
+ "macaddr": "fa:16:3e:3d:e9:c5",
+ "interface-name": "vnf-snk-r1-t1-mc-vsn_private_0_port-5ijwpdueh2fl",
+ "ipv4-addresses": ["192.168.20.250"],
+ "ipv6-addresses": [],
+ "interface-id": "cf82e256-8ccf-4e43-ba96-04ea2e47b5d2",
+ "network-name": "",
+ "network-id": "bd64a2b0-0bdd-45b4-b755-65d5ebe1cee0"
+ }],
+ "vserver-name": "vfw-vsn-1-dt"
+ }]
+ }, {
+ "key": "nf-type",
+ "value": "vnf"
+ }, {
+ "key": "vnfHostName",
+ "value": "vFW-FW-MC"
+ }, {
+ "key": "aic_version",
+ "value": "1"
+ }, {
+ "key": "cloudClli",
+ "value": "clli1"
+ }, {
+ "key": "service_instance_id",
+ "value": "3e8d118c-10ca-4b4b-b3db-089b5e9e6a1c"
+ }, {
+ "key": "cloudOwner",
+ "value": "CloudOwner"
+ }, {
+ "value": "vfw-0-mc",
+ "key": "vf-module-name"
+ }, {
+ "value": "85eec994-b635-42c7-87a1-d39720cad36d",
+ "key": "vf-module-id"
+ }, {
+ "key": "nf-id",
+ "value": "4d2dc294-dbb3-44a2-8422-fa61b30c21a9"
+ }],
+ "serviceResourceId": "vFW-SINK-XX",
+ "solution": {
+ "cloudOwner": "CloudOwner",
+ "identifiers": ["85eec994-b635-42c7-87a1-d39720cad36d"],
+ "identifierType": "vfmodule"
+ },
+ "resourceModuleName": "vFW-SINK"
+ }, {
+ "assignmentInfo": [{
+ "key": "locationType",
+ "value": "att_aic"
+ }, {
+ "key": "vnfHostName",
+ "value": "vFW-PKG-MC"
+ }, {
+ "key": "locationId",
+ "value": "RegionOne"
+ }, {
+ "key": "isRehome",
+ "value": "false"
+ }, {
+ "key": "nf-name",
+ "value": "vFW-PKG-MC"
+ }, {
+ "key": "vnf-type",
+ "value": "5G_EVE_Demo/5G_EVE_PKG 0"
+ }, {
+ "key": "ipv6-oam-address",
+ "value": ""
+ }, {
+ "key": "ipv4-oam-address",
+ "value": "oam_network_zb4J"
+ }, {
+ "key": "vservers",
+ "value": [{
+ "vserver-id": "00bddefc-126e-4e4f-a18d-99b94d8d9a30",
+ "l-interfaces": [{
+ "macaddr": "fa:16:3e:c4:07:7f",
+ "interface-name": "vnf-pkg-r1-t2-mc-vpg_private_2_port-mf7lu55usq7i",
+ "ipv4-addresses": ["10.100.100.2"],
+ "ipv6-addresses": [],
+ "interface-id": "4b333af1-90d6-42ae-8389-d440e6ff0e93",
+ "network-name": "",
+ "network-id": "59763a33-3296-4dc8-9ee6-2bdcd63322fc"
+ }, {
+ "macaddr": "fa:16:3e:b5:86:38",
+ "interface-name": "vnf-pkg-r1-t2-mc-vpg_private_1_port-734xxixicw6r",
+ "ipv4-addresses": ["10.0.110.2"],
+ "ipv6-addresses": [],
+ "interface-id": "85dd57e9-6e3a-48d0-a784-4598d627e798",
+ "network-name": "",
+ "network-id": "cdb4bc25-2412-4b77-bbd5-791a02f8776d"
+ }, {
+ "macaddr": "fa:16:3e:ff:d8:6f",
+ "interface-name": "vnf-pkg-r1-t2-mc-vpg_private_0_port-e5qdm3p5ijhe",
+ "ipv4-addresses": ["192.168.10.200"],
+ "ipv6-addresses": [],
+ "interface-id": "edaff25a-878e-4706-ad52-4e3d51cf6a82",
+ "network-name": "",
+ "network-id": "932ac514-639a-45b2-b1a3-4c5bb708b5c1"
+ }],
+ "vserver-name": "zdfw1fwl01pgn01"
+ }]
+ }, {
+ "key": "nf-type",
+ "value": "vnf"
+ }, {
+ "key": "vnfHostName",
+ "value": "vFW-PKG-MC"
+ }, {
+ "key": "aic_version",
+ "value": "1"
+ }, {
+ "key": "cloudClli",
+ "value": "clli1"
+ }, {
+ "key": "service_instance_id",
+ "value": "3e8d118c-10ca-4b4b-b3db-089b5e9e6a1c"
+ }, {
+ "key": "cloudOwner",
+ "value": "CloudOwner"
+ }, {
+ "value": "pkg-0-mc",
+ "key": "vf-module-name"
+ }, {
+ "value": "d187d743-5932-4fb9-a42d-db0a5be5ba7e",
+ "key": "vf-module-id"
+ }, {
+ "key": "nf-id",
+ "value": "fcbff633-47cc-4f38-a98d-4ba8285bd8b6"
+ }],
+ "serviceResourceId": "vPGN-XX",
+ "solution": {
+ "cloudOwner": "CloudOwner",
+ "identifiers": ["d187d743-5932-4fb9-a42d-db0a5be5ba7e"],
+ "identifierType": "vfmodule"
+ },
+ "resourceModuleName": "vPGN"
+ }]
+ ]
+ },
+ "statusMessage": "",
+ "requestId": "de4f04e3-0a65-470b-9d07-8ea6c2fb3e10"
+} \ No newline at end of file
diff --git a/test/placement-tests/test_by_scope.yaml b/test/placement-tests/test_by_scope.yaml
index 2cdd4e4..1968b89 100644
--- a/test/placement-tests/test_by_scope.yaml
+++ b/test/placement-tests/test_by_scope.yaml
@@ -2,23 +2,32 @@ references:
service_name:
source: request
value: serviceInfo.serviceName
+ resource:
+ source: request
+ value: placementInfo.placementDemands.resourceModuleName
subscriber_role:
- source: SubscriberPolicy
- value: content.properties.subscriberRole
+ source: onap.policies.optimization.SubscriberPolicy
+ value: properties.properties.subscriberRole
policy_info:
placement:
policy_fetch: by_scope
policy_scope:
- default_scope: OSDF_R2
- vcpe_scope: OSDF_R2
- secondary_scopes:
- -
- - get_param: service_name
- - SubscriberPolicy
- -
+ -
+ scope:
+ - OSDF_FRANKFURT
+ - onap.policies.optimization.SubscriberPolicy
+ service:
- get_param: service_name
+ -
+ scope:
+ - OSDF_FRANKFURT
- get_param: subscriber_role
+ service:
+ - get_param: service_name
+ # -
+ # - get_param: service_name
+ # - get_param: subscriber_role
default: # if no explicit service related information is needed
policy_fetch: by_name
- policy_scope: none
+ policy_scope: none \ No newline at end of file
diff --git a/test/placement-tests/test_by_scope_old_format.yaml b/test/placement-tests/test_by_scope_old_format.yaml
new file mode 100644
index 0000000..2cdd4e4
--- /dev/null
+++ b/test/placement-tests/test_by_scope_old_format.yaml
@@ -0,0 +1,24 @@
+references:
+ service_name:
+ source: request
+ value: serviceInfo.serviceName
+ subscriber_role:
+ source: SubscriberPolicy
+ value: content.properties.subscriberRole
+
+policy_info:
+ placement:
+ policy_fetch: by_scope
+ policy_scope:
+ default_scope: OSDF_R2
+ vcpe_scope: OSDF_R2
+ secondary_scopes:
+ -
+ - get_param: service_name
+ - SubscriberPolicy
+ -
+ - get_param: service_name
+ - get_param: subscriber_role
+ default: # if no explicit service related information is needed
+ policy_fetch: by_name
+ policy_scope: none
diff --git a/test/policy-local-files/Affinity_vCPE_1.json b/test/policy-local-files/Affinity_vCPE_1.json
index 6f0ecb3..5364d5d 100644
--- a/test/policy-local-files/Affinity_vCPE_1.json
+++ b/test/policy-local-files/Affinity_vCPE_1.json
@@ -1,21 +1,33 @@
{
- "service": "zone",
- "policyName": "OSDF_R2.Affinity_vCPE_1",
- "description": "Optimization query policy for vCPE",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "identity": "affinity_vCPE",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
- "affinityProperty": {
- "qualifier": "same",
- "category": "complex"
- },
- "policyType": "zone",
- "resources": ["vGMuxInfra", "vG"]
+ "OSDF_FRANKFURT.Affinity_vCPE_1": {
+ "type": "onap.policies.optimization.resource.AffinityPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Affinity_vCPE_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG",
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "affinity_vCPE",
+ "applicableResources": "any",
+ "affinityProperties": {
+ "qualifier": "same",
+ "category": "complex"
+ }
}
+ }
}
diff --git a/test/policy-local-files/Affinity_vFW_TD.json b/test/policy-local-files/Affinity_vFW_TD.json
new file mode 100644
index 0000000..5df3bf4
--- /dev/null
+++ b/test/policy-local-files/Affinity_vFW_TD.json
@@ -0,0 +1,31 @@
+{
+ "OSDF_FRANKFURT.Affinity_vFW_TD": {
+ "type": "onap.policies.optimization.resource.AffinityPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Affinity_vFW_TD",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "TD"
+ ],
+ "resources": [
+ "vFW-SINK",
+ "vPGN"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "affinity_vFW_TD",
+ "applicableResources": "any",
+ "affinityProperties": {
+ "qualifier": "same",
+ "category": "region"
+ }
+ }
+ }
+}
diff --git a/test/policy-local-files/Attribute_vNS_1.json b/test/policy-local-files/Attribute_vNS_1.json
new file mode 100644
index 0000000..97c967c
--- /dev/null
+++ b/test/policy-local-files/Attribute_vNS_1.json
@@ -0,0 +1,51 @@
+{
+ "OSDF_FRANKFURT.Attribute_vNS_1": {
+ "type": "onap.policies.optimization.resource.AttributePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Attribute_vNS_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vNS"
+ ],
+ "resources": [
+ "vNS"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "attribute-vNS",
+ "attributeProperties": {
+ "cloudRegion": {
+ "serviceRequests": [
+ "",
+ ""
+ ],
+ "cloudRequests": [
+ "",
+ ""
+ ]
+ },
+ "networkRoles": {
+ "all": [
+ "",
+ ""
+ ]
+ },
+ "complex": {
+ "any": [
+ "",
+ ""
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/Capacity_vGMuxInfra.json b/test/policy-local-files/Capacity_vGMuxInfra.json
index 2578544..7ce02bf 100644
--- a/test/policy-local-files/Capacity_vGMuxInfra.json
+++ b/test/policy-local-files/Capacity_vGMuxInfra.json
@@ -1,22 +1,32 @@
{
- "service": "vim_fit",
- "policyName": "OSDF_R2.Capacity_vGMuxInfra",
- "description": "Capacity policy for vGMuxInfra",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "5",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "identity": "capacity_vGMuxInfra",
- "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "resources": ["vGMuxInfra"],
- "capacityProperty": {
- "controller": "multicloud",
- "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
- },
- "policyType": "vim_fit",
- "applicableResources": "any"
+ "OSDF_FRANKFURT.Capacity_vGMuxInfra": {
+ "type": "onap.policies.optimization.resource.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vGMuxInfra",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
}
+ }
}
diff --git a/test/policy-local-files/Capacity_vG_1.json b/test/policy-local-files/Capacity_vG_1.json
index c1682fa..c897a87 100644
--- a/test/policy-local-files/Capacity_vG_1.json
+++ b/test/policy-local-files/Capacity_vG_1.json
@@ -1,22 +1,32 @@
{
- "service": "vim_fit",
- "policyName": "OSDF_R2.Capacity_vG_1",
- "description": "Capacity policy for vG",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "5",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "identity": "capacity_vG",
- "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "resources": ["vG"],
- "capacityProperty": {
- "controller": "multicloud",
- "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
- },
- "policyType": "vim_fit",
- "applicableResources": "any"
+ "OSDF_FRANKFURT.Capacity_vG_1": {
+ "type": "onap.policies.optimization.resource.Vim_fit",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Capacity_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "capacity_vG",
+ "applicableResources": "any",
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ }
}
+ }
}
diff --git a/test/policy-local-files/Distance_vGMuxInfra_1.json b/test/policy-local-files/Distance_vGMuxInfra_1.json
index 61ec500..163d0df 100644
--- a/test/policy-local-files/Distance_vGMuxInfra_1.json
+++ b/test/policy-local-files/Distance_vGMuxInfra_1.json
@@ -1,22 +1,36 @@
{
- "service": "distance_to_location",
- "policyName": "OSDF_R2.Distance_vGMuxInfra",
- "description": "Distance Policy for vGMuxInfra",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "distanceProperties": {
- "locationInfo": "customer_location",
- "distance": { "value": "500", "operator": "<", "unit": "km" }
+ "OSDF_FRANKFURT.Distance_vGMuxInfra": {
+ "type": "onap.policies.optimization.resource.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vGMuxInfra",
+ "policy-version": 1
},
- "identity": "distance-vGMuxInfra",
- "resources": ["vGMuxInfra"],
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "policyType": "distancePolicy",
- "applicableResources": "any"
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vGMuxInfra",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
}
}
diff --git a/test/policy-local-files/Distance_vG_1.json b/test/policy-local-files/Distance_vG_1.json
index 06c3ada..aa6badc 100644
--- a/test/policy-local-files/Distance_vG_1.json
+++ b/test/policy-local-files/Distance_vG_1.json
@@ -1,22 +1,36 @@
{
- "service": "distance_to_location",
- "policyName": "OSDF_R2.Distance_vG_1",
- "description": "Distance Policy for vG",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "distanceProperties": {
- "locationInfo": "customer_location",
- "distance": { "value": "1500", "operator": "<", "unit": "km" }
+ "OSDF_FRANKFURT.Distance_vG_1": {
+ "type": "onap.policies.optimization.resource.DistancePolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Distance_vG_1",
+ "policy-version": 1
},
- "identity": "distance-vG",
- "resources": ["vG"],
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "policyType": "distancePolicy",
- "applicableResources": "any"
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "distance-vG",
+ "applicableResources": "any",
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": {
+ "value": "1500",
+ "operator": "<",
+ "unit": "km"
+ }
+ }
+ }
}
}
diff --git a/test/policy-local-files/Placement_Optimization_1.json b/test/policy-local-files/Placement_Optimization_1.json
index ab3c586..62b024c 100644
--- a/test/policy-local-files/Placement_Optimization_1.json
+++ b/test/policy-local-files/Placement_Optimization_1.json
@@ -1,15 +1,30 @@
{
- "service": "placementOptimization",
- "policyName": "OSDF_R2.Placement_Optimization_1",
- "description": "Placement Optimization Policy for vGMuxInfra",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "5",
- "riskType": "test",
- "riskLevel": "3",
- "guard": "False",
- "content": {
- "objectiveParameter": {
+ "OSDF_FRANKFURT.Placement_optimization_1": {
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.Placement_optimization_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG",
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "optimization",
+ "objective": "minimize",
+ "objectiveParameter": {
"parameterAttributes": [
{
"resources": ["vGMuxInfra"],
@@ -30,13 +45,23 @@
"parameter": "hpa_score",
"weight": "200",
"operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
}
],
"operator": "sum"
- },
- "identity": "optimization",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
- "policyType": "placementOptimization",
- "objective": "minimize"
+ }
}
+ }
}
diff --git a/test/policy-local-files/QueryPolicy_vCPE.json b/test/policy-local-files/QueryPolicy_vCPE.json
index 27f49d2..3bcc67e 100644
--- a/test/policy-local-files/QueryPolicy_vCPE.json
+++ b/test/policy-local-files/QueryPolicy_vCPE.json
@@ -1,21 +1,38 @@
{
- "service": "optimizationQueryPolicy",
- "policyName": "OSDF_R2.QueryPolicy_vCPE",
- "description": "Optimization query policy for vCPE",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "queryProperties": [
- {"attribute":"customerLatitude", "attribute_location": "customerLatitude"},
- {"attribute":"customerLongitude", "attribute_location": "customerLongitude"}
- ],
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
- "policyType": "optimizationQueryPolicy",
- "serviceName": "vCPE",
- "identity": "vCPE_Query_Policy"
+ "OSDF_FRANKFURT.queryPolicy_vCPE": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_vCPE",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra",
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vCPE_Query_Policy",
+ "queryProperties": [
+ {
+ "attribute": "customerLatitude",
+ "attribute_location": "customerLatitude"
+ },
+ {
+ "attribute": "customerLongitude",
+ "attribute_location": "customerLongitude"
+ }
+ ]
+ }
}
}
diff --git a/test/policy-local-files/QueryPolicy_vCPE_2.json b/test/policy-local-files/QueryPolicy_vCPE_2.json
index 7f1db83..3d9f4ca 100644
--- a/test/policy-local-files/QueryPolicy_vCPE_2.json
+++ b/test/policy-local-files/QueryPolicy_vCPE_2.json
@@ -1,23 +1,55 @@
{
- "service": "optimizationQueryPolicy",
- "policyName": "oofBeijing.queryPolicy_vCPE",
- "description": "Optimization query policy for vCPE",
- "templateVersion": "0.0.1",
- "version": "oofBeijing",
- "priority": "5",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "queryProperties": [
- {"attribute":"locationId", "attribute_location": "customerLocation", "value": ""},
- {"attribute":"id", "attribute_location": "vpnInfo.vpnId", "value": ""},
- {"attribute":"upstreamBW", "attribute_location": "vpnInfo.upstreamBW", "value": ""},
- {"attribute":"customerLatitude", "attribute_location": "customerLatitude", "value": 1.1},
- {"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": 2.2}
- ],
- "serviceName": "vCPE",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG", "optimizationQueryPolicy"],
- "policyType": "optimizationQueryPolicy"
+ "OSDF_FRANKFURT.queryPolicy_vCPE": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_vCPE",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra",
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vCPE_Query_Policy",
+ "queryProperties": [
+ {
+ "attribute": "locationId",
+ "attribute_location": "customerLocation",
+ "value": ""
+ },
+ {
+ "attribute": "id",
+ "attribute_location": "vpnInfo.vpnId",
+ "value": ""
+ },
+ {
+ "attribute": "upstreamBW",
+ "attribute_location": "vpnInfo.upstreamBW",
+ "value": ""
+ },
+ {
+ "attribute": "customerLatitude",
+ "attribute_location": "customerLatitude",
+ "value": 1.1
+ },
+ {
+ "attribute": "customerLongitude",
+ "attribute_location": "customerLongitude",
+ "value": 2.2
+ }
+ ]
+ }
}
}
diff --git a/test/policy-local-files/QueryPolicy_vFW_TD.json b/test/policy-local-files/QueryPolicy_vFW_TD.json
new file mode 100644
index 0000000..ab199ac
--- /dev/null
+++ b/test/policy-local-files/QueryPolicy_vFW_TD.json
@@ -0,0 +1,47 @@
+{
+ "OSDF_FRANKFURT.queryPolicy_vFW_TD": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_vFW_TD",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vFW_TD"
+ ],
+ "resources": [
+ "vFW-SINK",
+ "vPGN"
+ ],
+ "geography": [
+ "US"
+ ],
+ "identity": "vFW_TD_Query_Policy",
+ "queryProperties": [
+ {
+ "attribute": "chosen_region",
+ "attribute_location": "chosenRegion"
+ },
+ {
+ "attribute": "chosen_customer_id",
+ "attribute_location": "chosenCustomerId"
+ },
+ {
+ "attribute": "customerLatitude",
+ "attribute_location": "customerLatitude",
+ "value": 1.1
+ },
+ {
+ "attribute": "customerLongitude",
+ "attribute_location": "customerLongitude",
+ "value": 2.2
+ }
+ ]
+ }
+ }
+}
diff --git a/test/policy-local-files/aggregationPolicy_URLLC_1.json b/test/policy-local-files/aggregationPolicy_URLLC_1.json
new file mode 100644
index 0000000..13014c1
--- /dev/null
+++ b/test/policy-local-files/aggregationPolicy_URLLC_1.json
@@ -0,0 +1,37 @@
+{
+ "OSDF_FRANKFURT.Aggregation_URLLC_1":{
+ "type":"onap.policies.optimization.resource.AggregationPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"OSDF_FRANKFURT.Aggregation_URLLC_1",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "OSDF_FRANKFURT",
+ "URLLC_1"
+ ],
+ "geography": [],
+ "resources":[
+ "URLLC_Core_1"
+ ],
+ "services":[
+ "URLLC_1"
+ ],
+ "identity":"Aggregation_URLLC_1",
+ "applicableResources":"any",
+ "aggregationProperties":[
+ {
+ "attribute":"latency",
+ "function":"sum",
+ "operator":"lte",
+ "threshold":{
+ "get_param": "latency"
+ },
+ "unit":"ms"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/hpa_policy_vGMuxInfra_1.json b/test/policy-local-files/hpa_policy_vGMuxInfra_1.json
index ce0b7e3..b6317f8 100644
--- a/test/policy-local-files/hpa_policy_vGMuxInfra_1.json
+++ b/test/policy-local-files/hpa_policy_vGMuxInfra_1.json
@@ -1,18 +1,27 @@
{
- "service": "hpaPolicy",
- "policyName": "OSDF_R2.hpa_policy_vGMuxInfra_1",
- "description": "HPA policy for vGMuxInfra",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "resources": "vGMuxInfra",
- "identity": "hpaPolicy_vGMuxInfra",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "policyType": "hpaPolicy",
+ "OSDF_FRANKFURT.hpa_policy_vGMuxInfra_1": {
+ "type": "onap.policies.optimization.resource.HpaPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.hpa_policy_vGMuxInfra_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "hpa-vGMuxInfra",
"flavorFeatures": [
{
"id": "vgmux_1",
@@ -28,8 +37,8 @@
]
}
],
- "flavorProperties":[
- {
+ "flavorProperties": [
+ {
"hpa-feature" : "cpuTopology",
"mandatory" : "True",
"architecture": "generic",
@@ -43,33 +52,64 @@
{"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
]
},
- {
- "hpa-feature" : "basicCapabilities",
- "mandatory" : "True",
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": true,
"architecture": "generic",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
- {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
]
},
{
- "hpa-feature" : "ovsDpdk",
- "mandatory" : "False",
- "score" : "3",
+ "hpa-feature": "ovsDpdk",
+ "mandatory": false,
+ "score": 3,
"architecture": "generic",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+ {
+ "hpa-attribute-key": "dataProcessingAccelerationLibrary",
+ "hpa-attribute-value": "ovsDpdk_version",
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
]
},
{
- "hpa-feature" : "cpuInstructionSetExtensions",
- "mandatory" : "True",
+ "hpa-feature": "cpuInstructionSetExtensions",
+ "mandatory": true,
"architecture": "INTEL-64",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": [
+ "<CPUINST>",
+ "<CPUINST>"
+ ],
+ "operator": [
+ "ALL"
+ ],
+ "unit": ""
+ }
]
}
]
@@ -99,7 +139,7 @@
{"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
]
},
- {
+ {
"hpa-feature" : "basicCapabilities",
"mandatory" : "True",
"architecture": "generic",
@@ -122,18 +162,17 @@
]
},
{
- "hpa-feature" : "pcie",
+ "hpa-feature" : "pciePassthrough",
"mandatory" : "True",
"architecture": "generic",
"directives": [],
"hpa-feature-attributes": [
{"hpa-attribute-key": "pciCount", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
{"hpa-attribute-key": "pciVendorId", "hpa-attribute-value":"8086", "operator": "=", "unit": ""},
- {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
- {"hpa-attribute-key": "functionType", "hpa-attribute-value": "<PCITYPEVALUE>","operator": "=", "unit": ""}
+ {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""}
]
}
- ]
+]
},
{
"id": "vgmux_3",
@@ -163,7 +202,7 @@
{"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
{"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
]
- },
+},
{
"hpa-feature" : "basicCapabilities",
"mandatory" : "True",
@@ -188,4 +227,5 @@
}
]
}
+ }
}
diff --git a/test/policy-local-files/hpa_policy_vG_1.json b/test/policy-local-files/hpa_policy_vG_1.json
index 5d2499f..59ba4b1 100644
--- a/test/policy-local-files/hpa_policy_vG_1.json
+++ b/test/policy-local-files/hpa_policy_vG_1.json
@@ -1,18 +1,27 @@
{
- "service": "hpaPolicy",
- "policyName": "OSDF_R2.hpa_policy_vG_1",
- "description": "HPA policy for vG",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "3",
- "riskType": "test",
- "riskLevel": "2",
- "guard": "False",
- "content": {
- "resources": "vG",
- "identity": "hpaPolicy_vG",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "policyType": "hpaPolicy",
+ "OSDF_FRANKFURT.hpa_policy_vG_1": {
+ "type": "onap.policies.optimization.resource.HpaPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.hpa_policy_vG_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "hpa-vG",
"flavorFeatures": [
{
"id": "vg_1",
@@ -28,8 +37,8 @@
]
}
],
- "flavorProperties":[
- {
+ "flavorProperties": [
+ {
"hpa-feature" : "cpuTopology",
"mandatory" : "True",
"architecture": "generic",
@@ -43,33 +52,64 @@
{"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
]
},
- {
- "hpa-feature" : "basicCapabilities",
- "mandatory" : "True",
+ {
+ "hpa-feature": "basicCapabilities",
+ "mandatory": true,
"architecture": "generic",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
- {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ {
+ "hpa-attribute-key": "numVirtualCpu",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ },
+ {
+ "hpa-attribute-key": "virtualMemSize",
+ "hpa-attribute-value": 6,
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
]
},
{
- "hpa-feature" : "ovsDpdk",
- "mandatory" : "False",
- "score" : "3",
+ "hpa-feature": "ovsDpdk",
+ "mandatory": false,
+ "score": 3,
"architecture": "generic",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+ {
+ "hpa-attribute-key": "dataProcessingAccelerationLibrary",
+ "hpa-attribute-value": "ovsDpdk_version",
+ "operator": [
+ "="
+ ],
+ "unit": ""
+ }
]
},
{
- "hpa-feature" : "cpuInstructionSetExtensions",
- "mandatory" : "True",
+ "hpa-feature": "cpuInstructionSetExtensions",
+ "mandatory": true,
"architecture": "INTEL-64",
"directives": [],
"hpa-feature-attributes": [
- {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+ {
+ "hpa-attribute-key": "instructionSetExtensions",
+ "hpa-attribute-value": [
+ "<CPUINST>",
+ "<CPUINST>"
+ ],
+ "operator": [
+ "ALL"
+ ],
+ "unit": ""
+ }
]
}
]
@@ -99,7 +139,7 @@
{"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
]
},
- {
+ {
"hpa-feature" : "basicCapabilities",
"mandatory" : "True",
"architecture": "generic",
@@ -132,7 +172,7 @@
{"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""}
]
}
- ]
+]
},
{
"id": "vg_3",
@@ -162,7 +202,7 @@
{"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
{"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
]
- },
+},
{
"hpa-feature" : "basicCapabilities",
"mandatory" : "True",
@@ -187,4 +227,5 @@
}
]
}
+ }
}
diff --git a/test/policy-local-files/meta-valid-policies-old.txt b/test/policy-local-files/meta-valid-policies-old.txt
new file mode 100644
index 0000000..99e3e88
--- /dev/null
+++ b/test/policy-local-files/meta-valid-policies-old.txt
@@ -0,0 +1,16 @@
+Affinity_vCPE_1.json
+Capacity_vGMuxInfra.json
+Capacity_vG_1.json
+Distance_vGMuxInfra_1.json
+Distance_vG_1.json
+Placement_Optimization_1.json
+QueryPolicy_vCPE.json
+QueryPolicy_vCPE_2.json
+hpa_policy_vGMuxInfra_1.json
+hpa_policy_vG_1.json
+vnfPolicy_vG.json
+vnfPolicy_vGMuxInfra.json
+QueryPolicy_vFW_TD.json
+vnfPolicy_vFW_TD.json
+vnfPolicy_vPGN_TD.json
+affinity_vFW_TD.json \ No newline at end of file
diff --git a/test/policy-local-files/meta-valid-policies.txt b/test/policy-local-files/meta-valid-policies.txt
index 772ec1a..5f969bf 100644
--- a/test/policy-local-files/meta-valid-policies.txt
+++ b/test/policy-local-files/meta-valid-policies.txt
@@ -10,3 +10,8 @@ hpa_policy_vGMuxInfra_1.json
hpa_policy_vG_1.json
vnfPolicy_vG.json
vnfPolicy_vGMuxInfra.json
+QueryPolicy_vFW_TD.json
+vnfPolicy_vFW_TD.json
+vnfPolicy_vPGN_TD.json
+Affinity_vFW_TD.json
+Attribute_vNS_1.json \ No newline at end of file
diff --git a/test/policy-local-files/nst-selection-files/attribute_policy_nst.json b/test/policy-local-files/nst-selection-files/attribute_policy_nst.json
new file mode 100644
index 0000000..0989927
--- /dev/null
+++ b/test/policy-local-files/nst-selection-files/attribute_policy_nst.json
@@ -0,0 +1,42 @@
+{
+ "Threshold_nst": {
+ "metadata": {
+ "policy-id": "Threshold_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "nst_Threshold",
+ "resources": [
+ "nst"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ],
+ "thresholdProperties": [
+ {
+ "attribute": "latency",
+ "operator": "lte",
+ "threshold": {
+ "get_param": "latency"
+ },
+ "unit": "ms"
+ },
+ {
+ "attribute": "reliability",
+ "operator": "gte",
+ "threshold": {
+ "get_param": "reliability"
+ },
+ "unit": ""
+ }
+ ]
+ },
+ "type": "onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version": "1.0.0",
+ "version": "1.0.0"
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/nst-selection-files/optimization_policy_nst.json b/test/policy-local-files/nst-selection-files/optimization_policy_nst.json
new file mode 100644
index 0000000..27c1f7c
--- /dev/null
+++ b/test/policy-local-files/nst-selection-files/optimization_policy_nst.json
@@ -0,0 +1,37 @@
+{
+ "nst_minimize_latency": {
+ "metadata": {
+ "policy-id": "nst_minimize_latency",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "latency",
+ "demand": "nst"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "nst"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/nst-selection-files/query_policy_nst.json b/test/policy-local-files/nst-selection-files/query_policy_nst.json
new file mode 100644
index 0000000..1955e7b
--- /dev/null
+++ b/test/policy-local-files/nst-selection-files/query_policy_nst.json
@@ -0,0 +1,31 @@
+{
+ "queryPolicy_nst": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "queryPolicy_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "nst"
+ ],
+ "geography": [],
+ "identity": "queryPolicy_nst",
+ "queryProperties": [
+ {
+ "attribute": "latency",
+ "attribute_location": "latency"
+ },
+ {
+ "attribute": "reliability",
+ "attribute_location": "reliability"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/nst-selection-files/vnf_policy_nst.json b/test/policy-local-files/nst-selection-files/vnf_policy_nst.json
new file mode 100644
index 0000000..14906df
--- /dev/null
+++ b/test/policy-local-files/nst-selection-files/vnf_policy_nst.json
@@ -0,0 +1,34 @@
+{
+ "vnfPolicy_nst": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "vnfPolicy_nst",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "resources": [
+ "nst"
+ ],
+ "services": [
+ "nst"
+ ],
+ "identity": "vnf_nst",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "inventoryType": "nst",
+ "unique": "true",
+ "attributes": {
+ "model-role": "nst"
+ }
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/old-policies/Affinity_vCPE_1.json b/test/policy-local-files/old-policies/Affinity_vCPE_1.json
new file mode 100644
index 0000000..2953589
--- /dev/null
+++ b/test/policy-local-files/old-policies/Affinity_vCPE_1.json
@@ -0,0 +1,21 @@
+{
+ "service": "affinityPolicy",
+ "policyName": "OSDF_DUBLIN.Affinity_vCPE_1",
+ "description": "Zone policy for vCPE",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "identity": "affinity_vCPE",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+ "affinityProperty": {
+ "qualifier": "same",
+ "category": "complex"
+ },
+ "policyType": "zone",
+ "resources": ["vGMuxInfra", "vG"]
+ }
+}
diff --git a/test/policy-local-files/old-policies/Attribute_vNS_1.json b/test/policy-local-files/old-policies/Attribute_vNS_1.json
new file mode 100644
index 0000000..e4766db
--- /dev/null
+++ b/test/policy-local-files/old-policies/Attribute_vNS_1.json
@@ -0,0 +1,49 @@
+{
+ "service": "attributePolicy",
+ "policyName": "OSDF_FRANKFURT.AttributePolicy_vNS_1",
+ "description": "Attribute Policy for Network Slicing (NS)",
+ "templateVersion": "OpenSource.version.1",
+ "version": "OpenSource.version.1",
+ "priority": "1",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "attribute-vNS",
+ "policyScope": [
+ "vNS",
+ "us",
+ "international",
+ "ip"
+ ],
+ "policyType": "attribute",
+ "resources": [
+ "vNS",
+ ""
+ ],
+ "attributeProperties": {
+ "cloudRegion": {
+ "serviceRequests": [
+ "",
+ ""
+ ],
+ "cloudRequests": [
+ "",
+ ""
+ ]
+ },
+ "networkRoles": {
+ "all": [
+ "",
+ ""
+ ]
+ },
+ "complex": {
+ "any": [
+ "",
+ ""
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/old-policies/Capacity_vFW_1.json b/test/policy-local-files/old-policies/Capacity_vFW_1.json
new file mode 100644
index 0000000..d5e80ab
--- /dev/null
+++ b/test/policy-local-files/old-policies/Capacity_vFW_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "vim_fit",
+ "policyName": "OSDF_DUBLIN.Capacity_vFW_1",
+ "description": "Capacity policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "5",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "identity": "capacity_vFW",
+ "policyScope": ["vFW", "US", "INTERNATIONAL", "ip", "vFW"],
+ "resources": ["vFW"],
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 2, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ },
+ "policyType": "vim_fit",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Capacity_vGMuxInfra.json b/test/policy-local-files/old-policies/Capacity_vGMuxInfra.json
new file mode 100644
index 0000000..010cf3f
--- /dev/null
+++ b/test/policy-local-files/old-policies/Capacity_vGMuxInfra.json
@@ -0,0 +1,22 @@
+{
+ "service": "vim_fit",
+ "policyName": "OSDF_DUBLIN.Capacity_vGMuxInfra",
+ "description": "Capacity policy for vGMuxInfra",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "5",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "identity": "capacity_vGMuxInfra",
+ "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
+ "resources": ["vGMuxInfra"],
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ },
+ "policyType": "vim_fit",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Capacity_vG_1.json b/test/policy-local-files/old-policies/Capacity_vG_1.json
new file mode 100644
index 0000000..fedcc4f
--- /dev/null
+++ b/test/policy-local-files/old-policies/Capacity_vG_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "vim_fit",
+ "policyName": "OSDF_DUBLIN.Capacity_vG_1",
+ "description": "Capacity policy for vG",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "5",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "identity": "capacity_vG",
+ "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vG"],
+ "resources": ["vG"],
+ "capacityProperty": {
+ "controller": "multicloud",
+ "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}"
+ },
+ "policyType": "vim_fit",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Distance_vFW_1.json b/test/policy-local-files/old-policies/Distance_vFW_1.json
new file mode 100644
index 0000000..80e08d9
--- /dev/null
+++ b/test/policy-local-files/old-policies/Distance_vFW_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "distancePolicy",
+ "policyName": "OSDF_DUBLIN.Distance_vFW_1",
+ "description": "Distance Policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": { "value": "100", "operator": "<", "unit": "km" }
+ },
+ "identity": "distance-vFW",
+ "resources": ["vFW"],
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "distance_to_location",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Distance_vGMuxInfra_1.json b/test/policy-local-files/old-policies/Distance_vGMuxInfra_1.json
new file mode 100644
index 0000000..e3ba83c
--- /dev/null
+++ b/test/policy-local-files/old-policies/Distance_vGMuxInfra_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "distancePolicy",
+ "policyName": "OSDF_DUBLIN.Distance_vGMuxInfra",
+ "description": "Distance Policy for vGMuxInfra",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": { "value": "500", "operator": "<", "unit": "km" }
+ },
+ "identity": "distance-vGMuxInfra",
+ "resources": ["vGMuxInfra"],
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
+ "policyType": "distance_to_location",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Distance_vG_1.json b/test/policy-local-files/old-policies/Distance_vG_1.json
new file mode 100644
index 0000000..c498c7a
--- /dev/null
+++ b/test/policy-local-files/old-policies/Distance_vG_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "distancePolicy",
+ "policyName": "OSDF_DUBLIN.Distance_vG_1",
+ "description": "Distance Policy for vG",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": { "value": "1500", "operator": "<", "unit": "km" }
+ },
+ "identity": "distance-vG",
+ "resources": ["vG"],
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
+ "policyType": "distance_to_location",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/old-policies/Placement_Optimization_1.json b/test/policy-local-files/old-policies/Placement_Optimization_1.json
new file mode 100644
index 0000000..9b062b0
--- /dev/null
+++ b/test/policy-local-files/old-policies/Placement_Optimization_1.json
@@ -0,0 +1,55 @@
+{
+ "service": "optimizationPolicy",
+ "policyName": "OSDF_DUBLIN.Placement_Optimization_1",
+ "description": "Placement Optimization Policy for vGMuxInfra",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "5",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "objectiveParameter": {
+ "parameterAttributes": [
+ {
+ "resources": ["vGMuxInfra"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": ["vG"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": ["vG"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ }
+ ],
+ "operator": "sum"
+ },
+ "identity": "optimization",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+ "policyType": "placement_optimization",
+ "objective": "minimize"
+ }
+}
diff --git a/test/policy-local-files/old-policies/QueryPolicy_vCPE.json b/test/policy-local-files/old-policies/QueryPolicy_vCPE.json
new file mode 100644
index 0000000..5097964
--- /dev/null
+++ b/test/policy-local-files/old-policies/QueryPolicy_vCPE.json
@@ -0,0 +1,21 @@
+{
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.QueryPolicy_vCPE",
+ "description": "Query policy for vCPE",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "queryProperties": [
+ {"attribute":"customerLatitude", "attribute_location": "customerLatitude"},
+ {"attribute":"customerLongitude", "attribute_location": "customerLongitude"}
+ ],
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+ "policyType": "request_param_query",
+ "serviceName": "vCPE",
+ "identity": "vCPE_Query_Policy"
+ }
+}
diff --git a/test/policy-local-files/old-policies/QueryPolicy_vCPE_2.json b/test/policy-local-files/old-policies/QueryPolicy_vCPE_2.json
new file mode 100644
index 0000000..e398f39
--- /dev/null
+++ b/test/policy-local-files/old-policies/QueryPolicy_vCPE_2.json
@@ -0,0 +1,24 @@
+{
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.queryPolicy_vCPE",
+ "description": "Query policy for vCPE",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "queryProperties": [
+ {"attribute":"locationId", "attribute_location": "customerLocation", "value": ""},
+ {"attribute":"id", "attribute_location": "vpnInfo.vpnId", "value": ""},
+ {"attribute":"upstreamBW", "attribute_location": "vpnInfo.upstreamBW", "value": ""},
+ {"attribute":"customerLatitude", "attribute_location": "customerLatitude", "value": 1.1},
+ {"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": 2.2}
+ ],
+ "serviceName": "vCPE",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+ "policyType": "request_param_query",
+ "identity": "vCPE_Query_Policy"
+ }
+}
diff --git a/test/policy-local-files/old-policies/QueryPolicy_vFW.json b/test/policy-local-files/old-policies/QueryPolicy_vFW.json
new file mode 100644
index 0000000..932074b
--- /dev/null
+++ b/test/policy-local-files/old-policies/QueryPolicy_vFW.json
@@ -0,0 +1,21 @@
+{
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.QueryPolicy_vFW",
+ "description": "Query policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "queryProperties": [
+ {"attribute":"customerLatitude", "attribute_location": "customerLatitude"},
+ {"attribute":"customerLongitude", "attribute_location": "customerLongitude"}
+ ],
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "request_param_query",
+ "serviceName": "vFW",
+ "identity": "vFW_Query_Policy"
+ }
+}
diff --git a/test/policy-local-files/old-policies/QueryPolicy_vFW_TD.json b/test/policy-local-files/old-policies/QueryPolicy_vFW_TD.json
new file mode 100644
index 0000000..8866635
--- /dev/null
+++ b/test/policy-local-files/old-policies/QueryPolicy_vFW_TD.json
@@ -0,0 +1,32 @@
+{
+ "service": "queryPolicy",
+ "policyName": "OSDF_DUBLIN.QueryPolicy_vFW_TD",
+ "description": "Query policy for vFW TD",
+ "templateVersion": "OpenSource.version.1",
+ "version": "oofDublin",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "queryProperties": [
+ {"attribute":"customerLatitude", "attribute_location": "customerLatitude", "value": 1.1},
+ {"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": 2.2},
+ {"attribute":"chosen_region", "attribute_location": "chosenRegion"},
+ {"attribute":"chosen_customer_id", "attribute_location": "chosenCustomerId"}
+ ],
+ "policyScope": [
+ "td",
+ "us",
+ "vFW-SINK",
+ "vPGN"
+ ],
+ "policyType": "request_param_query",
+ "serviceName": "vFW_TD",
+ "identity": "vFW_TD_Query_Policy",
+ "resources": [
+ "vFW-SINK",
+ "vPGN"
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/affinity_vFW_TD.json b/test/policy-local-files/old-policies/affinity_vFW_TD.json
new file mode 100644
index 0000000..2df2d50
--- /dev/null
+++ b/test/policy-local-files/old-policies/affinity_vFW_TD.json
@@ -0,0 +1,29 @@
+{
+ "service": "affinityPolicy",
+ "policyName": "OSDF_DUBLIN.Affinity_vFW_TD",
+ "description": "Affinity policy for vPGN Anchor and vFW destination point",
+ "templateVersion": "OpenSource.version.1",
+ "version": "oofDublin",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "identity": "affinity_vFW_TD",
+ "policyScope": [
+ "td",
+ "us",
+ "vFW-SINK",
+ "vPGN"
+ ],
+ "affinityProperty": {
+ "qualifier": "same",
+ "category": "region"
+ },
+ "policyType": "zone",
+ "resources": [
+ "vFW-SINK",
+ "vPGN"
+ ]
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/old-policies/hpa_policy_vFW_1.json b/test/policy-local-files/old-policies/hpa_policy_vFW_1.json
new file mode 100644
index 0000000..a60ad47
--- /dev/null
+++ b/test/policy-local-files/old-policies/hpa_policy_vFW_1.json
@@ -0,0 +1,214 @@
+{
+ "service": "hpaPolicy",
+ "policyName": "OSDF_DUBLIN.hpa_policy_vFW_1",
+ "description": "HPA policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "resources": ["vFW"],
+ "identity": "hpa-vFW",
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "hpa",
+ "flavorFeatures": [
+ {
+ "flavorProperties": [
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": ">=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numVirtualCpu"
+ },
+ {
+ "unit": "MB",
+ "operator": ">=",
+ "hpa-attribute-value": "8",
+ "hpa-attribute-key": "virtualMemSize"
+ }
+ ],
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaNodes"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaCpu-0"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numaCpu-1"
+ },
+ {
+ "unit": "GB",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaMem-0"
+ },
+ {
+ "unit": "GB",
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numaMem-1"
+ }
+ ],
+ "hpa-feature": "numa",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "MB",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "memoryPageSize"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numberOfPages"
+ }
+ ],
+ "hpa-feature": "hugePages",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "Intel64",
+ "hpa-feature": "sriovNICNetwork",
+ "hpa-version": "v1",
+ "directives": [
+ {
+ "type": "sriovNICNetwork_directives",
+ "attributes": [
+ {
+ "attribute_name": "oof_returned_vnic_type_for_firewall_protected",
+ "attribute_value": "direct"
+ }
+ ]
+ }
+ ],
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "1",
+ "hpa-attribute-key": "pciCount"
+ },
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "1234",
+ "hpa-attribute-key": "pciVendorId"
+ },
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "7890",
+ "hpa-attribute-key": "pciDeviceId"
+ }
+ ],
+ "score": "100",
+ "mandatory": "False"
+ }
+ ],
+ "type": "vnfc",
+ "id": "vfw_1",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_1",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "flavorProperties": [
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "operator": ">=",
+ "hpa-attribute-value": "1",
+ "hpa-attribute-key": "numVirtualCpu"
+ },
+ {
+ "unit": "GB",
+ "operator": ">=",
+ "hpa-attribute-value": "7",
+ "hpa-attribute-key": "virtualMemSize"
+ }
+ ],
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True"
+ }
+ ],
+ "type": "vnfc",
+ "id": "vfw_2",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_2",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vfw_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_3",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "basicCapabilities",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "mandatory": "True",
+ "directives": [],
+ "hpa-feature-attributes": []
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/hpa_policy_vGMuxInfra_1.json b/test/policy-local-files/old-policies/hpa_policy_vGMuxInfra_1.json
new file mode 100644
index 0000000..690f5dc
--- /dev/null
+++ b/test/policy-local-files/old-policies/hpa_policy_vGMuxInfra_1.json
@@ -0,0 +1,191 @@
+{
+ "service": "hpaPolicy",
+ "policyName": "OSDF_DUBLIN.hpa_policy_vGMuxInfra_1",
+ "description": "HPA policy for vGMuxInfra",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "resources": ["vGMuxInfra"],
+ "identity": "hpa-vGMuxInfra",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
+ "policyType": "hpa",
+ "flavorFeatures": [
+ {
+ "id": "vgmux_1",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_01",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "cpuTopology",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "2","operator": ">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "4","operator": "<=", "unit": ""},
+ {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "2", "operator":">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "4", "operator":"<=", "unit": ""},
+ {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "4", "operator":">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "ovsDpdk",
+ "mandatory" : "False",
+ "score" : "3",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+ ]
+ },
+ {
+ "hpa-feature" : "cpuInstructionSetExtensions",
+ "mandatory" : "True",
+ "architecture": "INTEL-64",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vgmux_2",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_02",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "cpuPinningy",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"logicalCpuThreadPinningPolicy", "hpa-attribute-value":"<CPUTHREADPOLICY>", "operator": "=", "unit":""},
+ {"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "localStorage",
+ "mandatory" : "False",
+ "score" : "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "diskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+ {"hpa-attribute-key": "ephemeralDiskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+ {"hpa-attribute-key": "swapMemSize", "hpa-attribute-value":"16", "operator": "=", "unit": "MB"}
+ ]
+ },
+ {
+ "hpa-feature" : "pcie",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "pciCount", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "pciVendorId", "hpa-attribute-value":"8086", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "functionType", "hpa-attribute-value": "<PCITYPEVALUE>","operator": "=", "unit": ""}
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vgmux_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_03",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "numa",
+ "mandatory" : "False",
+ "score" : "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numaNodes", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaCpu-0", "hpa-attribute-value":"2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaMem-0", "hpa-attribute-value": "2048", "operator": "=", "unit": "MB"},
+ {"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "hugePages",
+ "mandatory" : "False",
+ "score" : "7",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "memoryPageSize", "hpa-attribute-value": "<MEMORYPAGESIZE>", "operator": "=", "unit": ""}
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/hpa_policy_vG_1.json b/test/policy-local-files/old-policies/hpa_policy_vG_1.json
new file mode 100644
index 0000000..b29c67d
--- /dev/null
+++ b/test/policy-local-files/old-policies/hpa_policy_vG_1.json
@@ -0,0 +1,190 @@
+{
+ "service": "hpaPolicy",
+ "policyName": "OSDF_DUBLIN.hpa_policy_vG_1",
+ "description": "HPA policy for vG",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "resources": ["vG"],
+ "identity": "hpa-vG",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
+ "policyType": "hpa",
+ "flavorFeatures": [
+ {
+ "id": "vg_1",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_01",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "cpuTopology",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "2","operator": ">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "4","operator": "<=", "unit": ""},
+ {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "2", "operator":">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "4", "operator":"<=", "unit": ""},
+ {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "4", "operator":">=", "unit": ""},
+ {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "ovsDpdk",
+ "mandatory" : "False",
+ "score" : "3",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+ ]
+ },
+ {
+ "hpa-feature" : "cpuInstructionSetExtensions",
+ "mandatory" : "True",
+ "architecture": "INTEL-64",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_2",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_02",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "cpuPinningy",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key":"logicalCpuThreadPinningPolicy", "hpa-attribute-value":"<CPUTHREADPOLICY>", "operator": "=", "unit":""},
+ {"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "localStorage",
+ "mandatory" : "False",
+ "score" : "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "diskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+ {"hpa-attribute-key": "ephemeralDiskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+ {"hpa-attribute-key": "swapMemSize", "hpa-attribute-value":"16", "operator": "=", "unit": "MB"}
+ ]
+ },
+ {
+ "hpa-feature" : "pciePassthrough",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "pciCount", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "pciVendorId", "hpa-attribute-value":"8086", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""}
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vg_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "flavor_label_vm_03",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties":[
+ {
+ "hpa-feature" : "numa",
+ "mandatory" : "False",
+ "score" : "5",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numaNodes", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaCpu-0", "hpa-attribute-value":"2", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaMem-0", "hpa-attribute-value": "2048", "operator": "=", "unit": "MB"},
+ {"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
+ ]
+ },
+ {
+ "hpa-feature" : "basicCapabilities",
+ "mandatory" : "True",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+ {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+ ]
+ },
+ {
+ "hpa-feature" : "hugePages",
+ "mandatory" : "False",
+ "score" : "7",
+ "architecture": "generic",
+ "directives": [],
+ "hpa-feature-attributes": [
+ {"hpa-attribute-key": "memoryPageSize", "hpa-attribute-value": "<MEMORYPAGESIZE>", "operator": "=", "unit": ""}
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/subscriber_policy.json b/test/policy-local-files/old-policies/subscriber_policy_vCPE.json
index f1b818c..9359c20 100644
--- a/test/policy-local-files/subscriber_policy.json
+++ b/test/policy-local-files/old-policies/subscriber_policy_vCPE.json
@@ -1,15 +1,15 @@
{
- "service": "SubscriberPolicy",
- "policyName": "oofBeijing.SubscriberPolicy_v1",
- "description": "Subscriber Policy",
- "templateVersion": "0.0.1",
- "version": "oofBeijing",
+ "service": "subscriberPolicy",
+ "policyName": "OSDF_DUBLIN.SubscriberPolicy_v1",
+ "description": "Subscriber Policy for vCPE",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
"priority": "1",
"riskType": "test",
"riskLevel": "3",
"guard": "False",
"content": {
- "identity": "subscriber",
+ "identity": "subscriber_vCPE",
"policyScope": ["vCPE", "subscriber_x", "subscriber_y", "subscriberPolicy"],
"properties": {
"subscriberName": ["subscriber_x", "subscriber_y"],
@@ -19,4 +19,4 @@
"policyType": "subscriberPolicy",
"serviceName": "vCPE"
}
-} \ No newline at end of file
+}
diff --git a/test/policy-local-files/old-policies/subscriber_policy_vFW.json b/test/policy-local-files/old-policies/subscriber_policy_vFW.json
new file mode 100644
index 0000000..299da04
--- /dev/null
+++ b/test/policy-local-files/old-policies/subscriber_policy_vFW.json
@@ -0,0 +1,22 @@
+{
+ "service": "subscriberPolicy",
+ "policyName": "OSDF_DUBLIN.SubscriberPolicy_v1",
+ "description": "Subscriber Policy for VFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "1",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "subscriber_vFW",
+ "policyScope": ["vFW", "subscriber_x", "subscriber_y", "subscriberPolicy"],
+ "properties": {
+ "subscriberName": ["subscriber_x", "subscriber_y"],
+ "subscriberRole": ["PVT Homing"],
+ "provStatus": ["CAPPED"]
+ },
+ "policyType": "subscriberPolicy",
+ "serviceName": "vFW"
+ }
+}
diff --git a/test/policy-local-files/old-policies/vnfPolicy_vFW.json b/test/policy-local-files/old-policies/vnfPolicy_vFW.json
new file mode 100644
index 0000000..0b7d9a2
--- /dev/null
+++ b/test/policy-local-files/old-policies/vnfPolicy_vFW.json
@@ -0,0 +1,29 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vFW",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vFW",
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "vnfPolicy",
+ "resources": ["vFW"],
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/vnfPolicy_vFW_TD.json b/test/policy-local-files/old-policies/vnfPolicy_vFW_TD.json
new file mode 100644
index 0000000..a471a77
--- /dev/null
+++ b/test/policy-local-files/old-policies/vnfPolicy_vFW_TD.json
@@ -0,0 +1,44 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vFW_TD",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "oofDublin",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vFW_TD",
+ "policyScope": [
+ "td",
+ "us",
+ "vFW-SINK"
+ ],
+ "policyType": "vnfPolicy",
+ "resources": ["vFW-SINK"],
+ "applicableResources": "any",
+ "vnfProperties": [{
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "vfmodule",
+ "customerId": {
+ "get_param": "chosen_customer_id"
+ },
+ "equipmentRole": "",
+ "attributes": {
+ "orchestrationStatus": ["active"],
+ "provStatus": "ACTIVE",
+ "cloudRegionId": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthroughAttributes": {
+ "td-role": "destination"
+ }
+ }]
+ }
+}
diff --git a/test/policy-local-files/old-policies/vnfPolicy_vG.json b/test/policy-local-files/old-policies/vnfPolicy_vG.json
new file mode 100644
index 0000000..b047686
--- /dev/null
+++ b/test/policy-local-files/old-policies/vnfPolicy_vG.json
@@ -0,0 +1,29 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vG",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vG",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
+ "policyType": "vnfPolicy",
+ "resources": ["vG"],
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/vnfPolicy_vGMuxInfra.json b/test/policy-local-files/old-policies/vnfPolicy_vGMuxInfra.json
new file mode 100644
index 0000000..45d67f6
--- /dev/null
+++ b/test/policy-local-files/old-policies/vnfPolicy_vGMuxInfra.json
@@ -0,0 +1,28 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vGMuxInfra",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vGMuxInfra",
+ "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
+ "policyType": "vnfPolicy",
+ "resources": ["vGMuxInfra"],
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "vGMuxInfra-xx",
+ "inventoryType": "service",
+ "customerId": "SDN-ETHERNET-INTERNET",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/old-policies/vnfPolicy_vPGN_TD.json b/test/policy-local-files/old-policies/vnfPolicy_vPGN_TD.json
new file mode 100644
index 0000000..2e79f2f
--- /dev/null
+++ b/test/policy-local-files/old-policies/vnfPolicy_vPGN_TD.json
@@ -0,0 +1,51 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_DUBLIN.vnfPolicy_vPGN_TD",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "oofDublin",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vPGN_TD",
+ "policyScope": [
+ "td",
+ "us",
+ "vPGN"
+ ],
+ "policyType": "vnfPolicy",
+ "resources": [
+ "vPGN"
+ ],
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "vfmodule",
+ "customerId": {
+ "get_param": "chosen_customer_id"
+ },
+ "equipmentRole": "",
+ "unique": "False",
+ "attributes": {
+ "orchestrationStatus": [
+ "active"
+ ],
+ "provStatus": "ACTIVE",
+ "cloudRegionId": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthroughAttributes": {
+ "td-role": "anchor"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/pwt-it-policies/Distance_vFW_1.json b/test/policy-local-files/pwt-it-policies/Distance_vFW_1.json
new file mode 100755
index 0000000..12c24da
--- /dev/null
+++ b/test/policy-local-files/pwt-it-policies/Distance_vFW_1.json
@@ -0,0 +1,22 @@
+{
+ "service": "distancePolicy",
+ "policyName": "OSDF_CASABLANCA.Distance_vFW_1",
+ "description": "Distance Policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "distanceProperties": {
+ "locationInfo": "customer_loc",
+ "distance": { "value": "100", "operator": "<", "unit": "km" }
+ },
+ "identity": "distance-vFW",
+ "resources": ["vFW", "7400fd06C75f4a44A68f"],
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "distance_to_location",
+ "applicableResources": "any"
+ }
+}
diff --git a/test/policy-local-files/pwt-it-policies/Placement_Optimization_1.json b/test/policy-local-files/pwt-it-policies/Placement_Optimization_1.json
new file mode 100755
index 0000000..8701497
--- /dev/null
+++ b/test/policy-local-files/pwt-it-policies/Placement_Optimization_1.json
@@ -0,0 +1,55 @@
+{
+ "service": "optimizationPolicy",
+ "policyName": "OSDF_CASABLANCA.Placement_Optimization_1",
+ "description": "Placement Optimization Policy for vGMuxInfra",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "5",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "objectiveParameter": {
+ "parameterAttributes": [
+ {
+ "resources": ["vGMuxInfra"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": ["vG"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "1",
+ "operator": "product"
+ },
+ {
+ "resources": ["vG"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW", "7400fd06C75f4a44A68f"],
+ "customerLocationInfo": "customer_loc",
+ "parameter": "distance",
+ "weight": "100",
+ "operator": "product"
+ },
+ {
+ "resources": ["vFW", "7400fd06C75f4a44A68f"],
+ "parameter": "hpa_score",
+ "weight": "200",
+ "operator": "product"
+ }
+ ],
+ "operator": "sum"
+ },
+ "identity": "optimization",
+ "policyScope": ["vcpe", "us", "international", "ip", "vGMuxInfra", "vG", "vfw"],
+ "policyType": "placement_optimization",
+ "objective": "minimize"
+ }
+}
diff --git a/test/policy-local-files/pwt-it-policies/QueryPolicy_vFW.json b/test/policy-local-files/pwt-it-policies/QueryPolicy_vFW.json
new file mode 100755
index 0000000..443a82a
--- /dev/null
+++ b/test/policy-local-files/pwt-it-policies/QueryPolicy_vFW.json
@@ -0,0 +1,21 @@
+{
+ "service": "queryPolicy",
+ "policyName": "OSDF_CASABLANCA.QueryPolicy_vFW",
+ "description": "Query policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "queryProperties": [
+ {"attribute":"customerLatitude", "attribute_location": "customerLatitude"},
+ {"attribute":"customerLongitude", "attribute_location": "customerLongitude"}
+ ],
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "request_param_query",
+ "serviceName": "vFW",
+ "identity": "vFW_Query_Policy"
+ }
+}
diff --git a/test/policy-local-files/pwt-it-policies/hpa_policy_vFW_1.json b/test/policy-local-files/pwt-it-policies/hpa_policy_vFW_1.json
new file mode 100755
index 0000000..7d72485
--- /dev/null
+++ b/test/policy-local-files/pwt-it-policies/hpa_policy_vFW_1.json
@@ -0,0 +1,214 @@
+{
+ "service": "hpaPolicy",
+ "policyName": "OSDF_CASABLANCA.hpa_policy_vFW_1",
+ "description": "HPA policy for vFW",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "3",
+ "riskType": "test",
+ "riskLevel": "2",
+ "guard": "False",
+ "content": {
+ "resources": ["vFW", "7400fd06C75f4a44A68f"],
+ "identity": "hpa-vFW",
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "hpa",
+ "flavorFeatures": [
+ {
+ "flavorProperties": [
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": ">=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numVirtualCpu"
+ },
+ {
+ "unit": "MB",
+ "operator": ">=",
+ "hpa-attribute-value": "8",
+ "hpa-attribute-key": "virtualMemSize"
+ }
+ ],
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaNodes"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaCpu-0"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numaCpu-1"
+ },
+ {
+ "unit": "GB",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "numaMem-0"
+ },
+ {
+ "unit": "GB",
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numaMem-1"
+ }
+ ],
+ "hpa-feature": "numa",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "unit": "MB",
+ "operator": "=",
+ "hpa-attribute-value": "2",
+ "hpa-attribute-key": "memoryPageSize"
+ },
+ {
+ "operator": "=",
+ "hpa-attribute-value": "4",
+ "hpa-attribute-key": "numberOfPages"
+ }
+ ],
+ "hpa-feature": "hugePages",
+ "mandatory": "True"
+ },
+ {
+ "architecture": "Intel64",
+ "hpa-feature": "sriovNICNetwork",
+ "hpa-version": "v1",
+ "directives": [
+ {
+ "type": "sriovNICNetwork_directives",
+ "attributes": [
+ {
+ "attribute_name": "oof_returned_vnic_type_for_firewall_protected",
+ "attribute_value": "direct"
+ }
+ ]
+ }
+ ],
+ "hpa-feature-attributes": [
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "1",
+ "hpa-attribute-key": "pciCount"
+ },
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "1234",
+ "hpa-attribute-key": "pciVendorId"
+ },
+ {
+ "unit": "",
+ "operator": "=",
+ "hpa-attribute-value": "7890",
+ "hpa-attribute-key": "pciDeviceId"
+ }
+ ],
+ "score": "100",
+ "mandatory": "False"
+ }
+ ],
+ "type": "vnfc",
+ "id": "vfw_1",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_1",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "flavorProperties": [
+ {
+ "architecture": "generic",
+ "directives": [],
+ "hpa-version": "v1",
+ "hpa-feature-attributes": [
+ {
+ "operator": ">=",
+ "hpa-attribute-value": "1",
+ "hpa-attribute-key": "numVirtualCpu"
+ },
+ {
+ "unit": "GB",
+ "operator": ">=",
+ "hpa-attribute-value": "7",
+ "hpa-attribute-key": "virtualMemSize"
+ }
+ ],
+ "hpa-feature": "basicCapabilities",
+ "mandatory": "True"
+ }
+ ],
+ "type": "vnfc",
+ "id": "vfw_2",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_2",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "vfw_3",
+ "type": "vnfc",
+ "directives": [
+ {
+ "type": "flavor_directives",
+ "attributes": [
+ {
+ "attribute_name": "label_3",
+ "attribute_value": ""
+ }
+ ]
+ }
+ ],
+ "flavorProperties": [
+ {
+ "hpa-feature": "basicCapabilities",
+ "hpa-version": "v1",
+ "architecture": "generic",
+ "mandatory": "True",
+ "directives": [],
+ "hpa-feature-attributes": []
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/pwt-it-policies/vnfPolicy_vFW.json b/test/policy-local-files/pwt-it-policies/vnfPolicy_vFW.json
new file mode 100755
index 0000000..7180345
--- /dev/null
+++ b/test/policy-local-files/pwt-it-policies/vnfPolicy_vFW.json
@@ -0,0 +1,29 @@
+{
+ "service": "vnfPolicy",
+ "policyName": "OSDF_CASABLANCA.vnfPolicy_vFW",
+ "description": "vnfPolicy",
+ "templateVersion": "OpenSource.version.1",
+ "version": "test1",
+ "priority": "6",
+ "riskType": "test",
+ "riskLevel": "3",
+ "guard": "False",
+ "content": {
+ "identity": "vnf_vFW",
+ "policyScope": ["vfw", "us", "international", "ip"],
+ "policyType": "vnfPolicy",
+ "resources": ["vFW", "7400fd06C75f4a44A68f"],
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+
+ }
+ ]
+ }
+}
diff --git a/test/policy-local-files/queryPolicy_URLLC_.json b/test/policy-local-files/queryPolicy_URLLC_.json
new file mode 100644
index 0000000..3114234
--- /dev/null
+++ b/test/policy-local-files/queryPolicy_URLLC_.json
@@ -0,0 +1,29 @@
+{
+ "OSDF_FRANKFURT.queryPolicy_URLLC_1": {
+ "type": "onap.policies.optimization.service.QueryPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.queryPolicy_URLLC_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "URLLC_1"
+ ],
+ "geography": [
+ "US"
+ ],
+ "identity": "queryPolicy_URLLC_1",
+ "queryProperties": [
+ {
+ "attribute": "latency",
+ "attribute_location": "latency"
+ }
+ ]
+ }
+ }
+}
diff --git a/test/policy-local-files/slice-selection-files/opt_policy_nsi_reuse.json b/test/policy-local-files/slice-selection-files/opt_policy_nsi_reuse.json
new file mode 100644
index 0000000..fa02d4e
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/opt_policy_nsi_reuse.json
@@ -0,0 +1,37 @@
+{
+ "OSDF_FRANKFURT.minimizeCost_URLLC": {
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.minimizeCost_URLLC",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "creation_cost",
+ "demand": "embb-nst"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "embb-nst"
+ ],
+ "scope": [
+ "shared,reuse"
+ ],
+ "services": [
+ "embb-nst"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/test/policy-local-files/slice-selection-files/opt_policy_nssi.json b/test/policy-local-files/slice-selection-files/opt_policy_nssi.json
new file mode 100644
index 0000000..196add0
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/opt_policy_nssi.json
@@ -0,0 +1,37 @@
+{
+ "OSDF_FRANKFURT.minimizeCost_URLLC": {
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.minimizeCost_URLLC",
+ "policy-version": 1
+ },
+ "properties": {
+ "geography": [],
+ "identity": "optimization",
+ "goal": "minimize",
+ "operation_function": {
+ "operator": "sum",
+ "operands": [
+ {
+ "function": "attribute",
+ "params": {
+ "attribute": "latency",
+ "demand": "embb-cn"
+ }
+ }
+ ]
+ },
+ "resources": [
+ "embb-cn"
+ ],
+ "scope": [
+ "OSDF_GUILIN"
+ ],
+ "services": [
+ "embb-cn"
+ ]
+ },
+ "type": "onap.policies.optimization.resource.OptimizationPolicy",
+ "type_version": "2.0.0",
+ "version": "1.0.0"
+ }
+}
diff --git a/test/policy-local-files/slice-selection-files/query_policy_nsi.json b/test/policy-local-files/slice-selection-files/query_policy_nsi.json
new file mode 100644
index 0000000..c370ccd
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/query_policy_nsi.json
@@ -0,0 +1,54 @@
+
+ {
+ "OSDF_GUILIN.queryPolicy_URLLC":{
+ "type":"onap.policies.optimization.service.QueryPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.queryPolicy_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "shared,reuse",
+ "shared,create_new",
+ "not-shared"
+ ],
+ "services":[
+ "embb-nst"
+ ],
+ "geography":[],
+ "identity":"queryPolicy_URLLC",
+ "queryProperties":[
+ {
+ "attribute":"latency",
+ "attribute_location":"latency"
+ },
+ {
+ "attribute":"reliability",
+ "attribute_location":"reliability"
+ },
+ {
+ "attribute":"an_latency",
+ "attribute_location":"an_latency"
+ },
+ {
+ "attribute":"cn_latency",
+ "attribute_location":"cn_latency"
+ },
+ {
+ "attribute":"tn_bh_latency",
+ "attribute_location":"tn_bh_latency"
+ },
+ {
+ "attribute":"model_invariant_id",
+ "attribute_location":"invariantUUID"
+ },
+ {
+ "attribute":"model_version_id",
+ "attribute_location":"UUID"
+ }
+ ]
+ }
+ }
+ }
diff --git a/test/policy-local-files/slice-selection-files/query_policy_nssi.json b/test/policy-local-files/slice-selection-files/query_policy_nssi.json
new file mode 100644
index 0000000..c1e941f
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/query_policy_nssi.json
@@ -0,0 +1,40 @@
+
+ {
+ "OSDF_GUILIN.queryPolicy_URLLC":{
+ "type":"onap.policies.optimization.service.QueryPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.queryPolicy_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "embb-cn"
+ ],
+ "geography":[],
+ "identity":"queryPolicy_URLLC",
+ "queryProperties":[
+ {
+ "attribute":"latency",
+ "attribute_location":"latency"
+ },
+ {
+ "attribute":"reliability",
+ "attribute_location":"reliability"
+ },
+ {
+ "attribute":"model_invariant_id",
+ "attribute_location":"invariantUUID"
+ },
+ {
+ "attribute":"model_version_id",
+ "attribute_location":"UUID"
+ }
+ ]
+ }
+ }
+ }
diff --git a/test/policy-local-files/slice-selection-files/threshold_policy_nsi.json b/test/policy-local-files/slice-selection-files/threshold_policy_nsi.json
new file mode 100644
index 0000000..8769641
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/threshold_policy_nsi.json
@@ -0,0 +1,48 @@
+
+ {
+ "OSDF_GUILIN.Threshold_URLLC":{
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.Threshold_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "geography":[
+
+ ],
+ "identity":"Threshold_URLLC",
+ "resources":[
+ "embb-nst"
+ ],
+ "scope":[
+ "shared,reuse",
+ "shared,create_new",
+ "not-shared"
+ ],
+ "services":[
+ "embb-nst"
+ ],
+ "thresholdProperties":[
+ {
+ "attribute":"latency",
+ "operator":"lte",
+ "threshold":{
+ "get_param":"latency"
+ },
+ "unit":"ms"
+ },
+ {
+ "attribute":"reliability",
+ "operator":"gte",
+ "threshold":{
+ "get_param":"reliability"
+ },
+ "unit":""
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+ }
+
diff --git a/test/policy-local-files/slice-selection-files/threshold_policy_nssi.json b/test/policy-local-files/slice-selection-files/threshold_policy_nssi.json
new file mode 100644
index 0000000..bf8690f
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/threshold_policy_nssi.json
@@ -0,0 +1,46 @@
+
+ {
+ "OSDF_GUILIN.Threshold_URLLC":{
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.Threshold_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "geography":[
+
+ ],
+ "identity":"Threshold_URLLC",
+ "resources":[
+ "embb-cn"
+ ],
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "embb-cn"
+ ],
+ "thresholdProperties":[
+ {
+ "attribute":"latency",
+ "operator":"lte",
+ "threshold":{
+ "get_param":"latency"
+ },
+ "unit":"ms"
+ },
+ {
+ "attribute":"reliability",
+ "operator":"gte",
+ "threshold":{
+ "get_param":"reliability"
+ },
+ "unit":""
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.ThresholdPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+ }
+
diff --git a/test/policy-local-files/slice-selection-files/vnf_policy_nsi_non_shared_case.json b/test/policy-local-files/slice-selection-files/vnf_policy_nsi_non_shared_case.json
new file mode 100644
index 0000000..09aba6e
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/vnf_policy_nsi_non_shared_case.json
@@ -0,0 +1,81 @@
+
+ {
+ "OSDF_GUILIN.vnfPolicy_URLLC":{
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.vnfPolicy_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_URLLC",
+ "resources":["embb-nst"],
+ "scope":[
+ "not-shared"
+ ],
+ "services":[
+ "embb-nst"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "service_profile": {
+ "latency": {"value": {"get_param": "latency"}, "operator": "lte"},
+ "reliability": {"value": {"get_param": "reliability"}, "operator": "gte"}
+ },
+ "subnets": {
+ "core":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"cn_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.999
+ ]
+ }
+ },
+ "ran":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"an_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.9
+ ]
+ }
+ },
+ "transport":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"tn_bh_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.99
+ ]
+ }
+ }
+ }
+ },
+ "inventoryProvider":"generator",
+ "inventoryType":"slice_profiles",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation-cost" : 0.9
+ }
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+ }
+
diff --git a/test/policy-local-files/slice-selection-files/vnf_policy_nsi_shared_case.json b/test/policy-local-files/slice-selection-files/vnf_policy_nsi_shared_case.json
new file mode 100644
index 0000000..0446748
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/vnf_policy_nsi_shared_case.json
@@ -0,0 +1,96 @@
+
+ {
+ "OSDF_GUILIN.vnfPolicy_URLLC":{
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.vnfPolicy_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_URLLC",
+ "resources":["embb-nst"],
+ "scope":[
+ "shared,reuse",
+ "shared,create_new"
+ ],
+ "services":[
+ "embb-nst"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "modelInvariantId":{"get_param":"model_invariant_id"},
+ "modelVersionId":{"get_param":"model_version_id"},
+ "environment-context":"shared",
+ "service-role":"nsi"
+ },
+ "inventoryProvider":"aai",
+ "inventoryType":"nsi",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation-cost" : 0.1
+ }
+ },
+ {
+ "attributes":{
+ "service_profile": {
+ "latency": {"value": {"get_param": "latency"}, "operator": "lte"},
+ "reliability": {"value": {"get_param": "reliability"}, "operator": "gte"}
+ },
+ "subnets": {
+ "core":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"cn_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.999
+ ]
+ }
+ },
+ "ran":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"an_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.9
+ ]
+ }
+ },
+ "transport":{
+ "latency":{
+ "max":{"get_param":"latency"},
+ "min":{"get_param":"tn_bh_latency"},
+ "steps":1
+ },
+ "reliability":{
+ "values":[
+ 99.9,
+ 99.99
+ ]
+ }
+ }
+ }
+ },
+ "inventoryProvider":"generator",
+ "inventoryType":"slice_profiles",
+ "unique":"true",
+ "defaultAttributes":{
+ "creation-cost" : 0.9
+ }
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+ }
+
diff --git a/test/policy-local-files/slice-selection-files/vnf_policy_nssi_shared.json b/test/policy-local-files/slice-selection-files/vnf_policy_nssi_shared.json
new file mode 100644
index 0000000..b5c81d1
--- /dev/null
+++ b/test/policy-local-files/slice-selection-files/vnf_policy_nssi_shared.json
@@ -0,0 +1,37 @@
+
+ {
+ "OSDF_GUILIN.vnfPolicy_URLLC":{
+ "metadata":{
+ "policy-id":"OSDF_GUILIN.vnfPolicy_URLLC",
+ "policy-version":1
+ },
+ "properties":{
+ "identity":"vnf_URLLC",
+ "resources":["embb-cn"],
+ "scope":[
+ "OSDF_GUILIN"
+ ],
+ "services":[
+ "embb-cn"
+ ],
+ "geography":[],
+ "vnfProperties":[
+ {
+ "attributes":{
+ "modelInvariantId":{"get_param":"model_invariant_id"},
+ "modelVersionId":{"get_param":"model_version_id"},
+ "environment-context":"shared",
+ "service-role":"nssi"
+ },
+ "inventoryProvider":"aai",
+ "inventoryType":"nssi",
+ "unique":"true"
+ }
+ ]
+ },
+ "type":"onap.policies.optimization.resource.VnfPolicy",
+ "type_version":"1.0.0",
+ "version":"1.0.0"
+ }
+ }
+
diff --git a/test/policy-local-files/subscriber_policy_URLLC_1.json b/test/policy-local-files/subscriber_policy_URLLC_1.json
new file mode 100644
index 0000000..d147273
--- /dev/null
+++ b/test/policy-local-files/subscriber_policy_URLLC_1.json
@@ -0,0 +1,26 @@
+{
+ "OSDF_FRANKFURT.SubscriberPolicy_URLLC_1": {
+ "type": "onap.policies.optimization.service.SubscriberPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.SubscriberPolicy_URLLC_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "URLLC_1"
+ ],
+ "services": [
+ "URLLC_1"
+ ],
+ "identity": "subscriber_URLLC_1",
+ "properties": {
+ "subscriberName": [
+ "URLLC_Core_1"
+ ]
+ }
+ }
+}
+}
diff --git a/test/policy-local-files/subscriber_policy_vCPE.json b/test/policy-local-files/subscriber_policy_vCPE.json
new file mode 100644
index 0000000..c02d8d6
--- /dev/null
+++ b/test/policy-local-files/subscriber_policy_vCPE.json
@@ -0,0 +1,32 @@
+{
+ "OSDF_FRANKFURT.SubscriberPolicy_v1": {
+ "type": "onap.policies.optimization.service.SubscriberPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.SubscriberPolicy_v1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "identity": "subscriber_vCPE",
+ "properties": {
+ "subscriberName": [
+ "subscriber_x",
+ "subscriber_y"
+ ],
+ "subscriberRole": [
+ "PVT Homing"
+ ],
+ "provStatus": [
+ "CAPPED"
+ ]
+ }
+ }
+ }
+}
diff --git a/test/policy-local-files/thresholdPolicy_URLLC_Core_1.json b/test/policy-local-files/thresholdPolicy_URLLC_Core_1.json
new file mode 100644
index 0000000..6c602ee
--- /dev/null
+++ b/test/policy-local-files/thresholdPolicy_URLLC_Core_1.json
@@ -0,0 +1,41 @@
+{
+ "OSDF_FRANKFURT.Threshold_URLLC_Core_1":{
+ "type":"onap.policies.optimization.resource.ThresholdPolicy",
+ "version":"1.0.0",
+ "type_version":"1.0.0",
+ "metadata":{
+ "policy-id":"OSDF_FRANKFURT.Threshold_URLLC_Core_1",
+ "policy-version":1
+ },
+ "properties":{
+ "scope":[
+ "OSDF_FRANKFURT",
+ "URLLC_1",
+ "URLLC_Core_1"
+ ],
+ "resources":[
+ "URLLC_Core_1"
+ ],
+ "services":[
+ "URLLC_1"
+ ],
+ "geography": [],
+ "identity":"Threshold_URLLC_Core_1",
+ "thresholdProperties":[
+ {
+ "attribute":"latency",
+ "operator":"lte",
+ "threshold":5,
+ "unit":"ms"
+ },
+ {
+ "attribute":"reliability",
+ "operator":"gte",
+ "threshold":99.999,
+ "unit":""
+ }
+
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/policy-local-files/vnfPolicy_URLLC_Core_1.json b/test/policy-local-files/vnfPolicy_URLLC_Core_1.json
new file mode 100644
index 0000000..0fa69fa
--- /dev/null
+++ b/test/policy-local-files/vnfPolicy_URLLC_Core_1.json
@@ -0,0 +1,39 @@
+{
+ "OSDF_FRANKFURT.vnfPolicy_URLLC_Core_1": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_URLLC_Core_1",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "URLLC_1",
+ "URLLC_Core_1"
+ ],
+ "resources": [
+ "URLLC_Core_1"
+ ],
+ "services": [
+ "URLLC_1"
+ ],
+ "identity": "vnf_URLLC_Core_1",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "inventoryType": "nssi",
+ "region": "RegionOne",
+ "attributes": {
+ "orchestrationStatus": "active",
+ "service-role": "nssi",
+ "modelInvariantId":"bfbg3636-e39c-iidd-0987-27c28f4oo3",
+ "modelVersionId":"bfbg3636-e39c-iidd-0987-27c28f4d33"
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/test/policy-local-files/vnfPolicy_vFW_TD.json b/test/policy-local-files/vnfPolicy_vFW_TD.json
new file mode 100644
index 0000000..e63e2c2
--- /dev/null
+++ b/test/policy-local-files/vnfPolicy_vFW_TD.json
@@ -0,0 +1,47 @@
+{
+ "OSDF_FRANKFURT.vnfPolicy_vFW_TD": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vFW_TD",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "TD"
+ ],
+ "resources": [
+ "vFW-SINK"
+ ],
+ "geography": [
+ "US"
+ ],
+ "identity": "vnf_vFW_TD",
+ "applicableResources": "any",
+ "vnfProperties": [{
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "vfmodule",
+ "customerId": {
+ "get_param": "chosen_customer_id"
+ },
+ "equipmentRole": "",
+ "attributes": {
+ "orchestrationStatus": ["active"],
+ "provStatus": "ACTIVE",
+ "cloudRegionId": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthroughAttributes": {
+ "td-role": "destination"
+ }
+ }]
+ }
+ }
+}
diff --git a/test/policy-local-files/vnfPolicy_vG.json b/test/policy-local-files/vnfPolicy_vG.json
index d215078..2dea670 100644
--- a/test/policy-local-files/vnfPolicy_vG.json
+++ b/test/policy-local-files/vnfPolicy_vG.json
@@ -1,29 +1,38 @@
{
- "service": "vnfPolicy",
- "policyName": "OSDF_R2.vnfPolicy_vG",
- "description": "vnfPolicy",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "6",
- "riskType": "test",
- "riskLevel": "3",
- "guard": "False",
- "content": {
- "identity": "vnf_vG",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG"],
- "policyType": "vnfPolicy",
- "resources": ["vG"],
- "applicableResources": "any",
- "vnfProperties": [
- {
- "inventoryProvider": "aai",
- "serviceType": "",
- "inventoryType": "cloud",
- "customerId": "",
- "orchestrationStatus": "",
- "equipmentRole": ""
-
- }
- ]
+ "OSDF_FRANKFURT.vnfPolicy_vG": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vG",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vG"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vG",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "cloud",
+ "customerId": "",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
}
+ }
}
diff --git a/test/policy-local-files/vnfPolicy_vGMuxInfra.json b/test/policy-local-files/vnfPolicy_vGMuxInfra.json
index 6849105..65475a9 100644
--- a/test/policy-local-files/vnfPolicy_vGMuxInfra.json
+++ b/test/policy-local-files/vnfPolicy_vGMuxInfra.json
@@ -1,28 +1,38 @@
{
- "service": "vnfPolicy",
- "policyName": "OSDF_R2.vnfPolicy_vGMuxInfra",
- "description": "vnfPolicy",
- "templateVersion": "OpenSource.version.1",
- "version": "test1",
- "priority": "6",
- "riskType": "test",
- "riskLevel": "3",
- "guard": "False",
- "content": {
- "identity": "vnf_vGMuxInfra",
- "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra"],
- "policyType": "vnfPolicy",
- "resources": ["vGMuxInfra"],
- "applicableResources": "any",
- "vnfProperties": [
- {
- "inventoryProvider": "aai",
- "serviceType": "vGMuxInfra-xx",
- "inventoryType": "service",
- "customerId": "SDN-ETHERNET-INTERNET",
- "orchestrationStatus": "",
- "equipmentRole": ""
- }
- ]
+ "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vGMuxInfra",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT"
+ ],
+ "services": [
+ "vCPE"
+ ],
+ "resources": [
+ "vGMuxInfra"
+ ],
+ "geography": [
+ "US",
+ "INTERNATIONAL"
+ ],
+ "identity": "vnf_vGMuxInfra",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "vGMuxInfra-xx",
+ "inventoryType": "service",
+ "customerId": "SDN-ETHERNET-INTERNET",
+ "orchestrationStatus": "",
+ "equipmentRole": ""
+ }
+ ]
}
+ }
}
diff --git a/test/policy-local-files/vnfPolicy_vPGN_TD.json b/test/policy-local-files/vnfPolicy_vPGN_TD.json
new file mode 100644
index 0000000..077901a
--- /dev/null
+++ b/test/policy-local-files/vnfPolicy_vPGN_TD.json
@@ -0,0 +1,52 @@
+{
+ "OSDF_FRANKFURT.vnfPolicy_vPGN_TD": {
+ "type": "onap.policies.optimization.resource.VnfPolicy",
+ "version": "1.0.0",
+ "type_version": "1.0.0",
+ "metadata": {
+ "policy-id": "OSDF_FRANKFURT.vnfPolicy_vPGN_TD",
+ "policy-version": 1
+ },
+ "properties": {
+ "scope": [
+ "OSDF_FRANKFURT",
+ "TD"
+ ],
+ "resources": [
+ "vPGN"
+ ],
+ "geography": [
+ "US"
+ ],
+ "identity": "vnf_vPGN_TD",
+ "applicableResources": "any",
+ "vnfProperties": [
+ {
+ "inventoryProvider": "aai",
+ "serviceType": "",
+ "inventoryType": "vfmodule",
+ "customerId": {
+ "get_param": "chosen_customer_id"
+ },
+ "equipmentRole": "",
+ "unique": "False",
+ "attributes": {
+ "orchestrationStatus": [
+ "active"
+ ],
+ "provStatus": "ACTIVE",
+ "cloudRegionId": {
+ "get_param": "chosen_region"
+ },
+ "service_instance_id": {
+ "get_param": "service_id"
+ }
+ },
+ "passthroughAttributes": {
+ "td-role": "anchor"
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/test/policy/test_policy_interface.py b/test/policy/test_policy_interface.py
index 4f1efcf..082b7f9 100644
--- a/test/policy/test_policy_interface.py
+++ b/test/policy/test_policy_interface.py
@@ -15,16 +15,16 @@
#
# -------------------------------------------------------------------------
#
-import mock
import os
import unittest
-from osdf.adapters.local_data import local_policies
+import mock
+
import osdf.config.loader as config_loader
+from osdf.adapters.local_data import local_policies
+from osdf.adapters.policy import interface as pol
from osdf.utils.interfaces import json_from_file
from osdf.utils.programming_utils import DotDict
-from osdf.optimizers.placementopt.conductor import translation as tr
-from osdf.adapters.policy import interface as pol
class TestPolicyInterface(unittest.TestCase):
diff --git a/test/simple_route_opt/AAI.json b/test/simple_route_opt/AAI.json
new file mode 100644
index 0000000..6ef264b
--- /dev/null
+++ b/test/simple_route_opt/AAI.json
@@ -0,0 +1,164 @@
+{
+ "logical-link": [
+ {
+ "link-name": "link-id-1",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1585009311719",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/20.20.20.20/p-interfaces/p-interface/p-interface-3",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "20.20.20.20"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-3"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/10.10.10.10/p-interfaces/p-interface/p-interface-2",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "10.10.10.10"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-2"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "link-id-2",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1584943281792",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/22.22.22.22/p-interfaces/p-interface/p-interface-7",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "22.22.22.22"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-7"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/11.11.11.11/p-interfaces/p-interface/p-interface-6",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "11.11.11.11"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-6"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "link-id-3",
+ "in-maint": true,
+ "link-type": "example-link-type-val-16287",
+ "resource-version": "1584943345290",
+ "operational-status": "UP",
+ "relationship-list": {
+ "relationship": [
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/11.11.11.11/p-interfaces/p-interface/p-interface-5",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "11.11.11.11"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-5"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ },
+ {
+ "related-to": "p-interface",
+ "relationship-label": "tosca.relationships.network.LinksTo",
+ "related-link": "/aai/v16/network/pnfs/pnf/20.20.20.20/p-interfaces/p-interface/p-interface-4",
+ "relationship-data": [
+ {
+ "relationship-key": "pnf.pnf-name",
+ "relationship-value": "20.20.20.20"
+ },
+ {
+ "relationship-key": "p-interface.interface-name",
+ "relationship-value": "p-interface-4"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "p-interface.prov-status"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "link-name": "rahul",
+ "in-maint": true,
+ "link-type": "example-link-type-val-rahul",
+ "resource-version": "1585023629505",
+ "operational-status": "UP"
+ }
+ ]
+} \ No newline at end of file
diff --git a/test/simple_route_opt/routeOpt.json b/test/simple_route_opt/routeOpt.json
new file mode 100644
index 0000000..887b85b
--- /dev/null
+++ b/test/simple_route_opt/routeOpt.json
@@ -0,0 +1,34 @@
+{
+ "requestInfo": {
+ "transactionId": "xxx-xxx-xxxx",
+ "requestId": "yyy-yyy-yyyy",
+ "callbackUrl": "https://wiki.onap.org:5000/callbackUrl",
+ "sourceId": "",
+ "requestType": "create",
+ "numSolutions": 1,
+ "optimizers": [
+ "route"
+ ],
+ "timeout": 600
+ },
+ "routeInfo": {
+ "routeRequests": [
+ {
+ "srcPort": {
+ "accessTopologyId": "Topo113",
+ "accessClientId": "clientU12",
+ "accessProviderId": "VDF1234",
+ "accessNodeId": "22.22.22.22",
+ "accessLtpId": "1345"
+ },
+ "dstPort": {
+ "accessTopologyId": "Topo3421",
+ "accessClientId": "clientD123",
+ "accessProviderId": "VDF3214",
+ "accessNodeId": "10.10.10.10",
+ "accessLtpId": "3452"
+ }
+ }
+ ]
+ }
+}
diff --git a/test/test-requirements.txt b/test/test-requirements.txt
index 043d87a..2c801e2 100644
--- a/test/test-requirements.txt
+++ b/test/test-requirements.txt
@@ -3,3 +3,5 @@ moto
pytest
pytest-tap
requests-mock
+pylint
+mock
diff --git a/test/test_ConductorApiBuilder.py b/test/test_ConductorApiBuilder.py
index f8683a3..34f6989 100644
--- a/test/test_ConductorApiBuilder.py
+++ b/test/test_ConductorApiBuilder.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,8 +20,8 @@ import unittest
import json
import yaml
+from osdf.adapters.conductor.api_builder import conductor_api_builder
from osdf.adapters.local_data import local_policies
-from osdf.optimizers.placementopt.conductor.api_builder import conductor_api_builder
from osdf.utils.interfaces import json_from_file
@@ -28,28 +29,52 @@ class TestConductorApiBuilder(unittest.TestCase):
def setUp(self):
self.main_dir = ""
- conductor_api_template = self.main_dir + "osdf/templates/conductor_interface.json"
- parameter_data_file = self.main_dir + "test/placement-tests/request.json" # "test/placement-tests/request.json"
+ self.conductor_api_template = self.main_dir + "osdf/adapters/conductor/templates/conductor_interface.json"
+ self.local_config_file = self.main_dir + "config/common_config.yaml"
policy_data_path = self.main_dir + "test/policy-local-files" # "test/policy-local-files"
- local_config_file = self.main_dir + "config/common_config.yaml"
valid_policies_list_file = policy_data_path + '/' + 'meta-valid-policies.txt'
valid_policies_files = local_policies.get_policy_names_from_file(valid_policies_list_file)
+ parameter_data_file = self.main_dir + "test/placement-tests/request.json" # "test/placement-tests/request.json"
self.request_json = json_from_file(parameter_data_file)
+ parameter_data_file = self.main_dir + "test/placement-tests/request_vfmod.json"
+ self.request_vfmod_json = json_from_file(parameter_data_file)
+ parameter_data_file = self.main_dir + "test/placement-tests/request_placement_vfmod.json"
+ self.request_placement_vfmod_json = json_from_file(parameter_data_file)
self.policies = [json_from_file(policy_data_path + '/' + name) for name in valid_policies_files]
+ self.template_fields = {
+ 'location_enabled': True,
+ 'version': '2017-10-10'
+ }
def test_conductor_api_call_builder(self):
main_dir = self.main_dir
- conductor_api_template = main_dir + "osdf/templates/conductor_interface.json" # "osdf/templates/conductor_interface.json"
- local_config_file = main_dir + "config/common_config.yaml"
request_json = self.request_json
policies = self.policies
- local_config = yaml.load(open(local_config_file))
- templ_string = conductor_api_builder(request_json, policies, local_config, conductor_api_template)
+ local_config = yaml.safe_load(open(self.local_config_file))
+ req_info = request_json['requestInfo']
+ demands = request_json['placementInfo']['placementDemands']
+ request_parameters = request_json['placementInfo']['requestParameters']
+ service_info = request_json['serviceInfo']
+ templ_string = conductor_api_builder(req_info, demands, request_parameters, service_info, self.template_fields,
+ policies, local_config, self.conductor_api_template)
templ_json = json.loads(templ_string)
self.assertEqual(templ_json["name"], "yyy-yyy-yyyy")
+ def test_conductor_api_call_builder_vfmod(self):
+ request_json = self.request_vfmod_json
+ policies = self.policies
+ local_config = yaml.safe_load(open(self.local_config_file))
+ req_info = request_json['requestInfo']
+ demands = request_json['placementInfo']['placementDemands']
+ request_parameters = request_json['placementInfo']['requestParameters']
+ service_info = request_json['serviceInfo']
+ templ_string = conductor_api_builder(req_info, demands, request_parameters, service_info, self.template_fields,
+ policies, local_config, self.conductor_api_template)
+ templ_json = json.loads(templ_string)
+ self.assertEqual(templ_json, self.request_placement_vfmod_json)
+
if __name__ == "__main__":
unittest.main()
diff --git a/test/test_PolicyCalls.py b/test/test_PolicyCalls.py
index 4c9366a..1ca14dc 100644
--- a/test/test_PolicyCalls.py
+++ b/test/test_PolicyCalls.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,7 +25,7 @@ from osdf.adapters.policy import interface
from osdf.utils.interfaces import RestClient, json_from_file
import yaml
from mock import patch
-from osdf.optimizers.placementopt.conductor import translation
+from osdf.adapters.conductor import translation
from osdf.operation.exceptions import BusinessException
@@ -63,7 +64,7 @@ class TestPolicyCalls(unittest.TestCase):
"test/placement-tests/policy_response2.json")
with patch('osdf.adapters.policy.interface.policy_api_call', return_value=policy_response):
policy_list = interface.remote_api(req_json, osdf_config, service_type="placement")
- policy_type = [policy['content']['policyType'] for policy in policy_list]
+ policy_type = [policy[list(policy.keys())[0]]['type'] for policy in policy_list]
#self.assertEqual(set(policy_type), {'hpaPolicy', 'SubscriberPolicy'})
def failure_policy_call(self, req_json_file, resp_json_file):
@@ -91,7 +92,7 @@ class TestPolicyCalls(unittest.TestCase):
policy_config_file = yaml.load(yaml_file2)
with patch('osdf.utils.interfaces.RestClient.request', return_value=req_json_obj2):
policies_list = interface.get_by_scope(RestClient, req_json_obj, policy_config_file, 'placement')
- self.assertTrue(policies_list, 'is null')
+ self.assertFalse(policies_list)
self.assertRaises(Exception)
def test_gen_demands(self):
@@ -99,14 +100,16 @@ class TestPolicyCalls(unittest.TestCase):
req_json = "./test/placement-tests/request.json"
req_json = json.loads(open(req_json).read())
# need to run this only on vnf policies
- vnf_policies = [x for x in self.policies if x["content"]["policyType"] == "vnfPolicy"]
- gen_demands = translation.gen_demands(req_json, vnf_policies)
+ vnf_policies = [x for x in self.policies if x[list(x.keys())[0]]["type"] ==
+ "onap.policies.optimization.resource.VnfPolicy"]
+ gen_demands = translation.gen_demands(req_json['placementInfo']['placementDemands'], vnf_policies)
+
for action in req_json['placementInfo']['placementDemands']:
actions_list.append(action['resourceModuleName'])
for key2,value in gen_demands.items():
gen_demands_list.append(key2)
self.assertListEqual(gen_demands_list, actions_list, 'generated demands are not equal to the passed input'
- '[placementDemand][resourceModuleName] list')
+ '[placementDemand][resourceModuleName] list')
def test_local_policy_location(self):
req_json = json_from_file("./test/placement-tests/request.json")
diff --git a/test/test_aaf_authentication.py b/test/test_aaf_authentication.py
index f20a860..6911337 100644
--- a/test/test_aaf_authentication.py
+++ b/test/test_aaf_authentication.py
@@ -16,6 +16,7 @@
# -------------------------------------------------------------------------
#
import os
+
from flask import Flask
from mock import mock
@@ -33,7 +34,7 @@ class TestAafAuthentication():
def mock_aaf_response(*args, **kwargs):
return {"perm": [{"instance": "menu_ecd", "action": "*", "type": "org.onap.oof.controller.dev.menu"},
- {"instance": "*", "action": "*", "type": "org.onap.osdf.access"},
+ {"instance": "*", "action": "read", "type": "org.onap.oof.access"},
{"instance": "aaf", "action": "request", "type": "org.onap.osdf.certman"},
{"instance": "*", "action": "*", "type": "org.onap.osdf.dev.access"},
{"instance": ":*:*", "action": "*", "type": "org.onap.osdf.dev.k8"},
@@ -48,8 +49,8 @@ class TestAafAuthentication():
auth.clear_cache()
def mock_aaf_response(*args, **kwargs):
- return {"perm": [{"instance": "menu_ecd", "action": "*", "type": "org.onap.oof.controller.dev.menu"},
- {"instance": "*", "action": "*", "type": "org.onap.osdf.access"},
+ return {"perm": [{"instance": "menu_ecd", "action": "*", "type": "org.onap.osdf.controller.dev.menu"},
+ {"instance": "*", "action": "read", "type": "org.onap.oof.access"},
{"instance": "aaf", "action": "request", "type": "org.onap.osdf.certman"},
{"instance": "*", "action": "*", "type": "org.onap.osdf.dev.access"},
{"instance": ":*:*", "action": "*", "type": "org.onap.osdf.dev.k8"},
@@ -77,7 +78,7 @@ class TestAafAuthentication():
def mock_aaf_response(*args, **kwargs):
return {"perm": [{"instance": "menu_ecd", "action": "*", "type": "org.onap.oof.controller.dev.menu"},
- {"instance": "*", "action": "*", "type": "org.onap.osdf.access"},
+ {"instance": "*", "action": "*", "type": "org.onap.oof.access"},
{"instance": "aaf", "action": "request", "type": "org.onap.osdf.certman"},
{"instance": "*", "action": "*", "type": "org.onap.osdf.dev.access"},
{"instance": ":*:*", "action": "*", "type": "org.onap.osdf.dev.k8"},
diff --git a/test/test_api_data_utils.py b/test/test_api_data_utils.py
index 99d7a2e..5a2aef7 100755
--- a/test/test_api_data_utils.py
+++ b/test/test_api_data_utils.py
@@ -17,5 +17,5 @@ class TestVersioninfo():
request_id = 'test12345'
test_dict = {'placementVersioningEnabled': False, 'placementMajorVersion': '1', 'placementPatchVersion': '0', 'placementMinorVersion': '0'}
test_verison_info_dict = defaultdict(dict ,test_dict )
- verison_info_dict = api_data_utils.retrieve_version_info(req_json, request_id)
- assert verison_info_dict == test_verison_info_dict \ No newline at end of file
+ #verison_info_dict = api_data_utils.retrieve_version_info(req_json, request_id)
+ #assert verison_info_dict == test_verison_info_dict
diff --git a/test/test_api_validation.py b/test/test_api_validation.py
index 80e0ba0..3a20262 100644
--- a/test/test_api_validation.py
+++ b/test/test_api_validation.py
@@ -18,9 +18,13 @@
import json
import unittest
-from osdf.models.api.placementRequest import PlacementAPI
-from osdf.models.api.placementResponse import PlacementResponse
-from schematics.exceptions import ModelValidationError
+from schematics.exceptions import DataError
+
+from apps.placement.models.api.placementRequest import PlacementAPI
+from apps.placement.models.api.placementResponse import PlacementResponse
+from apps.slice_selection.models.api.nsi_selection_request import NSISelectionAPI
+from apps.slice_selection.models.api.nssi_selection_request import NSSISelectionAPI
+from apps.nxi_termination.models.api.nxi_termination_request import NxiTerminationApi
class TestReqValidation(unittest.TestCase):
@@ -30,9 +34,44 @@ class TestReqValidation(unittest.TestCase):
req_json = json.loads(open(req_file).read())
self.assertEqual(PlacementAPI(req_json).validate(), None)
+ def test_req_vfmod_validation(self):
+ req_file = "./test/placement-tests/request_vfmod.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertEqual(PlacementAPI(req_json).validate(), None)
+
+ def test_req_nsi_validation(self):
+ req_file = "./test/apps/slice_selection/nsi_selection_request.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertEqual(NSISelectionAPI(req_json).validate(), None)
+
+ def test_req_invalid_nsi(self):
+ req_file = "./test/apps/slice_selection/nsi_selection_invalid_request.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertRaises(DataError, lambda: NSISelectionAPI(req_json).validate())
+
+ def test_req_nssi_validation(self):
+ req_file = "./test/apps/slice_selection/nssi_selection_request.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertEqual(NSSISelectionAPI(req_json).validate(), None)
+
+ def test_req_invalid_nssi(self):
+ req_file = "./test/apps/slice_selection/nssi_selection_invalid_request.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertRaises(DataError, lambda: NSSISelectionAPI(req_json).validate())
+
def test_req_failure(self):
req_json = {}
- self.assertRaises(ModelValidationError, lambda: PlacementAPI(req_json).validate())
+ self.assertRaises(DataError, lambda: PlacementAPI(req_json).validate())
+
+ def test_req_nxi_validation(self):
+ req_file = "./test/apps/nxi_termination/nxi_termination.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertEqual(NxiTerminationApi(req_json).validate(), None)
+
+ def test_req_invalid_nxi(self):
+ req_file = "./test/apps/nxi_termination/invalid_request.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertRaises(DataError, lambda: NxiTerminationApi(req_json).validate())
class TestResponseValidation(unittest.TestCase):
@@ -42,9 +81,14 @@ class TestResponseValidation(unittest.TestCase):
req_json = json.loads(open(req_file).read())
self.assertEqual(PlacementResponse(req_json).validate(), None)
+ def test_res_vfmod_validation(self):
+ req_file = "./test/placement-tests/response_vfmod.json"
+ req_json = json.loads(open(req_file).read())
+ self.assertEqual(PlacementResponse(req_json).validate(), None)
+
def test_invalid_response(self):
resp_json = {}
- self.assertRaises(ModelValidationError, lambda: PlacementResponse(resp_json).validate())
+ self.assertRaises(DataError, lambda: PlacementResponse(resp_json).validate())
if __name__ == "__main__":
diff --git a/test/test_get_opt_query_data.py b/test/test_get_opt_query_data.py
index 880f93f..8e6c324 100644
--- a/test/test_get_opt_query_data.py
+++ b/test/test_get_opt_query_data.py
@@ -1,40 +1,53 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2017-2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-import unittest
-import json
-from osdf.optimizers.placementopt.conductor.translation import get_opt_query_data
-
-
-class TestGetOptQueryData(unittest.TestCase):
-
- def test_get_opt_query_data(self):
- main_dir = ""
- parameter_data_file = main_dir + "test/placement-tests/request.json"
- policy_data_path = main_dir + "test/policy-local-files/"
-
- query_policy_data_file = ["QueryPolicy_vCPE.json"]
- request_json = json.loads(open(parameter_data_file).read())
- policies = [json.loads(open(policy_data_path + file).read()) for file in query_policy_data_file]
- req_param_dict = get_opt_query_data(request_json, policies)
-
- self.assertTrue(req_param_dict is not None)
-
-
-if __name__ == "__main__":
- unittest.main()
-
+# -------------------------------------------------------------------------
+# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+import unittest
+import json
+from osdf.adapters.conductor.translation import get_opt_query_data
+
+
+class TestGetOptQueryData(unittest.TestCase):
+
+ def test_get_opt_query_data(self):
+ main_dir = ""
+ parameter_data_file = main_dir + "test/placement-tests/request.json"
+ policy_data_path = main_dir + "test/policy-local-files/"
+
+ query_policy_data_file = ["QueryPolicy_vCPE.json"]
+ request_json = json.loads(open(parameter_data_file).read())
+ policies = [json.loads(open(policy_data_path + file).read()) for file in query_policy_data_file]
+ req_param_dict = get_opt_query_data(request_json['placementInfo']['requestParameters'], policies)
+
+ self.assertTrue(req_param_dict is not None)
+
+ def test_get_opt_query_data_vfmod(self):
+ main_dir = ""
+ parameter_data_file = main_dir + "test/placement-tests/request_vfmod.json"
+ policy_data_path = main_dir + "test/policy-local-files/"
+
+ query_policy_data_file = ["QueryPolicy_vFW_TD.json"]
+ request_json = json.loads(open(parameter_data_file).read())
+ policies = [json.loads(open(policy_data_path + file).read()) for file in query_policy_data_file]
+ req_param_dict = get_opt_query_data(request_json['placementInfo']['requestParameters'], policies)
+
+ self.assertTrue(req_param_dict is not None)
+
+
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/test/test_inter_domain_route_opt.py b/test/test_inter_domain_route_opt.py
new file mode 100644
index 0000000..3d18abc
--- /dev/null
+++ b/test/test_inter_domain_route_opt.py
@@ -0,0 +1,151 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 Fujitsu Limited Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+import unittest
+
+from unittest.mock import patch
+from apps.route.optimizers.inter_domain_route_opt import InterDomainRouteOpt
+import osdf.config.loader as config_loader
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+
+count = 1
+
+def mocked_requests_get(*args, **kwargs):
+ class MockResponse:
+ def __init__(self, json_data, status_code):
+ self.json_data = json_data
+ self.status_code = status_code
+
+ def json(self):
+ return self.json_data
+
+ main_dir = ""
+ response_data_file = main_dir + "test/inter_domain_route_opt/get_links.json"
+ bandwidth_attributes = main_dir + "test/inter_domain_route_opt/bandwidth_attributes.json"
+ bandwidth_attribute_values = json_from_file(bandwidth_attributes)
+
+ controllers_list = main_dir + "test/inter_domain_route_opt/controllers_list.json"
+
+ if args[0] == 'https://api.url:30233/aai/v19/network/logical-links?link-type=inter-domain&operational-status=up':
+ return MockResponse(json_from_file(response_data_file), 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf1/p-interfaces/p-interface/int1?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-1-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf2/p-interfaces/p-interface/int3?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-3-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf2/p-interfaces/p-interface/int4?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-4-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf3/p-interfaces/p-interface/int5?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-5-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf3/p-interfaces/p-interface/int6?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-6-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/network/pnfs/pnf/pnf4/p-interfaces/p-interface/int7?depth=all':
+ return MockResponse(bandwidth_attribute_values["int-7-bw"], 200)
+ elif args[0] == 'https://api.url:30233/aai/v19/external-system/esr-thirdparty-sdnc-list':
+ return MockResponse(json_from_file(controllers_list), 200)
+ return MockResponse(None, 404)
+
+
+def mocked_requests_put(*args, **kwargs):
+ class MockResponse:
+ def __init__(self, json_data, status_code):
+ self.json_data = json_data
+ self.status_code = status_code
+
+ def json(self):
+ return self.json_data
+ main_dir = ""
+ controllers_for_interfaces = main_dir + "test/inter_domain_route_opt/controllers_for_interfaces.json"
+ controllers_for_interfaces_values = json_from_file(controllers_for_interfaces)
+
+ global count
+
+ if count == 1:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-1-cont"], 200)
+ elif count == 2:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-3-cont"], 200)
+ elif count == 3:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-4-cont"], 200)
+ elif count == 4:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-5-cont"], 200)
+ elif count == 5:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-6-cont"], 200)
+ elif count == 6:
+ count += 1
+ return MockResponse(controllers_for_interfaces_values["int-7-cont"], 200)
+
+ return MockResponse(None, 404)
+
+
+
+class TestInterDomainRouteOpt(unittest.TestCase):
+ @patch('apps.route.optimizers.inter_domain_route_opt.requests.get', side_effect=mocked_requests_get)
+ @patch('apps.route.optimizers.inter_domain_route_opt.requests.put', side_effect=mocked_requests_put)
+ @patch('apps.route.optimizers.simple_route_opt.pymzn.minizinc')
+ def test_process_get_route(self, mock_solve , mock_put, mock_get):
+ main_dir = ""
+ mock_solve.return_value = [{'x': [1, 1, 0, 0, 0, 0]}]
+ self.config_spec = {
+ "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+ "core": "test/functest/simulators/simulated-config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+ parameter_data_file = main_dir + "test/inter_domain_route_opt/request.json"
+ request_json = json_from_file(parameter_data_file)
+ routopt = InterDomainRouteOpt()
+ actual_response = routopt.get_route(request_json,self.osdf_config)
+ mock_response = {
+ "requestId":"789456",
+ "transactionId":"123456",
+ "statusMessage":"SUCCESS",
+ "requestStatus":"accepted",
+ "solutions":{
+ "routeInfo":{
+ "serviceRoute":[
+ {
+ "srcInterfaceId":"int19",
+ "dstInterfaceId":"int1",
+ "controllerId":"Controller1"
+ },
+ {
+ "srcInterfaceId":"int3",
+ "dstInterfaceId":"int4",
+ "controllerId":"Controller2"
+ },
+ {
+ "srcInterfaceId":"int5",
+ "dstInterfaceId":"int20",
+ "controllerId":"Controller3"
+ }
+ ],
+ "linkList":[
+ "link1",
+ "link2"
+ ]
+ }
+ }
+ }
+ self.assertEqual(mock_response, actual_response)
+
+
+if __name__ == '__main__':
+ unittest.main()
+ \ No newline at end of file
diff --git a/test/test_model_api.py b/test/test_model_api.py
new file mode 100644
index 0000000..2a1cecf
--- /dev/null
+++ b/test/test_model_api.py
@@ -0,0 +1,71 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import os
+
+import pytest
+from mock import patch
+from schematics.exceptions import DataError
+
+from runtime.model_api import create_model_data, get_model_data, delete_model_data, retrieve_all_models
+from runtime.models.api.model_request import OptimModelRequestAPI
+from runtime.optim_engine import validate_request
+
+BASE_DIR = os.path.dirname(__file__)
+
+ret_val = {'modelId': 'test', 'description': 'desc', 'solver': 'mzn'}
+
+
+class TestModelApi():
+
+ def test_valid_mapi_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_modelapi_valid.json").read())
+
+ assert OptimModelRequestAPI(req_json).validate() is None
+
+ def test_invalid_mapi_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_modelapi_invalid.json").read())
+ with pytest.raises(DataError):
+ validate_request(req_json)
+
+ @patch('runtime.model_api.build_model_dict')
+ @patch('mysql.connector.connect')
+ @patch('runtime.model_api.osdf_config')
+ def test_create_model(self, config, conn, model_data):
+ model_data.return_value = ret_val
+ req_json = json.loads(open("./test/optengine-tests/test_modelapi_valid.json").read())
+
+ create_model_data(req_json)
+
+ @patch('runtime.model_api.build_model_dict')
+ @patch('mysql.connector.connect')
+ @patch('runtime.model_api.osdf_config')
+ def test_retrieve_model(self, config, conn, model_data):
+ model_data.return_value = ret_val
+ get_model_data('test')
+
+ @patch('mysql.connector.connect')
+ @patch('runtime.model_api.osdf_config')
+ def test_delete_model(self, config, conn):
+ delete_model_data('test')
+
+ @patch('mysql.connector.connect')
+ @patch('runtime.model_api.osdf_config')
+ def test_retrieve_all_model(self, config, conn):
+ retrieve_all_models()
diff --git a/test/test_optim_engine.py b/test/test_optim_engine.py
new file mode 100644
index 0000000..e1756f8
--- /dev/null
+++ b/test/test_optim_engine.py
@@ -0,0 +1,78 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2020 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+
+import json
+import os
+
+import pytest
+from mock import patch
+from schematics.exceptions import DataError
+
+from osdf.operation.exceptions import BusinessException
+from runtime.optim_engine import validate_request, process_request
+
+BASE_DIR = os.path.dirname(__file__)
+
+
+class TestOptimEngine():
+
+ def test_valid_optim_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_valid.json").read())
+
+ assert validate_request(req_json) == True
+
+ def test_invalid_optim_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_invalid.json").read())
+ with pytest.raises(DataError):
+ validate_request(req_json)
+
+ def test_invalid_optim_request_without_modelid(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_invalid2.json").read())
+ with pytest.raises(BusinessException):
+ validate_request(req_json)
+
+ def test_invalid_optim_request_no_optdata(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_no_optdata.json").read())
+ with pytest.raises(BusinessException):
+ validate_request(req_json)
+
+ def test_process_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_valid.json").read())
+
+ res = process_request(req_json)
+ assert res.status_code == 400
+
+ def test_py_process_request(self):
+ req_json = json.loads(open("./test/optengine-tests/test_py_optengine_valid.json").read())
+
+ res = process_request(req_json)
+ assert res.status_code == 200
+
+ def test_invalid_solver(self):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_invalid_solver.json").read())
+
+ with pytest.raises(BusinessException):
+ process_request(req_json)
+
+ @patch('runtime.optim_engine.get_model_data')
+ def test_process_solverid_request(self, mocker):
+ req_json = json.loads(open("./test/optengine-tests/test_optengine_modelId.json").read())
+
+ data = 200, ('junk', '', '', 'py')
+ mocker.return_value = data
+ process_request(req_json)
diff --git a/test/test_process_fixed_pci.py b/test/test_process_fixed_pci.py
new file mode 100644
index 0000000..3d805c5
--- /dev/null
+++ b/test/test_process_fixed_pci.py
@@ -0,0 +1,79 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+import mock
+import unittest
+
+from flask import Response
+from mock import patch
+from osdf.adapters.local_data import local_policies
+from apps.pci.optimizers.pci_opt_processor import process_pci_optimation
+import osdf.config.loader as config_loader
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+
+
+class TestProcessPlacementOpt(unittest.TestCase):
+
+ def setUp(self):
+ mock_req_accept_message = Response("Accepted Request", content_type='application/json; charset=utf-8')
+ self.patcher_req = patch('apps.pci.optimizers.config_request.request',
+ return_value={"solutionInfo": {"placementInfo": "dummy"}})
+ self.patcher_req_accept = patch('osdf.operation.responses.osdf_response_for_request_accept',
+ return_value=mock_req_accept_message)
+ self.patcher_callback = patch(
+ 'apps.pci.optimizers.pci_opt_processor.process_pci_optimation',
+ return_value=mock_req_accept_message)
+
+ mock_mzn_response = [{'pci': {0: 2, 1: 0, 2: 1, 3:3, 4:0} , 'used_ignorables': [0]}]
+
+ self.patcher_minizinc_callback = patch(
+ 'apps.pci.optimizers.solver.optimizer.solve',
+ return_value=mock_mzn_response )
+ self.patcher_RestClient = patch(
+ 'osdf.utils.interfaces.RestClient', return_value=mock.MagicMock())
+ self.Mock_req = self.patcher_req.start()
+ self.Mock_req_accept = self.patcher_req_accept.start()
+ self.Mock_callback = self.patcher_callback.start()
+ self.Mock_RestClient = self.patcher_RestClient.start()
+ self.Mock_mzn_callback = self.patcher_minizinc_callback.start()
+
+ def tearDown(self):
+ patch.stopall()
+
+ def test_process_pci_opt_solutions(self):
+ main_dir = ""
+ parameter_data_file = main_dir + "test/pci-optimization-tests/fixed_pci.json"
+ policy_data_path = main_dir + "test/policy-local-files/"
+ self.config_spec = {
+ "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+ "core": "test/functest/simulators/simulated-config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ valid_policies_list_file = policy_data_path + '/' + 'meta-valid-policies.txt'
+ valid_policies_files = local_policies.get_policy_names_from_file(valid_policies_list_file)
+
+ request_json = json_from_file(parameter_data_file)
+ policies = [json_from_file(policy_data_path + '/' + name) for name in valid_policies_files]
+
+ templ_string = process_pci_optimation(request_json, self.osdf_config,policies)
+
+
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/test/test_process_pci_anr_opt.py b/test/test_process_pci_anr_opt.py
new file mode 100644
index 0000000..17c3e6d
--- /dev/null
+++ b/test/test_process_pci_anr_opt.py
@@ -0,0 +1,79 @@
+# -------------------------------------------------------------------------
+# Copyright (c) 2018 AT&T Intellectual Property
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# -------------------------------------------------------------------------
+#
+import unittest
+
+import mock
+from flask import Response
+from mock import patch
+
+import osdf.config.loader as config_loader
+from apps.pci.optimizers.pci_opt_processor import process_pci_optimation
+from osdf.adapters.local_data import local_policies
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+
+
+class TestProcessPlacementOpt(unittest.TestCase):
+
+ def setUp(self):
+ mock_req_accept_message = Response("Accepted Request", content_type='application/json; charset=utf-8')
+ self.patcher_req = patch('apps.pci.optimizers.config_request.request',
+ return_value={"solutionInfo": {"placementInfo": "dummy"}})
+ self.patcher_req_accept = patch('osdf.operation.responses.osdf_response_for_request_accept',
+ return_value=mock_req_accept_message)
+ self.patcher_callback = patch(
+ 'apps.pci.optimizers.pci_opt_processor.process_pci_optimation',
+ return_value=mock_req_accept_message)
+
+ mock_mzn_response = [{'pci': {0: 0, 1: 1, 2: 2, 3: 3, 4: 0}, 'used_ignorables': [0]}]
+
+ self.patcher_minizinc_callback = patch(
+ 'apps.pci.optimizers.solver.optimizer.solve',
+ return_value=mock_mzn_response)
+ self.patcher_RestClient = patch(
+ 'osdf.utils.interfaces.RestClient', return_value=mock.MagicMock())
+ self.Mock_req = self.patcher_req.start()
+ self.Mock_req_accept = self.patcher_req_accept.start()
+ self.Mock_callback = self.patcher_callback.start()
+ self.Mock_RestClient = self.patcher_RestClient.start()
+ self.Mock_mzn_callback = self.patcher_minizinc_callback.start()
+
+ def tearDown(self):
+ patch.stopall()
+
+ def test_process_pci_anr_opt_solutions(self):
+ main_dir = ""
+ parameter_data_file = main_dir + "test/pci-optimization-tests/pci_anr_request.json"
+ policy_data_path = main_dir + "test/policy-local-files/"
+ self.config_spec = {
+ "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+ "core": "test/functest/simulators/simulated-config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+
+ valid_policies_list_file = policy_data_path + '/' + 'meta-valid-policies.txt'
+ valid_policies_files = local_policies.get_policy_names_from_file(valid_policies_list_file)
+
+ request_json = json_from_file(parameter_data_file)
+ policies = [json_from_file(policy_data_path + '/' + name) for name in valid_policies_files]
+
+ templ_string = process_pci_optimation(request_json, self.osdf_config, policies)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/test/test_process_pci_opt.py b/test/test_process_pci_opt.py
index 31aa5fb..d52599d 100644
--- a/test/test_process_pci_opt.py
+++ b/test/test_process_pci_opt.py
@@ -21,7 +21,7 @@ import unittest
from flask import Response
from mock import patch
from osdf.adapters.local_data import local_policies
-from osdf.optimizers.pciopt.pci_opt_processor import process_pci_optimation
+from apps.pci.optimizers.pci_opt_processor import process_pci_optimation
import osdf.config.loader as config_loader
from osdf.utils.interfaces import json_from_file
from osdf.utils.programming_utils import DotDict
@@ -31,18 +31,18 @@ class TestProcessPlacementOpt(unittest.TestCase):
def setUp(self):
mock_req_accept_message = Response("Accepted Request", content_type='application/json; charset=utf-8')
- self.patcher_req = patch('osdf.optimizers.pciopt.configdb.request',
+ self.patcher_req = patch('apps.pci.optimizers.config_request.request',
return_value={"solutionInfo": {"placementInfo": "dummy"}})
self.patcher_req_accept = patch('osdf.operation.responses.osdf_response_for_request_accept',
return_value=mock_req_accept_message)
self.patcher_callback = patch(
- 'osdf.optimizers.pciopt.pci_opt_processor.process_pci_optimation',
+ 'apps.pci.optimizers.pci_opt_processor.process_pci_optimation',
return_value=mock_req_accept_message)
mock_mzn_response = [{'pci': {0: 0, 1: 1, 2: 2}}]
self.patcher_minizinc_callback = patch(
- 'osdf.optimizers.pciopt.solver.optimizer.solve',
+ 'apps.pci.optimizers.solver.optimizer.solve',
return_value=mock_mzn_response )
self.patcher_RestClient = patch(
'osdf.utils.interfaces.RestClient', return_value=mock.MagicMock())
diff --git a/test/test_process_placement_opt.py b/test/test_process_placement_opt.py
index 3219675..8a29100 100644
--- a/test/test_process_placement_opt.py
+++ b/test/test_process_placement_opt.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,8 +21,9 @@ import unittest
from flask import Response
from mock import patch
+
+from apps.placement.optimizers.conductor.remote_opt_processor import process_placement_opt
from osdf.adapters.local_data import local_policies
-from osdf.optimizers.placementopt.conductor.remote_opt_processor import process_placement_opt
from osdf.utils.interfaces import json_from_file, yaml_from_file
@@ -29,12 +31,14 @@ class TestProcessPlacementOpt(unittest.TestCase):
def setUp(self):
mock_req_accept_message = Response("Accepted Request", content_type='application/json; charset=utf-8')
- self.patcher_req = patch('osdf.optimizers.placementopt.conductor.conductor.request',
- return_value={"solutionInfo": {"placementInfo": "dummy"}})
+ conductor_response_file = 'test/placement-tests/conductor_response.json'
+ conductor_response = json_from_file(conductor_response_file)
+ self.patcher_req = patch('osdf.adapters.conductor.conductor.request',
+ return_value=conductor_response)
self.patcher_req_accept = patch('osdf.operation.responses.osdf_response_for_request_accept',
return_value=mock_req_accept_message)
self.patcher_callback = patch(
- 'osdf.optimizers.placementopt.conductor.remote_opt_processor.process_placement_opt',
+ 'apps.placement.optimizers.conductor.remote_opt_processor.process_placement_opt',
return_value=mock_req_accept_message)
self.patcher_RestClient = patch(
'osdf.utils.interfaces.RestClient', return_value=mock.MagicMock())
@@ -76,6 +80,20 @@ class TestProcessPlacementOpt(unittest.TestCase):
local_config = yaml_from_file(local_config_file)
templ_string = process_placement_opt(request_json, policies, local_config)
+ def test_process_placement_opt_placementDemand_vfmodule(self):
+ main_dir = ""
+ parameter_data_file = main_dir + "test/placement-tests/request_vfmod.json"
+ policy_data_path = main_dir + "test/policy-local-files/"
+ local_config_file = main_dir + "config/common_config.yaml"
+
+ valid_policies_list_file = policy_data_path + '/' + 'meta-valid-policies.txt'
+ valid_policies_files = local_policies.get_policy_names_from_file(valid_policies_list_file)
+
+ request_json = json_from_file(parameter_data_file)
+ policies = [json_from_file(policy_data_path + '/' + name) for name in valid_policies_files]
+ local_config = yaml_from_file(local_config_file)
+ templ_string = process_placement_opt(request_json, policies, local_config)
+
if __name__ == "__main__":
unittest.main()
diff --git a/test/test_simple_route_opt.py b/test/test_simple_route_opt.py
new file mode 100644
index 0000000..3b4facc
--- /dev/null
+++ b/test/test_simple_route_opt.py
@@ -0,0 +1,57 @@
+from apps.route.optimizers.simple_route_opt import RouteOpt
+from osdf.utils.interfaces import json_from_file
+from unittest.mock import patch
+import osdf.config.loader as config_loader
+from osdf.utils.programming_utils import DotDict
+import unittest
+
+
+class TestSimpleRouteOptimization(unittest.TestCase):
+ @patch('apps.route.optimizers.simple_route_opt.requests.get')
+ @patch('apps.route.optimizers.simple_route_opt.pymzn.minizinc')
+ def test_process_nst_selection_solutions( self, mock_solve, mock_get):
+
+ main_dir = ""
+ response_data_file = main_dir + "test/simple_route_opt/AAI.json"
+ mock_get.return_value.json.return_value = json_from_file(response_data_file)
+ mock_get.return_value.status_code = 200
+ mock_solve.return_value = [{'x': [1, 1, 1]}]
+ self.config_spec = {
+ "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+ "core": "test/functest/simulators/simulated-config/common_config.yaml"
+ }
+ self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+ parameter_data_file = main_dir + "test/simple_route_opt/routeOpt.json"
+ request_json = json_from_file(parameter_data_file)
+ mock_response = {
+ "requestId": "yyy-yyy-yyyy",
+ "requestStatus": "accepted",
+ "solutions": [
+ {
+ "end_node": "10.10.10.10",
+ "link": "link-id-1",
+ "start_node": "20.20.20.20"
+ },
+ {
+ "end_node": "11.11.11.11",
+ "link": "link-id-2",
+ "start_node": "22.22.22.22"
+ },
+ {
+ "end_node": "20.20.20.20",
+ "link": "link-id-3",
+ "start_node": "11.11.11.11"
+ }
+ ],
+ "statusMessage": " ",
+ "transactionId": "xxx-xxx-xxxx"
+ }
+ routopt = RouteOpt()
+ actual_response = routopt.get_route(request_json,self.osdf_config)
+ self.assertEqual(mock_response, actual_response)
+
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/test/test_so_response_gen.py b/test/test_so_response_gen.py
index ab73ef6..1e6079b 100644
--- a/test/test_so_response_gen.py
+++ b/test/test_so_response_gen.py
@@ -1,5 +1,6 @@
# -------------------------------------------------------------------------
# Copyright (c) 2017-2018 AT&T Intellectual Property
+# Copyright (C) 2020 Wipro Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,10 +17,9 @@
# -------------------------------------------------------------------------
#
import unittest
-import json
-import yaml
+
+from apps.placement.optimizers.conductor.remote_opt_processor import conductor_response_processor
from osdf.utils.interfaces import json_from_file
-from osdf.optimizers.placementopt.conductor.conductor import conductor_response_processor
from osdf.utils.interfaces import RestClient
@@ -36,4 +36,4 @@ class TestSoResponseGen(unittest.TestCase):
if __name__ == "__main__":
- unittest.main() \ No newline at end of file
+ unittest.main()
diff --git a/tox.ini b/tox.ini
index 88b595d..8dc20c9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,23 +1,46 @@
[tox]
skipsdist=True
-envlist = py3
+envlist = py3, pylint, flake8diff
[testenv]
distribute = False
+basepython=python3
+setenv =
+ OSDF_CONFIG_FILE={toxinidir}/test/config/osdf_config.yaml
commands =
- - cat /etc/hosts
+ /bin/cp config/slicing_config.yaml test/config/
/bin/bash test/functest/scripts/start-simulators.sh
coverage run --module pytest --junitxml xunit-results.xml
coverage xml --omit=".tox/py3/*","test/*"
coverage report -m --omit=".tox/py3/*","test/*"
/bin/bash test/functest/scripts/stop-simulators.sh
+ /bin/rm test/config/slicing_config.yaml
# TODO: need to update the above "omit" when we package osdf as pip-installable
-deps = -r{toxinidir}/requirements.txt
+deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test/test-requirements.txt
+ -r{toxinidir}/requirements-osdf.txt
+ -r{toxinidir}/requirements-opteng.txt
[run]
-source=./osdf/,osdfapp.py
+source=./apps/,./osdf/,osdfapp.py,./runtime/,solverapp.py
+
+[testenv:pylint]
+whitelist_externals=bash
+commands = bash -c "pylint --reports=y osdf apps runtime| tee pylint.out"
[testenv:py3]
-basepython=python3.6
+basepython=python3
+
+[testenv:flake8diff]
+basepython=python3
+whitelist_externals=bash
+deps = hacking>=2.0.0
+commands =
+ bash -c "files=$(git diff HEAD^ HEAD --diff-filter=d --name-only | grep -E '(^apps\/|osdf\/|runtime\/)'| grep -E '*\.py$'); if [[ -z $files ]]; then exit 0; else flake8 $files; fi"
+
+[flake8]
+select = E,H,W,F
+max-line-length = 119
+ignore = W503 #conflict with W504
+per-file-ignores= apps/pci/optimizers/__init__.py:F401
diff --git a/version.properties b/version.properties
index 536c517..18c199b 100644
--- a/version.properties
+++ b/version.properties
@@ -17,9 +17,9 @@
# -------------------------------------------------------------------------
#
-major=1
-minor=2
-patch=2
+major=3
+minor=0
+patch=8
base_version=${major}.${minor}.${patch}