summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--requirements.txt1
-rw-r--r--setup.cfg18
-rw-r--r--setup.py4
-rwxr-xr-xtests/functest_run.sh3
-rw-r--r--tosca2heat/README.md4
-rw-r--r--tosca2heat/heat-translator/README.rst11
-rw-r--r--tosca2heat/heat-translator/doc/source/conf.py1
-rw-r--r--tosca2heat/heat-translator/doc/source/usage.rst52
-rw-r--r--tosca2heat/heat-translator/requirements.txt13
-rw-r--r--tosca2heat/heat-translator/setup.cfg5
-rw-r--r--tosca2heat/heat-translator/test-requirements.txt9
-rw-r--r--tosca2heat/heat-translator/tools/tox_install.sh30
-rw-r--r--tosca2heat/heat-translator/translator/common/exception.py5
-rw-r--r--tosca2heat/heat-translator/translator/common/flavors.py64
-rw-r--r--tosca2heat/heat-translator/translator/common/images.py91
-rw-r--r--tosca2heat/heat-translator/translator/common/utils.py67
-rw-r--r--tosca2heat/heat-translator/translator/conf/heat_translator_logging.conf3
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_output.py7
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py275
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_template.py35
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py91
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py134
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py7
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py8
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py165
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py4
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py4
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py7
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py131
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca_translator.py51
-rw-r--r--tosca2heat/heat-translator/translator/hot/translate_node_templates.py400
-rw-r--r--tosca2heat/heat-translator/translator/hot/translate_outputs.py14
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py5
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/translate.py10
-rw-r--r--tosca2heat/heat-translator/translator/shell.py223
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_autoscaling.yaml40
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_cluster_autoscaling.yaml62
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/senlin_cluster_policies.yaml11
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/asg_res.yaml10
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_autoscaling.yaml39
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_cluster_autoscaling.yaml60
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml19
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml3
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml6
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_exchange_public_ssh_key.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_get_functions_semantic.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_script_types.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component_multiple_hosts.yaml75
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/interfaces/hot_interface_on_compute.yaml (renamed from tosca2heat/heat-translator/translator/tests/data/hot_output/hot_interface_on_compute.yaml)2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/SP1_res.yaml39
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_nfv_sample.yaml (renamed from tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml)12
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_tosca_nfv_autoscaling.yaml30
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/policies/hot_policies.yaml (renamed from tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml)2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_interface_on_compute.yaml48
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_script_types.yaml48
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/nfv/tacker_defs.yaml183
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/nfv/tacker_nfv_defs.yaml261
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_autoscaling.yaml67
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_sample.yaml90
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/policies/tosca_policies.yaml28
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_get_functions_semantic.yaml18
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_unsupported_type.yaml15
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_software_component_multiple_hosts.yaml55
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/rnc_definition.yaml16
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/vRNC.yaml25
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_shell.py103
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py446
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_utils.py34
-rw-r--r--tosca2heat/tosca-parser/README.rst9
-rw-r--r--tosca2heat/tosca-parser/doc/source/conf.py1
-rw-r--r--tosca2heat/tosca-parser/doc/source/installation.rst15
-rw-r--r--tosca2heat/tosca-parser/requirements.txt8
-rw-r--r--tosca2heat/tosca-parser/setup.cfg3
-rw-r--r--tosca2heat/tosca-parser/test-requirements.txt6
-rw-r--r--tosca2heat/tosca-parser/tools/tox_install.sh30
-rw-r--r--tosca2heat/tosca-parser/toscaparser/__init__.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml11
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/constraints.py8
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/entity_type.py7
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/grouptype.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/interfaces.py13
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/nodetype.py6
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/policytype.py5
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/portspectype.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py16
-rw-r--r--tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py3
-rw-r--r--tosca2heat/tosca-parser/toscaparser/entity_template.py1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml (renamed from tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml)0
-rw-r--r--tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py (renamed from tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py)2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/functions.py110
-rw-r--r--tosca2heat/tosca-parser/toscaparser/imports.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/nodetemplate.py74
-rw-r--r--tosca2heat/tosca-parser/toscaparser/parameters.py11
-rw-r--r--tosca2heat/tosca-parser/toscaparser/policy.py6
-rw-r--r--tosca2heat/tosca-parser/toscaparser/shell.py40
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/base.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csarbin17488 -> 17490 bytes
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zipbin17488 -> 17490 bytes
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml44
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml20
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml4
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml23
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml25
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml23
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml19
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml75
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml18
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml183
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml261
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml95
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml48
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml23
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml26
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml67
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml21
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml3
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml37
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml4
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml70
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml31
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml31
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml6
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml19
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py2
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_functions.py57
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py6
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_shell.py10
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py80
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py9
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py58
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py235
-rw-r--r--tosca2heat/tosca-parser/toscaparser/topology_template.py32
-rw-r--r--tosca2heat/tosca-parser/toscaparser/tosca_template.py16
-rw-r--r--tosca2heat/tosca-parser/toscaparser/unsupportedtype.py12
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py1
-rw-r--r--tosca2heat/tosca-parser/toscaparser/utils/validateutils.py2
-rw-r--r--tox.ini26
-rw-r--r--verigraph/LICENSE13
-rw-r--r--verigraph/README.rst258
-rw-r--r--verigraph/buildVeriGraph_gRPC.xml210
-rw-r--r--verigraph/pom.xml213
-rw-r--r--verigraph/service/src/mcnet/components/Checker.java363
-rw-r--r--verigraph/service/src/mcnet/components/Core.java44
-rw-r--r--verigraph/service/src/mcnet/components/DataIsolationResult.java41
-rw-r--r--verigraph/service/src/mcnet/components/IsolationResult.java42
-rw-r--r--verigraph/service/src/mcnet/components/NetContext.java340
-rw-r--r--verigraph/service/src/mcnet/components/Network.java296
-rw-r--r--verigraph/service/src/mcnet/components/NetworkObject.java57
-rw-r--r--verigraph/service/src/mcnet/components/Result.java43
-rw-r--r--verigraph/service/src/mcnet/components/Tuple.java35
-rw-r--r--verigraph/service/src/mcnet/netobjs/AclFirewall.java123
-rw-r--r--verigraph/service/src/mcnet/netobjs/DumbNode.java42
-rw-r--r--verigraph/service/src/mcnet/netobjs/EndHost.java100
-rw-r--r--verigraph/service/src/mcnet/netobjs/PacketModel.java70
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoAntispam.java124
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoCache.java177
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoEndHost.java100
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoErrFunction.java96
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoFieldModifier.java91
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoIDS.java140
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoMailClient.java106
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoMailServer.java117
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoNF.java101
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoNat.java176
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoVpnAccess.java142
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoVpnExit.java142
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoWebClient.java107
-rw-r--r--verigraph/service/src/mcnet/netobjs/PolitoWebServer.java114
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/README.rst54
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/__init__.py8
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/batch_generator.py186
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/code_generator.py59
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/config.py88
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/json_generator.py261
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/routing_generator.py80
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/test_class_generator.py399
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/test_generator.py160
-rw-r--r--verigraph/service/src/tests/j-verigraph-generator/utility.py257
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/client/Neo4jManagerClient.java339
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/client/VerifyClient.java444
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/client/VerifyClientException.java24
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/database/DatabaseClass.java175
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/deserializer/ConfigurationCustomDeserializer.java42
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/deserializer/GraphCustomDeserializer.java87
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/deserializer/NodeCustomDeserializer.java92
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/deserializer/PathsMessageBodyReader.java52
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestException.java23
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestExceptionMapper.java30
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundException.java23
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundExceptionMapper.java30
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenException.java23
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenExceptionMapper.java30
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/GenericExceptionMapper.java29
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorException.java23
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorExceptionMapper.java30
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Configuration.java75
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Entry.java37
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/ErrorMessage.java62
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Graph.java105
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Link.java71
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Neighbour.java70
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Node.java152
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Test.java62
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/Verification.java69
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/model/jaxb.properties1
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/resources/GraphResource.java167
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/resources/NeighbourResource.java141
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/resources/NodeResource.java230
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/resources/beans/VerificationBean.java67
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/serializer/CustomConfigurationSerializer.java35
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/serializer/CustomMapSerializer.java30
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/GraphService.java129
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/JsonValidationService.java136
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/NeighbourService.java182
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/NodeService.java258
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/ValidationUtils.java132
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/service/VerificationService.java1185
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/test/MultiThreadedTestCase.java201
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/test/Scalability.java409
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/test/TestCase.java161
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/test/TestExecutionException.java24
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/test/Tester.java220
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/DpiValidator.java45
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/EndhostValidator.java25
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/ValidationInterface.java21
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/VpnaccessValidator.java51
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/VpnexitValidator.java51
-rw-r--r--verigraph/src/main/java/it/polito/escape/verify/validation/exception/ValidationException.java31
-rw-r--r--verigraph/src/main/java/it/polito/grpc/Client.java550
-rw-r--r--verigraph/src/main/java/it/polito/grpc/GrpcUtils.java156
-rw-r--r--verigraph/src/main/java/it/polito/grpc/README.rst442
-rw-r--r--verigraph/src/main/java/it/polito/grpc/Service.java462
-rw-r--r--verigraph/src/main/java/it/polito/grpc/test/GrpcServerTest.java292
-rw-r--r--verigraph/src/main/java/it/polito/grpc/test/GrpcTest.java349
-rw-r--r--verigraph/src/main/java/it/polito/grpc/test/MultiThreadTest.java220
-rw-r--r--verigraph/src/main/java/it/polito/grpc/test/ReachabilityTest.java252
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionEnumType.java59
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionType.java81
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionsType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CiType.java206
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpType.java86
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpointsType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CtrlInterfacesType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpCpType.java89
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpType.java260
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpointsType.java65
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpsCpsType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/FlowrulesType.java619
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/HttpMessage.java108
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/MonParamsType.java122
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NeType.java133
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NelementsType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfType.java181
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Nffg.java183
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NffgSet.java69
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfunctionsType.java67
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ObjectFactory.java319
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Paths.java163
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortDirEnumType.java60
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortType.java104
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Property.java152
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/SpecType.java577
-rw-r--r--verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/package-info.java11
-rw-r--r--verigraph/src/main/proto/verigraph.proto154
-rw-r--r--verigraph/src/main/schema/net_types.xsd62
-rw-r--r--verigraph/src/main/schema/nffg.xsd363
-rw-r--r--verigraph/src/main/webapp/json/antispam.json11
-rw-r--r--verigraph/src/main/webapp/json/cache.json11
-rw-r--r--verigraph/src/main/webapp/json/database.json5
-rw-r--r--verigraph/src/main/webapp/json/dpi.json11
-rw-r--r--verigraph/src/main/webapp/json/endhost.json42
-rw-r--r--verigraph/src/main/webapp/json/endpoint.json9
-rw-r--r--verigraph/src/main/webapp/json/fieldmodifier.json12
-rw-r--r--verigraph/src/main/webapp/json/firewall.json11
-rw-r--r--verigraph/src/main/webapp/json/mailclient.json22
-rw-r--r--verigraph/src/main/webapp/json/mailserver.json12
-rw-r--r--verigraph/src/main/webapp/json/nat.json11
-rw-r--r--verigraph/src/main/webapp/json/vpnaccess.json22
-rw-r--r--verigraph/src/main/webapp/json/vpnexit.json22
-rw-r--r--verigraph/src/main/webapp/json/webclient.json22
-rw-r--r--verigraph/src/main/webapp/json/webserver.json12
-rw-r--r--verigraph/target/m2e-wtp/web-resources/META-INF/MANIFEST.MF5
-rw-r--r--verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.properties7
-rw-r--r--verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.xml211
-rw-r--r--verigraph/tester/README.rst38
-rw-r--r--verigraph/tester/test.py115
-rw-r--r--verigraph/tester/testcase_schema.json33
-rw-r--r--verigraph/tester/testcases/test_budapest_sap1_webserver_sat.json122
-rw-r--r--verigraph/tester/testcases/test_budapest_sap1_webserver_unsat.json122
-rw-r--r--verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficAllowed.json59
-rw-r--r--verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficBlocked.json59
-rw-r--r--verigraph/tester/testcases/test_user_nat_vpn_fieldmod_webserver_unsat.json94
-rw-r--r--verigraph/tester/testcases/test_user_nat_vpn_webserver_sat.json82
-rw-r--r--verigraph/tester/testcases/test_webserver_vpn_nat_user_unsat.json82
342 files changed, 25231 insertions, 1127 deletions
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..053148f
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+tox
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..58941f7
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,18 @@
+[metadata]
+name = parser
+summary = OPNFV Parser Project
+author = OPNFV
+author-email = opnfv-tech-discuss@lists.opnfv.org
+home-page = https://wiki.opnfv.org/display/parser
+classifier =
+ Environment :: OPNFV
+ Intended Audience :: Information Technology
+ Intended Audience :: System Administrators
+ License :: OSI Approved :: Apache Software License
+ Operating System :: POSIX :: Linux
+ Programming Language :: Python
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.5
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..b341513
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,4 @@
+import setuptools
+
+setuptools.setup(
+ )
diff --git a/tests/functest_run.sh b/tests/functest_run.sh
index 7b65da0..95cf629 100755
--- a/tests/functest_run.sh
+++ b/tests/functest_run.sh
@@ -109,6 +109,9 @@ change_env_to_parser_user_project() {
export OS_PROJECT_NAME=${PARSER_PROJECT}
export OS_TENANT_NAME=${PARSER_TENANT}
+ export OS_PROJECT_DOMAIN_NAME=${OS_PROJECT_DOMAIN_NAME:-'Default'}
+ export OS_USER_DOMAIN_NAME=${OS_USER_DOMAIN_NAME:-'Default'}
+
}
diff --git a/tosca2heat/README.md b/tosca2heat/README.md
index 3a29629..a1f6289 100644
--- a/tosca2heat/README.md
+++ b/tosca2heat/README.md
@@ -1,5 +1,5 @@
##TOSCA To HOT Translation##
Basic version information:
-1. tosca-paser is based on the stable version of 0.6 in openstack community;
-2. heat-translator is based on the stable version of 0.5 in openstack community;
+1. tosca-paser is based on the stable version of 0.7 in openstack community;
+2. heat-translator is based on the stable version of 0.7 in openstack community;
3. refer to the file of diff_file_list.rst for the detail difference between parser and upstream project.
diff --git a/tosca2heat/heat-translator/README.rst b/tosca2heat/heat-translator/README.rst
index 1bad459..c8af42a 100644
--- a/tosca2heat/heat-translator/README.rst
+++ b/tosca2heat/heat-translator/README.rst
@@ -1,3 +1,12 @@
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/heat-translator.svg
+ :target: http://governance.openstack.org/reference/tags/index.html
+
+.. Change things from this point on
+
===============
Heat-Translator
===============
@@ -31,7 +40,7 @@ Directory Structure
Three main directories related to the heat-translator are:
-1. hot: It is the generator, that has logic of converting TOSCA in memory graph to HOT yaml files.
+1. hot: It is the generator, that has logic of converting TOSCA in memory graph to HOT YAML files.
2. common: It has all the file that can support the execution of parser and generator.
3. tests: It contains test programs and more importantly several templates which are used for testing.
diff --git a/tosca2heat/heat-translator/doc/source/conf.py b/tosca2heat/heat-translator/doc/source/conf.py
index 23aa050..e051aeb 100644
--- a/tosca2heat/heat-translator/doc/source/conf.py
+++ b/tosca2heat/heat-translator/doc/source/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
diff --git a/tosca2heat/heat-translator/doc/source/usage.rst b/tosca2heat/heat-translator/doc/source/usage.rst
index e8f132a..383c696 100644
--- a/tosca2heat/heat-translator/doc/source/usage.rst
+++ b/tosca2heat/heat-translator/doc/source/usage.rst
@@ -12,7 +12,8 @@ Assuming that OpenStackClient (OSC) is available in your environment, you can ea
Alternatively, you can install a particular release of Heat-Translator as available at https://pypi.python.org/pypi/heat-translator.
-Once installation is complete, Heat-Translator is ready to use. Currently you can use it in following three ways.
+Once installation is complete, Heat-Translator is ready to use. The only required argument is ``--template-file``. By default, the ``--template-type`` is set to ``tosca`` which is the
+only supported template type at present. Currently you can use Heat-Translator in following three ways.
Translate and get output on command line. For example: ::
@@ -39,15 +40,13 @@ Heat-Translator can be used without any specific OpenStack environment set up as
python heat_translator.py --template-file==<path to the YAML template> --template-type=<type of template e.g. tosca> --parameters="purpose=test"
The heat_translator.py test program is at the root level of the project. The program has currently tested with TOSCA templates.
-It requires two arguments::
-
-1. Path to the file that needs to be translated. The file, flat yaml template or CSAR, can be specified as a local file in your
+The only required argument is ``--template-file``. By default, the ``--template-type`` is set to ``tosca`` which is the only supported template type at present.
+The value to the ``--template-file`` is a path to the file that needs to be translated. The file, flat YAML template or CSAR, can be specified as a local file in your
system or via URL.
-2. Type of translation (e.g. tosca)
For example, a TOSCA hello world template can be translated by running the following command from the project location::
- python heat_translator.py --template-file=translator/tests/data/tosca_helloworld.yaml --template-type=tosca
+ python heat_translator.py --template-file=translator/tests/data/tosca_helloworld.yaml
This should produce a translated Heat Orchestration Template on the command line. The translated content can be saved to a desired file by setting --output-file=<path>.
For example: ::
@@ -57,7 +56,7 @@ For example: ::
An optional argument can be provided to handle user inputs parameters. Also, a template file can only be validated instead of translation by using --validate-only=true
optional argument. The command below shows an example usage::
- python heat_translator.py --template-file==<path to the YAML template> --template-type=<type of template e.g. tosca> --validate-only=true
+ python heat_translator.py --template-file=<path to the YAML template> --template-type=<type of template e.g. tosca> --validate-only=true
Alternatively, you can install a particular release of Heat-Translator as available at https://pypi.python.org/pypi/heat-translator.
In this case, you can simply run translation via CLI entry point::
@@ -79,4 +78,41 @@ Things To Consider
capabilities. However, user may required to use these properties in template in certain circumstances, so in that case, TOSCA Compute can be extended
with these properties and later used in the node template. For a good example, refer to the ``translator/tests/data/test_tosca_flavor_and_image.yaml`` test
template.
-
+* The Heat-Translator can be used to automatically deploy translated TOSCA template given that your environment has python-heatclient and python-keystoneclient.
+ This can be achieved by providing ``--deploy`` argument to the Heat-Translator. You can provide desired stack name by providing it as ``--stack-name <name>``
+ argument. If you do not provide ``--stack-name``, an unique name will be created and used.
+ Below is an example command to deploy translated template with a desired stack name::
+ heat-translator --template-file translator/tests/data/tosca_helloworld.yaml --stack-name mystack --deploy
+* The Heat-Translator supports translation of TOSCA templates to Heat Senlin
+ resources (e.g. ``OS::Senlin::Cluster``) but that requires to use a specific
+ TOSCA node type called ``tosca.policies.Scaling.Cluster``.
+ The ``tosca.policies.Scaling.Cluster`` is a custom type that derives from
+ ``tosca.policies.Scaling``. For example usage, refer to the
+ ``tosca_cluster_autoscaling.yaml`` and ``hot_cluster_autoscaling.yaml``
+ provided under the ``translator/tests/data/autoscaling`` and
+ ``translator/tests/data/hot_output/autoscaling`` directories respectively in
+ the heat-translator project (``https://github.com/openstack/heat-translator``).
+ When you use ``tosca.policies.Scaling`` normative node type, the
+ Heat-Translator will translate it to ``OS::Heat::AutoScalingGroup`` Heat
+ resource. Related example templates, ``tosca_autoscaling.yaml`` and
+ ``hot_autoscaling.yaml`` can be found for reference purposes under the same
+ directory structure mentioned above.
+* With the version 0.7.0 of Heat-Translator, output of multiple template files
+ (for example, nested templates in autoscaling) can be accessed via newly
+ introduced API called ``translate_to_yaml_files_dict(<output_filename>)``
+ where ``<output_filename>`` is the name of file where you want to store parent
+ HOT template. The return value of this API call will be a dictionary in HOT
+ YAML with one or multiple file names as keys and translated content as values.
+ In order to use this on the command line, simply invoke Heat-Translator with
+ ``--output-file`` argument. Here, the parent template will be stored in the
+ value specified to the ``--output-file``. Whereas, child templates, if any,
+ will be saved at the same location of the parent template.
+
+ Below is an example of how to call the API in your code, where
+ ``translator`` is an instance of Heat-Translator::
+
+ yaml_files = translator.translate_to_yaml_files_dict(filename)
+
+ Below is an example of how to use this on the command line::
+
+ heat-translator --template-file translator/tests/data/autoscaling/tosca_autoscaling.yaml --output-file /tmp/hot.yaml \ No newline at end of file
diff --git a/tosca2heat/heat-translator/requirements.txt b/tosca2heat/heat-translator/requirements.txt
index b9792da..b211383 100644
--- a/tosca2heat/heat-translator/requirements.txt
+++ b/tosca2heat/heat-translator/requirements.txt
@@ -1,10 +1,15 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr>=1.6 # Apache-2.0
+pbr>=1.8 # Apache-2.0
Babel>=2.3.4 # BSD
-cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
-PyYAML>=3.1.0 # MIT
+cliff>=2.3.0 # Apache-2.0
+PyYAML>=3.10.0 # MIT
python-dateutil>=2.4.2 # BSD
six>=1.9.0 # MIT
-tosca-parser>=0.5.0 # Apache-2.0
+tosca-parser>=0.7.0 # Apache-2.0
+keystoneauth1>=2.18.0 # Apache-2.0
+python-novaclient>=7.1.0 # Apache-2.0
+python-heatclient>=1.6.1 # Apache-2.0
+python-glanceclient>=2.5.0 # Apache-2.0
+requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
diff --git a/tosca2heat/heat-translator/setup.cfg b/tosca2heat/heat-translator/setup.cfg
index 029eeff..21d0c6f 100644
--- a/tosca2heat/heat-translator/setup.cfg
+++ b/tosca2heat/heat-translator/setup.cfg
@@ -5,7 +5,7 @@ description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
-home-page = http://www.openstack.org/
+home-page = http://docs.openstack.org/developer/heat-translator/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -17,10 +17,13 @@ classifier =
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
+ Programming Language :: Python :: 3.5
[files]
packages =
translator
+package_data =
+ conf = conf/*.conf
[entry_points]
openstack.cli.extension =
diff --git a/tosca2heat/heat-translator/test-requirements.txt b/tosca2heat/heat-translator/test-requirements.txt
index 17a507c..d4b59c3 100644
--- a/tosca2heat/heat-translator/test-requirements.txt
+++ b/tosca2heat/heat-translator/test-requirements.txt
@@ -2,13 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.0
-coverage>=3.6 # Apache-2.0
-discover # BSD
-fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
+coverage>=4.0 # Apache-2.0
+fixtures>=3.0.0 # Apache-2.0/BSD
oslotest>=1.10.0 # Apache-2.0
-oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
+oslosphinx>=4.7.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
-sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
+sphinx>=1.5.1 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
diff --git a/tosca2heat/heat-translator/tools/tox_install.sh b/tosca2heat/heat-translator/tools/tox_install.sh
new file mode 100644
index 0000000..e61b63a
--- /dev/null
+++ b/tosca2heat/heat-translator/tools/tox_install.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE="$1"
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ "$CONSTRAINTS_FILE" != http* ]]; then
+ CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
+
+pip install -c"$localfile" openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints "$localfile" -- "$CLIENT_NAME"
+
+pip install -c"$localfile" -U "$@"
+exit $?
diff --git a/tosca2heat/heat-translator/translator/common/exception.py b/tosca2heat/heat-translator/translator/common/exception.py
index be86116..f16d3d7 100644
--- a/tosca2heat/heat-translator/translator/common/exception.py
+++ b/tosca2heat/heat-translator/translator/common/exception.py
@@ -43,6 +43,11 @@ class ToscaClassImportError(TOSCAException):
'exists and has no language definition errors.')
+class UnsupportedTypeError(TOSCAException):
+ msg_fmt = _('Type "%(type)s" is valid TOSCA type but translation '
+ 'support is not yet available.')
+
+
class ToscaClassAttributeError(TOSCAException):
msg_fmt = _('Class attribute referenced not found. '
'%(message)s. Check to see that it is defined.')
diff --git a/tosca2heat/heat-translator/translator/common/flavors.py b/tosca2heat/heat-translator/translator/common/flavors.py
new file mode 100644
index 0000000..c44f883
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/common/flavors.py
@@ -0,0 +1,64 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+
+try:
+ import novaclient.client
+ client_available = True
+except ImportError:
+ client_available = False
+ pass
+
+log = logging.getLogger('heat-translator')
+
+
+PREDEF_FLAVORS = {
+ 'm1.xlarge': {'mem_size': 16384, 'disk_size': 160, 'num_cpus': 8},
+ 'm1.large': {'mem_size': 8192, 'disk_size': 80, 'num_cpus': 4},
+ 'm1.medium': {'mem_size': 4096, 'disk_size': 40, 'num_cpus': 2},
+ 'm1.small': {'mem_size': 2048, 'disk_size': 20, 'num_cpus': 1},
+ 'm1.tiny': {'mem_size': 512, 'disk_size': 1, 'num_cpus': 1},
+ 'm1.micro': {'mem_size': 128, 'disk_size': 0, 'num_cpus': 1},
+ 'm1.nano': {'mem_size': 64, 'disk_size': 0, 'num_cpus': 1}
+}
+
+SESSION = None
+
+FLAVORS = {}
+
+
+def get_flavors():
+ global FLAVORS
+
+ if FLAVORS:
+ return FLAVORS
+
+ if SESSION is not None and client_available:
+ try:
+ client = novaclient.client.Client("2", session=SESSION)
+ except Exception as e:
+ # Handles any exception coming from openstack
+ log.warn(_('Choosing predefined flavors since received '
+ 'Openstack Exception: %s') % str(e))
+ else:
+ for flv in client.flavors.list(detailed=True):
+ FLAVORS[str(flv.name)] = {
+ "mem_size": flv.ram,
+ "disk_size": flv.disk,
+ "num_cpus": flv.vcpus
+ }
+
+ if not FLAVORS:
+ FLAVORS = PREDEF_FLAVORS
+
+ return FLAVORS
diff --git a/tosca2heat/heat-translator/translator/common/images.py b/tosca2heat/heat-translator/translator/common/images.py
new file mode 100644
index 0000000..f9fa4f1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/common/images.py
@@ -0,0 +1,91 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+
+try:
+ import glanceclient.client
+ client_available = True
+except ImportError:
+ client_available = False
+ pass
+
+log = logging.getLogger('heat-translator')
+
+
+PREDEF_IMAGES = {
+ 'ubuntu-software-config-os-init': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Ubuntu',
+ 'version': '14.04'},
+ 'ubuntu-12.04-software-config-os-init': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Ubuntu',
+ 'version': '12.04'},
+ 'fedora-amd64-heat-config': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fedora',
+ 'version': '18.0'},
+ 'F18-x86_64-cfntools': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fedora',
+ 'version': '19'},
+ 'Fedora-x86_64-20-20131211.1-sda': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fedora',
+ 'version': '20'},
+ 'cirros-0.3.1-x86_64-uec': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'CirrOS',
+ 'version': '0.3.1'},
+ 'cirros-0.3.2-x86_64-uec': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'CirrOS',
+ 'version': '0.3.2'},
+ 'rhel-6.5-test-image': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'RHEL',
+ 'version': '6.5'}
+}
+
+SESSION = None
+
+IMAGES = {}
+
+
+def get_images():
+ global IMAGES
+
+ if IMAGES:
+ return IMAGES
+
+ if SESSION is not None and client_available:
+ try:
+ client = glanceclient.client.Client("2", session=SESSION)
+ except Exception as e:
+ # Handles any exception coming from openstack
+ log.warn(_('Choosing predefined images since received '
+ 'Openstack Exception: %s') % str(e))
+ else:
+ for image in client.images.list():
+ image_name = image.name.encode('ascii', 'ignore')
+ metadata = ["architecture", "type", "distribution", "version"]
+ if any(key in image.keys() for key in metadata):
+ IMAGES[image_name] = {}
+ for key in metadata:
+ if key in image.keys():
+ IMAGES[image_name][key] = image[key]
+
+ if not IMAGES:
+ IMAGES = PREDEF_IMAGES
+
+ return IMAGES
diff --git a/tosca2heat/heat-translator/translator/common/utils.py b/tosca2heat/heat-translator/translator/common/utils.py
index 459b5ee..874c8ec 100644
--- a/tosca2heat/heat-translator/translator/common/utils.py
+++ b/tosca2heat/heat-translator/translator/common/utils.py
@@ -18,8 +18,11 @@ import numbers
import os
import re
import requests
+import six
from six.moves.urllib.parse import urlparse
+import tempfile
import yaml
+import zipfile
from toscaparser.utils.gettextutils import _
import toscaparser.utils.yamlparser
@@ -193,7 +196,7 @@ class YamlUtils(object):
def get_dict(yaml_file):
'''Returns the dictionary representation of the given YAML spec.'''
try:
- return yaml.load(open(yaml_file))
+ return yaml.safe_load(open(yaml_file))
except IOError:
return None
@@ -213,7 +216,7 @@ class YamlUtils(object):
class TranslationUtils(object):
@staticmethod
- def compare_tosca_translation_with_hot(tosca_file, hot_file, params):
+ def compare_tosca_translation_with_hot(tosca_file, hot_files, params):
'''Verify tosca translation against the given hot specification.
inputs:
@@ -234,16 +237,28 @@ class TranslationUtils(object):
if not a_file:
tosca_tpl = tosca_file
- expected_hot_tpl = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), hot_file)
+ expected_hot_templates = []
+ for hot_file in hot_files:
+ expected_hot_templates.append(os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), hot_file))
tosca = ToscaTemplate(tosca_tpl, params, a_file)
translate = TOSCATranslator(tosca, params)
- output = translate.translate()
- output_dict = toscaparser.utils.yamlparser.simple_parse(output)
- expected_output_dict = YamlUtils.get_dict(expected_hot_tpl)
- return CompareUtils.diff_dicts(output_dict, expected_output_dict)
+ basename = os.path.basename(hot_files[0])
+ output_hot_templates = translate.translate_to_yaml_files_dict(basename)
+ output_dict = {}
+ for output_hot_template_name in output_hot_templates:
+ output_dict[output_hot_template_name] = \
+ toscaparser.utils.yamlparser.simple_parse(
+ output_hot_templates[output_hot_template_name])
+
+ expected_output_dict = {}
+ for expected_hot_template in expected_hot_templates:
+ expected_output_dict[os.path.basename(expected_hot_template)] = \
+ YamlUtils.get_dict(expected_hot_template)
+
+ return CompareUtils.diff_dicts(expected_output_dict, output_dict)
class UrlUtils(object):
@@ -262,12 +277,17 @@ class UrlUtils(object):
def str_to_num(value):
"""Convert a string representation of a number into a numeric type."""
- if isinstance(value, numbers.Number):
+ if isinstance(value, numbers.Number) \
+ or isinstance(value, six.integer_types) \
+ or isinstance(value, float):
return value
try:
return int(value)
except ValueError:
- return float(value)
+ try:
+ return float(value)
+ except ValueError:
+ return None
def check_for_env_variables():
@@ -317,3 +337,30 @@ def get_token_id(access_dict):
if access_dict is None:
return None
return access_dict['access']['token']['id']
+
+
+def decompress(zip_file, dir=None):
+ """Decompress Zip file
+
+ Decompress any zip file. For example, TOSCA CSAR
+
+ inputs:
+ zip_file: file in zip format
+ dir: directory to decompress zip. If not provided an unique temporary
+ directory will be generated and used.
+ return:
+ dir: absolute path to the decopressed directory
+ """
+ if not dir:
+ dir = tempfile.NamedTemporaryFile().name
+ with zipfile.ZipFile(zip_file, "r") as zf:
+ zf.extractall(dir)
+ return dir
+
+
+def get_dict_value(dict_item, key, get_files):
+ if key in dict_item:
+ return get_files.append(dict_item[key])
+ for k, v in dict_item.items():
+ if isinstance(v, dict):
+ get_dict_value(v, key, get_files)
diff --git a/tosca2heat/heat-translator/translator/conf/heat_translator_logging.conf b/tosca2heat/heat-translator/translator/conf/heat_translator_logging.conf
index e01a889..bac00cc 100644
--- a/tosca2heat/heat-translator/translator/conf/heat_translator_logging.conf
+++ b/tosca2heat/heat-translator/translator/conf/heat_translator_logging.conf
@@ -30,7 +30,10 @@ args=('/tmp/heat-translator.log', 'a', 100000000, 5, 'utf8')
class=handlers.SysLogHandler
formatter=form01
level=INFO
+# for linux
args=('/dev/log', handlers.SysLogHandler.LOG_SYSLOG)
+# for mac
+#args=('/var/run/syslog', handlers.SysLogHandler.LOG_SYSLOG)
[handler_NullHandler]
class=NullHandler
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
index ad77fb3..a41208a 100644
--- a/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
@@ -21,5 +21,8 @@ class HotOutput(object):
self.description = description
def get_dict_output(self):
- return {self.name: {'value': self.value,
- 'description': self.description}}
+ if self.description:
+ return {self.name: {'value': self.value,
+ 'description': self.description}}
+ else:
+ return {self.name: {'value': self.value}}
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
index 54e0d96..80a62ff 100644
--- a/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
@@ -25,6 +25,13 @@ SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
DELETION_POLICY) = \
('type', 'properties', 'metadata',
'depends_on', 'update_policy', 'deletion_policy')
+
+policy_type = ['tosca.policies.Placement',
+ 'tosca.policies.Scaling',
+ 'tosca.policies.Scaling.Cluster',
+ 'tosca.policies.Placement.Colocate',
+ 'tosca.policies.Placement.Antilocate']
+
log = logging.getLogger('heat-translator')
@@ -33,7 +40,7 @@ class HotResource(object):
def __init__(self, nodetemplate, name=None, type=None, properties=None,
metadata=None, depends_on=None,
- update_policy=None, deletion_policy=None):
+ update_policy=None, deletion_policy=None, csar_dir=None):
log.debug(_('Translating TOSCA node type to HOT resource type.'))
self.nodetemplate = nodetemplate
if name:
@@ -42,11 +49,19 @@ class HotResource(object):
self.name = nodetemplate.name
self.type = type
self.properties = properties or {}
+
+ self.csar_dir = csar_dir
# special case for HOT softwareconfig
+ cwd = os.getcwd()
if type == 'OS::Heat::SoftwareConfig':
config = self.properties.get('config')
- if config:
- implementation_artifact = config.get('get_file')
+ if isinstance(config, dict):
+ if self.csar_dir:
+ os.chdir(self.csar_dir)
+ implementation_artifact = os.path.abspath(config.get(
+ 'get_file'))
+ else:
+ implementation_artifact = config.get('get_file')
if implementation_artifact:
filename, file_extension = os.path.splitext(
implementation_artifact)
@@ -63,7 +78,7 @@ class HotResource(object):
if self.properties.get('group') is None:
self.properties['group'] = 'script'
-
+ os.chdir(cwd)
self.metadata = metadata
# The difference between depends_on and depends_on_nodes is
@@ -103,7 +118,7 @@ class HotResource(object):
# scenarios and cannot be fixed or hard coded here
operations_deploy_sequence = ['create', 'configure', 'start']
- operations = HotResource._get_all_operations(self.nodetemplate)
+ operations = HotResource.get_all_operations(self.nodetemplate)
# create HotResource for each operation used for deployment:
# create, start, configure
@@ -126,68 +141,151 @@ class HotResource(object):
hosting_server = None
if self.nodetemplate.requirements is not None:
hosting_server = self._get_hosting_server()
+
+ sw_deployment_resouce = HOTSoftwareDeploymentResources(hosting_server)
+ server_key = sw_deployment_resouce.server_key
+ servers = sw_deployment_resouce.servers
+ sw_deploy_res = sw_deployment_resouce.software_deployment
+
+ # hosting_server is None if requirements is None
+ hosting_on_server = hosting_server if hosting_server else None
+ base_type = HotResource.get_base_type_str(
+ self.nodetemplate.type_definition)
+ # if we are on a compute node the host is self
+ if hosting_on_server is None and base_type == 'tosca.nodes.Compute':
+ hosting_on_server = self.name
+ servers = {'get_resource': self.name}
+
+ cwd = os.getcwd()
for operation in operations.values():
if operation.name in operations_deploy_sequence:
config_name = node_name + '_' + operation.name + '_config'
deploy_name = node_name + '_' + operation.name + '_deploy'
+ if self.csar_dir:
+ os.chdir(self.csar_dir)
+ get_file = os.path.abspath(operation.implementation)
+ else:
+ get_file = operation.implementation
hot_resources.append(
HotResource(self.nodetemplate,
config_name,
'OS::Heat::SoftwareConfig',
{'config':
- {'get_file': operation.implementation}}))
-
- # hosting_server is None if requirements is None
- hosting_on_server = (hosting_server.name if
- hosting_server else None)
- if operation.name == reserve_current:
+ {'get_file': get_file}},
+ csar_dir=self.csar_dir))
+ if operation.name == reserve_current and \
+ base_type != 'tosca.nodes.Compute':
deploy_resource = self
self.name = deploy_name
- self.type = 'OS::Heat::SoftwareDeployment'
+ self.type = sw_deploy_res
self.properties = {'config': {'get_resource': config_name},
- 'server': {'get_resource':
- hosting_on_server},
+ server_key: servers,
'signal_transport': 'HEAT_SIGNAL'}
- deploy_lookup[operation.name] = self
+ deploy_lookup[operation] = self
else:
sd_config = {'config': {'get_resource': config_name},
- 'server': {'get_resource':
- hosting_on_server},
+ server_key: servers,
'signal_transport': 'HEAT_SIGNAL'}
deploy_resource = \
HotResource(self.nodetemplate,
deploy_name,
- 'OS::Heat::SoftwareDeployment',
- sd_config)
+ sw_deploy_res,
+ sd_config, csar_dir=self.csar_dir)
hot_resources.append(deploy_resource)
- deploy_lookup[operation.name] = deploy_resource
+ deploy_lookup[operation] = deploy_resource
lifecycle_inputs = self._get_lifecycle_inputs(operation)
if lifecycle_inputs:
deploy_resource.properties['input_values'] = \
lifecycle_inputs
+ os.chdir(cwd)
# Add dependencies for the set of HOT resources in the sequence defined
# in operations_deploy_sequence
# TODO(anyone): find some better way to encode this implicit sequence
group = {}
+ op_index_min = None
+ op_index_max = -1
for op, hot in deploy_lookup.items():
# position to determine potential preceding nodes
- op_index = operations_deploy_sequence.index(op)
- for preceding_op in \
+ op_index = operations_deploy_sequence.index(op.name)
+ if op_index_min is None or op_index < op_index_min:
+ op_index_min = op_index
+ if op_index > op_index_max:
+ op_index_max = op_index
+ for preceding_op_name in \
reversed(operations_deploy_sequence[:op_index]):
- preceding_hot = deploy_lookup.get(preceding_op)
+ preceding_hot = deploy_lookup.get(
+ operations.get(preceding_op_name))
if preceding_hot:
hot.depends_on.append(preceding_hot)
hot.depends_on_nodes.append(preceding_hot)
group[preceding_hot] = hot
break
+ if op_index_max >= 0:
+ last_deploy = deploy_lookup.get(operations.get(
+ operations_deploy_sequence[op_index_max]))
+ else:
+ last_deploy = None
+
# save this dependency chain in the set of HOT resources
self.group_dependencies.update(group)
for hot in hot_resources:
hot.group_dependencies.update(group)
- return hot_resources
+ roles_deploy_resource = self._handle_ansiblegalaxy_roles(
+ hot_resources, node_name, servers)
+
+ # add a dependency to this ansible roles deploy to
+ # the first "classic" deploy generated for this node
+ if roles_deploy_resource and op_index_min:
+ first_deploy = deploy_lookup.get(operations.get(
+ operations_deploy_sequence[op_index_min]))
+ first_deploy.depends_on.append(roles_deploy_resource)
+ first_deploy.depends_on_nodes.append(roles_deploy_resource)
+
+ return hot_resources, deploy_lookup, last_deploy
+
+ def _handle_ansiblegalaxy_roles(self, hot_resources, initial_node_name,
+ hosting_on_server):
+ artifacts = self.get_all_artifacts(self.nodetemplate)
+ install_roles_script = ''
+
+ sw_deployment_resouce = \
+ HOTSoftwareDeploymentResources(hosting_on_server)
+ server_key = sw_deployment_resouce.server_key
+ sw_deploy_res = sw_deployment_resouce.software_deployment
+ for artifact_name, artifact in artifacts.items():
+ artifact_type = artifact.get('type', '').lower()
+ if artifact_type == 'tosca.artifacts.ansiblegalaxy.role':
+ role = artifact.get('file', None)
+ if role:
+ install_roles_script += 'ansible-galaxy install ' + role \
+ + '\n'
+
+ if install_roles_script:
+ # remove trailing \n
+ install_roles_script = install_roles_script[:-1]
+ # add shebang and | to use literal scalar type (for multiline)
+ install_roles_script = '|\n#!/bin/bash\n' + install_roles_script
+
+ config_name = initial_node_name + '_install_roles_config'
+ deploy_name = initial_node_name + '_install_roles_deploy'
+ hot_resources.append(
+ HotResource(self.nodetemplate, config_name,
+ 'OS::Heat::SoftwareConfig',
+ {'config': install_roles_script},
+ csar_dir=self.csar_dir))
+ sd_config = {'config': {'get_resource': config_name},
+ server_key: hosting_on_server,
+ 'signal_transport': 'HEAT_SIGNAL'}
+ deploy_resource = \
+ HotResource(self.nodetemplate, deploy_name,
+ sw_deploy_res,
+ sd_config, csar_dir=self.csar_dir)
+ hot_resources.append(deploy_resource)
+
+ return deploy_resource
def handle_connectsto(self, tosca_source, tosca_target, hot_source,
hot_target, config_location, operation):
@@ -202,17 +300,22 @@ class HotResource(object):
elif config_location == 'source':
hosting_server = self._get_hosting_server()
hot_depends = hot_source
+ sw_deployment_resouce = HOTSoftwareDeploymentResources(hosting_server)
+ server_key = sw_deployment_resouce.server_key
+ servers = sw_deployment_resouce.servers
+ sw_deploy_res = sw_deployment_resouce.software_deployment
+
deploy_name = tosca_source.name + '_' + tosca_target.name + \
'_connect_deploy'
sd_config = {'config': {'get_resource': self.name},
- 'server': {'get_resource': hosting_server.name},
+ server_key: servers,
'signal_transport': 'HEAT_SIGNAL'}
deploy_resource = \
HotResource(self.nodetemplate,
deploy_name,
- 'OS::Heat::SoftwareDeployment',
+ sw_deploy_res,
sd_config,
- depends_on=[hot_depends])
+ depends_on=[hot_depends], csar_dir=self.csar_dir)
connect_inputs = self._get_connect_inputs(config_location, operation)
if connect_inputs:
deploy_resource.properties['input_values'] = connect_inputs
@@ -226,17 +329,31 @@ class HotResource(object):
# handle hosting server for the OS:HEAT::SoftwareDeployment
# from the TOSCA nodetemplate, traverse the relationship chain
# down to the server
- if self.type == 'OS::Heat::SoftwareDeployment':
+ sw_deploy_group = \
+ HOTSoftwareDeploymentResources.HOT_SW_DEPLOYMENT_GROUP_RESOURCE
+ sw_deploy = HOTSoftwareDeploymentResources.HOT_SW_DEPLOYMENT_RESOURCE
+
+ if self.properties.get('servers') and \
+ self.properties.get('server'):
+ del self.properties['server']
+ if self.type == sw_deploy_group or self.type == sw_deploy:
# skip if already have hosting
# If type is NodeTemplate, look up corresponding HotResrouce
- host_server = self.properties.get('server')
- if host_server is None or not host_server['get_resource']:
+ host_server = self.properties.get('servers') \
+ or self.properties.get('server')
+ if host_server is None:
raise Exception(_("Internal Error: expecting host "
"in software deployment"))
- elif isinstance(host_server['get_resource'], NodeTemplate):
+
+ elif isinstance(host_server.get('get_resource'), NodeTemplate):
self.properties['server']['get_resource'] = \
host_server['get_resource'].name
+ elif isinstance(host_server, dict) and \
+ not host_server.get('get_resource'):
+ self.properties['servers'] = \
+ host_server
+
def top_of_chain(self):
dependent = self.group_dependencies.get(self)
if dependent is None:
@@ -244,6 +361,19 @@ class HotResource(object):
else:
return dependent.top_of_chain()
+ # this function allows to provides substacks as external files
+ # those files will be dumped along the output file.
+ #
+ # return a dict of filename-content
+ def extract_substack_templates(self, base_filename, hot_template_version):
+ return {}
+
+ # this function asks the resource to embed substacks
+ # into the main template, if any.
+ # this is used when the final output is stdout
+ def embed_substack_templates(self, hot_template_version):
+ pass
+
def get_dict_output(self):
resource_sections = OrderedDict()
resource_sections[TYPE] = self.type
@@ -273,7 +403,7 @@ class HotResource(object):
inputs = operation.value.get('inputs')
deploy_inputs = {}
if inputs:
- for name, value in six.iteritems(inputs):
+ for name, value in inputs.items():
deploy_inputs[name] = value
return deploy_inputs
@@ -284,17 +414,19 @@ class HotResource(object):
inputs = operation.get('pre_configure_source').get('inputs')
deploy_inputs = {}
if inputs:
- for name, value in six.iteritems(inputs):
+ for name, value in inputs.items():
deploy_inputs[name] = value
return deploy_inputs
def _get_hosting_server(self, node_template=None):
# find the server that hosts this software by checking the
# requirements and following the hosting chain
+ hosting_servers = []
+ host_exists = False
this_node_template = self.nodetemplate \
if node_template is None else node_template
for requirement in this_node_template.requirements:
- for requirement_name, assignment in six.iteritems(requirement):
+ for requirement_name, assignment in requirement.items():
for check_node in this_node_template.related_nodes:
# check if the capability is Container
if isinstance(assignment, dict):
@@ -304,17 +436,20 @@ class HotResource(object):
if node_name and node_name == check_node.name:
if self._is_container_type(requirement_name,
check_node):
- return check_node
- elif check_node.related_nodes:
+ hosting_servers.append(check_node.name)
+ host_exists = True
+ elif check_node.related_nodes and not host_exists:
return self._get_hosting_server(check_node)
+ if hosting_servers:
+ return hosting_servers
return None
def _is_container_type(self, requirement_name, node):
# capability is a list of dict
# For now just check if it's type tosca.nodes.Compute
# TODO(anyone): match up requirement and capability
- base_type = HotResource.get_base_type(node.type_definition)
- if base_type.type == 'tosca.nodes.Compute':
+ base_type = HotResource.get_base_type_str(node.type_definition)
+ if base_type == 'tosca.nodes.Compute':
return True
else:
return False
@@ -335,7 +470,24 @@ class HotResource(object):
return tosca_props
@staticmethod
- def _get_all_operations(node):
+ def get_all_artifacts(nodetemplate):
+ # workaround bug in the parser
+ base_type = HotResource.get_base_type_str(nodetemplate.type_definition)
+ if base_type in policy_type:
+ artifacts = {}
+ else:
+ artifacts = nodetemplate.type_definition.get_value('artifacts',
+ parent=True)
+ if not artifacts:
+ artifacts = {}
+ tpl_artifacts = nodetemplate.entity_tpl.get('artifacts')
+ if tpl_artifacts:
+ artifacts.update(tpl_artifacts)
+
+ return artifacts
+
+ @staticmethod
+ def get_all_operations(node):
operations = {}
for operation in node.interfaces:
operations[operation.name] = operation
@@ -388,5 +540,48 @@ class HotResource(object):
return node_type
else:
return HotResource.get_base_type(node_type.parent_type)
- else:
+ return node_type.type
+
+ @staticmethod
+ def get_base_type_str(node_type):
+ if isinstance(node_type, six.string_types):
return node_type
+ if node_type.parent_type is not None:
+ parent_type_str = None
+ if isinstance(node_type.parent_type, six.string_types):
+ parent_type_str = node_type.parent_type
+ else:
+ parent_type_str = node_type.parent_type.type
+
+ if parent_type_str and parent_type_str.endswith('.Root'):
+ return node_type.type
+ else:
+ return HotResource.get_base_type_str(node_type.parent_type)
+
+ return node_type.type
+
+
+class HOTSoftwareDeploymentResources(object):
+ """Provides HOT Software Deployment resources
+
+ SoftwareDeployment or SoftwareDeploymentGroup Resource
+ """
+
+ HOT_SW_DEPLOYMENT_RESOURCE = 'OS::Heat::SoftwareDeployment'
+ HOT_SW_DEPLOYMENT_GROUP_RESOURCE = 'OS::Heat::SoftwareDeploymentGroup'
+
+ def __init__(self, hosting_server=None):
+ self.software_deployment = self.HOT_SW_DEPLOYMENT_RESOURCE
+ self.software_deployment_group = self.HOT_SW_DEPLOYMENT_GROUP_RESOURCE
+ self.server_key = 'server'
+ self.hosting_server = hosting_server
+ self.servers = {}
+ if hosting_server is not None:
+ if len(self.hosting_server) == 1:
+ if isinstance(hosting_server, list):
+ self.servers['get_resource'] = self.hosting_server[0]
+ else:
+ for server in self.hosting_server:
+ self.servers[server] = {'get_resource': server}
+ self.software_deployment = self.software_deployment_group
+ self.server_key = 'servers'
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
index c92d341..7fae022 100644
--- a/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
@@ -13,6 +13,7 @@
from collections import OrderedDict
import logging
+import os
import textwrap
from toscaparser.utils.gettextutils import _
import yaml
@@ -28,7 +29,7 @@ class HotTemplate(object):
('heat_template_version', 'description', 'parameter_groups',
'parameters', 'resources', 'outputs', '__undefined__')
- VERSIONS = (LATEST,) = ('2014-10-16',)
+ VERSIONS = (LATEST,) = ('2013-05-23',)
def __init__(self):
self.resources = []
@@ -44,11 +45,34 @@ class HotTemplate(object):
nodes.append((node_key, node_value))
return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes)
- def output_to_yaml(self):
+ def output_to_yaml_files_dict(self, base_filename,
+ hot_template_version=LATEST):
+ yaml_files_dict = {}
+ base_filename, ext = os.path.splitext(base_filename)
+
+ # convert from inlined substack to a substack defined in another file
+ for resource in self.resources:
+ yaml_files_dict.update(
+ resource.extract_substack_templates(base_filename,
+ hot_template_version))
+
+ yaml_files_dict[base_filename + ext] = \
+ self.output_to_yaml(hot_template_version, False)
+
+ return yaml_files_dict
+
+ def output_to_yaml(self, hot_template_version=LATEST,
+ embed_substack_templates=True):
log.debug(_('Converting translated output to yaml format.'))
+
+ if embed_substack_templates:
+ # fully inlined substack by storing the template as a blob string
+ for resource in self.resources:
+ resource.embed_substack_templates(hot_template_version)
+
dict_output = OrderedDict()
# Version
- version_string = self.VERSION + ": " + self.LATEST + "\n\n"
+ version_string = self.VERSION + ": " + hot_template_version + "\n\n"
# Description
desc_str = ""
@@ -77,7 +101,10 @@ class HotTemplate(object):
dict_output.update({self.OUTPUTS: all_outputs})
yaml.add_representer(OrderedDict, self.represent_ordereddict)
+ yaml.add_representer(dict, self.represent_ordereddict)
yaml_string = yaml.dump(dict_output, default_flow_style=False)
# get rid of the '' from yaml.dump around numbers
- yaml_string = yaml_string.replace('\'', '')
+ # also replace double return lines with a single one
+ # seems to be a bug in the serialization of multiline literal scalars
+ yaml_string = yaml_string.replace('\'', '') .replace('\n\n', '\n')
return version_string + desc_str + yaml_string
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py
new file mode 100644
index 0000000..978e965
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py
@@ -0,0 +1,91 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 toscaparser.nodetemplate import NodeTemplate
+from toscaparser.policy import Policy
+from toscaparser.tests.base import TestCase
+import toscaparser.utils.yamlparser
+from translator.hot.tosca.tosca_compute import ToscaCompute
+from translator.hot.tosca.tosca_policies_scaling import ToscaAutoscaling
+
+
+class AutoscalingTest(TestCase):
+
+ def _tosca_scaling_test(self, tpl_snippet, expectedprops):
+ nodetemplates = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['node_templates'])
+ policies = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['policies'])
+ name = list(nodetemplates.keys())[0]
+ policy_name = list(policies[0].keys())[0]
+ for policy in policies:
+ tpl = policy[policy_name]
+ targets = tpl["targets"]
+ properties = tpl["properties"]
+ try:
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ toscacompute = ToscaCompute(nodetemplate)
+ toscacompute.handle_properties()
+ policy = Policy(policy_name, tpl, targets,
+ properties, "node_templates")
+ toscascaling = ToscaAutoscaling(policy)
+ parameters = toscascaling.handle_properties([toscacompute])
+ self.assertEqual(parameters[0].properties, expectedprops)
+ except Exception:
+ raise
+
+ def test_compute_with_scaling(self):
+ tpl_snippet = '''
+ node_templates:
+ my_server_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ policies:
+ - asg:
+ type: tosca.policies.Scaling
+ description: Simple node autoscaling
+ targets: [my_server_1]
+ triggers:
+ resize_compute:
+ description: trigger
+ condition:
+ constraint: utilization greater_than 50%
+ period: 60
+ evaluations: 1
+ method: average
+ properties:
+ min_instances: 2
+ max_instances: 10
+ default_instances: 3
+ increment: 1
+ '''
+
+ expectedprops = {'desired_capacity': 3,
+ 'max_size': 10,
+ 'min_size': 2,
+ 'resource': {'type': 'asg_res.yaml'}}
+
+ self._tosca_scaling_test(
+ tpl_snippet,
+ expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
index 408ee8b..1a135f4 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
@@ -10,13 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
import mock
-from mock import patch
from toscaparser.nodetemplate import NodeTemplate
from toscaparser.tests.base import TestCase
-from toscaparser.utils.gettextutils import _
import toscaparser.utils.yamlparser
from translator.hot.tosca.tosca_compute import ToscaCompute
@@ -27,22 +24,12 @@ class ToscaComputeTest(TestCase):
nodetemplates = (toscaparser.utils.yamlparser.
simple_parse(tpl_snippet)['node_templates'])
name = list(nodetemplates.keys())[0]
- try:
- nodetemplate = NodeTemplate(name, nodetemplates)
- nodetemplate.validate()
- toscacompute = ToscaCompute(nodetemplate)
- toscacompute.handle_properties()
- if not self._compare_properties(toscacompute.properties,
- expectedprops):
- raise Exception(_("Hot Properties are not"
- " same as expected properties"))
- except Exception:
- # for time being rethrowing. Will be handled future based
- # on new development in Glance and Graffiti
- raise
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ nodetemplate.validate()
+ toscacompute = ToscaCompute(nodetemplate)
+ toscacompute.handle_properties()
- def _compare_properties(self, hotprops, expectedprops):
- return all(item in hotprops.items() for item in expectedprops.items())
+ self.assertEqual(expectedprops, toscacompute.properties)
def test_node_compute_with_host_and_os_capabilities(self):
tpl_snippet = '''
@@ -84,7 +71,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -123,7 +109,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -137,7 +122,6 @@ class ToscaComputeTest(TestCase):
type: tosca.nodes.Compute
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -155,7 +139,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -174,7 +157,6 @@ class ToscaComputeTest(TestCase):
mem_size: 4 GB
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -193,7 +175,6 @@ class ToscaComputeTest(TestCase):
disk_size: 10 GB
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -211,18 +192,14 @@ class ToscaComputeTest(TestCase):
num_cpus: 4
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
tpl_snippet,
expectedprops)
- @patch('requests.post')
- @patch('requests.get')
- @patch('os.getenv')
- def test_node_compute_with_nova_flavor(self, mock_os_getenv,
- mock_get, mock_post):
+ @mock.patch('translator.common.flavors.get_flavors')
+ def test_node_compute_with_nova_flavor(self, mock_flavor):
tpl_snippet = '''
node_templates:
server:
@@ -234,56 +211,19 @@ class ToscaComputeTest(TestCase):
disk_size: 1 GB
mem_size: 1 GB
'''
- with patch('translator.common.utils.'
- 'check_for_env_variables') as mock_check_env:
- mock_check_env.return_value = True
- mock_os_getenv.side_effect = ['demo', 'demo',
- 'demo', 'http://abc.com/5000/',
- 'demo', 'demo',
- 'demo', 'http://abc.com/5000/']
- mock_ks_response = mock.MagicMock()
- mock_ks_response.status_code = 200
- mock_ks_content = {
- 'access': {
- 'token': {
- 'id': 'd1dfa603-3662-47e0-b0b6-3ae7914bdf76'
- },
- 'serviceCatalog': [{
- 'type': 'compute',
- 'endpoints': [{
- 'publicURL': 'http://abc.com'
- }]
- }]
- }
- }
- mock_ks_response.content = json.dumps(mock_ks_content)
- mock_nova_response = mock.MagicMock()
- mock_nova_response.status_code = 200
- mock_flavor_content = {
- 'flavors': [{
- 'name': 'm1.mock_flavor',
- 'ram': 1024,
- 'disk': 1,
- 'vcpus': 1
- }]
- }
- mock_nova_response.content = \
- json.dumps(mock_flavor_content)
- mock_post.return_value = mock_ks_response
- mock_get.return_value = mock_nova_response
- expectedprops = {'flavor': 'm1.mock_flavor',
- 'image': None,
- 'user_data_format': 'SOFTWARE_CONFIG',
- 'software_config_transport': 'POLL_SERVER_HEAT'}
- self._tosca_compute_test(
- tpl_snippet,
- expectedprops)
+ mock_flavor.return_value = {
+ 'm1.mock_flavor': {
+ 'mem_size': 1024,
+ 'disk_size': 1,
+ 'num_cpus': 1}
+ }
+ expectedprops = {'flavor': 'm1.mock_flavor',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'software_config_transport': 'POLL_SERVER_HEAT'}
+ self._tosca_compute_test(tpl_snippet, expectedprops)
- @patch('requests.post')
- @patch('requests.get')
- @patch('os.getenv')
- def test_node_compute_without_nova_flavor(self, mock_os_getenv,
- mock_get, mock_post):
+ @mock.patch('translator.common.images.get_images')
+ def test_node_compute_with_glance_image(self, mock_images):
tpl_snippet = '''
node_templates:
server:
@@ -294,19 +234,25 @@ class ToscaComputeTest(TestCase):
num_cpus: 1
disk_size: 1 GB
mem_size: 1 GB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fake Distribution
+ version: 19.0
'''
- with patch('translator.common.utils.'
- 'check_for_env_variables') as mock_check_env:
- mock_check_env.return_value = True
- mock_os_getenv.side_effect = ['demo', 'demo',
- 'demo', 'http://abc.com/5000/']
- mock_ks_response = mock.MagicMock()
- mock_ks_content = {}
- mock_ks_response.content = json.dumps(mock_ks_content)
- expectedprops = {'flavor': 'm1.small',
- 'image': None,
- 'user_data_format': 'SOFTWARE_CONFIG',
- 'software_config_transport': 'POLL_SERVER_HEAT'}
- self._tosca_compute_test(
- tpl_snippet,
- expectedprops)
+ mock_images.return_value = {
+ 'fake-image-foobar': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fake Distribution',
+ 'version': '19.0'},
+ 'fake-image-foobar-old': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fake Distribution',
+ 'version': '18.0'}
+ }
+ expectedprops = {'flavor': 'm1.small',
+ 'image': 'fake-image-foobar',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'software_config_transport': 'POLL_SERVER_HEAT'}
+ self._tosca_compute_test(tpl_snippet, expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
index d4b2f44..27c1033 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
@@ -29,9 +29,10 @@ class ToscaBlockStorage(HotResource):
toscatype = 'tosca.nodes.BlockStorage'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaBlockStorage, self).__init__(nodetemplate,
- type='OS::Cinder::Volume')
+ type='OS::Cinder::Volume',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
@@ -67,5 +68,5 @@ class ToscaBlockStorage(HotResource):
# attribute for the matching resource. Unless there is additional
# runtime support, this should be a one to one mapping.
if attribute == 'volume_id':
- attr['get_resource'] = args[0]
+ attr['get_resource'] = self.name
return attr
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
index 71b9822..f471b83 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
@@ -23,9 +23,11 @@ class ToscaBlockStorageAttachment(HotResource):
toscatype = 'tosca.nodes.BlockStorageAttachment'
- def __init__(self, template, nodetemplates, instance_uuid, volume_id):
+ def __init__(self, template, nodetemplates, instance_uuid, volume_id,
+ csar_dir=None):
super(ToscaBlockStorageAttachment,
- self).__init__(template, type='OS::Cinder::VolumeAttachment')
+ self).__init__(template, type='OS::Cinder::VolumeAttachment',
+ csar_dir=csar_dir)
self.nodetemplates = nodetemplates
self.instance_uuid = {'get_resource': instance_uuid}
self.volume_id = {'get_resource': volume_id}
@@ -50,4 +52,4 @@ class ToscaBlockStorageAttachment(HotResource):
self.properties.pop('device')
def handle_life_cycle(self):
- pass
+ return None, None, None
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
index b685d6a..5f6b751 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
@@ -11,68 +11,21 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
import logging
-import requests
from toscaparser.utils.gettextutils import _
+from translator.common import flavors as nova_flavors
+from translator.common import images as glance_images
import translator.common.utils
from translator.hot.syntax.hot_resource import HotResource
+
log = logging.getLogger('heat-translator')
# Name used to dynamically load appropriate map class.
TARGET_CLASS_NAME = 'ToscaCompute'
-# A design issue to be resolved is how to translate the generic TOSCA server
-# properties to OpenStack flavors and images. At the Atlanta design summit,
-# there was discussion on using Glance to store metadata and Graffiti to
-# describe artifacts. We will follow these projects to see if they can be
-# leveraged for this TOSCA translation.
-# For development purpose at this time, we temporarily hardcode a list of
-# flavors and images here
-FLAVORS = {'m1.xlarge': {'mem_size': 16384, 'disk_size': 160, 'num_cpus': 8},
- 'm1.large': {'mem_size': 8192, 'disk_size': 80, 'num_cpus': 4},
- 'm1.medium': {'mem_size': 4096, 'disk_size': 40, 'num_cpus': 2},
- 'm1.small': {'mem_size': 2048, 'disk_size': 20, 'num_cpus': 1},
- 'm1.tiny': {'mem_size': 512, 'disk_size': 1, 'num_cpus': 1},
- 'm1.micro': {'mem_size': 128, 'disk_size': 0, 'num_cpus': 1},
- 'm1.nano': {'mem_size': 64, 'disk_size': 0, 'num_cpus': 1}}
-
-IMAGES = {'ubuntu-software-config-os-init': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Ubuntu',
- 'version': '14.04'},
- 'ubuntu-12.04-software-config-os-init': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Ubuntu',
- 'version': '12.04'},
- 'fedora-amd64-heat-config': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '18.0'},
- 'F18-x86_64-cfntools': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '19'},
- 'Fedora-x86_64-20-20131211.1-sda': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '20'},
- 'cirros-0.3.1-x86_64-uec': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'CirrOS',
- 'version': '0.3.1'},
- 'cirros-0.3.2-x86_64-uec': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'CirrOS',
- 'version': '0.3.2'},
- 'rhel-6.5-test-image': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'RHEL',
- 'version': '6.5'}}
-
class ToscaCompute(HotResource):
'''Translate TOSCA node type tosca.nodes.Compute.'''
@@ -84,9 +37,18 @@ class ToscaCompute(HotResource):
('architecture', 'distribution', 'type', 'version')
toscatype = 'tosca.nodes.Compute'
- def __init__(self, nodetemplate):
+ ALLOWED_NOVA_SERVER_PROPS = \
+ ('admin_pass', 'availability_zone', 'block_device_mapping',
+ 'block_device_mapping_v2', 'config_drive', 'diskConfig', 'flavor',
+ 'flavor_update_policy', 'image', 'image_update_policy', 'key_name',
+ 'metadata', 'name', 'networks', 'personality', 'reservation_id',
+ 'scheduler_hints', 'security_groups', 'software_config_transport',
+ 'user_data', 'user_data_format', 'user_data_update_policy')
+
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaCompute, self).__init__(nodetemplate,
- type='OS::Nova::Server')
+ type='OS::Nova::Server',
+ csar_dir=csar_dir)
# List with associated hot port resources with this server
self.assoc_port_resources = []
pass
@@ -99,7 +61,8 @@ class ToscaCompute(HotResource):
self.properties['software_config_transport'] = 'POLL_SERVER_HEAT'
tosca_props = self.get_tosca_props()
for key, value in tosca_props.items():
- self.properties[key] = value
+ if key in self.ALLOWED_NOVA_SERVER_PROPS:
+ self.properties[key] = value
# To be reorganized later based on new development in Glance and Graffiti
def translate_compute_flavor_and_image(self,
@@ -125,91 +88,16 @@ class ToscaCompute(HotResource):
if os_cap_props:
image = self._best_image(os_cap_props)
hot_properties['flavor'] = flavor
- hot_properties['image'] = image
+ if image:
+ hot_properties['image'] = image
+ else:
+ hot_properties.pop('image', None)
return hot_properties
- def _create_nova_flavor_dict(self):
- '''Populates and returns the flavors dict using Nova ReST API'''
- try:
- access_dict = translator.common.utils.get_ks_access_dict()
- access_token = translator.common.utils.get_token_id(access_dict)
- if access_token is None:
- return None
- nova_url = translator.common.utils.get_url_for(access_dict,
- 'compute')
- if not nova_url:
- return None
- nova_response = requests.get(nova_url + '/flavors/detail',
- headers={'X-Auth-Token':
- access_token})
- if nova_response.status_code != 200:
- return None
- flavors = json.loads(nova_response.content)['flavors']
- flavor_dict = dict()
- for flavor in flavors:
- flavor_name = str(flavor['name'])
- flavor_dict[flavor_name] = {
- 'mem_size': flavor['ram'],
- 'disk_size': flavor['disk'],
- 'num_cpus': flavor['vcpus'],
- }
- except Exception as e:
- # Handles any exception coming from openstack
- log.warn(_('Choosing predefined flavors since received '
- 'Openstack Exception: %s') % str(e))
- return None
- return flavor_dict
-
- def _populate_image_dict(self):
- '''Populates and returns the images dict using Glance ReST API'''
- images_dict = {}
- try:
- access_dict = translator.common.utils.get_ks_access_dict()
- access_token = translator.common.utils.get_token_id(access_dict)
- if access_token is None:
- return None
- glance_url = translator.common.utils.get_url_for(access_dict,
- 'image')
- if not glance_url:
- return None
- glance_response = requests.get(glance_url + '/v2/images',
- headers={'X-Auth-Token':
- access_token})
- if glance_response.status_code != 200:
- return None
- images = json.loads(glance_response.content)["images"]
- for image in images:
- image_resp = requests.get(glance_url + '/v2/images/' +
- image["id"],
- headers={'X-Auth-Token':
- access_token})
- if image_resp.status_code != 200:
- continue
- metadata = ["architecture", "type", "distribution", "version"]
- image_data = json.loads(image_resp.content)
- if any(key in image_data.keys() for key in metadata):
- images_dict[image_data["name"]] = dict()
- for key in metadata:
- if key in image_data.keys():
- images_dict[image_data["name"]][key] = \
- image_data[key]
- else:
- continue
-
- except Exception as e:
- # Handles any exception coming from openstack
- log.warn(_('Choosing predefined flavors since received '
- 'Openstack Exception: %s') % str(e))
- return images_dict
-
def _best_flavor(self, properties):
log.info(_('Choosing the best flavor for given attributes.'))
# Check whether user exported all required environment variables.
- flavors = FLAVORS
- if translator.common.utils.check_for_env_variables():
- resp = self._create_nova_flavor_dict()
- if resp:
- flavors = resp
+ flavors = nova_flavors.get_flavors()
# start with all flavors
match_all = flavors.keys()
@@ -252,11 +140,7 @@ class ToscaCompute(HotResource):
def _best_image(self, properties):
# Check whether user exported all required environment variables.
- images = IMAGES
- if translator.common.utils.check_for_env_variables():
- resp = self._populate_image_dict()
- if len(resp.keys()) > 0:
- images = resp
+ images = glance_images.get_images()
match_all = images.keys()
architecture = properties.get(self.ARCHITECTURE)
if architecture is None:
@@ -307,7 +191,10 @@ class ToscaCompute(HotResource):
return this_list
matching_images = []
for image in this_list:
- if this_dict[image][attr].lower() == str(prop).lower():
+ if attr in this_dict[image]:
+ if this_dict[image][attr].lower() == str(prop).lower():
+ matching_images.insert(0, image)
+ else:
matching_images.append(image)
return matching_images
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
index 26c9d4d..7c8bc45 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
@@ -22,8 +22,8 @@ class ToscaDatabase(HotResource):
toscatype = 'tosca.nodes.Database'
- def __init__(self, nodetemplate):
- super(ToscaDatabase, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaDatabase, self).__init__(nodetemplate, csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
index 38c31bd..3136792 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
@@ -22,8 +22,8 @@ class ToscaDbms(HotResource):
toscatype = 'tosca.nodes.DBMS'
- def __init__(self, nodetemplate):
- super(ToscaDbms, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaDbms, self).__init__(nodetemplate, csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
index a4e565e..10e6405 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
@@ -28,9 +28,10 @@ class ToscaNetwork(HotResource):
existing_resource_id = None
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaNetwork, self).__init__(nodetemplate,
- type='OS::Neutron::Net')
+ type='OS::Neutron::Net',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
@@ -57,8 +58,6 @@ class ToscaNetwork(HotResource):
self.existing_resource_id = value
break
elif key == 'segmentation_id':
- # net_props['segmentation_id'] = \
- # tosca_props['segmentation_id']
# Hardcode to vxlan for now until we add the network type
# and physical network to the spec.
net_props['value_specs'] = {'provider:segmentation_id':
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
index 4fd2d70..86733e4 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
@@ -24,9 +24,10 @@ class ToscaNetworkPort(HotResource):
toscatype = 'tosca.nodes.network.Port'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaNetworkPort, self).__init__(nodetemplate,
- type='OS::Neutron::Port')
+ type='OS::Neutron::Port',
+ csar_dir=csar_dir)
# Default order
self.order = 0
pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
index 177503f..e30c46c 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
@@ -23,9 +23,10 @@ class ToscaObjectStorage(HotResource):
toscatype = 'tosca.nodes.ObjectStorage'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaObjectStorage, self).__init__(nodetemplate,
- type='OS::Swift::Container')
+ type='OS::Swift::Container',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
index b32fc1d..12b40d5 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
@@ -22,9 +22,10 @@ class ToscaPolicies(HotResource):
toscatype = 'tosca.policies.Placement'
- def __init__(self, policy):
+ def __init__(self, policy, csar_dir=None):
super(ToscaPolicies, self).__init__(policy,
- type='OS::Nova::ServerGroup')
+ type='OS::Nova::ServerGroup',
+ csar_dir=csar_dir)
self.policy = policy
def handle_properties(self, resources):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py
new file mode 100644
index 0000000..1b63f24
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py
@@ -0,0 +1,131 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 OrderedDict
+import yaml
+
+from translator.hot.syntax.hot_resource import HotResource
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaAutoscaling'
+HEAT_TEMPLATE_BASE = """
+heat_template_version: 2013-05-23
+"""
+ALARM_STATISTIC = {'average': 'avg'}
+SCALING_RESOURCES = ["OS::Heat::ScalingPolicy", "OS::Heat::AutoScalingGroup",
+ "OS::Aodh::Alarm"]
+
+
+class ToscaAutoscaling(HotResource):
+ '''Translate TOSCA node type tosca.policies.Scaling'''
+
+ toscatype = 'tosca.policies.Scaling'
+
+ def __init__(self, policy, csar_dir=None):
+ hot_type = "OS::Heat::ScalingPolicy"
+ super(ToscaAutoscaling, self).__init__(policy,
+ type=hot_type,
+ csar_dir=csar_dir)
+ self.policy = policy
+
+ def handle_expansion(self):
+ if self.policy.entity_tpl.get('triggers'):
+ sample = self.policy.\
+ entity_tpl["triggers"]["resize_compute"]["condition"]
+ prop = {}
+ prop["description"] = self.policy.entity_tpl.get('description')
+ prop["meter_name"] = "cpu_util"
+ if sample:
+ prop["statistic"] = ALARM_STATISTIC[sample["method"]]
+ prop["period"] = sample["period"]
+ prop["threshold"] = sample["evaluations"]
+ prop["comparison_operator"] = "gt"
+ alarm_name = self.name.replace('_scale_in', '').\
+ replace('_scale_out', '')
+ ceilometer_resources = HotResource(self.nodetemplate,
+ type='OS::Aodh::Alarm',
+ name=alarm_name + '_alarm',
+ properties=prop)
+ hot_resources = [ceilometer_resources]
+ return hot_resources
+
+ def represent_ordereddict(self, dumper, data):
+ nodes = []
+ for key, value in data.items():
+ node_key = dumper.represent_data(key)
+ node_value = dumper.represent_data(value)
+ nodes.append((node_key, node_value))
+ return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes)
+
+ def _handle_nested_template(self, scale_res):
+ template_dict = yaml.safe_load(HEAT_TEMPLATE_BASE)
+ template_dict['description'] = 'Tacker Scaling template'
+ template_dict["resources"] = {}
+ dict_res = OrderedDict()
+ for res in scale_res:
+ dict_res = res.get_dict_output()
+ res_name = list(dict_res.keys())[0]
+ template_dict["resources"][res_name] = \
+ dict_res[res_name]
+
+ yaml.add_representer(OrderedDict, self.represent_ordereddict)
+ yaml.add_representer(dict, self.represent_ordereddict)
+ yaml_string = yaml.dump(template_dict, default_flow_style=False)
+ yaml_string = yaml_string.replace('\'', '') .replace('\n\n', '\n')
+ self.nested_template = {
+ self.policy.name + '_res.yaml': yaml_string
+ }
+
+ def handle_properties(self, resources):
+ self.properties = {}
+ self.properties["auto_scaling_group_id"] = {
+ 'get_resource': self.policy.name + '_group'
+ }
+ self.properties["adjustment_type"] = "change_in_capacity "
+ self.properties["scaling_adjustment"] = self.\
+ policy.entity_tpl["properties"]["increment"]
+ delete_res_names = []
+ scale_res = []
+ for index, resource in enumerate(resources):
+ if resource.name in self.policy.targets and \
+ resource.type != 'OS::Heat::AutoScalingGroup':
+ temp = self.policy.entity_tpl["properties"]
+ props = {}
+ res = {}
+ res["min_size"] = temp["min_instances"]
+ res["max_size"] = temp["max_instances"]
+ res["desired_capacity"] = temp["default_instances"]
+ props['type'] = resource.type
+ props['properties'] = resource.properties
+ res['resource'] = {'type': self.policy.name + '_res.yaml'}
+ scaling_resources = \
+ HotResource(resource,
+ type='OS::Heat::AutoScalingGroup',
+ name=self.policy.name + '_group',
+ properties=res)
+
+ if resource.type not in SCALING_RESOURCES:
+ delete_res_names.append(resource.name)
+ scale_res.append(resource)
+ self._handle_nested_template(scale_res)
+ resources = [tmp_res
+ for tmp_res in resources
+ if tmp_res.name not in delete_res_names]
+ resources.append(scaling_resources)
+ return resources
+
+ def extract_substack_templates(self, base_filename, hot_template_version):
+ return self.nested_template
+
+ def embed_substack_templates(self, hot_template_version):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
index 044de43..9b0819e 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
@@ -22,8 +22,9 @@ class ToscaSoftwareComponent(HotResource):
toscatype = 'tosca.nodes.SoftwareComponent'
- def __init__(self, nodetemplate):
- super(ToscaSoftwareComponent, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaSoftwareComponent, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
index d0a9c5d..03474aa 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
@@ -22,8 +22,9 @@ class ToscaWebApplication(HotResource):
toscatype = 'tosca.nodes.WebApplication'
- def __init__(self, nodetemplate):
- super(ToscaWebApplication, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaWebApplication, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
index 83bda80..32b80c5 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
@@ -22,8 +22,9 @@ class ToscaWebserver(HotResource):
toscatype = 'tosca.nodes.WebServer'
- def __init__(self, nodetemplate):
- super(ToscaWebserver, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir):
+ super(ToscaWebserver, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca_translator.py b/tosca2heat/heat-translator/translator/hot/tosca_translator.py
index 14ef8a1..b9d4c77 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca_translator.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca_translator.py
@@ -12,6 +12,7 @@
# under the License.
import logging
+import six
from toscaparser.utils.gettextutils import _
from translator.hot.syntax.hot_template import HotTemplate
from translator.hot.translate_inputs import TranslateInputs
@@ -24,24 +25,64 @@ log = logging.getLogger('heat-translator')
class TOSCATranslator(object):
'''Invokes translation methods.'''
- def __init__(self, tosca, parsed_params, deploy=None):
+ def __init__(self, tosca, parsed_params, deploy=None, csar_dir=None):
super(TOSCATranslator, self).__init__()
self.tosca = tosca
self.hot_template = HotTemplate()
self.parsed_params = parsed_params
self.deploy = deploy
+ self.csar_dir = csar_dir
self.node_translator = None
log.info(_('Initialized parmaters for translation.'))
- def translate(self):
+ def _translate_to_hot_yaml(self):
self._resolve_input()
self.hot_template.description = self.tosca.description
self.hot_template.parameters = self._translate_inputs()
self.node_translator = TranslateNodeTemplates(self.tosca,
- self.hot_template)
- self.hot_template.resources = self.node_translator.translate()
+ self.hot_template,
+ csar_dir=self.csar_dir)
+ self.hot_template.resources = \
+ self.node_translator.translate()
self.hot_template.outputs = self._translate_outputs()
- return self.hot_template.output_to_yaml()
+ if self.node_translator.hot_template_version is None:
+ self.node_translator.hot_template_version = HotTemplate.LATEST
+
+ def translate(self):
+ """Translate to HOT YAML
+
+ This method produces a translated output for main template.
+ The nested template, if any referenced by main, will be created
+ as a separate file.
+ """
+ self._translate_to_hot_yaml()
+
+ # TODO(mvelten) go back to calling hot_template.output_to_yaml instead
+ # for stdout once embed_substack_templates is correctly implemented
+ # return self.hot_template.output_to_yaml(
+ # self.node_translator.hot_template_version)
+ yaml_files = self.hot_template.output_to_yaml_files_dict(
+ "output.yaml",
+ self.node_translator.hot_template_version)
+ for name, content in six.iteritems(yaml_files):
+ if name != "output.yaml":
+ with open(name, 'w+') as f:
+ f.write(content)
+
+ return yaml_files["output.yaml"]
+
+ def translate_to_yaml_files_dict(self, base_filename):
+ """Translate to HOT YAML
+
+ This method produces a translated output containing main and
+ any nested templates referenced by main. This output can be
+ programmatically stored into different files by using key as
+ template name and value as template content.
+ """
+ self._translate_to_hot_yaml()
+ return self.hot_template.output_to_yaml_files_dict(
+ base_filename,
+ self.node_translator.hot_template_version)
def _translate_inputs(self):
translator = TranslateInputs(self.tosca.inputs, self.parsed_params,
diff --git a/tosca2heat/heat-translator/translator/hot/translate_node_templates.py b/tosca2heat/heat-translator/translator/hot/translate_node_templates.py
index 0aefd48..1a1a4d7 100644
--- a/tosca2heat/heat-translator/translator/hot/translate_node_templates.py
+++ b/tosca2heat/heat-translator/translator/hot/translate_node_templates.py
@@ -11,13 +11,17 @@
# License for the specific language governing permissions and limitations
# under the License.
+import copy
import importlib
import logging
import os
import six
+from collections import OrderedDict
+from toscaparser.functions import Concat
from toscaparser.functions import GetAttribute
from toscaparser.functions import GetInput
+from toscaparser.functions import GetOperationOutput
from toscaparser.functions import GetProperty
from toscaparser.properties import Property
from toscaparser.relationship_template import RelationshipTemplate
@@ -25,6 +29,8 @@ from toscaparser.utils.gettextutils import _
from translator.common.exception import ToscaClassAttributeError
from translator.common.exception import ToscaClassImportError
from translator.common.exception import ToscaModImportError
+from translator.common.exception import UnsupportedTypeError
+from translator.common import utils
from translator.conf.config import ConfigProvider as translatorConfig
from translator.hot.syntax.hot_resource import HotResource
from translator.hot.tosca.tosca_block_storage_attachment import (
@@ -132,20 +138,31 @@ log = logging.getLogger('heat-translator')
TOSCA_TO_HOT_TYPE = _generate_type_map()
+BASE_TYPES = six.string_types + six.integer_types + (dict, OrderedDict)
+
+HOT_SCALING_POLICY_TYPE = ["OS::Heat::AutoScalingGroup",
+ "OS::Senlin::Profile"]
+
class TranslateNodeTemplates(object):
'''Translate TOSCA NodeTemplates to Heat Resources.'''
- def __init__(self, tosca, hot_template):
+ def __init__(self, tosca, hot_template, csar_dir=None):
self.tosca = tosca
self.nodetemplates = self.tosca.nodetemplates
self.hot_template = hot_template
+ self.csar_dir = csar_dir
# list of all HOT resources generated
self.hot_resources = []
# mapping between TOSCA nodetemplate and HOT resource
log.debug(_('Mapping between TOSCA nodetemplate and HOT resource.'))
self.hot_lookup = {}
self.policies = self.tosca.topology_template.policies
+ # stores the last deploy of generated behavior for a resource
+ # useful to satisfy underlying dependencies between interfaces
+ self.last_deploy_map = {}
+ self.hot_template_version = None
+ self.processed_policy_res = []
def translate(self):
return self._translate_nodetemplates()
@@ -161,23 +178,56 @@ class TranslateNodeTemplates(object):
if resource.type == "OS::Nova::ServerGroup":
resource.handle_properties(self.hot_resources)
+ elif resource.type in ("OS::Heat::ScalingPolicy",
+ "OS::Senlin::Policy"):
+ if resource.name in self.processed_policy_res:
+ return
+ self.processed_policy_res.append(resource.name)
+ self.hot_resources = \
+ resource.handle_properties(self.hot_resources)
+ extra_hot_resources = []
+ for res in self.hot_resources:
+ if res.type == 'OS::Heat::ScalingPolicy':
+ extra_res = copy.deepcopy(res)
+ scaling_adjustment = res.properties['scaling_adjustment']
+ if scaling_adjustment < 0:
+ res.name = res.name + '_scale_in'
+ extra_res.name = extra_res.name + '_scale_out'
+ extra_res.properties['scaling_adjustment'] = \
+ -1 * scaling_adjustment
+ extra_hot_resources.append(extra_res)
+ self.processed_policy_res.append(res.name)
+ self.processed_policy_res.append(extra_res.name)
+ elif scaling_adjustment > 0:
+ res.name = res.name + '_scale_out'
+ extra_res.name = extra_res.name + '_scale_in'
+ extra_res.properties['scaling_adjustment'] = \
+ -1 * scaling_adjustment
+ extra_hot_resources.append(extra_res)
+ self.processed_policy_res.append(res.name)
+ self.processed_policy_res.append(extra_res.name)
+ else:
+ continue
+ self.hot_resources += extra_hot_resources
else:
resource.handle_properties()
def _translate_nodetemplates(self):
-
log.debug(_('Translating the node templates.'))
suffix = 0
# Copy the TOSCA graph: nodetemplate
for node in self.nodetemplates:
- base_type = HotResource.get_base_type(node.type_definition)
- hot_node = TOSCA_TO_HOT_TYPE[base_type.type](node)
+ base_type = HotResource.get_base_type_str(node.type_definition)
+ if base_type not in TOSCA_TO_HOT_TYPE:
+ raise UnsupportedTypeError(type=_('%s') % base_type)
+ hot_node = TOSCA_TO_HOT_TYPE[base_type](node,
+ csar_dir=self.csar_dir)
self.hot_resources.append(hot_node)
self.hot_lookup[node] = hot_node
# BlockStorage Attachment is a special case,
# which doesn't match to Heat Resources 1 to 1.
- if base_type.type == "tosca.nodes.Compute":
+ if base_type == "tosca.nodes.Compute":
volume_name = None
requirements = node.requirements
if requirements:
@@ -192,7 +242,7 @@ class TranslateNodeTemplates(object):
"tosca.nodes.BlockStorage"):
volume_name = node_name
break
- else: # unreachable code !
+ else:
for n in self.nodetemplates:
if n.name == value and \
n.is_derived_from(
@@ -201,9 +251,8 @@ class TranslateNodeTemplates(object):
break
suffix = suffix + 1
- attachment_node = self._get_attachment_node(node,
- suffix,
- volume_name)
+ attachment_node = self._get_attachment_node(
+ node, suffix, volume_name)
if attachment_node:
self.hot_resources.append(attachment_node)
for i in self.tosca.inputs:
@@ -216,6 +265,15 @@ class TranslateNodeTemplates(object):
for policy in self.policies:
policy_type = policy.type_definition
+ if policy.is_derived_from('tosca.policies.Scaling') and \
+ policy_type.type != 'tosca.policies.Scaling.Cluster':
+ TOSCA_TO_HOT_TYPE[policy_type.type] = \
+ TOSCA_TO_HOT_TYPE['tosca.policies.Scaling']
+ if not policy.is_derived_from('tosca.policies.Scaling') and \
+ policy_type.type not in TOSCA_TO_HOT_TYPE:
+ raise UnsupportedTypeError(type=_('%s') % policy_type.type)
+ elif policy_type.type == 'tosca.policies.Scaling.Cluster':
+ self.hot_template_version = '2016-04-08'
policy_node = TOSCA_TO_HOT_TYPE[policy_type.type](policy)
self.hot_resources.append(policy_node)
@@ -223,9 +281,14 @@ class TranslateNodeTemplates(object):
# into multiple HOT resources and may change their name
lifecycle_resources = []
for resource in self.hot_resources:
- expanded = resource.handle_life_cycle()
- if expanded:
- lifecycle_resources += expanded
+ expanded_resources, deploy_lookup, last_deploy = resource.\
+ handle_life_cycle()
+ if expanded_resources:
+ lifecycle_resources += expanded_resources
+ if deploy_lookup:
+ self.hot_lookup.update(deploy_lookup)
+ if last_deploy:
+ self.last_deploy_map[resource] = last_deploy
self.hot_resources += lifecycle_resources
# Handle configuration from ConnectsTo relationship in the TOSCA node:
@@ -234,7 +297,7 @@ class TranslateNodeTemplates(object):
connectsto_resources = []
for node in self.nodetemplates:
for requirement in node.requirements:
- for endpoint, details in six.iteritems(requirement):
+ for endpoint, details in requirement.items():
relation = None
if isinstance(details, dict):
target = details.get('node')
@@ -257,7 +320,9 @@ class TranslateNodeTemplates(object):
# if the source of dependency is a server and the
# relationship type is 'tosca.relationships.HostedOn',
# add dependency as properties.server
- if node_depend.type == 'tosca.nodes.Compute' and \
+ base_type = HotResource.get_base_type_str(
+ node_depend.type_definition)
+ if base_type == 'tosca.nodes.Compute' and \
node.related[node_depend].type == \
node.type_definition.HOSTEDON:
self.hot_lookup[node].properties['server'] = \
@@ -270,6 +335,13 @@ class TranslateNodeTemplates(object):
self.hot_lookup[node].depends_on_nodes.append(
self.hot_lookup[node_depend].top_of_chain())
+ last_deploy = self.last_deploy_map.get(
+ self.hot_lookup[node_depend])
+ if last_deploy and \
+ last_deploy not in self.hot_lookup[node].depends_on:
+ self.hot_lookup[node].depends_on.append(last_deploy)
+ self.hot_lookup[node].depends_on_nodes.append(last_deploy)
+
# handle hosting relationship
for resource in self.hot_resources:
resource.handle_hosting()
@@ -281,7 +353,8 @@ class TranslateNodeTemplates(object):
# dependent nodes in correct order
self.processed_resources = []
for resource in self.hot_resources:
- self._recursive_handle_properties(resource)
+ if resource.type not in HOT_SCALING_POLICY_TYPE:
+ self._recursive_handle_properties(resource)
# handle resources that need to expand to more than one HOT resource
expansion_resources = []
@@ -298,66 +371,215 @@ class TranslateNodeTemplates(object):
# traverse the reference chain to get the actual value
inputs = resource.properties.get('input_values')
if inputs:
- for name, value in six.iteritems(inputs):
- inputs[name] = self._translate_input(value, resource)
+ for name, value in inputs.items():
+ inputs[name] = self.translate_param_value(value, resource)
+
+ # remove resources without type defined
+ # for example a SoftwareComponent without interfaces
+ # would fall in this case
+ to_remove = []
+ for resource in self.hot_resources:
+ if resource.type is None:
+ to_remove.append(resource)
+
+ for resource in to_remove:
+ self.hot_resources.remove(resource)
return self.hot_resources
- def _translate_input(self, input_value, resource):
+ def translate_param_value(self, param_value, resource):
+ tosca_template = None
+ if resource:
+ tosca_template = resource.nodetemplate
+
get_property_args = None
- if isinstance(input_value, GetProperty):
- get_property_args = input_value.args
+ if isinstance(param_value, GetProperty):
+ get_property_args = param_value.args
# to remove when the parser is fixed to return GetProperty
- if isinstance(input_value, dict) and 'get_property' in input_value:
- get_property_args = input_value['get_property']
+ elif isinstance(param_value, dict) and 'get_property' in param_value:
+ get_property_args = param_value['get_property']
if get_property_args is not None:
- hot_target = self._find_hot_resource_for_tosca(
- get_property_args[0], resource)
- if hot_target:
- props = hot_target.get_tosca_props()
- prop_name = get_property_args[1]
- if prop_name in props:
- return props[prop_name]
- elif isinstance(input_value, GetAttribute):
+ tosca_target, prop_name, prop_arg = \
+ self.decipher_get_operation(get_property_args,
+ tosca_template)
+ if tosca_target:
+ prop_value = tosca_target.get_property_value(prop_name)
+ if prop_value:
+ prop_value = self.translate_param_value(
+ prop_value, resource)
+ return self._unfold_value(prop_value, prop_arg)
+ get_attr_args = None
+ if isinstance(param_value, GetAttribute):
+ get_attr_args = param_value.result().args
+ # to remove when the parser is fixed to return GetAttribute
+ elif isinstance(param_value, dict) and 'get_attribute' in param_value:
+ get_attr_args = param_value['get_attribute']
+ if get_attr_args is not None:
# for the attribute
# get the proper target type to perform the translation
- args = input_value.result().args
- hot_target = self._find_hot_resource_for_tosca(args[0], resource)
-
- return hot_target.get_hot_attribute(args[1], args)
- # most of artifacts logic should move to the parser
- elif isinstance(input_value, dict) and 'get_artifact' in input_value:
- get_artifact_args = input_value['get_artifact']
-
- hot_target = self._find_hot_resource_for_tosca(
- get_artifact_args[0], resource)
- artifacts = TranslateNodeTemplates.get_all_artifacts(
- hot_target.nodetemplate)
-
- if get_artifact_args[1] in artifacts:
- artifact = artifacts[get_artifact_args[1]]
- if artifact.get('type', None) == 'tosca.artifacts.File':
- return {'get_file': artifact.get('file')}
- elif isinstance(input_value, GetInput):
- if isinstance(input_value.args, list) \
- and len(input_value.args) == 1:
- return {'get_param': input_value.args[0]}
+ tosca_target, attr_name, attr_arg = \
+ self.decipher_get_operation(get_attr_args, tosca_template)
+ attr_args = []
+ if attr_arg:
+ attr_args += attr_arg
+ if tosca_target:
+ if tosca_target in self.hot_lookup:
+ attr_value = self.hot_lookup[tosca_target].\
+ get_hot_attribute(attr_name, attr_args)
+ attr_value = self.translate_param_value(
+ attr_value, resource)
+ return self._unfold_value(attr_value, attr_arg)
+ elif isinstance(param_value, dict) and 'get_artifact' in param_value:
+ get_artifact_args = param_value['get_artifact']
+ tosca_target, artifact_name, _ = \
+ self.decipher_get_operation(get_artifact_args,
+ tosca_template)
+
+ if tosca_target:
+ artifacts = HotResource.get_all_artifacts(tosca_target)
+ if artifact_name in artifacts:
+ cwd = os.getcwd()
+ artifact = artifacts[artifact_name]
+ if self.csar_dir:
+ os.chdir(self.csar_dir)
+ get_file = os.path.abspath(artifact.get('file'))
+ else:
+ get_file = artifact.get('file')
+ if artifact.get('type', None) == 'tosca.artifacts.File':
+ return {'get_file': get_file}
+ os.chdir(cwd)
+ get_input_args = None
+ if isinstance(param_value, GetInput):
+ get_input_args = param_value.args
+ elif isinstance(param_value, dict) and 'get_input' in param_value:
+ get_input_args = param_value['get_input']
+ if get_input_args is not None:
+ if isinstance(get_input_args, list) \
+ and len(get_input_args) == 1:
+ return {'get_param': self.translate_param_value(
+ get_input_args[0], resource)}
else:
- return {'get_param': input_value.args}
+ return {'get_param': self.translate_param_value(
+ get_input_args, resource)}
+ elif isinstance(param_value, GetOperationOutput):
+ res = self._translate_get_operation_output_function(
+ param_value.args, tosca_template)
+ if res:
+ return res
+ elif isinstance(param_value, dict) \
+ and 'get_operation_output' in param_value:
+ res = self._translate_get_operation_output_function(
+ param_value['get_operation_output'], tosca_template)
+ if res:
+ return res
+ concat_list = None
+ if isinstance(param_value, Concat):
+ concat_list = param_value.args
+ elif isinstance(param_value, dict) and 'concat' in param_value:
+ concat_list = param_value['concat']
+ if concat_list is not None:
+ res = self._translate_concat_function(concat_list, resource)
+ if res:
+ return res
+
+ if isinstance(param_value, list):
+ translated_list = []
+ for elem in param_value:
+ translated_elem = self.translate_param_value(elem, resource)
+ if translated_elem:
+ translated_list.append(translated_elem)
+ return translated_list
+
+ if isinstance(param_value, BASE_TYPES):
+ return param_value
+
+ return None
- return input_value
+ def _translate_concat_function(self, concat_list, resource):
+ str_replace_template = ''
+ str_replace_params = {}
+ index = 0
+ for elem in concat_list:
+ str_replace_template += '$s' + str(index)
+ str_replace_params['$s' + str(index)] = \
+ self.translate_param_value(elem, resource)
+ index += 1
+
+ return {'str_replace': {
+ 'template': str_replace_template,
+ 'params': str_replace_params
+ }}
+
+ def _translate_get_operation_output_function(self, args, tosca_template):
+ tosca_target = self._find_tosca_node(args[0],
+ tosca_template)
+ if tosca_target and len(args) >= 4:
+ operations = HotResource.get_all_operations(tosca_target)
+ # ignore Standard interface name,
+ # it is the only one supported in the translator anyway
+ op_name = args[2]
+ output_name = args[3]
+ if op_name in operations:
+ operation = operations[op_name]
+ if operation in self.hot_lookup:
+ matching_deploy = self.hot_lookup[operation]
+ matching_config_name = matching_deploy.\
+ properties['config']['get_resource']
+ matching_config = self.find_hot_resource(
+ matching_config_name)
+ if matching_config:
+ outputs = matching_config.properties.get('outputs')
+ if outputs is None:
+ outputs = []
+ outputs.append({'name': output_name})
+ matching_config.properties['outputs'] = outputs
+ return {'get_attr': [
+ matching_deploy.name,
+ output_name
+ ]}
@staticmethod
- def get_all_artifacts(nodetemplate):
- artifacts = nodetemplate.type_definition.get_value('artifacts',
- parent=True)
- if not artifacts:
- artifacts = {}
- tpl_artifacts = nodetemplate.entity_tpl.get('artifacts')
- if tpl_artifacts:
- artifacts.update(tpl_artifacts)
+ def _unfold_value(value, value_arg):
+ if value_arg is not None:
+ if isinstance(value, dict):
+ val = value.get(value_arg)
+ if val is not None:
+ return val
+
+ index = utils.str_to_num(value_arg)
+ if isinstance(value, list) and index is not None:
+ return value[index]
+ return value
+
+ def decipher_get_operation(self, args, current_tosca_node):
+ tosca_target = self._find_tosca_node(args[0],
+ current_tosca_node)
+ new_target = None
+ if tosca_target and len(args) > 2:
+ cap_or_req_name = args[1]
+ cap = tosca_target.get_capability(cap_or_req_name)
+ if cap:
+ new_target = cap
+ else:
+ for req in tosca_target.requirements:
+ if cap_or_req_name in req:
+ new_target = self._find_tosca_node(
+ req[cap_or_req_name])
+ cap = new_target.get_capability(cap_or_req_name)
+ if cap:
+ new_target = cap
+ break
+
+ if new_target:
+ tosca_target = new_target
+
+ prop_name = args[2]
+ prop_arg = args[3] if len(args) >= 4 else None
+ else:
+ prop_name = args[1]
+ prop_arg = args[2] if len(args) >= 3 else None
- return artifacts
+ return tosca_target, prop_name, prop_arg
def _get_attachment_node(self, node, suffix, volume_name):
attach = False
@@ -420,23 +642,29 @@ class TranslateNodeTemplates(object):
if resource.name == name:
return resource
- def _find_tosca_node(self, tosca_name):
- for node in self.nodetemplates:
- if node.name == tosca_name:
- return node
-
- def _find_hot_resource_for_tosca(self, tosca_name,
- current_hot_resource=None):
+ def _find_tosca_node(self, tosca_name, current_tosca_template=None):
+ tosca_node = None
if tosca_name == 'SELF':
- return current_hot_resource
- if tosca_name == 'HOST' and current_hot_resource is not None:
- for req in current_hot_resource.nodetemplate.requirements:
+ tosca_node = current_tosca_template
+ if tosca_name == 'HOST' and current_tosca_template:
+ for req in current_tosca_template.requirements:
if 'host' in req:
- return self._find_hot_resource_for_tosca(req['host'])
+ tosca_node = self._find_tosca_node(req['host'])
- for node in self.nodetemplates:
- if node.name == tosca_name:
- return self.hot_lookup[node]
+ if tosca_node is None:
+ for node in self.nodetemplates:
+ if node.name == tosca_name:
+ tosca_node = node
+ break
+ return tosca_node
+
+ def _find_hot_resource_for_tosca(self, tosca_name,
+ current_hot_resource=None):
+ current_tosca_resource = current_hot_resource.nodetemplate \
+ if current_hot_resource else None
+ tosca_node = self._find_tosca_node(tosca_name, current_tosca_resource)
+ if tosca_node:
+ return self.hot_lookup[tosca_node]
return None
@@ -444,7 +672,7 @@ class TranslateNodeTemplates(object):
connect_interfaces):
connectsto_resources = []
if connect_interfaces:
- for iname, interface in six.iteritems(connect_interfaces):
+ for iname, interface in connect_interfaces.items():
connectsto_resources += \
self._create_connect_config(source_node, target_name,
interface)
@@ -470,16 +698,30 @@ class TranslateNodeTemplates(object):
raise Exception(msg)
config_name = source_node.name + '_' + target_name + '_connect_config'
implement = connect_config.get('implementation')
+ cwd = os.getcwd()
if config_location == 'target':
+ if self.csar_dir:
+ os.chdir(self.csar_dir)
+ get_file = os.path.abspath(implement)
+ else:
+ get_file = implement
hot_config = HotResource(target_node,
config_name,
'OS::Heat::SoftwareConfig',
- {'config': {'get_file': implement}})
+ {'config': {'get_file': get_file}},
+ csar_dir=self.csar_dir)
elif config_location == 'source':
+ if self.csar_dir:
+ os.chdir(self.csar_dir)
+ get_file = os.path.abspath(implement)
+ else:
+ get_file = implement
hot_config = HotResource(source_node,
config_name,
'OS::Heat::SoftwareConfig',
- {'config': {'get_file': implement}})
+ {'config': {'get_file': get_file}},
+ csar_dir=self.csar_dir)
+ os.chdir(cwd)
connectsto_resources.append(hot_config)
hot_target = self._find_hot_resource_for_tosca(target_name)
hot_source = self._find_hot_resource_for_tosca(source_node.name)
diff --git a/tosca2heat/heat-translator/translator/hot/translate_outputs.py b/tosca2heat/heat-translator/translator/hot/translate_outputs.py
index 4197cdd..87ec02a 100644
--- a/tosca2heat/heat-translator/translator/hot/translate_outputs.py
+++ b/tosca2heat/heat-translator/translator/hot/translate_outputs.py
@@ -33,16 +33,8 @@ class TranslateOutputs(object):
def _translate_outputs(self):
hot_outputs = []
for output in self.outputs:
- if output.value.name == 'get_attribute':
- get_parameters = output.value.args
- hot_target = self.nodes.find_hot_resource(get_parameters[0])
- hot_value = hot_target.get_hot_attribute(get_parameters[1],
- get_parameters)
- hot_outputs.append(HotOutput(output.name,
- hot_value,
- output.description))
- else:
- hot_outputs.append(HotOutput(output.name,
- output.value,
+ hot_value = self.nodes.translate_param_value(output.value, None)
+ if hot_value is not None:
+ hot_outputs.append(HotOutput(output.name, hot_value,
output.description))
return hot_outputs
diff --git a/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py b/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py
index a08c3ac..3bab0b7 100644
--- a/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py
+++ b/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py
@@ -12,6 +12,8 @@
import sys
+import mock
+
class FakeApp(object):
def __init__(self):
@@ -20,6 +22,9 @@ class FakeApp(object):
self.stdout = sys.stdout
self.stderr = sys.stderr
+ self.cloud = mock.Mock()
+ self.cloud.get_session.return_value = None
+
class FakeClientManager(object):
def __init__(self):
diff --git a/tosca2heat/heat-translator/translator/osc/v1/translate.py b/tosca2heat/heat-translator/translator/osc/v1/translate.py
index ef005e2..afe3ba2 100644
--- a/tosca2heat/heat-translator/translator/osc/v1/translate.py
+++ b/tosca2heat/heat-translator/translator/osc/v1/translate.py
@@ -21,6 +21,8 @@ from cliff import command
from toscaparser.tosca_template import ToscaTemplate
from toscaparser.utils.gettextutils import _
+from translator.common import flavors
+from translator.common import images
from translator.common.utils import UrlUtils
from translator.conf.config import ConfigProvider
from translator.hot.tosca_translator import TOSCATranslator
@@ -35,7 +37,7 @@ class TranslateTemplate(command.Command):
"""Translate a template"""
- auth_required = False
+ auth_required = True
def get_parser(self, prog_name):
parser = super(TranslateTemplate, self).get_parser(prog_name)
@@ -73,6 +75,10 @@ class TranslateTemplate(command.Command):
'(%s).'), parsed_args)
output = None
+ session = self.app.cloud.get_session()
+ flavors.SESSION = session
+ images.SESSION = session
+
if parsed_args.parameter:
parsed_params = parsed_args.parameter
else:
@@ -94,7 +100,7 @@ class TranslateTemplate(command.Command):
translator = TOSCATranslator(tosca, parsed_params)
output = translator.translate()
else:
- msg = _('Could not find template file.')
+ msg = _('Could not find template file.\n')
log.error(msg)
sys.stdout.write(msg)
raise SystemExit
diff --git a/tosca2heat/heat-translator/translator/shell.py b/tosca2heat/heat-translator/translator/shell.py
index dc49b5c..1d67c2a 100644
--- a/tosca2heat/heat-translator/translator/shell.py
+++ b/tosca2heat/heat-translator/translator/shell.py
@@ -12,20 +12,38 @@
import argparse
-import ast
-import json
+import codecs
import logging
import logging.config
import os
-import prettytable
-import requests
+import six
import sys
import uuid
import yaml
+import zipfile
+
+# NOTE(aloga): As per upstream developers requirement this needs to work
+# without the clients, therefore we need to pass if we cannot import them
+try:
+ from keystoneauth1 import loading
+except ImportError:
+ keystone_client_avail = False
+else:
+ keystone_client_avail = True
+
+try:
+ import heatclient.client
+except ImportError:
+ heat_client_avail = False
+else:
+ heat_client_avail = True
+
from toscaparser.tosca_template import ToscaTemplate
from toscaparser.utils.gettextutils import _
from toscaparser.utils.urlutils import UrlUtils
+from translator.common import flavors
+from translator.common import images
from translator.common import utils
from translator.conf.config import ConfigProvider
from translator.hot.tosca_translator import TOSCATranslator
@@ -37,8 +55,8 @@ Test the heat-translator translation from command line as:
--template-type=<type of template e.g. tosca>
--parameters="purpose=test"
Takes three user arguments,
-1. type of translation (e.g. tosca) (required)
-2. Path to the file that needs to be translated (required)
+1. Path to the file that needs to be translated (required)
+2. type of translation (e.g. tosca) (optional)
3. Input parameters (optional)
In order to use heat-translator to only validate template,
@@ -54,8 +72,9 @@ log = logging.getLogger("heat-translator")
class TranslatorShell(object):
SUPPORTED_TYPES = ['tosca']
+ TOSCA_CSAR_META_DIR = "TOSCA-Metadata"
- def get_parser(self):
+ def get_parser(self, argv):
parser = argparse.ArgumentParser(prog="heat-translator")
parser.add_argument('--template-file',
@@ -94,14 +113,28 @@ class TranslatorShell(object):
parser.add_argument('--stack-name',
metavar='<stack-name>',
required=False,
- help=_('Stack name when deploy the generated '
- 'template.'))
+ help=_('The name to use for the Heat stack when '
+ 'deploy the generated template.'))
+
+ self._append_global_identity_args(parser, argv)
return parser
+ def _append_global_identity_args(self, parser, argv):
+ if not keystone_client_avail:
+ return
+
+ loading.register_session_argparse_arguments(parser)
+
+ default_auth_plugin = 'password'
+ if 'os-token' in argv:
+ default_auth_plugin = 'token'
+ loading.register_auth_argparse_arguments(
+ parser, argv, default=default_auth_plugin)
+
def main(self, argv):
- parser = self.get_parser()
+ parser = self.get_parser(argv)
(args, args_list) = parser.parse_known_args(argv)
template_file = args.template_file
@@ -124,19 +157,43 @@ class TranslatorShell(object):
'validation.') % {'template_file': template_file})
print(msg)
else:
- heat_tpl = self._translate(template_type, template_file,
- parsed_params, a_file, deploy)
- if heat_tpl:
- if utils.check_for_env_variables() and deploy:
- try:
- file_name = os.path.basename(
- os.path.splitext(template_file)[0])
- heatclient(heat_tpl, stack_name,
- file_name, parsed_params)
- except Exception:
- log.error(_("Unable to launch the heat stack"))
-
- self._write_output(heat_tpl, output_file)
+ if keystone_client_avail:
+ try:
+ keystone_auth = (
+ loading.load_auth_from_argparse_arguments(args)
+ )
+ keystone_session = (
+ loading.load_session_from_argparse_arguments(
+ args,
+ auth=keystone_auth
+ )
+ )
+ images.SESSION = keystone_session
+ flavors.SESSION = keystone_session
+ except Exception:
+ keystone_session = None
+
+ translator = self._get_translator(template_type,
+ template_file,
+ parsed_params, a_file,
+ deploy)
+
+ if translator and deploy:
+ if not keystone_client_avail or not heat_client_avail:
+ raise RuntimeError(_('Could not find Heat or Keystone'
+ 'client to deploy, aborting '))
+ if not keystone_session:
+ raise RuntimeError(_('Impossible to login with '
+ 'Keystone to deploy on Heat, '
+ 'please check your credentials'))
+
+ file_name = os.path.basename(
+ os.path.splitext(template_file)[0])
+ self.deploy_on_heat(keystone_session, keystone_auth,
+ translator, stack_name, file_name,
+ parsed_params)
+
+ self._write_output(translator, output_file)
else:
msg = (_('The path %(template_file)s is not a valid '
'file or URL.') % {'template_file': template_file})
@@ -144,6 +201,46 @@ class TranslatorShell(object):
log.error(msg)
raise ValueError(msg)
+ def deploy_on_heat(self, session, auth, translator,
+ stack_name, file_name, parameters):
+ endpoint = auth.get_endpoint(session, service_type="orchestration")
+ heat_client = heatclient.client.Client('1',
+ session=session,
+ auth=auth,
+ endpoint=endpoint)
+
+ heat_stack_name = stack_name if stack_name else \
+ 'heat_' + file_name + '_' + str(uuid.uuid4()).split("-")[0]
+ msg = _('Deploy the generated template, the stack name is %(name)s.')\
+ % {'name': heat_stack_name}
+ log.debug(msg)
+ tpl = yaml.safe_load(translator.translate())
+
+ # get all the values for get_file from a translated template
+ get_files = []
+ utils.get_dict_value(tpl, "get_file", get_files)
+ files = {}
+ if get_files:
+ for file in get_files:
+ with codecs.open(file, encoding='utf-8', errors='strict') \
+ as f:
+ text = f.read()
+ files[file] = text
+ tpl['heat_template_version'] = str(tpl['heat_template_version'])
+ self._create_stack(heat_client=heat_client,
+ stack_name=heat_stack_name,
+ template=tpl,
+ parameters=parameters,
+ files=files)
+
+ def _create_stack(self, heat_client, stack_name, template, parameters,
+ files):
+ if heat_client:
+ heat_client.stacks.create(stack_name=stack_name,
+ template=template,
+ parameters=parameters,
+ files=files)
+
def _parse_parameters(self, parameter_list):
parsed_inputs = {}
@@ -168,67 +265,33 @@ class TranslatorShell(object):
raise ValueError(msg)
return parsed_inputs
- def _translate(self, sourcetype, path, parsed_params, a_file, deploy):
- output = None
+ def _get_translator(self, sourcetype, path, parsed_params, a_file, deploy):
if sourcetype == "tosca":
log.debug(_('Loading the tosca template.'))
tosca = ToscaTemplate(path, parsed_params, a_file)
- translator = TOSCATranslator(tosca, parsed_params, deploy)
+ csar_dir = None
+ if deploy and zipfile.is_zipfile(path):
+ # set CSAR directory to the root of TOSCA-Metadata
+ csar_decompress = utils.decompress(path)
+ csar_dir = os.path.join(csar_decompress,
+ self.TOSCA_CSAR_META_DIR)
+ msg = _("'%(csar)s' is the location of decompressed "
+ "CSAR file.") % {'csar': csar_dir}
+ log.info(msg)
+ translator = TOSCATranslator(tosca, parsed_params, deploy,
+ csar_dir=csar_dir)
log.debug(_('Translating the tosca template.'))
- output = translator.translate()
- return output
-
- def _write_output(self, output, output_file=None):
- if output:
- if output_file:
- with open(output_file, 'w+') as f:
- f.write(output)
- else:
- print(output)
-
-
-def heatclient(output, stack_name, file_name, params):
- try:
- access_dict = utils.get_ks_access_dict()
- endpoint = utils.get_url_for(access_dict, 'orchestration')
- token = utils.get_token_id(access_dict)
- except Exception as e:
- log.error(e)
- headers = {
- 'Content-Type': 'application/json',
- 'X-Auth-Token': token
- }
-
- heat_stack_name = stack_name if stack_name else \
- "heat_" + file_name + '_' + str(uuid.uuid4()).split("-")[0]
- output = yaml.load(output)
- output['heat_template_version'] = str(output['heat_template_version'])
- data = {
- 'stack_name': heat_stack_name,
- 'template': output,
- 'parameters': params
- }
- response = requests.post(endpoint + '/stacks',
- data=json.dumps(data),
- headers=headers)
- content = ast.literal_eval(response._content)
- if response.status_code == 201:
- stack_id = content["stack"]["id"]
- get_url = endpoint + '/stacks/' + heat_stack_name + '/' + stack_id
- get_stack_response = requests.get(get_url,
- headers=headers)
- stack_details = json.loads(get_stack_response.content)["stack"]
- col_names = ["id", "stack_name", "stack_status", "creation_time",
- "updated_time"]
- pt = prettytable.PrettyTable(col_names)
- stack_list = []
- for col in col_names:
- stack_list.append(stack_details[col])
- pt.add_row(stack_list)
- print(pt)
- else:
- err_msg = content["error"]["message"]
- log(_("Unable to deploy to Heat\n%s\n") % err_msg)
+ return translator
+
+ def _write_output(self, translator, output_file=None):
+ if output_file:
+ path, filename = os.path.split(output_file)
+ yaml_files = translator.translate_to_yaml_files_dict(filename)
+ for name, content in six.iteritems(yaml_files):
+ with open(os.path.join(path, name), 'w+') as f:
+ f.write(content)
+ else:
+ print(translator.translate())
def main(args=None):
diff --git a/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_autoscaling.yaml
new file mode 100644
index 0000000..f58d727
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_autoscaling.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Template for deploying servers based on policies.
+
+topology_template:
+ node_templates:
+ my_server_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ policies:
+ - asg:
+ type: tosca.policies.Scaling
+ description: Simple node autoscaling
+ targets: [my_server_1]
+ triggers:
+ resize_compute:
+ description: trigger
+ condition:
+ constraint: utilization greater_than 50%
+ period: 60
+ evaluations: 1
+ method: average
+ properties:
+ min_instances: 2
+ max_instances: 10
+ default_instances: 3
+ increment: 1
diff --git a/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_cluster_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_cluster_autoscaling.yaml
new file mode 100644
index 0000000..208c589
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/autoscaling/tosca_cluster_autoscaling.yaml
@@ -0,0 +1,62 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Template for deploying servers based on policies.
+
+imports:
+ - ../custom_types/senlin_cluster_policies.yaml
+
+topology_template:
+ node_templates:
+ my_server_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ my_port_1:
+ type: tosca.nodes.network.Port
+ requirements:
+ - link:
+ node: my_network_1
+ - binding:
+ node: my_server_1
+ my_network_1:
+ type: tosca.nodes.network.Network
+ properties:
+ network_name: net0
+ policies:
+ - cluster_scaling:
+ type: tosca.policies.Scaling.Cluster
+ description: Cluster node autoscaling
+ targets: [my_server_1]
+ triggers:
+ scale_out:
+ description: trigger
+ event_type:
+ type: tosca.events.resource.cpu.utilization
+ metrics: cpu_util
+ implementation: Ceilometer
+ condition:
+ constraint: utilization greater_than 50%
+ period: 60
+ evaluations: 1
+ method: average
+ action:
+ scale_out:
+ type: SCALE_OUT
+ implementation: Senlin.webhook
+ properties:
+ min_instances: 2
+ max_instances: 10
+ default_instances: 3
+ increment: 1
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/senlin_cluster_policies.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/senlin_cluster_policies.yaml
new file mode 100644
index 0000000..c809ca0
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/senlin_cluster_policies.yaml
@@ -0,0 +1,11 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ The TOSCA Policy Type definition that is used to govern
+ Senlin Policy of TOSCA nodes or groups of nodes
+
+policy_types:
+ tosca.policies.Scaling.Cluster:
+ derived_from: tosca.policies.Scaling
+ description: The TOSCA Policy Type definition that is used to govern
+ scaling of TOSCA nodes or groups of nodes. \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/asg_res.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/asg_res.yaml
new file mode 100644
index 0000000..d3415ea
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/asg_res.yaml
@@ -0,0 +1,10 @@
+heat_template_version: 2013-05-23
+description: Tacker Scaling template
+resources:
+ my_server_1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ user_data_format: SOFTWARE_CONFIG
+ software_config_transport: POLL_SERVER_HEAT
+ image: rhel-6.5-test-image
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_autoscaling.yaml
new file mode 100644
index 0000000..1cd2c03
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_autoscaling.yaml
@@ -0,0 +1,39 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying servers based on policies.
+
+parameters: {}
+resources:
+ asg_group:
+ type: OS::Heat::AutoScalingGroup
+ properties:
+ min_size: 2
+ desired_capacity: 3
+ resource:
+ type: asg_res.yaml
+ max_size: 10
+ asg_scale_out:
+ type: OS::Heat::ScalingPolicy
+ properties:
+ auto_scaling_group_id:
+ get_resource: asg_group
+ adjustment_type: change_in_capacity
+ scaling_adjustment: 1
+ asg_scale_in:
+ type: OS::Heat::ScalingPolicy
+ properties:
+ auto_scaling_group_id:
+ get_resource: asg_group
+ adjustment_type: change_in_capacity
+ scaling_adjustment: -1
+ asg_alarm:
+ type: OS::Aodh::Alarm
+ properties:
+ meter_name: cpu_util
+ description: Simple node autoscaling
+ period: 60
+ statistic: avg
+ threshold: 1
+ comparison_operator: gt
+outputs: {} \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_cluster_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_cluster_autoscaling.yaml
new file mode 100644
index 0000000..ca0fb3a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/autoscaling/hot_cluster_autoscaling.yaml
@@ -0,0 +1,60 @@
+heat_template_version: 2016-04-08
+
+description: >
+ Template for deploying servers based on policies.
+
+parameters: {}
+resources:
+ my_server_1:
+ type: OS::Senlin::Profile
+ properties:
+ type: os.nova.server-1.0
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ networks:
+ - network: net0
+ cluster_scaling_scale_out:
+ type: OS::Senlin::Policy
+ properties:
+ bindings:
+ - cluster:
+ get_resource: my_server_1_cluster
+ type: senlin.policy.scaling-1.0
+ properties:
+ adjustment:
+ type: CHANGE_IN_CAPACITY
+ number: 1
+ event: CLUSTER_SCALE_OUT
+ my_server_1_cluster:
+ type: OS::Senlin::Cluster
+ properties:
+ profile:
+ get_resource: my_server_1
+ min_size: 2
+ max_size: 10
+ desired_capacity: 3
+ my_server_1_scale_out_receiver:
+ type: OS::Senlin::Receiver
+ properties:
+ action: CLUSTER_SCALE_OUT
+ cluster:
+ get_resource: my_server_1_cluster
+ type: webhook
+ scale_out_alarm:
+ type: OS::Aodh::Alarm
+ properties:
+ meter_name: cpu_util
+ alarm_actions:
+ - get_attr:
+ - my_server_1_scale_out_receiver
+ - channel
+ - alarm_url
+ description: Cluster node autoscaling
+ evaluation_periods: 1
+ repeat_actions: True
+ period: 60
+ statistic: avg
+ threshold: 50
+ comparison_operator: gt
+outputs: {}
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml
index 6c4b477..ec5dad1 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml
@@ -1,10 +1,25 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
- TOSCA template to test artifact usage
+ TOSCA template to test file and Ansible Galaxy role artifacts
parameters: {}
resources:
+ customwebserver_install_roles_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: customwebserver_install_roles_config
+ server:
+ get_resource: server
+ signal_transport: HEAT_SIGNAL
+ customwebserver_install_roles_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config: |
+ #!/bin/bash
+ ansible-galaxy install user.role
+ group: script
customwebserver_create_deploy:
type: OS::Heat::SoftwareDeployment
properties:
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml
index e2b6855..f60a1bb 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml
@@ -1,5 +1,5 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test custom type with an interface defined on it
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml
index 4408840..f973f58 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test custom type with an interface defined on it,
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml
index 1b3c9ac..b1ce63c 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test custom type with an interface defined on it,
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml
index dbfe69e..c7bc9cd 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
This TOSCA simple profile deploys nodejs, mongodb, elasticsearch, logstash and
@@ -552,3 +552,4 @@ outputs:
get_attr:
- kibana_server
- first_address
+
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml
index 258f3bf..2966391 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
This TOSCA simple profile deploys nodejs, mongodb, elasticsearch, logstash and
@@ -53,7 +53,6 @@ resources:
get_attr:
- mongo_server
- first_address
-
server:
get_resource: app_server
signal_transport: HEAT_SIGNAL
@@ -113,7 +112,6 @@ resources:
get_attr:
- mongo_server
- first_address
-
server:
get_resource: mongo_server
signal_transport: HEAT_SIGNAL
@@ -447,7 +445,6 @@ resources:
get_attr:
- kibana_server
- first_address
-
server:
get_resource: kibana_server
signal_transport: HEAT_SIGNAL
@@ -555,3 +552,4 @@ outputs:
get_attr:
- kibana_server
- first_address
+
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_exchange_public_ssh_key.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_exchange_public_ssh_key.yaml
index f3a3cc0..e90289d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_exchange_public_ssh_key.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_exchange_public_ssh_key.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test get_operation_output by exchanging ssh public key
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml
index 715ee3f..cb337d1 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a server with custom properties for image, flavor and key_name.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml
index 311da65..3de636d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a server with custom properties for image, flavor and key_name.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_get_functions_semantic.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_get_functions_semantic.yaml
index 25ad5a7..fcba383 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_get_functions_semantic.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_get_functions_semantic.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test get_* functions semantic
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml
index f6b3e8f..59a4f88 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a single server with predefined properties.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml
index 8798eb9..79fe30d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a single server with predefined properties.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml
index 85c5be4..8a031e2 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
A template to test host assignment for translated hot resources.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml
index 6b416c1..df35a10 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with nodejs and mongodb.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_script_types.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_script_types.yaml
index 7f2bc2c..f0f7021 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_script_types.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_script_types.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test usage of different script types like Ansible and Puppet
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml
index 1922fee..22c5212 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with wordpress, web server and mysql on the same server.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml
index 62671b1..7d01352 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with wordpress, web server and mysql on the same server.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml
index 2f25b65..91491e3 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Tosca template for creating an object storage service.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml
index 3ed6d3a..44a53d0 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile that just defines a single compute instance and selects a
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml
index df404f9..8235ebf 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile that just defines a single compute instance and selects a
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml
index c3a8196..cb92d01 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile that just defines a single compute instance and selects a
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml
index 2f13052..b0b2e02 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile that just defines a single compute instance and selects a
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml
index f676a8b..41663c6 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a software component.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component_multiple_hosts.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component_multiple_hosts.yaml
new file mode 100644
index 0000000..ebe9728
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component_multiple_hosts.yaml
@@ -0,0 +1,75 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a software component.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ server1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ software_config_transport: POLL_SERVER_HEAT
+
+ server2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ software_config_transport: POLL_SERVER_HEAT
+
+ my_software_create_deploy:
+ type: OS::Heat::SoftwareDeploymentGroup
+ properties:
+ config:
+ get_resource: my_software_create_config
+ signal_transport: HEAT_SIGNAL
+ servers:
+ server1:
+ get_resource: server1
+ server2:
+ get_resource: server2
+
+ my_software_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: software_install.sh
+ group: script
+
+ my_software_start_deploy:
+ type: OS::Heat::SoftwareDeploymentGroup
+ properties:
+ config:
+ get_resource: my_software_start_config
+ signal_transport: HEAT_SIGNAL
+ servers:
+ server1:
+ get_resource: server1
+ server2:
+ get_resource: server2
+ depends_on:
+ - my_software_create_deploy
+
+ my_software_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: software_start.sh
+ group: script
+
+outputs: {}
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml
index cf372d7..278031b 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a web application.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_interface_on_compute.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/interfaces/hot_interface_on_compute.yaml
index b863ac7..f085b9d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_interface_on_compute.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/interfaces/hot_interface_on_compute.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA template to test Compute node with interface
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml
index 5676566..a2f1e4a 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a single server with predefined properties.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml
index 9eb80fb..67653e6 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 server bound to a new network
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml
index bba7c58..81f69d1 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 server bound to 3 networks
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml
index 5116bcc..5b04831 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 1 server bound to an existing network
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml
index 6247282..64fc008 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 2 servers bound to the 1 network
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/SP1_res.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/SP1_res.yaml
new file mode 100644
index 0000000..ca47df2
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/SP1_res.yaml
@@ -0,0 +1,39 @@
+heat_template_version: 2013-05-23
+description: Tacker Scaling template
+resources:
+ VDU1:
+ type: OS::Nova::Server
+ properties:
+ user_data_format: SOFTWARE_CONFIG
+ software_config_transport: POLL_SERVER_HEAT
+ availability_zone: nova
+ image: cirros-0.3.4-x86_64-uec
+ flavor: m1.tiny
+ networks:
+ - port: { get_resource: CP1 }
+ config_drive: false
+ CP1:
+ type: OS::Neutron::Port
+ properties:
+ anti_spoofing_protection: false
+ management: true
+ network: net_mgmt
+ CP2:
+ type: OS::Neutron::Port
+ properties:
+ anti_spoofing_protection: false
+ management: true
+ network: net_mgmt
+ VDU2:
+ type: OS::Nova::Server
+ properties:
+ user_data_format: SOFTWARE_CONFIG
+ software_config_transport: POLL_SERVER_HEAT
+ availability_zone: nova
+ image: cirros-0.3.4-x86_64-uec
+ flavor: m1.tiny
+ networks:
+ - port: { get_resource: CP2 }
+ config_drive: false
+ VL1:
+ type: OS::Neutron::Net
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_nfv_sample.yaml
index 3d431ae..e4ee44d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_nfv_sample.yaml
@@ -1,19 +1,21 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying a single server with predefined properties.
parameters: {}
resources:
+
VDU1:
type: OS::Nova::Server
properties:
- flavor: m1.tiny
+ flavor: m1.medium
image: rhel-6.5-test-image
networks:
- port: { get_resource: CP1 }
user_data_format: SOFTWARE_CONFIG
software_config_transport: POLL_SERVER_HEAT
+
depends_on:
- VDU2
- BlockStorage
@@ -21,7 +23,7 @@ resources:
VDU2:
type: OS::Nova::Server
properties:
- flavor: m1.tiny
+ flavor: m1.medium
image: rhel-6.5-test-image
networks:
- port: { get_resource: CP2 }
@@ -31,14 +33,14 @@ resources:
BlockStorage:
type: OS::Cinder::Volume
properties:
- size: 1
+ size: 10
tosca.relationships.attachesto_1:
type: OS::Cinder::VolumeAttachment
properties:
instance_uuid:
get_resource: VDU1
- mountpoint: /dev/vdb1
+ mountpoint: /data
volume_id:
get_resource: BlockStorage
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_tosca_nfv_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_tosca_nfv_autoscaling.yaml
new file mode 100644
index 0000000..7d1e2f6
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/nfv/hot_tosca_nfv_autoscaling.yaml
@@ -0,0 +1,30 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying servers based on policies.
+
+parameters: {}
+resources:
+ SP1_scale_out:
+ type: OS::Heat::ScalingPolicy
+ properties:
+ auto_scaling_group_id:
+ get_resource: SP1_group
+ adjustment_type: change_in_capacity
+ scaling_adjustment: 1
+ SP1_group:
+ type: OS::Heat::AutoScalingGroup
+ properties:
+ min_size: 1
+ desired_capacity: 2
+ resource:
+ type: SP1_res.yaml
+ max_size: 3
+ SP1_scale_in:
+ type: OS::Heat::ScalingPolicy
+ properties:
+ auto_scaling_group_id:
+ get_resource: SP1_group
+ adjustment_type: change_in_capacity
+ scaling_adjustment: -1
+outputs: {} \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/policies/hot_policies.yaml
index d6ba13a..786a2e9 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/policies/hot_policies.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
Template for deploying the nodes based on given policies.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml
index a4396fa..e664124 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with server and attached block storage using the normative
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml
index a029f0c..5e1c3eb 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a Single Block Storage node shared by 2-Tier
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml
index 0aafd92..487501d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a Single Block Storage node shared by 2-Tier
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml
index 87e6bd3..d615a8d 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a single Block Storage node shared by 2-Tier
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml
index 45bb8b0..73a574b 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with a single Block Storage node shared by 2-Tier
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml
index 4eec76c..a520c83 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with server and attached block storage using a custom
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml
index 13a7eee..2dc574c 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with server and attached block storage using a named
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml
index 4000324..dc5fad6 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 2 servers each with different attached block storage.
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml
index 777f832..ec5c61f 100644
--- a/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml
@@ -1,4 +1,4 @@
-heat_template_version: 2014-10-16
+heat_template_version: 2013-05-23
description: >
TOSCA simple profile with 2 servers each with different attached block storage.
diff --git a/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_interface_on_compute.yaml b/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_interface_on_compute.yaml
new file mode 100644
index 0000000..e033c3c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_interface_on_compute.yaml
@@ -0,0 +1,48 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: TOSCA template to test Compute node with interface
+
+node_types:
+ tosca.nodes.CustomCompute:
+ derived_from: tosca.nodes.Compute
+ properties:
+ install_path:
+ type: string
+ default: /opt
+ interfaces:
+ Standard:
+ create:
+ implementation: install.sh
+ inputs:
+ install_path: { get_property: [ SELF, install_path ] }
+
+topology_template:
+ node_templates:
+
+ softwarecomponent_without_behavior:
+ type: tosca.nodes.SoftwareComponent
+ requirements:
+ - host: server
+
+ softwarecomponent_depending_on_customcompute_install:
+ type: tosca.nodes.SoftwareComponent
+ interfaces:
+ Standard:
+ create:
+ implementation: post_install.sh
+ requirements:
+ - host: server
+
+ server:
+ type: tosca.nodes.CustomCompute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 1
+ mem_size: 1 GB
+ os:
+ properties:
+ type: Linux
+ distribution: Ubuntu
+ version: 12.04
+ architecture: x86_64
diff --git a/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_script_types.yaml b/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_script_types.yaml
new file mode 100644
index 0000000..b54cbcb
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/interfaces/test_tosca_script_types.yaml
@@ -0,0 +1,48 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA template to test usage of different script types like
+ Ansible and Puppet one.
+
+topology_template:
+
+ node_templates:
+ customwebserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: install.yaml
+ configure:
+ implementation: configure.yml
+ start:
+ implementation: start.pp
+
+ customwebserver2:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: install.sh
+ configure:
+ implementation: configure.py
+ start:
+ implementation: start.sh
+
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 1
+ mem_size: 1 GB
+ os:
+ properties:
+ type: Linux
+ distribution: Ubuntu
+ version: 12.04
+ architecture: x86_64
diff --git a/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_defs.yaml b/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_defs.yaml
new file mode 100644
index 0000000..96b0d45
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_defs.yaml
@@ -0,0 +1,183 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+data_types:
+ tosca.datatypes.tacker.ActionMap:
+ properties:
+ trigger:
+ type: string
+ required: true
+ action:
+ type: string
+ required: true
+ params:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+
+ tosca.datatypes.tacker.MonitoringParams:
+ properties:
+ monitoring_delay:
+ type: int
+ required: false
+ count:
+ type: int
+ required: false
+ interval:
+ type: int
+ required: false
+ timeout:
+ type: int
+ required: false
+ retry:
+ type: int
+ required: false
+ port:
+ type: int
+ required: false
+
+ tosca.datatypes.tacker.MonitoringType:
+ properties:
+ name:
+ type: string
+ required: true
+ actions:
+ type: map
+ required: true
+ parameters:
+ type: tosca.datatypes.tacker.MonitoringParams
+ required: false
+
+ tosca.datatypes.compute_properties:
+ properties:
+ num_cpus:
+ type: integer
+ required: false
+ mem_size:
+ type: string
+ required: false
+ disk_size:
+ type: string
+ required: false
+ mem_page_size:
+ type: string
+ required: false
+ numa_node_count:
+ type: integer
+ constraints:
+ - greater_or_equal: 2
+ required: false
+ numa_nodes:
+ type: map
+ required: false
+ cpu_allocation:
+ type: map
+ required: false
+
+policy_types:
+ tosca.policies.tacker.Placement:
+ derived_from: tosca.policies.Root
+
+ tosca.policies.tacker.Failure:
+ derived_from: tosca.policies.Root
+ action:
+ type: string
+
+ tosca.policies.tacker.Failure.Respawn:
+ derived_from: tosca.policies.tacker.Failure
+ action: respawn
+
+ tosca.policies.tacker.Failure.Terminate:
+ derived_from: tosca.policies.tacker.Failure
+ action: log_and_kill
+
+ tosca.policies.tacker.Failure.Log:
+ derived_from: tosca.policies.tacker.Failure
+ action: log
+
+ tosca.policies.tacker.Monitoring:
+ derived_from: tosca.policies.Root
+ properties:
+ name:
+ type: string
+ required: true
+ parameters:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ actions:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+
+ tosca.policies.tacker.Monitoring.NoOp:
+ derived_from: tosca.policies.tacker.Monitoring
+ properties:
+ name: noop
+
+ tosca.policies.tacker.Monitoring.Ping:
+ derived_from: tosca.policies.tacker.Monitoring
+ properties:
+ name: ping
+
+ tosca.policies.tacker.Monitoring.HttpPing:
+ derived_from: tosca.policies.tacker.Monitoring.Ping
+ properties:
+ name: http-ping
+
+ tosca.policies.tacker.Alarming:
+ derived_from: tosca.policies.Monitoring
+ triggers:
+ resize_compute:
+ event_type:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+ metrics:
+ type: string
+ required: true
+ condition:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ action:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+
+ tosca.policies.tacker.Scaling:
+ derived_from: tosca.policies.Scaling
+ description: Defines policy for scaling the given targets.
+ properties:
+ increment:
+ type: integer
+ required: true
+ description: Number of nodes to add or remove during the scale out/in.
+ targets:
+ type: list
+ entry_schema:
+ type: string
+ required: true
+ description: List of Scaling nodes.
+ min_instances:
+ type: integer
+ required: true
+ description: Minimum number of instances to scale in.
+ max_instances:
+ type: integer
+ required: true
+ description: Maximum number of instances to scale out.
+ default_instances:
+ type: integer
+ required: true
+ description: Initial number of instances.
+ cooldown:
+ type: integer
+ required: false
+ default: 120
+ description: Wait time (in seconds) between consecutive scaling operations. During the cooldown period...
diff --git a/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_nfv_defs.yaml b/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_nfv_defs.yaml
new file mode 100644
index 0000000..1387509
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/nfv/tacker_nfv_defs.yaml
@@ -0,0 +1,261 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+data_types:
+ tosca.nfv.datatypes.pathType:
+ properties:
+ forwarder:
+ type: string
+ required: true
+ capability:
+ type: string
+ required: true
+
+ tosca.nfv.datatypes.aclType:
+ properties:
+ eth_type:
+ type: string
+ required: false
+ eth_src:
+ type: string
+ required: false
+ eth_dst:
+ type: string
+ required: false
+ vlan_id:
+ type: integer
+ constraints:
+ - in_range: [ 1, 4094 ]
+ required: false
+ vlan_pcp:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7 ]
+ required: false
+ mpls_label:
+ type: integer
+ constraints:
+ - in_range: [ 16, 1048575]
+ required: false
+ mpls_tc:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7 ]
+ required: false
+ ip_dscp:
+ type: integer
+ constraints:
+ - in_range: [ 0, 63 ]
+ required: false
+ ip_ecn:
+ type: integer
+ constraints:
+ - in_range: [ 0, 3 ]
+ required: false
+ ip_src_prefix:
+ type: string
+ required: false
+ ip_dst_prefix:
+ type: string
+ required: false
+ ip_proto:
+ type: integer
+ constraints:
+ - in_range: [ 1, 254 ]
+ required: false
+ destination_port_range:
+ type: string
+ required: false
+ source_port_range:
+ type: string
+ required: false
+ network_src_port_id:
+ type: string
+ required: false
+ network_dst_port_id:
+ type: string
+ required: false
+ network_id:
+ type: string
+ required: false
+ network_name:
+ type: string
+ required: false
+ tenant_id:
+ type: string
+ required: false
+ icmpv4_type:
+ type: integer
+ constraints:
+ - in_range: [ 0, 254 ]
+ required: false
+ icmpv4_code:
+ type: integer
+ constraints:
+ - in_range: [ 0, 15 ]
+ required: false
+ arp_op:
+ type: integer
+ constraints:
+ - in_range: [ 1, 25 ]
+ required: false
+ arp_spa:
+ type: string
+ required: false
+ arp_tpa:
+ type: string
+ required: false
+ arp_sha:
+ type: string
+ required: false
+ arp_tha:
+ type: string
+ required: false
+ ipv6_src:
+ type: string
+ required: false
+ ipv6_dst:
+ type: string
+ required: false
+ ipv6_flabel:
+ type: integer
+ constraints:
+ - in_range: [ 0, 1048575]
+ required: false
+ icmpv6_type:
+ type: integer
+ constraints:
+ - in_range: [ 0, 255]
+ required: false
+ icmpv6_code:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7]
+ required: false
+ ipv6_nd_target:
+ type: string
+ required: false
+ ipv6_nd_sll:
+ type: string
+ required: false
+ ipv6_nd_tll:
+ type: string
+ required: false
+
+ tosca.nfv.datatypes.policyType:
+ properties:
+ type:
+ type: string
+ required: false
+ constraints:
+ - valid_values: [ ACL ]
+ criteria:
+ type: list
+ required: true
+ entry_schema:
+ type: tosca.nfv.datatypes.aclType
+
+node_types:
+ tosca.nodes.nfv.VDU.Tacker:
+ derived_from: tosca.nodes.nfv.VDU
+ capabilities:
+ nfv_compute:
+ type: tosca.datatypes.compute_properties
+ properties:
+ name:
+ type: string
+ required: false
+ image:
+# type: tosca.artifacts.Deployment.Image.VM
+ type: string
+ required: false
+ flavor:
+ type: string
+ required: false
+ availability_zone:
+ type: string
+ required: false
+ metadata:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ config_drive:
+ type: boolean
+ default: false
+ required: false
+
+ placement_policy:
+# type: tosca.policies.tacker.Placement
+ type: string
+ required: false
+
+ monitoring_policy:
+# type: tosca.policies.tacker.Monitoring
+# type: tosca.datatypes.tacker.MonitoringType
+ type: map
+ required: false
+
+ config:
+ type: string
+ required: false
+
+ mgmt_driver:
+ type: string
+ default: noop
+ required: false
+
+ service_type:
+ type: string
+ required: false
+
+ user_data:
+ type: string
+ required: false
+
+ user_data_format:
+ type: string
+ required: false
+
+ key_name:
+ type: string
+ required: false
+
+ tosca.nodes.nfv.CP.Tacker:
+ derived_from: tosca.nodes.nfv.CP
+ properties:
+ mac_address:
+ type: string
+ required: false
+ name:
+ type: string
+ required: false
+ management:
+ type: boolean
+ required: false
+ anti_spoofing_protection:
+ type: boolean
+ required: false
+ security_groups:
+ type: list
+ required: false
+ type:
+ type: string
+ required: false
+ constraints:
+ - valid_values: [ sriov, vnic ]
+
+ tosca.nodes.nfv.FP.Tacker:
+ derived_from: tosca.nodes.Root
+ properties:
+ id:
+ type: integer
+ required: false
+ policy:
+ type: tosca.nfv.datatypes.policyType
+ required: true
+ description: policy to use to match traffic for this FP
+ path:
+ type: list
+ required: true
+ entry_schema:
+ type: tosca.nfv.datatypes.pathType
diff --git a/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_autoscaling.yaml b/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_autoscaling.yaml
new file mode 100644
index 0000000..10c8074
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_autoscaling.yaml
@@ -0,0 +1,67 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+description: >
+ Template for deploying servers based on policies.
+
+imports:
+ - tacker_defs.yaml
+ - tacker_nfv_defs.yaml
+
+topology_template:
+ node_templates:
+ VDU1:
+ type: tosca.nodes.nfv.VDU.Tacker
+ properties:
+ image: cirros-0.3.4-x86_64-uec
+ mgmt_driver: noop
+ availability_zone: nova
+ flavor: m1.tiny
+
+ CP1:
+ type: tosca.nodes.nfv.CP.Tacker
+ properties:
+ management: true
+ order: 0
+ anti_spoofing_protection: false
+ requirements:
+ - virtualLink:
+ node: VL1
+ - virtualBinding:
+ node: VDU1
+
+ VDU2:
+ type: tosca.nodes.nfv.VDU.Tacker
+ properties:
+ image: cirros-0.3.4-x86_64-uec
+ mgmt_driver: noop
+ availability_zone: nova
+ flavor: m1.tiny
+
+ CP2:
+ type: tosca.nodes.nfv.CP.Tacker
+ properties:
+ management: true
+ order: 0
+ anti_spoofing_protection: false
+ requirements:
+ - virtualLink:
+ node: VL1
+ - virtualBinding:
+ node: VDU2
+
+ VL1:
+ type: tosca.nodes.nfv.VL
+ properties:
+ network_name: net_mgmt
+ vendor: Tacker
+
+ policies:
+ - SP1:
+ type: tosca.policies.tacker.Scaling
+ targets: [VDU1, VDU2]
+ properties:
+ increment: 1
+ cooldown: 120
+ min_instances: 1
+ max_instances: 3
+ default_instances: 2
diff --git a/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_sample.yaml b/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_sample.yaml
new file mode 100644
index 0000000..5e938da
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/nfv/test_tosca_nfv_sample.yaml
@@ -0,0 +1,90 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+description: Template for deploying a single server with predefined properties.
+
+topology_template:
+ node_templates:
+
+ VDU1:
+ type: tosca.nodes.nfv.VDU
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ requirements:
+ - high_availability: VDU2
+ - local_storage:
+ node: BlockStorage
+ relationship:
+ type: tosca.relationships.AttachesTo
+ properties:
+ location: /data
+
+
+ BlockStorage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: 10 GB
+
+ VDU2:
+ type: tosca.nodes.nfv.VDU
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+
+ CP1:
+ type: tosca.nodes.nfv.CP
+ properties:
+ ip_address: 192.168.0.55
+ requirements:
+ - virtualLink:
+ node: VL1
+# relationship: tosca.relationships.nfv.VirtualLinksTo
+ - virtualBinding:
+ node: VDU1
+ relationship: tosca.relationships.nfv.VirtualBindsTo
+
+ CP2:
+ type: tosca.nodes.nfv.CP
+ properties:
+ ip_address: 192.168.0.56
+ requirements:
+ - virtualLink:
+ node: VL1
+# relationship: tosca.relationships.nfv.VirtualLinksTo
+ - virtualBinding:
+ node: VDU2
+ relationship: tosca.relationships.nfv.VirtualBindsTo
+
+ VL1:
+ type: tosca.nodes.nfv.VL
+ properties:
+ vendor: ACME
+ cidr: '192.168.0.0/24'
+ start_ip: '192.168.0.50'
+ end_ip: '192.168.0.200'
+ gateway_ip: '192.168.0.1'
+ network_name: test_net
+ network_type: vxlan
+ segmentation_id: 100
diff --git a/tosca2heat/heat-translator/translator/tests/data/policies/tosca_policies.yaml b/tosca2heat/heat-translator/translator/tests/data/policies/tosca_policies.yaml
new file mode 100644
index 0000000..26417d3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/policies/tosca_policies.yaml
@@ -0,0 +1,28 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying the nodes based on given policies.
+
+topology_template:
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ # Host container properties
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ policies:
+ - my_compute_placement_policy:
+ type: tosca.policies.Placement
+ description: Apply my placement policy to my application’s servers
+ targets: [ my_server ]
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml
index be2caca..161020c 100644
--- a/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml
@@ -1,11 +1,14 @@
tosca_definitions_version: tosca_simple_yaml_1_0
-description: TOSCA template to test artifact usage
+description: TOSCA template to test file and Ansible Galaxy role artifacts
node_types:
tosca.nodes.CustomWebServer:
derived_from: tosca.nodes.WebServer
artifacts:
+ my_galaxyansible_role:
+ file: user.role
+ type: tosca.artifacts.AnsibleGalaxy.role
web_content:
file: http://www.mycompany.org/content.tgz
type: tosca.artifacts.File
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml
index 3247589..e5af6e4 100644
--- a/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml
@@ -3,7 +3,7 @@ tosca_definitions_version: tosca_simple_yaml_1_0
description: Template for deploying a server with custom properties for image, flavor and key_name.
node_types:
- tosca.nodes.nfv.VDU:
+ tosca.nodes.nfv.MyType:
derived_from: tosca.nodes.Compute
properties:
key_name:
@@ -21,7 +21,7 @@ topology_template:
node_templates:
my_server:
- type: tosca.nodes.nfv.VDU
+ type: tosca.nodes.nfv.MyType
properties:
flavor: m1.medium
image: rhel-6.5-test-image
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_get_functions_semantic.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_get_functions_semantic.yaml
index 2a76978..6a6a485 100644
--- a/tosca2heat/heat-translator/translator/tests/data/test_tosca_get_functions_semantic.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_get_functions_semantic.yaml
@@ -3,6 +3,12 @@ tosca_definitions_version: tosca_simple_yaml_1_0
description: TOSCA template to test get_* functions semantic
node_types:
+ tosca.capabilities.custom.Endpoint:
+ derived_from: tosca.capabilities.Endpoint
+ attributes:
+ credential:
+ type: tosca.datatypes.Credential
+
tosca.capabilities.MyFeature:
derived_from: tosca.capabilities.Root
properties:
@@ -25,6 +31,12 @@ node_types:
myfeature:
type: tosca.capabilities.MyFeature
+ tosca.nodes.custom.Compute:
+ derived_from: tosca.nodes.Compute
+ capabilities:
+ endpoint:
+ type: tosca.capabilities.custom.Endpoint
+
topology_template:
inputs:
map_val:
@@ -32,7 +44,7 @@ topology_template:
node_templates:
server:
- type: tosca.nodes.Compute
+ type: tosca.nodes.custom.Compute
capabilities:
host:
properties:
@@ -82,3 +94,7 @@ topology_template:
test_list_of_functions:
value: [ { get_property: [ myapp, myfeature, my_map, test_key ] }, { get_property: [ myapp, myfeature, my_map, test_key_static ] } ]
+
+ # should not be translated : complex type
+ credential:
+ value: { get_attribute: [server, endpoint, credential] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_unsupported_type.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_unsupported_type.yaml
new file mode 100644
index 0000000..fdbb771
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_unsupported_type.yaml
@@ -0,0 +1,15 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template to test unsupported translation. Load Balancer is a
+ > valid TOSCA type but not supported in translator yet.
+
+topology_template:
+ node_templates:
+ simple_load_balancer:
+ type: tosca.nodes.LoadBalancer
+ capabilities:
+ client:
+ properties:
+ network_name: PUBLIC
+ floating: true
+ dns_name: http://mycompany.com/ \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_software_component_multiple_hosts.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_software_component_multiple_hosts.yaml
new file mode 100644
index 0000000..e8aefb7
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_software_component_multiple_hosts.yaml
@@ -0,0 +1,55 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with a software component.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+
+ node_templates:
+ my_software:
+ type: tosca.nodes.SoftwareComponent
+ properties:
+ component_version: 1.0
+ requirements:
+ - host: server1
+ - host: server2
+ interfaces:
+ Standard:
+ create: software_install.sh
+ start: software_start.sh
+
+ server1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 1024 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+ server2:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 1024 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
diff --git a/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/rnc_definition.yaml b/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/rnc_definition.yaml
index 62ed2ad..33883fb 100644
--- a/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/rnc_definition.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/rnc_definition.yaml
@@ -42,6 +42,22 @@ node_types:
required: false
constraints:
- valid_values: [ TDS-CDMA, UMTS, CDMA ]
+ attributes:
+ private_ip_of_MM:
+ type: string
+ description: The private IP address of the MM.
+
+ private_ip_of_CM:
+ type: string
+ description: The private IP address of the CM.
+
+ private_ip_of_DM:
+ type: string
+ description: The private IP address of the DM.
+
+ private_ip_of_LB:
+ type: string
+ description: The private IP address of the LB.
requirements:
- virtualLink_VNFM:
capability: tosca.capabilities.nfv.VirtualLinkable
diff --git a/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/vRNC.yaml b/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/vRNC.yaml
index 6c9b092..458271a 100644
--- a/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/vRNC.yaml
+++ b/tosca2heat/heat-translator/translator/tests/data/vRNC/Definitions/vRNC.yaml
@@ -117,9 +117,9 @@ topology_template:
- local_storage:
node: MM_BlockStorage
relationship: Storage_attachesto
- artifacts:
+ #artifacts:
#the VM image of MM
- vm_image: mm.image
+ #vm_image: mm.image
MM_Passive:
type: tosca.nodes.SoftwareComponent
@@ -146,9 +146,9 @@ topology_template:
node: MM_BlockStorage
relationship: Storage_attachesto
- high_availability: MM_Active_Host
- artifacts:
+ #artifacts:
#the VM image of MM
- vm_image: mm.image
+ #vm_image: mm.image
MM_BlockStorage:
type: rnc.nodes.BlockStorage
@@ -184,9 +184,9 @@ topology_template:
min_instances: 1
max_instances: 12
default_instances: 1
- artifacts:
+ #artifacts:
#the VM image of CM
- vm_image: cm.image
+ #vm_image: cm.image
CM_Passive:
type: tosca.nodes.SoftwareComponent
@@ -215,9 +215,9 @@ topology_template:
default_instances: 1
requirements:
- high_availability: CM_Active_Host
- artifacts:
+ #artifacts:
#the VM image of CM
- vm_image: mm.image
+ #vm_image: mm.image
DM:
type: tosca.nodes.SoftwareComponent
@@ -244,8 +244,9 @@ topology_template:
min_instances: 1
max_instances: 12
default_instances: 1
- artifacts:
- vm_image: dm.image
+ #artifacts:
+ #the VM image of DM
+ #vm_image: dm.image
LB:
type: tosca.nodes.SoftwareComponent
@@ -272,9 +273,9 @@ topology_template:
min_instances: 1
max_instances: 2
default_instances: 1
- artifacts:
+ #artifacts:
#the VM image of LB
- vm_image: lb.image
+ #vm_image: lb.image
CTRL_Net:
type: rnc.nodes.VL
diff --git a/tosca2heat/heat-translator/translator/tests/test_shell.py b/tosca2heat/heat-translator/translator/tests/test_shell.py
index ef8592d..9bdf01c 100644
--- a/tosca2heat/heat-translator/translator/tests/test_shell.py
+++ b/tosca2heat/heat-translator/translator/tests/test_shell.py
@@ -10,13 +10,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-import ast
+
import json
+import mock
import os
import shutil
import tempfile
-from mock import patch
from toscaparser.common import exception
from toscaparser.utils.gettextutils import _
import translator.shell as shell
@@ -49,10 +49,7 @@ class ShellTest(TestCase):
'--parameters=key'))
def test_valid_template(self):
- try:
- shell.main([self.template_file, self.template_type])
- except Exception:
- self.fail(self.failure_msg)
+ shell.main([self.template_file, self.template_type])
def test_valid_template_without_type(self):
try:
@@ -101,25 +98,19 @@ class ShellTest(TestCase):
self.assertTrue(temp_dir is None or
not os.path.exists(temp_dir))
- @patch('uuid.uuid4')
- @patch('translator.common.utils.check_for_env_variables')
- @patch('requests.post')
- @patch('translator.common.utils.get_url_for')
- @patch('translator.common.utils.get_token_id')
- @patch('os.getenv')
- @patch('translator.hot.tosca.tosca_compute.'
- 'ToscaCompute._create_nova_flavor_dict')
- @patch('translator.hot.tosca.tosca_compute.'
- 'ToscaCompute._populate_image_dict')
- def test_template_deploy_with_credentials(self, mock_populate_image_dict,
- mock_flavor_dict,
- mock_os_getenv,
- mock_token,
- mock_url, mock_post,
- mock_env,
- mock_uuid):
+ @mock.patch('uuid.uuid4')
+ @mock.patch.object(shell.TranslatorShell, '_create_stack')
+ @mock.patch('keystoneauth1.loading.load_auth_from_argparse_arguments')
+ @mock.patch('keystoneauth1.loading.load_session_from_argparse_arguments')
+ @mock.patch('translator.common.flavors.get_flavors')
+ @mock.patch('translator.common.images.get_images')
+ def test_template_deploy(self, mock_populate_image_dict,
+ mock_flavor_dict,
+ mock_keystone_session,
+ mock_keystone_auth,
+ mock_client,
+ mock_uuid):
mock_uuid.return_value = 'abcXXX-abcXXX'
- mock_env.return_value = True
mock_flavor_dict.return_value = {
'm1.medium': {'mem_size': 4096, 'disk_size': 40, 'num_cpus': 2}
}
@@ -131,43 +122,34 @@ class ShellTest(TestCase):
"type": "Linux"
}
}
- mock_url.return_value = 'http://abc.com'
- mock_token.return_value = 'mock_token'
- mock_os_getenv.side_effect = ['demo', 'demo',
- 'demo', 'http://www.abc.com']
+
try:
data = {
- 'stack_name': 'heat_tosca_helloworld_abcXXX',
+ 'outputs': {},
+ 'heat_template_version': '2013-05-23',
+ 'description': 'Template for deploying a single server '
+ 'with predefined properties.\n',
'parameters': {},
- 'template': {
- 'outputs': {},
- 'heat_template_version': '2014-10-16',
- 'description': 'Template for deploying a single server '
- 'with predefined properties.\n',
- 'parameters': {},
- 'resources': {
- 'my_server': {
- 'type': 'OS::Nova::Server',
- 'properties': {
- 'flavor': 'm1.medium',
- 'user_data_format': 'SOFTWARE_CONFIG',
- 'software_config_transport':
- 'POLL_SERVER_HEAT',
- 'image': 'rhel-6.5-test-image'
- }
+ 'resources': {
+ 'my_server': {
+ 'type': 'OS::Nova::Server',
+ 'properties': {
+ 'flavor': 'm1.medium',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'software_config_transport': 'POLL_SERVER_HEAT',
+ 'image': 'rhel-6.5-test-image'
}
}
}
}
mock_heat_res = {
- "stack": {
- "id": 1234
- }
- }
- headers = {
- 'Content-Type': 'application/json',
- 'X-Auth-Token': 'mock_token'
+ "stacks": [
+ {
+ "id": "d648ad27-fb9c-44d1-b293-646ea6c4f8da",
+ "stack_status": "CREATE_IN_PROGRESS",
+ }
+ ]
}
class mock_response(object):
@@ -176,12 +158,11 @@ class ShellTest(TestCase):
self._content = _content
mock_response_obj = mock_response(201, json.dumps(mock_heat_res))
- mock_post.return_value = mock_response_obj
- shell.main([self.template_file, self.template_type,
- "--deploy"])
- args, kwargs = mock_post.call_args
- self.assertEqual(args[0], 'http://abc.com/stacks')
- self.assertEqual(ast.literal_eval(kwargs['data']), data)
- self.assertEqual(kwargs['headers'], headers)
- except Exception:
- self.fail(self.failure_msg)
+ mock_client.return_value = mock_response_obj
+ shell.main([self.template_file, self.template_type, "--deploy"])
+ args, kwargs = mock_client.call_args
+ self.assertEqual(kwargs["stack_name"],
+ 'heat_tosca_helloworld_abcXXX')
+ self.assertEqual(kwargs["template"], data)
+ except Exception as e:
+ self.fail(e)
diff --git a/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py b/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
index bd98904..6d0d316 100644
--- a/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
+++ b/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
@@ -16,42 +16,60 @@ import os
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import URLException
from toscaparser.common.exception import ValidationError
+from toscaparser.tosca_template import ToscaTemplate
from toscaparser.utils.gettextutils import _
+from translator.common.exception import UnsupportedTypeError
from translator.common.utils import TranslationUtils
+from translator.hot.tosca_translator import TOSCATranslator
from translator.tests.base import TestCase
class ToscaHotTranslationTest(TestCase):
- def test_hot_translate_single_server(self):
- tosca_file = '../tests/data/tosca_single_server.yaml'
- hot_file = '../tests/data/hot_output/hot_single_server.yaml'
- params = {'cpus': 1}
+ def _test_successful_translation(self, tosca_file, hot_files, params=None):
+ if not params:
+ params = {}
+ if not isinstance(hot_files, list):
+ hot_files = [hot_files]
diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
+ hot_files,
params)
self.assertEqual({}, diff, '<difference> : ' +
json.dumps(diff, indent=4, separators=(', ', ': ')))
+ def _test_failed_translation(self, tosca_file, hot_file, params, msg,
+ msg_path, error_raise, error_collect):
+ if msg_path:
+ path = os.path.normpath(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), tosca_file))
+ msg = msg % path
+ self.assertRaises(
+ error_raise,
+ TranslationUtils.compare_tosca_translation_with_hot,
+ tosca_file, hot_file, params)
+ ExceptionCollector.assertExceptionMessage(error_collect, msg)
+
+ def test_hot_translate_single_server(self):
+ tosca_file = '../tests/data/tosca_single_server.yaml'
+ hot_file = '../tests/data/hot_output/hot_single_server.yaml'
+ params = {'cpus': 1}
+ self._test_successful_translation(tosca_file, hot_file, params)
+
def test_hot_translate_single_server_with_defaults(self):
tosca_file = \
'../tests/data/tosca_single_server_with_defaults.yaml'
+
hot_file_with_input = '../tests/data/hot_output/' \
'hot_single_server_with_defaults_with_input.yaml'
- hot_file_without_input = '../tests/data/hot_output/' \
- 'hot_single_server_with_defaults_without_input.yaml'
-
params1 = {'cpus': '1'}
- diff1 = TranslationUtils.compare_tosca_translation_with_hot(
- tosca_file, hot_file_with_input, params1)
- self.assertEqual({}, diff1, '<difference> : ' +
- json.dumps(diff1, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file_with_input,
+ params1)
+ hot_file_without_input = '../tests/data/hot_output/' \
+ 'hot_single_server_with_defaults_without_input.yaml'
params2 = {}
- diff2 = TranslationUtils.compare_tosca_translation_with_hot(
- tosca_file, hot_file_without_input, params2)
- self.assertEqual({}, diff2, '<difference> : ' +
- json.dumps(diff2, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file_without_input,
+ params2)
def test_hot_translate_wordpress_single_instance(self):
tosca_file = '../tests/data/tosca_single_instance_wordpress.yaml'
@@ -63,29 +81,17 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_helloworld(self):
tosca_file = '../tests/data/tosca_helloworld.yaml'
hot_file = '../tests/data/hot_output/hot_hello_world.yaml'
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- {})
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file)
def test_hot_translate_host_assignment(self):
tosca_file = '../tests/data/test_host_assignment.yaml'
hot_file = '../tests/data/hot_output/hot_host_assignment.yaml'
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- {})
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file)
def test_hot_translate_elk(self):
tosca_file = '../tests/data/tosca_elk.yaml'
@@ -93,11 +99,7 @@ class ToscaHotTranslationTest(TestCase):
params = {'github_url':
'http://github.com/paypal/rest-api-sample-app-nodejs.git',
'my_cpus': 4}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_nodejs_mongodb_two_instances(self):
tosca_file = '../tests/data/tosca_nodejs_mongodb_two_instances.yaml'
@@ -106,11 +108,7 @@ class ToscaHotTranslationTest(TestCase):
params = {'github_url':
'http://github.com/paypal/rest-api-sample-app-nodejs.git',
'my_cpus': 4}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_blockstorage_with_attachment(self):
tosca_file = '../tests/data/storage/' \
@@ -121,11 +119,7 @@ class ToscaHotTranslationTest(TestCase):
'storage_location': '/dev/vdc',
'storage_size': '2000 MB',
'storage_snapshot_id': 'ssid'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_blockstorage_with_custom_relationship_type(self):
tosca_file = '../tests/data/storage/' \
@@ -136,11 +130,7 @@ class ToscaHotTranslationTest(TestCase):
'storage_location': '/dev/vdc',
'storage_size': '1 GB',
'storage_snapshot_id': 'ssid'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_blockstorage_with_relationship_template(self):
tosca_file = '../tests/data/storage/' \
@@ -150,11 +140,7 @@ class ToscaHotTranslationTest(TestCase):
params = {'cpus': 1,
'storage_location': '/dev/vdc',
'storage_size': '1 GB'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_blockstorage_with_attachment_notation1(self):
tosca_file = '../tests/data/storage/' \
@@ -167,19 +153,11 @@ class ToscaHotTranslationTest(TestCase):
'storage_location': 'some_folder',
'storage_size': '1 GB',
'storage_snapshot_id': 'ssid'}
- diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file1,
- params)
+
try:
- self.assertEqual({}, diff1, '<difference> : ' +
- json.dumps(diff1, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file1, params)
except Exception:
- diff2 = TranslationUtils.compare_tosca_translation_with_hot(
- tosca_file, hot_file2, params)
- self.assertEqual({}, diff2, '<difference> : ' +
- json.dumps(diff2, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file2, params)
def test_hot_translate_blockstorage_with_attachment_notation2(self):
tosca_file = '../tests/data/storage/' \
@@ -192,19 +170,10 @@ class ToscaHotTranslationTest(TestCase):
'storage_location': '/dev/vdc',
'storage_size': '1 GB',
'storage_snapshot_id': 'ssid'}
- diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file1,
- params)
try:
- self.assertEqual({}, diff1, '<difference> : ' +
- json.dumps(diff1, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file1, params)
except Exception:
- diff2 = TranslationUtils.compare_tosca_translation_with_hot(
- tosca_file, hot_file2, params)
- self.assertEqual({}, diff2, '<difference> : ' +
- json.dumps(diff2, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file2, params)
def test_hot_translate_multiple_blockstorage_with_attachment(self):
tosca_file = '../tests/data/storage/' \
@@ -217,40 +186,23 @@ class ToscaHotTranslationTest(TestCase):
'storage_location': '/dev/vdc',
'storage_size': '1 GB',
'storage_snapshot_id': 'ssid'}
- diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file1,
- params)
try:
- self.assertEqual({}, diff1, '<difference> : ' +
- json.dumps(diff1, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file1, params)
except Exception:
- diff2 = TranslationUtils.compare_tosca_translation_with_hot(
- tosca_file, hot_file2, params)
- self.assertEqual({}, diff2, '<difference> : ' +
- json.dumps(diff2, indent=4,
- separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file2, params)
def test_hot_translate_single_object_store(self):
tosca_file = '../tests/data/storage/tosca_single_object_store.yaml'
hot_file = '../tests/data/hot_output/hot_single_object_store.yaml'
params = {'objectstore_name': 'myobjstore'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_one_server_one_network(self):
tosca_file = '../tests/data/network/tosca_one_server_one_network.yaml'
hot_file = '../tests/data/hot_output/network/' \
'hot_one_server_one_network.yaml'
params = {'network_name': 'private_net'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_server_on_existing_network(self):
tosca_file = '../tests/data/network/' \
@@ -258,11 +210,7 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/network/' \
'hot_server_on_existing_network.yaml'
params = {'network_name': 'private_net'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_two_servers_one_network(self):
tosca_file = '../tests/data/network/tosca_two_servers_one_network.yaml'
@@ -272,11 +220,7 @@ class ToscaHotTranslationTest(TestCase):
'network_cidr': '10.0.0.0/24',
'network_start_ip': '10.0.0.100',
'network_end_ip': '10.0.0.150'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_one_server_three_networks(self):
tosca_file = '../tests/data/network/' \
@@ -284,32 +228,29 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/network/' \
'hot_one_server_three_networks.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_software_component(self):
tosca_file = '../tests/data/tosca_software_component.yaml'
hot_file = '../tests/data/hot_output/hot_software_component.yaml'
params = {'cpus': '1',
'download_url': 'http://www.software.com/download'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_translate_software_component_multiple_hosts(self):
+ tosca_file = '../tests/data/tosca_software_component'\
+ '_multiple_hosts.yaml'
+ hot_file = '../tests/data/hot_output/hot_software_component'\
+ '_multiple_hosts.yaml'
+ params = {'cpus': '1',
+ 'download_url': 'http://www.software.com/download'}
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_web_application(self):
tosca_file = '../tests/data/tosca_web_application.yaml'
hot_file = '../tests/data/hot_output/hot_web_application.yaml'
params = {'cpus': '2', 'context_root': 'my_web_app'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_template_with_url_import(self):
tosca_file = '../tests/data/' \
@@ -322,11 +263,7 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_template_by_url_with_local_import(self):
tosca_file = 'https://raw.githubusercontent.com/openstack/' \
@@ -340,11 +277,7 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_template_by_url_with_local_abspath_import(self):
tosca_file = 'https://raw.githubusercontent.com/openstack/' \
@@ -359,17 +292,15 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
expected_msg = _('Absolute file name "/tmp/wordpress.yaml" cannot be '
'used in a URL-based input template "https://raw.'
'githubusercontent.com/openstack/heat-translator/'
'master/translator/tests/data/tosca_single_instance_'
'wordpress_with_local_abspath_import.yaml".')
- ExceptionCollector.assertExceptionMessage(ImportError, expected_msg)
+ msg_path = False
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ ImportError)
def test_hot_translate_template_by_url_with_url_import(self):
tosca_url = 'https://raw.githubusercontent.com/openstack/' \
@@ -383,20 +314,12 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_url,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_url, hot_file, params)
def test_translate_hello_world_csar(self):
tosca_file = '../tests/data/csar_hello_world.zip'
hot_file = '../tests/data/hot_output/hot_hello_world.yaml'
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- {})
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file)
def test_translate_single_instance_wordpress_csar(self):
tosca_file = '../tests/data/csar_single_instance_wordpress.zip'
@@ -408,11 +331,7 @@ class ToscaHotTranslationTest(TestCase):
'db_root_pwd': 'passw0rd',
'db_port': 3366,
'cpus': 8}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_translate_elk_csar_from_url(self):
tosca_file = 'https://github.com/openstack/heat-translator/raw/' \
@@ -421,150 +340,103 @@ class ToscaHotTranslationTest(TestCase):
params = {'github_url':
'http://github.com/paypal/rest-api-sample-app-nodejs.git',
'my_cpus': 4}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_translate_csar_not_zip(self):
tosca_file = '../tests/data/csar_not_zip.zip'
hot_file = ''
params = {}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
- path = os.path.normpath(os.path.join(
- os.path.dirname(os.path.realpath(__file__)), tosca_file))
- expected_msg = _('"%s" is not a valid zip file.') % path
- ExceptionCollector.assertExceptionMessage(ValidationError,
- expected_msg)
+ expected_msg = _('"%s" is not a valid zip file.')
+ msg_path = True
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ ValidationError)
def test_translate_csar_metadata_not_yaml(self):
tosca_file = '../tests/data/csar_metadata_not_yaml.zip'
hot_file = ''
params = {}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
- path = os.path.normpath(os.path.join(
- os.path.dirname(os.path.realpath(__file__)), tosca_file))
expected_msg = _('The file "TOSCA-Metadata/TOSCA.meta" in the CSAR '
- '"%s" does not contain valid YAML content.') % path
- ExceptionCollector.assertExceptionMessage(ValidationError,
- expected_msg)
+ '"%s" does not contain valid YAML content.')
+ msg_path = True
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ ValidationError)
def test_translate_csar_wrong_metadata_file(self):
tosca_file = '../tests/data/csar_wrong_metadata_file.zip'
hot_file = ''
params = {}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
- path = os.path.normpath(os.path.join(
- os.path.dirname(os.path.realpath(__file__)), tosca_file))
expected_msg = _('"%s" is not a valid CSAR as it does not contain the '
'required file "TOSCA.meta" in the folder '
- '"TOSCA-Metadata".') % path
- ExceptionCollector.assertExceptionMessage(ValidationError,
- expected_msg)
+ '"TOSCA-Metadata".')
+ msg_path = True
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ ValidationError)
def test_translate_csar_wordpress_invalid_import_path(self):
tosca_file = '../tests/data/csar_wordpress_invalid_import_path.zip'
hot_file = ''
params = {}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
expected_msg = _('Import '
'"Invalid_import_path/wordpress.yaml" is not valid.')
- ExceptionCollector.assertExceptionMessage(ImportError, expected_msg)
+ msg_path = False
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ ImportError)
def test_translate_csar_wordpress_invalid_script_url(self):
tosca_file = '../tests/data/csar_wordpress_invalid_script_url.zip'
hot_file = ''
params = {}
-
- self.assertRaises(
- ValidationError,
- TranslationUtils.compare_tosca_translation_with_hot,
- tosca_file, hot_file, params)
expected_msg = _('The resource at '
'"https://raw.githubusercontent.com/openstack/'
'heat-translator/master/translator/tests/data/'
'custom_types/wordpress1.yaml" cannot be accessed.')
- ExceptionCollector.assertExceptionMessage(URLException, expected_msg)
+ msg_path = False
+ self._test_failed_translation(tosca_file, hot_file, params,
+ expected_msg, msg_path, ValidationError,
+ URLException)
def test_hot_translate_flavor_image(self):
tosca_file = '../tests/data/test_tosca_flavor_and_image.yaml'
hot_file = '../tests/data/hot_output/hot_flavor_and_image.yaml'
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- {})
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file)
def test_hot_translate_flavor_image_params(self):
tosca_file = '../tests/data/test_tosca_flavor_and_image.yaml'
hot_file = '../tests/data/hot_output/hot_flavor_and_image_params.yaml'
params = {'key_name': 'paramkey'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_custom_type(self):
tosca_file = '../tests/data/test_tosca_custom_type.yaml'
hot_file = '../tests/data/hot_output/' \
'hot_custom_type.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_custom_type_with_override(self):
tosca_file = '../tests/data/test_tosca_custom_type_with_override.yaml'
hot_file = '../tests/data/hot_output/' \
'hot_custom_type_with_override.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_custom_type_with_param_override(self):
tosca_file = '../tests/data/test_tosca_custom_type_with_override.yaml'
hot_file = '../tests/data/hot_output/' \
'hot_custom_type_with_param_override.yaml'
params = {'install_path': '/home/custom/from/cli'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_artifact(self):
tosca_file = '../tests/data/test_tosca_artifact.yaml'
hot_file = '../tests/data/hot_output/' \
'hot_artifact.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_without_tosca_os_version(self):
tosca_file = '../tests/data/' \
@@ -572,21 +444,13 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/' \
'hot_single_server_without_tosca_os_version.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_helloworld_with_userkey(self):
tosca_file = '../tests/data/tosca_helloworld.yaml'
hot_file = '../tests/data/hot_output/hot_hello_world_userkey.yaml'
params = {'key_name': 'userkey'}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_custom_networks_nodes_inline(self):
tosca_file = '../tests/data/network/' \
@@ -594,11 +458,7 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/network/' \
'hot_custom_network_nodes.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_custom_networks_nodes_imports(self):
tosca_file = '../tests/data/network/' \
@@ -606,38 +466,80 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/network/' \
'hot_custom_network_nodes.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_nfv_sample(self):
- tosca_file = '../tests/data/test_tosca_nfv_sample.yaml'
- hot_file = '../tests/data/hot_output/hot_nfv_sample.yaml'
+ tosca_file = '../tests/data/nfv/test_tosca_nfv_sample.yaml'
+ hot_file = '../tests/data/hot_output/nfv/hot_nfv_sample.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_policy(self):
- tosca_file = '../tests/data/tosca_policies.yaml'
- hot_file = '../tests/data/hot_output/hot_policies.yaml'
+ tosca_file = '../tests/data/policies/tosca_policies.yaml'
+ hot_file = '../tests/data/hot_output/policies/hot_policies.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_script_types(self):
- tosca_file = '../tests/data/test_tosca_script_types.yaml'
+ tosca_file = '../tests/data/interfaces/test_tosca_script_types.yaml'
hot_file = '../tests/data/hot_output/hot_script_types.yaml'
params = {}
- diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
- hot_file,
- params)
- self.assertEqual({}, diff, '<difference> : ' +
- json.dumps(diff, indent=4, separators=(', ', ': ')))
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_interface_on_compute(self):
+ tosca_file = '../tests/data/interfaces/' \
+ 'test_tosca_interface_on_compute.yaml'
+ hot_file = '../tests/data/hot_output/interfaces/' \
+ 'hot_interface_on_compute.yaml'
+ params = {}
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_get_functions_semantic(self):
+ tosca_file = '../tests/data/test_tosca_get_functions_semantic.yaml'
+ hot_file = '../tests/data/hot_output/hot_get_functions_semantic.yaml'
+ params = {}
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_exchange_public_ssh_key(self):
+ tosca_file = '../tests/data/tosca_exchange_public_ssh_key.yaml'
+ hot_file = '../tests/data/hot_output/hot_exchange_public_ssh_key.yaml'
+ params = {}
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_translate_scaling_policy(self):
+ tosca_file = '../tests/data/autoscaling/tosca_autoscaling.yaml'
+ hot_files = [
+ '../tests/data/hot_output/autoscaling/hot_autoscaling.yaml',
+ '../tests/data/hot_output/autoscaling/asg_res.yaml',
+ ]
+ params = {}
+ self._test_successful_translation(tosca_file, hot_files, params)
+
+ def test_translate_unsupported_tosca_type(self):
+ tosca_file = '../tests/data/test_tosca_unsupported_type.yaml'
+ tosca_tpl = os.path.normpath(os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), tosca_file))
+ params = {}
+ expected_msg = _('Type "tosca.nodes.LoadBalancer" is valid TOSCA '
+ 'type but translation support is not yet available.')
+ tosca = ToscaTemplate(tosca_tpl, params, True)
+ err = self.assertRaises(UnsupportedTypeError,
+ TOSCATranslator(tosca, params)
+ .translate)
+ self.assertEqual(expected_msg, err.__str__())
+
+ def _translate_nodetemplates(self):
+ tosca_file = '../tests/data/autoscaling/tosca_cluster_autoscaling.yaml'
+ hot_file = '../tests/data/hot_output/autoscaling/' \
+ 'hot_cluster_autoscaling.yaml'
+ params = {}
+ self._test_successful_translation(tosca_file, hot_file, params)
+
+ def test_hot_translate_nfv_scaling(self):
+ tosca_file = '../tests/data/nfv/test_tosca_nfv_autoscaling.yaml'
+ hot_files = [
+ '../tests/data/hot_output/nfv/hot_tosca_nfv_autoscaling.yaml',
+ '../tests/data/hot_output/nfv/SP1_res.yaml',
+ ]
+ params = {}
+ self._test_successful_translation(tosca_file, hot_files, params)
diff --git a/tosca2heat/heat-translator/translator/tests/test_utils.py b/tosca2heat/heat-translator/translator/tests/test_utils.py
index b6d75d9..555555b 100644
--- a/tosca2heat/heat-translator/translator/tests/test_utils.py
+++ b/tosca2heat/heat-translator/translator/tests/test_utils.py
@@ -234,3 +234,37 @@ class CommonUtilsTest(TestCase):
self.assertFalse(self.UrlUtils.validate_url("github.com"))
self.assertFalse(self.UrlUtils.validate_url("123"))
self.assertFalse(self.UrlUtils.validate_url("a/b/c"))
+
+ def test_get_dict_value(self):
+ single_snippet = \
+ {'nodejs_create_config':
+ {'type': 'tosca.nodes.SoftwareConfig',
+ 'properties':
+ {'config':
+ {'get_file': 'create.sh'}}}}
+ actual_output_single_snippet = []
+ ex_output_single_snippet = ['create.sh']
+ translator.common.utils.get_dict_value(single_snippet, "get_file",
+ actual_output_single_snippet)
+ self.assertEqual(actual_output_single_snippet,
+ ex_output_single_snippet)
+ multi_snippet = \
+ {'resources':
+ {'nodejs_create_config':
+ {'type': 'tosca.nodes.SoftwareConfig',
+ 'properties':
+ {'config':
+ {'get_file': 'nodejs/create.sh'}}},
+ 'mongodb_create_config':
+ {'type': 'tosca.nodes.SoftwareConfig',
+ 'properties':
+ {'config':
+ {'get_file': 'mongodb/create.sh'}}}}}
+
+ actual_output_multi_snippet = []
+ ex_output_multi_snippet = ['mongodb/create.sh',
+ 'nodejs/create.sh']
+ translator.common.utils.get_dict_value(multi_snippet, "get_file",
+ actual_output_multi_snippet)
+ self.assertEqual(sorted(actual_output_multi_snippet),
+ ex_output_multi_snippet)
diff --git a/tosca2heat/tosca-parser/README.rst b/tosca2heat/tosca-parser/README.rst
index d80d75b..0f94072 100644
--- a/tosca2heat/tosca-parser/README.rst
+++ b/tosca2heat/tosca-parser/README.rst
@@ -1,3 +1,12 @@
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/tosca-parser.svg
+ :target: http://governance.openstack.org/reference/tags/index.html
+
+.. Change things from this point on
+
===============
TOSCA Parser
===============
diff --git a/tosca2heat/tosca-parser/doc/source/conf.py b/tosca2heat/tosca-parser/doc/source/conf.py
index e461246..d5d9189 100644
--- a/tosca2heat/tosca-parser/doc/source/conf.py
+++ b/tosca2heat/tosca-parser/doc/source/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
diff --git a/tosca2heat/tosca-parser/doc/source/installation.rst b/tosca2heat/tosca-parser/doc/source/installation.rst
index f3805a5..5476d41 100644
--- a/tosca2heat/tosca-parser/doc/source/installation.rst
+++ b/tosca2heat/tosca-parser/doc/source/installation.rst
@@ -2,8 +2,17 @@
Installation
============
-You can clone the project and use it as below::
+PyPI Installation
+-----------------
+Tosca-Parser can be installed via a PyPI package. Refer to https://pypi.python.org/pypi/tosca-parser for available packages.
+The latest release can be simply installed by running the following command::
- git clone https://github.com/openstack/tosca-parser
+ sudo pip install tosca-parser
+
+Manual Installation
+-------------------
+You can manually install the latest code available at the TOSCA-Parser github repository by following these steps::
-Tosca-Parser can be installed via PyPI package as well. Refer to https://pypi.python.org/pypi/tosca-parser for available packages. \ No newline at end of file
+ git clone https://github.com/openstack/tosca-parser
+ cd tosca-parser
+ sudo python setup.py install
diff --git a/tosca2heat/tosca-parser/requirements.txt b/tosca2heat/tosca-parser/requirements.txt
index b30cc51..45a19f0 100644
--- a/tosca2heat/tosca-parser/requirements.txt
+++ b/tosca2heat/tosca-parser/requirements.txt
@@ -1,10 +1,10 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr>=1.6 # Apache-2.0
+pbr>=1.8 # Apache-2.0
Babel>=2.3.4 # BSD
-cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
-PyYAML>=3.1.0 # MIT
+cliff>=2.3.0 # Apache-2.0
+PyYAML>=3.10.0 # MIT
python-dateutil>=2.4.2 # BSD
six>=1.9.0 # MIT
-requests>=2.10.0 # Apache-2.0
+requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
diff --git a/tosca2heat/tosca-parser/setup.cfg b/tosca2heat/tosca-parser/setup.cfg
index c109228..77e1b2e 100644
--- a/tosca2heat/tosca-parser/setup.cfg
+++ b/tosca2heat/tosca-parser/setup.cfg
@@ -1,11 +1,12 @@
[metadata]
name = tosca-parser
+url = https://launchpad.net/tosca-parser
summary = Parser for TOSCA Simple Profile in YAML.
description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
-home-page = http://www.openstack.org/
+home-page = http://docs.openstack.org/developer/tosca-parser/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
diff --git a/tosca2heat/tosca-parser/test-requirements.txt b/tosca2heat/tosca-parser/test-requirements.txt
index 1bb6623..d4b59c3 100644
--- a/tosca2heat/tosca-parser/test-requirements.txt
+++ b/tosca2heat/tosca-parser/test-requirements.txt
@@ -2,12 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.0
-coverage>=3.6 # Apache-2.0
+coverage>=4.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD
oslotest>=1.10.0 # Apache-2.0
-oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
+oslosphinx>=4.7.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
-sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
+sphinx>=1.5.1 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
diff --git a/tosca2heat/tosca-parser/tools/tox_install.sh b/tosca2heat/tosca-parser/tools/tox_install.sh
new file mode 100644
index 0000000..e61b63a
--- /dev/null
+++ b/tosca2heat/tosca-parser/tools/tox_install.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE="$1"
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ "$CONSTRAINTS_FILE" != http* ]]; then
+ CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
+
+pip install -c"$localfile" openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints "$localfile" -- "$CLIENT_NAME"
+
+pip install -c"$localfile" -U "$@"
+exit $?
diff --git a/tosca2heat/tosca-parser/toscaparser/__init__.py b/tosca2heat/tosca-parser/toscaparser/__init__.py
index d6fa60c..d9745ed 100644
--- a/tosca2heat/tosca-parser/toscaparser/__init__.py
+++ b/tosca2heat/tosca-parser/toscaparser/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml
index 6f3b331..9f3369e 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml
@@ -70,6 +70,8 @@ node_types:
type: tosca.capabilities.OperatingSystem
scalable:
type: tosca.capabilities.Scalable
+ endpoint:
+ type: tosca.capabilities.Endpoint.Admin
requirements:
- local_storage:
capability: tosca.capabilities.Attachment
@@ -527,6 +529,7 @@ capability_types:
network_name:
type: string
required: false
+ default: PRIVATE
initiator:
type: string
required: false
@@ -671,7 +674,7 @@ capability_types:
publish_ports:
type: list
entry_schema:
- type: PortSpec
+ type: tosca.datatypes.network.PortSpec
required: false
description: >
List of ports mappings from source (Docker container)
@@ -679,7 +682,7 @@ capability_types:
expose_ports:
type: list
entry_schema:
- type: PortSpec
+ type: tosca.datatypes.network.PortSpec
required: false
description: >
List of ports mappings from source (Docker container) to expose
@@ -799,7 +802,7 @@ data_types:
constraints:
- valid_values: [ udp, tcp, igmp ]
target:
- type: PortDef
+ type: tosca.datatypes.network.PortDef
required: false
target_range:
type: range
@@ -807,7 +810,7 @@ data_types:
constraints:
- in_range: [ 1, 65535 ]
source:
- type: PortDef
+ type: tosca.datatypes.network.PortDef
required: false
source_range:
type: range
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py b/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py
index 865690e..54cd9fe 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py
@@ -44,7 +44,7 @@ class CapabilityTypeDef(StatefulEntityType):
for prop, schema in props.items():
# add parent property if not overridden by children type
if not self.properties or \
- prop not in self.properties.keys():
+ prop not in self.properties.keys():
properties.append(PropertyDef(prop, None, schema))
return properties
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/constraints.py b/tosca2heat/tosca-parser/toscaparser/elements/constraints.py
index 8594b85..70863bc 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/constraints.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/constraints.py
@@ -27,10 +27,10 @@ class Schema(collections.Mapping):
KEYS = (
TYPE, REQUIRED, DESCRIPTION,
- DEFAULT, CONSTRAINTS, ENTRYSCHEMA
+ DEFAULT, CONSTRAINTS, ENTRYSCHEMA, STATUS
) = (
'type', 'required', 'description',
- 'default', 'constraints', 'entry_schema'
+ 'default', 'constraints', 'entry_schema', 'status'
)
PROPERTY_TYPES = (
@@ -86,6 +86,10 @@ class Schema(collections.Mapping):
return self.schema.get(self.DEFAULT)
@property
+ def status(self):
+ return self.schema.get(self.STATUS, '')
+
+ @property
def constraints(self):
if not self.constraints_list:
constraint_schemata = self.schema.get(self.CONSTRAINTS)
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py
index d7fcb18..9fd6c4d 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py
@@ -93,7 +93,7 @@ class EntityType(object):
return False
def entity_value(self, defs, key):
- if key in defs:
+ if defs and key in defs:
return defs[key]
def get_value(self, ndtype, defs=None, parent=None):
@@ -102,7 +102,7 @@ class EntityType(object):
if not hasattr(self, 'defs'):
return None
defs = self.defs
- if ndtype in defs:
+ if defs and ndtype in defs:
# copy the value to avoid that next operations add items in the
# item definitions
value = copy.copy(defs[ndtype])
@@ -110,7 +110,7 @@ class EntityType(object):
p = self
if p:
while p:
- if ndtype in p.defs:
+ if p.defs and ndtype in p.defs:
# get the parent value
parent_value = p.defs[ndtype]
if value:
@@ -159,7 +159,6 @@ class EntityType(object):
def update_definitions(version):
exttools = ExtTools()
extension_defs_file = exttools.get_defs_file(version)
-
loader = toscaparser.utils.yamlparser.load_yaml
nfv_def_file = loader(extension_defs_file)
nfv_def = {}
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py b/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py
index 02c285a..4e58d64 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py
@@ -87,7 +87,7 @@ class GroupType(StatefulEntityType):
'metadata' % (meta_data.get('type'))))
for entry_schema, entry_schema_type in meta_data.items():
if isinstance(entry_schema_type, dict) and not \
- entry_schema_type.get('type') == 'string':
+ entry_schema_type.get('type') == 'string':
ExceptionCollector.appendException(
InvalidTypeError(what='"%s" defined in group for '
'metadata "%s"'
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py b/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py
index 88fb8ab..47ec90a 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py
@@ -22,6 +22,9 @@ SECTIONS = (LIFECYCLE, CONFIGURE, LIFECYCLE_SHORTNAME,
INTERFACEVALUE = (IMPLEMENTATION, INPUTS) = ('implementation', 'inputs')
+INTERFACE_DEF_RESERVED_WORDS = ['type', 'inputs', 'derived_from', 'version',
+ 'description']
+
class InterfacesDef(StatefulEntityType):
'''TOSCA built-in interfaces type.'''
@@ -40,8 +43,16 @@ class InterfacesDef(StatefulEntityType):
interfacetype = LIFECYCLE
if interfacetype == CONFIGURE_SHORTNAME:
interfacetype = CONFIGURE
+ if hasattr(self.ntype, 'interfaces') \
+ and self.ntype.interfaces \
+ and interfacetype in self.ntype.interfaces:
+ interfacetype = self.ntype.interfaces[interfacetype]['type']
if node_type:
- self.defs = self.TOSCA_DEF[interfacetype]
+ if self.node_template and self.node_template.custom_def \
+ and interfacetype in self.node_template.custom_def:
+ self.defs = self.node_template.custom_def[interfacetype]
+ else:
+ self.defs = self.TOSCA_DEF[interfacetype]
if value:
if isinstance(self.value, dict):
for i, j in self.value.items():
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py
index f5e4eb0..7d68c0b 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py
@@ -98,10 +98,6 @@ class NodeType(StatefulEntityType):
provided capability.
'''
- # All types,include normative and custom types, here will
- # be substituted because the global moification of TOSCA_DEF
- self.TOSCA_DEF.update(self.custom_def)
-
# Filter the node types
node_types = [node_type for node_type in self.TOSCA_DEF.keys()
if node_type.startswith(self.NODE_PREFIX) and
@@ -141,8 +137,6 @@ class NodeType(StatefulEntityType):
'''Return a list of capability objects.'''
typecapabilities = []
caps = self.get_value(self.CAPABILITIES, None, True)
- if caps is None:
- caps = self.get_value(self.CAPABILITIES, None, True)
if caps:
# 'name' is symbolic name of the capability
# 'value' is a dict { 'type': <capability type name> }
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py
index 8fbb0f0..a922d26 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py
@@ -20,9 +20,10 @@ from toscaparser.utils.validateutils import TOSCAVersionProperty
class PolicyType(StatefulEntityType):
'''TOSCA built-in policies type.'''
- SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, TARGETS) = \
+ SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION,
+ TARGETS, TRIGGERS, TYPE) = \
('derived_from', 'metadata', 'properties', 'version',
- 'description', 'targets')
+ 'description', 'targets', 'triggers', 'type')
def __init__(self, ptype, custom_def=None):
super(PolicyType, self).__init__(ptype, self.POLICY_PREFIX,
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py b/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py
index d32e97e..0218305 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py
@@ -58,7 +58,7 @@ class PortSpec(object):
# verify one of the specified values is set
if source is None and source_range is None and \
- target is None and target_range is None:
+ target is None and target_range is None:
ExceptionCollector.appendException(
InvalidTypeAdditionalRequirementsError(
type=PortSpec.TYPE_URI))
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py
index 25440ca..8eefbea 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py
@@ -10,16 +10,25 @@
# License for the specific language governing permissions and limitations
# under the License.
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import UnknownFieldError
from toscaparser.elements.statefulentitytype import StatefulEntityType
class RelationshipType(StatefulEntityType):
'''TOSCA built-in relationship type.'''
+ SECTIONS = (DERIVED_FROM, VALID_TARGET_TYPES, INTERFACES,
+ ATTRIBUTES, PROPERTIES, DESCRIPTION, VERSION,
+ CREDENTIAL) = ('derived_from', 'valid_target_types',
+ 'interfaces', 'attributes', 'properties',
+ 'description', 'version', 'credential')
+
def __init__(self, type, capability_name=None, custom_def=None):
super(RelationshipType, self).__init__(type, self.RELATIONSHIP_PREFIX,
custom_def)
self.capability_name = capability_name
self.custom_def = custom_def
+ self._validate_keys()
@property
def parent_type(self):
@@ -31,3 +40,10 @@ class RelationshipType(StatefulEntityType):
@property
def valid_target_types(self):
return self.entity_value(self.defs, 'valid_target_types')
+
+ def _validate_keys(self):
+ for key in self.defs.keys():
+ if key not in self.SECTIONS:
+ ExceptionCollector.appendException(
+ UnknownFieldError(what='Relationshiptype "%s"' % self.type,
+ field=key))
diff --git a/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py b/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py
index be9933e..2f221b3 100644
--- a/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py
+++ b/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py
@@ -35,6 +35,9 @@ class StatefulEntityType(EntityType):
if UnsupportedType.validate_type(entire_entitytype):
self.defs = None
else:
+ if entitytype.startswith(self.TOSCA + ":"):
+ entitytype = entitytype[(len(self.TOSCA) + 1):]
+ entire_entitytype = prefix + entitytype
if not entitytype.startswith(self.TOSCA):
entire_entitytype = prefix + entitytype
if entire_entitytype in list(self.TOSCA_DEF.keys()):
diff --git a/tosca2heat/tosca-parser/toscaparser/entity_template.py b/tosca2heat/tosca-parser/toscaparser/entity_template.py
index 7ce8cec..cc3d620 100644
--- a/tosca2heat/tosca-parser/toscaparser/entity_template.py
+++ b/tosca2heat/tosca-parser/toscaparser/entity_template.py
@@ -68,7 +68,6 @@ class EntityTemplate(object):
' a "type" ''attribute.') % dict(pname=name))
ExceptionCollector.appendException(
ValidationError(msg))
-
self.type_definition = PolicyType(type, custom_def)
if entity_name == 'group_type':
self.type_definition = GroupType(type, custom_def) \
diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml
index 365d70e..365d70e 100644
--- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml
diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py
index 0c7c2b9..24eabab 100644
--- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py
+++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py
@@ -14,6 +14,6 @@
VERSION = 'tosca_simple_profile_for_nfv_1_0_0'
-DEFS_FILE = "TOSCA_nfv_definition_1_0.yaml"
+DEFS_FILE = "TOSCA_nfv_definition_1_0_0.yaml"
SECTIONS = ('metadata')
diff --git a/tosca2heat/tosca-parser/toscaparser/functions.py b/tosca2heat/tosca-parser/toscaparser/functions.py
index 1b64416..d498229 100644
--- a/tosca2heat/tosca-parser/toscaparser/functions.py
+++ b/tosca2heat/tosca-parser/toscaparser/functions.py
@@ -14,6 +14,7 @@
import abc
import six
+import toscaparser.elements.interfaces
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import UnknownInputError
@@ -22,12 +23,14 @@ from toscaparser.elements.constraints import Schema
from toscaparser.elements.datatype import DataType
from toscaparser.elements.entity_type import EntityType
from toscaparser.elements.relationshiptype import RelationshipType
+from toscaparser.elements.statefulentitytype import StatefulEntityType
from toscaparser.utils.gettextutils import _
GET_PROPERTY = 'get_property'
GET_ATTRIBUTE = 'get_attribute'
GET_INPUT = 'get_input'
+GET_OPERATION_OUTPUT = 'get_operation_output'
CONCAT = 'concat'
TOKEN = 'token'
@@ -143,6 +146,8 @@ class GetAttribute(Function):
self._find_node_template_containing_attribute()
else:
node_tpl = self._find_node_template(self.args[0])
+ if node_tpl is None:
+ return
index = 2
attrs = node_tpl.type_definition.get_attributes_def()
found = [attrs[self.args[1]]] if self.args[1] in attrs else []
@@ -202,10 +207,13 @@ class GetAttribute(Function):
"""
return self._find_node_template_containing_attribute()
+ # Attributes can be explicitly created as part of the type definition
+ # or a property name can be implicitly used as an attribute name
def _find_node_template_containing_attribute(self):
node_tpl = self._find_node_template(self.args[0])
if node_tpl and \
- not self._attribute_exists_in_type(node_tpl.type_definition):
+ not self._attribute_exists_in_type(node_tpl.type_definition) \
+ and self.attribute_name not in node_tpl.get_properties():
ExceptionCollector.appendException(
KeyError(_('Attribute "%(att)s" was not found in node '
'template "%(ntpl)s".') %
@@ -229,7 +237,7 @@ class GetAttribute(Function):
target_type = target_node.type_definition
for capability in target_type.get_capabilities_objects():
if capability.type in \
- hosted_on_rel['valid_target_types']:
+ hosted_on_rel['valid_target_types']:
if self._attribute_exists_in_type(target_type):
return target_node
return self._find_host_containing_attribute(
@@ -609,6 +617,88 @@ class GetProperty(Function):
return None
+class GetOperationOutput(Function):
+ def validate(self):
+ if len(self.args) == 4:
+ self._find_node_template(self.args[0])
+ interface_name = self._find_interface_name(self.args[1])
+ self._find_operation_name(interface_name, self.args[2])
+ else:
+ ExceptionCollector.appendException(
+ ValueError(_('Illegal arguments for function "{0}". Expected '
+ 'arguments: "template_name","interface_name",'
+ '"operation_name","output_variable_name"'
+ ).format(GET_OPERATION_OUTPUT)))
+ return
+
+ def _find_interface_name(self, interface_name):
+ if interface_name in toscaparser.elements.interfaces.SECTIONS:
+ return interface_name
+ else:
+ ExceptionCollector.appendException(
+ ValueError(_('Enter a valid interface name'
+ ).format(GET_OPERATION_OUTPUT)))
+ return
+
+ def _find_operation_name(self, interface_name, operation_name):
+ if(interface_name == 'Configure' or
+ interface_name == 'tosca.interfaces.node.relationship.Configure'):
+ if(operation_name in
+ StatefulEntityType.
+ interfaces_relationship_configure_operations):
+ return operation_name
+ else:
+ ExceptionCollector.appendException(
+ ValueError(_('Enter an operation of Configure interface'
+ ).format(GET_OPERATION_OUTPUT)))
+ return
+ elif(interface_name == 'Standard' or
+ interface_name == 'tosca.interfaces.node.lifecycle.Standard'):
+ if(operation_name in
+ StatefulEntityType.interfaces_node_lifecycle_operations):
+ return operation_name
+ else:
+ ExceptionCollector.appendException(
+ ValueError(_('Enter an operation of Standard interface'
+ ).format(GET_OPERATION_OUTPUT)))
+ return
+ else:
+ ExceptionCollector.appendException(
+ ValueError(_('Enter a valid operation name'
+ ).format(GET_OPERATION_OUTPUT)))
+ return
+
+ def _find_node_template(self, node_template_name):
+ if node_template_name == TARGET:
+ if not isinstance(self.context.type_definition, RelationshipType):
+ ExceptionCollector.appendException(
+ KeyError(_('"TARGET" keyword can only be used in context'
+ ' to "Relationships" target node')))
+ return
+ return self.context.target
+ if node_template_name == SOURCE:
+ if not isinstance(self.context.type_definition, RelationshipType):
+ ExceptionCollector.appendException(
+ KeyError(_('"SOURCE" keyword can only be used in context'
+ ' to "Relationships" source node')))
+ return
+ return self.context.source
+ name = self.context.name \
+ if node_template_name == SELF and \
+ not isinstance(self.context, list) \
+ else node_template_name
+ for node_template in self.tosca_tpl.nodetemplates:
+ if node_template.name == name:
+ return node_template
+ ExceptionCollector.appendException(
+ KeyError(_(
+ 'Node template "{0}" was not found.'
+ ).format(node_template_name)))
+
+ def result(self):
+ return self
+
+
class Concat(Function):
"""Validate the function and provide an instance of the function
@@ -687,6 +777,7 @@ function_mappings = {
GET_PROPERTY: GetProperty,
GET_INPUT: GetInput,
GET_ATTRIBUTE: GetAttribute,
+ GET_OPERATION_OUTPUT: GetOperationOutput,
CONCAT: Concat,
TOKEN: Token
}
@@ -724,11 +815,12 @@ def get_function(tosca_tpl, node_template, raw_function):
parsing was unsuccessful.
"""
if is_function(raw_function):
- func_name = list(raw_function.keys())[0]
- if func_name in function_mappings:
- func = function_mappings[func_name]
- func_args = list(raw_function.values())[0]
- if not isinstance(func_args, list):
- func_args = [func_args]
- return func(tosca_tpl, node_template, func_name, func_args)
+ if isinstance(raw_function, dict):
+ func_name = list(raw_function.keys())[0]
+ if func_name in function_mappings:
+ func = function_mappings[func_name]
+ func_args = list(raw_function.values())[0]
+ if not isinstance(func_args, list):
+ func_args = [func_args]
+ return func(tosca_tpl, node_template, func_name, func_args)
return raw_function
diff --git a/tosca2heat/tosca-parser/toscaparser/imports.py b/tosca2heat/tosca-parser/toscaparser/imports.py
index 451c952..b69bf4d 100644
--- a/tosca2heat/tosca-parser/toscaparser/imports.py
+++ b/tosca2heat/tosca-parser/toscaparser/imports.py
@@ -221,7 +221,7 @@ class ImportsLoader(object):
dir_path = os.path.dirname(os.path.abspath(
self.path))
if file_path[0] != '' and dir_path.endswith(
- file_path[0]):
+ file_path[0]):
import_template = dir_path + "/" +\
file_path[2]
if not os.path.isfile(import_template):
diff --git a/tosca2heat/tosca-parser/toscaparser/nodetemplate.py b/tosca2heat/tosca-parser/toscaparser/nodetemplate.py
index 10eae33..ca855ad 100644
--- a/tosca2heat/tosca-parser/toscaparser/nodetemplate.py
+++ b/tosca2heat/tosca-parser/toscaparser/nodetemplate.py
@@ -22,6 +22,7 @@ from toscaparser.common.exception import ValidationError
from toscaparser.dataentity import DataEntity
from toscaparser.elements.interfaces import CONFIGURE
from toscaparser.elements.interfaces import CONFIGURE_SHORTNAME
+from toscaparser.elements.interfaces import INTERFACE_DEF_RESERVED_WORDS
from toscaparser.elements.interfaces import InterfacesDef
from toscaparser.elements.interfaces import LIFECYCLE
from toscaparser.elements.interfaces import LIFECYCLE_SHORTNAME
@@ -54,7 +55,7 @@ class NodeTemplate(EntityTemplate):
def relationships(self):
if not self._relationships:
requires = self.requirements
- if requires:
+ if requires and isinstance(requires, list):
for r in requires:
for r1, value in r.items():
explicit = self._get_explicit_relationship(r, value)
@@ -206,13 +207,15 @@ class NodeTemplate(EntityTemplate):
TypeMismatchError(
what='"requirements" of template "%s"' % self.name,
type='list'))
- for req in requires:
- for r1, value in req.items():
- if isinstance(value, dict):
- self._validate_requirements_keys(value)
- self._validate_requirements_properties(value)
- allowed_reqs.append(r1)
- self._common_validate_field(req, allowed_reqs, 'requirements')
+ else:
+ for req in requires:
+ for r1, value in req.items():
+ if isinstance(value, dict):
+ self._validate_requirements_keys(value)
+ self._validate_requirements_properties(value)
+ allowed_reqs.append(r1)
+ self._common_validate_field(req, allowed_reqs,
+ 'requirements')
def _validate_requirements_properties(self, requirements):
# TODO(anyone): Only occurrences property of the requirements is
@@ -229,7 +232,7 @@ class NodeTemplate(EntityTemplate):
for value in occurrences:
DataEntity.validate_datatype('integer', value)
if len(occurrences) != 2 or not (0 <= occurrences[0] <= occurrences[1]) \
- or occurrences[1] == 0:
+ or occurrences[1] == 0:
ExceptionCollector.appendException(
InvalidPropertyValueError(what=(occurrences)))
@@ -245,23 +248,42 @@ class NodeTemplate(EntityTemplate):
ifaces = self.type_definition.get_value(self.INTERFACES,
self.entity_tpl)
if ifaces:
- for i in ifaces:
- for name, value in ifaces.items():
- if name in (LIFECYCLE, LIFECYCLE_SHORTNAME):
- self._common_validate_field(
- value, InterfacesDef.
- interfaces_node_lifecycle_operations,
- 'interfaces')
- elif name in (CONFIGURE, CONFIGURE_SHORTNAME):
- self._common_validate_field(
- value, InterfacesDef.
- interfaces_relationship_configure_operations,
- 'interfaces')
- else:
- ExceptionCollector.appendException(
- UnknownFieldError(
- what='"interfaces" of template "%s"' %
- self.name, field=name))
+ for name, value in ifaces.items():
+ if name in (LIFECYCLE, LIFECYCLE_SHORTNAME):
+ self._common_validate_field(
+ value, InterfacesDef.
+ interfaces_node_lifecycle_operations,
+ 'interfaces')
+ elif name in (CONFIGURE, CONFIGURE_SHORTNAME):
+ self._common_validate_field(
+ value, InterfacesDef.
+ interfaces_relationship_configure_operations,
+ 'interfaces')
+ elif name in self.type_definition.interfaces.keys():
+ self._common_validate_field(
+ value,
+ self._collect_custom_iface_operations(name),
+ 'interfaces')
+ else:
+ ExceptionCollector.appendException(
+ UnknownFieldError(
+ what='"interfaces" of template "%s"' %
+ self.name, field=name))
+
+ def _collect_custom_iface_operations(self, name):
+ allowed_operations = []
+ nodetype_iface_def = self.type_definition.interfaces[name]
+ allowed_operations.extend(nodetype_iface_def.keys())
+ if 'type' in nodetype_iface_def:
+ iface_type = nodetype_iface_def['type']
+ if iface_type in self.type_definition.custom_def:
+ iface_type_def = self.type_definition.custom_def[iface_type]
+ else:
+ iface_type_def = self.type_definition.TOSCA_DEF[iface_type]
+ allowed_operations.extend(iface_type_def.keys())
+ allowed_operations = [op for op in allowed_operations if
+ op not in INTERFACE_DEF_RESERVED_WORDS]
+ return allowed_operations
def _validate_fields(self, nodetemplate):
for name in nodetemplate.keys():
diff --git a/tosca2heat/tosca-parser/toscaparser/parameters.py b/tosca2heat/tosca-parser/toscaparser/parameters.py
index ca8e697..787db00 100644
--- a/tosca2heat/tosca-parser/toscaparser/parameters.py
+++ b/tosca2heat/tosca-parser/toscaparser/parameters.py
@@ -27,9 +27,10 @@ log = logging.getLogger('tosca')
class Input(object):
- INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, REQUIRED,
- STATUS) = ('type', 'description', 'default',
- 'constraints', 'required', 'status')
+ INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, REQUIRED, STATUS,
+ ENTRY_SCHEMA) = ('type', 'description', 'default',
+ 'constraints', 'required', 'status',
+ 'entry_schema')
def __init__(self, name, schema_dict):
self.name = name
@@ -58,6 +59,10 @@ class Input(object):
def constraints(self):
return self.schema.constraints
+ @property
+ def status(self):
+ return self.schema.status
+
def validate(self, value=None):
if value is not None:
self._validate_value(value)
diff --git a/tosca2heat/tosca-parser/toscaparser/policy.py b/tosca2heat/tosca-parser/toscaparser/policy.py
index 61c09ec..fedbeb4 100644
--- a/tosca2heat/tosca-parser/toscaparser/policy.py
+++ b/tosca2heat/tosca-parser/toscaparser/policy.py
@@ -29,7 +29,8 @@ log = logging.getLogger('tosca')
class Policy(EntityTemplate):
'''Policies defined in Topology template.'''
- def __init__(self, name, policy, targets, targets_type, custom_def=None):
+ def __init__(self, name, policy, targets=None, targets_type=None,
+ custom_def=None):
super(Policy, self).__init__(name,
policy,
'policy_type',
@@ -41,6 +42,9 @@ class Policy(EntityTemplate):
self.targets_list = targets
self.targets_type = targets_type
self.triggers = self._triggers(policy.get(TRIGGERS))
+ self.properties = None
+ if 'properties' in policy:
+ self.properties = policy['properties']
self._validate_keys()
@property
diff --git a/tosca2heat/tosca-parser/toscaparser/shell.py b/tosca2heat/tosca-parser/toscaparser/shell.py
index b41c024..1d98f1a 100644
--- a/tosca2heat/tosca-parser/toscaparser/shell.py
+++ b/tosca2heat/tosca-parser/toscaparser/shell.py
@@ -11,6 +11,7 @@
# under the License.
+import argparse
import os
import sys
@@ -40,19 +41,20 @@ e.g.
class ParserShell(object):
- def _validate(self, args):
- if len(args) < 1:
- msg = _('The program requires a template or a CSAR file as an '
- 'argument. Please refer to the usage documentation.')
- raise ValueError(msg)
- if "--template-file=" not in args[0]:
- msg = _('The program expects "--template-file" as the first '
- 'argument. Please refer to the usage documentation.')
- raise ValueError(msg)
-
- def main(self, args):
- self._validate(args)
- path = args[0].split('--template-file=')[1]
+ def get_parser(self, argv):
+ parser = argparse.ArgumentParser(prog="tosca-parser")
+
+ parser.add_argument('--template-file',
+ metavar='<filename>',
+ required=True,
+ help=_('YAML template or CSAR file to parse.'))
+
+ return parser
+
+ def main(self, argv):
+ parser = self.get_parser(argv)
+ (args, extra_args) = parser.parse_known_args(argv)
+ path = args.template_file
if os.path.isfile(path):
self.parse(path)
elif toscaparser.utils.urlutils.UrlUtils.validate_url(path):
@@ -88,6 +90,18 @@ class ParserShell(object):
for node in nodetemplates:
print("\t" + node.name)
+ # example of retrieving policy object
+ '''if hasattr(tosca, 'policies'):
+ policies = tosca.policies
+ if policies:
+ print("policies:")
+ for policy in policies:
+ print("\t" + policy.name)
+ if policy.triggers:
+ print("\ttriggers:")
+ for trigger in policy.triggers:
+ print("\ttrigger name:" + trigger.name)'''
+
if hasattr(tosca, 'outputs'):
outputs = tosca.outputs
if outputs:
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/base.py b/tosca2heat/tosca-parser/toscaparser/tests/base.py
index f6ff8d1..2619889 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/base.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/base.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar
index 5fae801..a514dc6 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar
Binary files differ
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip
index 5fae801..0d860d4 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip
Binary files differ
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml
new file mode 100644
index 0000000..3fd4466
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml
@@ -0,0 +1,44 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with mysql docker container.
+
+# Repositories to retrieve code artifacts from
+repositories:
+ docker_hub: https://registry.hub.docker.com/
+
+topology_template:
+
+ inputs:
+ mysql_root_pwd:
+ type: string
+ description: Root password for MySQL.
+
+ node_templates:
+ # The MYSQL container based on official MySQL image in Docker hub
+ mysql_container:
+ type: tosca.nodes.Container.Application.Docker
+ requirements:
+ - host: mysql_runtime
+ artifacts:
+ my_image:
+ file: mysql
+ type: tosca.artifacts.Deployment.Image.Container.Docker
+ repository: docker_hub
+ interfaces:
+ Standard:
+ create:
+ implementation: my_image
+ inputs:
+ MYSQL_ROOT_PASSWORD: { get_input: mysql_root_pwd }
+
+ # The properties of the runtime to host the container
+ mysql_runtime:
+ type: tosca.nodes.Container.Runtime
+ capabilities:
+ host:
+ properties:
+ num_cpus: 1
+ disk_size: 10 GB
+ mem_size: 2 MB
+
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml
index f23a8a1..909a297 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml
@@ -1,6 +1,6 @@
tosca_definitions_version: tosca_simple_yaml_1_0
-description: Compute node type with capability with an atribute of type list
+description: Compute node type with capability with an attribute of type list
capability_types:
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml
new file mode 100644
index 0000000..2d9bec4
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml
@@ -0,0 +1,20 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ This template contains custom defined interface type
+ and a node type which uses this custom interface
+
+interface_types:
+ tosca.interfaces.CustomInterface:
+ derived_from: tosca.interfaces.Root
+ CustomOp:
+ CustomOp2:
+
+node_types:
+ tosca.nodes.CustomInterfaceTest:
+ derived_from: tosca.nodes.WebApplication
+ interfaces:
+ CustomInterface:
+ type: tosca.interfaces.CustomInterface
+ CustomOp3:
+
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml
index 70d0b0f..c8e4532 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml
@@ -32,3 +32,7 @@ policy_types:
type: map
entry_schema:
type: string
+relationship_types1:
+relationship_types:
+ test.relation.connects:
+ derived_from4: tosca.relationships.ConnectsTo
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml
new file mode 100644
index 0000000..6155595
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml
@@ -0,0 +1,23 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Test template demonstrating usage of nested dsl_definitions value.
+
+dsl_definitions:
+ caps: &caps
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 2
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+topology_template:
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities: *caps \ No newline at end of file
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml
index 923305c..34c1c33 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml
@@ -26,3 +26,5 @@ topology_template:
outputs:
ip_address:
value: { get_attribute: [ unknown_node_template, private_address ] }
+ network:
+ value: { get_attribute: [ unknown_node_template, networks, public ] }
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml
new file mode 100644
index 0000000..a269005
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Attribute can be defined explicitly as part of type definition
+ or implicitly via property. This TOSCA template tests validation
+ of attribute name implicitly created as a property and referenced
+ via get_attribute function.
+
+node_types:
+ ServerNode:
+ derived_from: SoftwareComponent
+ properties:
+ notification_port:
+ type: integer
+
+topology_template:
+ node_templates:
+ my_server:
+ type: ServerNode
+ properties:
+ notification_port: 8000
+
+ outputs:
+ ip_address:
+ value: { get_attribute: [ my_server, notification_port ] } \ No newline at end of file
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml
index 1e5f5e6..1ca69ca 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml
@@ -23,7 +23,6 @@ topology_template:
db_root_pwd:
type: string
description: Root password for MySQL.
- default: '12345678'
db_port:
type: PortDef
description: Port for the MySQL database.
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml
new file mode 100644
index 0000000..c23917c
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml
@@ -0,0 +1,23 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with valid custom interface and operations.
+
+imports:
+ - ../custom_types/custom_interface.yaml
+
+topology_template:
+
+ node_templates:
+ customInterfaceTest:
+ type: tosca.nodes.CustomInterfaceTest
+ interfaces:
+ CustomInterface:
+ CustomOp: # operation from interface_type with additional inputs
+ inputs:
+ param:
+ type: string
+ CustomOp3: # operation from node_type with additional inputs
+ inputs:
+ param3:
+ type: string
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml
new file mode 100644
index 0000000..d56ad9c
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with invalid custom operation.
+
+imports:
+ - ../custom_types/custom_interface.yaml
+
+topology_template:
+
+ node_templates:
+ customInterfaceTest:
+ type: tosca.nodes.CustomInterfaceTest
+ interfaces:
+ CustomInterface:
+ CustomOp4: # invalid operation
+ inputs:
+ param3:
+ type: string
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml
new file mode 100644
index 0000000..2fcdb48
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml
@@ -0,0 +1,75 @@
+# Note: this could eventually be translated to a Neutron Load Balancer
+# However, in Heat/HOT the preferred way of doing this is creating an Autoscale Group
+#
+#heat_template_version: 2015-04-30 ...
+#resources:
+#load_bal_resource:
+# type: OS::Neutron::Pool
+# properties:
+# admin_state_up: Boolean
+# description: String
+# lb_method: String
+# monitors: [Value, Value, ...]
+# name: String
+# protocol: String
+# provider: String
+# subnet: String
+# vip: {
+# "description": String,
+# "name": String,
+# "connection_limit": Integer,
+# "protocol_port": Integer,
+# "subnet": String,
+# "address": String,
+# "admin_state_up": Boolean,
+# "session_persistence":
+# {
+# "cookie_name": String,
+# "type": String}
+# }
+#
+# example from: https://gist.github.com/therve/9231701
+#
+#resources:
+# web_server_group:
+# type: AWS::AutoScaling::AutoScalingGroup
+# properties:
+# AvailabilityZones: [nova]
+# LaunchConfigurationName: {get_resource: launch_config}
+# MinSize: 1
+# MaxSize: 3
+# LoadBalancerNames:
+# - {get_resource: mylb}
+# mypool:
+# type: OS::Neutron::Pool
+# properties:
+# protocol: HTTP
+# monitors: [{get_resource: mymonitor}]
+# subnet_id: {get_param: subnet_id}
+# lb_method: ROUND_ROBIN
+# vip:
+# protocol_port: 80
+# mylb:
+# type: OS::Neutron::LoadBalancer
+# properties:
+# protocol_port: 80
+# pool_id: {get_resource: mypool}
+
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a load balancer with predefined endpoint properties.
+
+topology_template:
+ node_templates:
+ simple_load_balancer:
+ type: tosca.nodes.LoadBalancer
+ capabilities:
+ # properties:
+ # algorithm: DEFAULT (define new keyword, ROUND_ROBIN?)
+ # Client, public facing endpoint
+ client:
+ properties:
+ network_name: PUBLIC
+ floating: true
+ dns_name: http://mycompany.com/
+
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml
new file mode 100644
index 0000000..3dd8e26
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml
@@ -0,0 +1,18 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template with requirements against hosting infrastructure.
+
+topology_template:
+
+ node_templates:
+ test:
+ type: tosca.nodes.DBMS
+ requirements:
+ - host:
+ node_filter:
+ capabilities:
+ - host:
+ properties:
+ - num_cpus: { in_range: [ 1, 4 ] }
+ - mem_size: { greater_or_equal: 2 GB }
+
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml
new file mode 100644
index 0000000..96b0d45
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml
@@ -0,0 +1,183 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+data_types:
+ tosca.datatypes.tacker.ActionMap:
+ properties:
+ trigger:
+ type: string
+ required: true
+ action:
+ type: string
+ required: true
+ params:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+
+ tosca.datatypes.tacker.MonitoringParams:
+ properties:
+ monitoring_delay:
+ type: int
+ required: false
+ count:
+ type: int
+ required: false
+ interval:
+ type: int
+ required: false
+ timeout:
+ type: int
+ required: false
+ retry:
+ type: int
+ required: false
+ port:
+ type: int
+ required: false
+
+ tosca.datatypes.tacker.MonitoringType:
+ properties:
+ name:
+ type: string
+ required: true
+ actions:
+ type: map
+ required: true
+ parameters:
+ type: tosca.datatypes.tacker.MonitoringParams
+ required: false
+
+ tosca.datatypes.compute_properties:
+ properties:
+ num_cpus:
+ type: integer
+ required: false
+ mem_size:
+ type: string
+ required: false
+ disk_size:
+ type: string
+ required: false
+ mem_page_size:
+ type: string
+ required: false
+ numa_node_count:
+ type: integer
+ constraints:
+ - greater_or_equal: 2
+ required: false
+ numa_nodes:
+ type: map
+ required: false
+ cpu_allocation:
+ type: map
+ required: false
+
+policy_types:
+ tosca.policies.tacker.Placement:
+ derived_from: tosca.policies.Root
+
+ tosca.policies.tacker.Failure:
+ derived_from: tosca.policies.Root
+ action:
+ type: string
+
+ tosca.policies.tacker.Failure.Respawn:
+ derived_from: tosca.policies.tacker.Failure
+ action: respawn
+
+ tosca.policies.tacker.Failure.Terminate:
+ derived_from: tosca.policies.tacker.Failure
+ action: log_and_kill
+
+ tosca.policies.tacker.Failure.Log:
+ derived_from: tosca.policies.tacker.Failure
+ action: log
+
+ tosca.policies.tacker.Monitoring:
+ derived_from: tosca.policies.Root
+ properties:
+ name:
+ type: string
+ required: true
+ parameters:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ actions:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+
+ tosca.policies.tacker.Monitoring.NoOp:
+ derived_from: tosca.policies.tacker.Monitoring
+ properties:
+ name: noop
+
+ tosca.policies.tacker.Monitoring.Ping:
+ derived_from: tosca.policies.tacker.Monitoring
+ properties:
+ name: ping
+
+ tosca.policies.tacker.Monitoring.HttpPing:
+ derived_from: tosca.policies.tacker.Monitoring.Ping
+ properties:
+ name: http-ping
+
+ tosca.policies.tacker.Alarming:
+ derived_from: tosca.policies.Monitoring
+ triggers:
+ resize_compute:
+ event_type:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+ metrics:
+ type: string
+ required: true
+ condition:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ action:
+ type: map
+ entry_schema:
+ type: string
+ required: true
+
+ tosca.policies.tacker.Scaling:
+ derived_from: tosca.policies.Scaling
+ description: Defines policy for scaling the given targets.
+ properties:
+ increment:
+ type: integer
+ required: true
+ description: Number of nodes to add or remove during the scale out/in.
+ targets:
+ type: list
+ entry_schema:
+ type: string
+ required: true
+ description: List of Scaling nodes.
+ min_instances:
+ type: integer
+ required: true
+ description: Minimum number of instances to scale in.
+ max_instances:
+ type: integer
+ required: true
+ description: Maximum number of instances to scale out.
+ default_instances:
+ type: integer
+ required: true
+ description: Initial number of instances.
+ cooldown:
+ type: integer
+ required: false
+ default: 120
+ description: Wait time (in seconds) between consecutive scaling operations. During the cooldown period...
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml
new file mode 100644
index 0000000..1387509
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml
@@ -0,0 +1,261 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+data_types:
+ tosca.nfv.datatypes.pathType:
+ properties:
+ forwarder:
+ type: string
+ required: true
+ capability:
+ type: string
+ required: true
+
+ tosca.nfv.datatypes.aclType:
+ properties:
+ eth_type:
+ type: string
+ required: false
+ eth_src:
+ type: string
+ required: false
+ eth_dst:
+ type: string
+ required: false
+ vlan_id:
+ type: integer
+ constraints:
+ - in_range: [ 1, 4094 ]
+ required: false
+ vlan_pcp:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7 ]
+ required: false
+ mpls_label:
+ type: integer
+ constraints:
+ - in_range: [ 16, 1048575]
+ required: false
+ mpls_tc:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7 ]
+ required: false
+ ip_dscp:
+ type: integer
+ constraints:
+ - in_range: [ 0, 63 ]
+ required: false
+ ip_ecn:
+ type: integer
+ constraints:
+ - in_range: [ 0, 3 ]
+ required: false
+ ip_src_prefix:
+ type: string
+ required: false
+ ip_dst_prefix:
+ type: string
+ required: false
+ ip_proto:
+ type: integer
+ constraints:
+ - in_range: [ 1, 254 ]
+ required: false
+ destination_port_range:
+ type: string
+ required: false
+ source_port_range:
+ type: string
+ required: false
+ network_src_port_id:
+ type: string
+ required: false
+ network_dst_port_id:
+ type: string
+ required: false
+ network_id:
+ type: string
+ required: false
+ network_name:
+ type: string
+ required: false
+ tenant_id:
+ type: string
+ required: false
+ icmpv4_type:
+ type: integer
+ constraints:
+ - in_range: [ 0, 254 ]
+ required: false
+ icmpv4_code:
+ type: integer
+ constraints:
+ - in_range: [ 0, 15 ]
+ required: false
+ arp_op:
+ type: integer
+ constraints:
+ - in_range: [ 1, 25 ]
+ required: false
+ arp_spa:
+ type: string
+ required: false
+ arp_tpa:
+ type: string
+ required: false
+ arp_sha:
+ type: string
+ required: false
+ arp_tha:
+ type: string
+ required: false
+ ipv6_src:
+ type: string
+ required: false
+ ipv6_dst:
+ type: string
+ required: false
+ ipv6_flabel:
+ type: integer
+ constraints:
+ - in_range: [ 0, 1048575]
+ required: false
+ icmpv6_type:
+ type: integer
+ constraints:
+ - in_range: [ 0, 255]
+ required: false
+ icmpv6_code:
+ type: integer
+ constraints:
+ - in_range: [ 0, 7]
+ required: false
+ ipv6_nd_target:
+ type: string
+ required: false
+ ipv6_nd_sll:
+ type: string
+ required: false
+ ipv6_nd_tll:
+ type: string
+ required: false
+
+ tosca.nfv.datatypes.policyType:
+ properties:
+ type:
+ type: string
+ required: false
+ constraints:
+ - valid_values: [ ACL ]
+ criteria:
+ type: list
+ required: true
+ entry_schema:
+ type: tosca.nfv.datatypes.aclType
+
+node_types:
+ tosca.nodes.nfv.VDU.Tacker:
+ derived_from: tosca.nodes.nfv.VDU
+ capabilities:
+ nfv_compute:
+ type: tosca.datatypes.compute_properties
+ properties:
+ name:
+ type: string
+ required: false
+ image:
+# type: tosca.artifacts.Deployment.Image.VM
+ type: string
+ required: false
+ flavor:
+ type: string
+ required: false
+ availability_zone:
+ type: string
+ required: false
+ metadata:
+ type: map
+ entry_schema:
+ type: string
+ required: false
+ config_drive:
+ type: boolean
+ default: false
+ required: false
+
+ placement_policy:
+# type: tosca.policies.tacker.Placement
+ type: string
+ required: false
+
+ monitoring_policy:
+# type: tosca.policies.tacker.Monitoring
+# type: tosca.datatypes.tacker.MonitoringType
+ type: map
+ required: false
+
+ config:
+ type: string
+ required: false
+
+ mgmt_driver:
+ type: string
+ default: noop
+ required: false
+
+ service_type:
+ type: string
+ required: false
+
+ user_data:
+ type: string
+ required: false
+
+ user_data_format:
+ type: string
+ required: false
+
+ key_name:
+ type: string
+ required: false
+
+ tosca.nodes.nfv.CP.Tacker:
+ derived_from: tosca.nodes.nfv.CP
+ properties:
+ mac_address:
+ type: string
+ required: false
+ name:
+ type: string
+ required: false
+ management:
+ type: boolean
+ required: false
+ anti_spoofing_protection:
+ type: boolean
+ required: false
+ security_groups:
+ type: list
+ required: false
+ type:
+ type: string
+ required: false
+ constraints:
+ - valid_values: [ sriov, vnic ]
+
+ tosca.nodes.nfv.FP.Tacker:
+ derived_from: tosca.nodes.Root
+ properties:
+ id:
+ type: integer
+ required: false
+ policy:
+ type: tosca.nfv.datatypes.policyType
+ required: true
+ description: policy to use to match traffic for this FP
+ path:
+ type: list
+ required: true
+ entry_schema:
+ type: tosca.nfv.datatypes.pathType
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml
new file mode 100644
index 0000000..452dbb5
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml
@@ -0,0 +1,95 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
+
+description: sample-tosca-vnfd-scaling
+
+imports:
+ - tacker_defs.yaml
+ - tacker_nfv_defs.yaml
+
+metadata:
+ template_name: sample-tosca-vnfd-scaling
+
+topology_template:
+ node_templates:
+ VDU1:
+ type: tosca.nodes.nfv.VDU.Tacker
+ properties:
+ image: cirros-0.3.4-x86_64-uec
+ mgmt_driver: noop
+ availability_zone: nova
+ flavor: m1.tiny
+
+ CP1:
+ type: tosca.nodes.nfv.CP.Tacker
+ properties:
+ management: true
+ order: 0
+ anti_spoofing_protection: false
+ requirements:
+ - virtualLink:
+ node: VL1
+ - virtualBinding:
+ node: VDU1
+
+ VDU2:
+ type: tosca.nodes.nfv.VDU.Tacker
+ properties:
+ image: cirros-0.3.4-x86_64-uec
+ mgmt_driver: noop
+ availability_zone: nova
+ flavor: m1.tiny
+
+ CP2:
+ type: tosca.nodes.nfv.CP.Tacker
+ properties:
+ management: true
+ order: 0
+ anti_spoofing_protection: false
+ requirements:
+ - virtualLink:
+ node: VL1
+ - virtualBinding:
+ node: VDU2
+
+ VL1:
+ type: tosca.nodes.nfv.VL
+ properties:
+ network_name: net_mgmt
+ vendor: Tacker
+
+ policies:
+ - SP1:
+ type: tosca.policies.tacker.Scaling
+ targets: [VDU1]
+ properties:
+ increment: 1
+ cooldown: 120
+ min_instances: 1
+ max_instances: 2
+ default_instances: 1
+
+ - SP2:
+ type: tosca.policies.tacker.Scaling
+ targets: [VDU2]
+ properties:
+ increment: 1
+ cooldown: 120
+ min_instances: 1
+ max_instances: 2
+ default_instances: 1
+
+ - ALRM1:
+ type: tosca.policies.tacker.Monitoring
+ triggers:
+ resize_compute:
+ event_type:
+ type: tosca.events.resource.utilization
+ implementation: ceilometer
+ condition:
+ constraint: 50
+ period: 600
+ evaluations: 1
+ method: avg
+ action:
+ resize_compute:
+ action_name: SP1
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml
index 92bebe5..47f7870 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml
@@ -66,7 +66,7 @@ topology_template:
requirement: host
capability: Container
condition:
- constraint: utilization greater_than 50%
+ constraint: { greater_than: 50 }
period: 60
evaluations: 1
method: average
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml
new file mode 100644
index 0000000..81b92b4
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml
@@ -0,0 +1,48 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Test template for deploying a single server with predefined properties and custom relationship types
+
+imports:
+ - ../custom_types/custom_relationship_type_defs.yaml
+
+topology_template:
+ node_templates:
+ server1:
+ type: tosca.nodes.HACompute
+ capabilities:
+ # Host container properties
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ requirements:
+ - high_availability: server2
+
+ server2:
+ type: tosca.nodes.HACompute
+ capabilities:
+ # Host container properties
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ requirements:
+ - high_availability: server1
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml
new file mode 100644
index 0000000..c2856c8
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml
@@ -0,0 +1,23 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+repositories:
+ some_repository:
+ description: Some repo
+ url: https://raw.githubusercontent.com/openstack/tosca-parser/master/toscaparser/tests/data/custom_types/
+ credential: #type: Credential
+ token_type: basic_auth
+ token: myusername:mypassword
+imports:
+ - some_import:
+ file: compute_with_prop.yaml
+ repository: some_repository
+
+description: >
+ TOSCA test for testing repositories definition
+
+ node_templates:
+
+ server:
+ type: tosca.nodes.ComputeWithProp
+ properties:
+ test: yes
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml
new file mode 100644
index 0000000..0001d06
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml
@@ -0,0 +1,26 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: TOSCA simple profile with repositories validation and imports.
+
+repositories:
+ repo_code0: https://raw.githubusercontent.com/nandinivemula/intern
+ repo_code1:
+ description: My project's code Repository in github usercontent.
+ url: https://raw.githubusercontent.com/nandinivemula/intern/master
+ credential: #type: Credential
+ token_type: basic_auth
+ token: myusername:mypassword
+
+ repo_code2:
+ description: My Project's code Repository in github.
+ url: https://github.com/nandinivemula/intern/master
+ credential: #type: Credential
+ token_type: basic_auth
+ token: myusername:mypassword
+
+imports:
+ - sample_import:
+ file: tosca_repository_import.yaml
+ repository: repo_code1
+ namespace_uri: https://github.com/nandinivemula/intern
+ namespace_prefix: intern
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml
new file mode 100644
index 0000000..bb67577
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml
@@ -0,0 +1,67 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Test Requirements.
+
+imports:
+ - ../custom_types/wordpress.yaml
+
+topology_template:
+ node_templates:
+ my_app:
+ description: >
+ Specify multiple requirement via node and relationship keyword,
+ as an explicit relationship. Also demonstrates relationship with
+ type keyword and without it as an in-line reference.
+ type: tosca.nodes.WebApplication.WordPress
+ requirements:
+ - req1:
+ node: my_webserver
+ relationship: tosca.relationships.HostedOn
+ - req2:
+ node: mysql_database
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ mysql_database:
+ description: Specify requirement via a capability as an implicit relationship.
+ type: tosca.nodes.Database
+ requirements:
+ - host:
+ node: my_dbms
+ relationship: tosca.relationships.HostedOn
+ my_dbms:
+ type: tosca.nodes.DBMS
+ my_webserver:
+ type: tosca.nodes.WebServer
+ my_server:
+ description: >
+ Specify requirement via a relationship template, as an explicit relationship.
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 4 MB
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: linux
+ distribution: rhel
+ version: 6.5
+ requirements:
+ - req1:
+ node: my_storage
+ relationship: storage_attachment
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: 1 GiB
+ snapshot_id: id
+
+ relationship_templates:
+ storage_attachment:
+ type: tosca.relationships.AttachesTo
+ properties:
+ location: /temp
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml
new file mode 100644
index 0000000..cf2ec94
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml
@@ -0,0 +1,21 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+topology_template:
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+ endpoint:
+ properties:
+ network_name: PUBLIC
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml
index ccae4eb..479a1ec 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml
@@ -35,6 +35,9 @@ topology_template:
default: 3306
node_templates:
+ xyz:
+ type: tosca.nodes.XYZ
+
wordpress:
type: tosca.nodes.WebApplication.WordPress
requirement:
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml
new file mode 100644
index 0000000..3c3e272
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml
@@ -0,0 +1,37 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Test template for deploying a server with custom properties for image,
+ flavor and key_name. This template provides an example of how to
+ override TOSCA normative type's (e.g. Compute) properties. Here new
+ properties are injected in the tosca.nodes.myserver which derives from
+ tosca.nodes.Compute. Note that tosca.nodes.myserver can not be a name of
+ another normative type (e.g. tosca.nodes.WebServer or tosca.nodes.nfv.VDU)
+ because that will create conflict while resolving type definition by the
+ TOSCA Parser.
+
+node_types:
+ tosca.nodes.myserver:
+ derived_from: tosca.nodes.Compute
+ properties:
+ key_name:
+ type: string
+ image:
+ type: string
+ flavor:
+ type: string
+
+topology_template:
+ inputs:
+ key_name:
+ type: string
+ default: inputkey
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.myserver
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ key_name:
+ get_input: key_name
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml
index 77829c6..ba5eac1 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml
@@ -27,8 +27,10 @@ node_types:
properties:
mq_server_ip:
type: string
+ required: False
receiver_port:
type: integer
+ required: False
attributes:
receiver_ip:
type: string
@@ -51,8 +53,10 @@ node_types:
properties:
admin_user:
type: string
+ required: False
pool_size:
type: integer
+ required: False
capabilities:
message_receiver:
type: example.capabilities.Receiver
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml
new file mode 100644
index 0000000..718022a
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml
@@ -0,0 +1,70 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Template showing an example TOSCA type to demonstrate usage
+ of output in the substitution mappings.
+
+node_types:
+ example.app:
+ derived_from: tosca.nodes.WebApplication
+ properties:
+ mq_server_ip:
+ type: string
+ required: False
+ receiver_port:
+ type: integer
+ required: False
+ attributes:
+ receiver_ip:
+ type: string
+ receiver_port:
+ type: integer
+
+topology_template:
+ inputs:
+ mq_server_ip:
+ type: string
+ description: IP address of the message queuing server to receive messages from.
+ default: 127.0.0.1
+ receiver_port:
+ type: integer
+ description: Port to be used for receiving messages.
+ default: 8080
+ my_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ default: 2
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+
+ substitution_mappings:
+ node_type: example.app
+
+ node_templates:
+ app:
+ type: example.app
+ properties:
+ mq_server_ip: { get_input: mq_server_ip }
+ receiver_port: { get_input: receiver_port }
+ requirements:
+ - host:
+ node: websrv
+ websrv:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host:
+ node: server
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: my_cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml
new file mode 100644
index 0000000..ef21811
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+ - test_example_app_substitution_mappings.yaml
+
+topology_template:
+ description: >
+ Test template showing valid output section containing attribute defined
+ in the substitution mappings in the imported yaml file.
+
+ inputs:
+ mq_server_ip:
+ type: string
+ default: 127.0.0.1
+ description: IP address of the message queuing server to receive messages from.
+ mq_server_port:
+ type: integer
+ default: 8080
+ description: Port to be used for receiving messages.
+
+ node_templates:
+ substitute_app:
+ type: example.app
+ properties:
+ mq_server_ip: { get_input: mq_server_ip }
+ receiver_port: { get_input: mq_server_port }
+
+ outputs:
+ receiver_ip:
+ description: private IP address of the message receiver application
+ value: { get_attribute: [ substitute_app, my_cpu_output ] } \ No newline at end of file
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml
new file mode 100644
index 0000000..766ca87
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+ - test_example_app_substitution_mappings.yaml
+
+topology_template:
+ description: >
+ Test template showing valid output section containing attribute defined
+ in the substitution mappings in the imported yaml file.
+
+ inputs:
+ mq_server_ip:
+ type: string
+ default: 127.0.0.1
+ description: IP address of the message queuing server to receive messages from.
+ mq_server_port:
+ type: integer
+ default: 8080
+ description: Port to be used for receiving messages.
+
+ node_templates:
+ sustitute_app:
+ type: example.app
+ properties:
+ mq_server_ip: { get_input: mq_server_ip }
+ receiver_port: { get_input: mq_server_port }
+
+ outputs:
+ receiver_ip:
+ description: private IP address of the message receiver application
+ value: { get_attribute: [ sustitute_app, receiver_ip ] } \ No newline at end of file
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml
index 9c3fef4..257beb8 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml
@@ -37,3 +37,9 @@ topology_template:
metadata:
user1: 1001
user2: 1003
+ relationship_templates:
+ my_custom_rel:
+ type: test.relation.connects
+ interfaces:
+ Configure:
+ pre_configure_source: scripts/wp_db_configure.sh
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml
index f605b05..9e686ab 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml
@@ -29,7 +29,6 @@ topology_template:
db_root_pwd:
type: string
description: Root password for MySQL.
- default: '12345678'
db_port:
type: PortDef
description: Port for the MySQL database.
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
index 9a57eb0..6caac11 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
@@ -31,7 +31,6 @@ topology_template:
db_root_pwd:
type: string
description: Root password for MySQL.
- default: '12345678'
db_port:
type: PortDef
description: Port for the MySQL database.
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
index 5d41749..e5f1580 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
@@ -29,7 +29,6 @@ topology_template:
db_root_pwd:
type: string
description: Root password for MySQL.
- default: '12345678'
db_port:
type: PortDef
description: Port for the MySQL database.
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml
new file mode 100644
index 0000000..f47f33c
--- /dev/null
+++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: TOSCA simple profile to test the GET OPERATION OUTPUT functionality
+
+imports:
+ - custom_types/compute_with_prop.yaml
+
+topology_template:
+
+ node_templates:
+
+ front_end:
+ type: tosca.nodes.ComputeWithProp
+ interfaces:
+ Standard:
+ create:
+ implementation: nodejs/create.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end,Standard,create,data_dir]}
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py b/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py
index 71de0c2..9ae85d5 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py
@@ -21,7 +21,7 @@ class CustomRelationshipTypesTest(TestCase):
'''TOSCA template.'''
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/test_custom_relationships.yaml")
+ "data/relationship/test_custom_relationship.yaml")
tosca = ToscaTemplate(tosca_tpl)
def test_version(self):
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py
index 81de909..fa60140 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py
@@ -24,7 +24,8 @@ class IntrinsicFunctionsTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml")
- params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user'}
+ params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
+ 'db_root_pwd': '12345678'}
tosca = ToscaTemplate(tosca_tpl, parsed_params=params)
def _get_node(self, node_name, tosca=None):
@@ -56,7 +57,7 @@ class IntrinsicFunctionsTest(TestCase):
wordpress = self._get_node('wordpress')
operation = self._get_operation(wordpress.interfaces, 'configure')
wp_db_password = operation.inputs['wp_db_password']
- self.assertTrue(isinstance(wp_db_password, functions.GetProperty))
+ self.assertIsInstance(wp_db_password, functions.GetProperty)
result = wp_db_password.result()
self.assertEqual('wp_pass', result)
@@ -64,7 +65,7 @@ class IntrinsicFunctionsTest(TestCase):
wordpress = self._get_node('wordpress')
operation = self._get_operation(wordpress.interfaces, 'configure')
wp_db_user = operation.inputs['wp_db_user']
- self.assertTrue(isinstance(wp_db_user, functions.GetProperty))
+ self.assertIsInstance(wp_db_user, functions.GetProperty)
result = wp_db_user.result()
self.assertEqual('my_db_user', result)
@@ -83,7 +84,7 @@ class IntrinsicFunctionsTest(TestCase):
props = mysql_dbms.get_properties()
for key in props.keys():
prop = props[key]
- self.assertTrue(isinstance(prop.value, functions.GetInput))
+ self.assertIsInstance(prop.value, functions.GetInput)
expected_inputs.remove(prop.value.input_name)
self.assertListEqual(expected_inputs, [])
@@ -116,21 +117,24 @@ class IntrinsicFunctionsTest(TestCase):
self.assertEqual(3306, dbms_port.result())
dbms_root_password = self._get_property(mysql_dbms,
'root_password')
- self.assertEqual(dbms_root_password.result(), "12345678")
+ self.assertEqual(dbms_root_password.result(), '12345678')
def test_get_property_with_host(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/test_get_property_with_host.yaml")
mysql_database = self._get_node('mysql_database',
- ToscaTemplate(tosca_tpl))
+ ToscaTemplate(tosca_tpl,
+ parsed_params={
+ 'db_root_pwd': '123'
+ }))
operation = self._get_operation(mysql_database.interfaces, 'configure')
db_port = operation.inputs['db_port']
- self.assertTrue(isinstance(db_port, functions.GetProperty))
+ self.assertIsInstance(db_port, functions.GetProperty)
result = db_port.result()
self.assertEqual(3306, result)
test = operation.inputs['test']
- self.assertTrue(isinstance(test, functions.GetProperty))
+ self.assertIsInstance(test, functions.GetProperty)
result = test.result()
self.assertEqual(1, result)
@@ -138,30 +142,37 @@ class IntrinsicFunctionsTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/tosca_nested_property_names_indexes.yaml")
- webserver = self._get_node('wordpress', ToscaTemplate(tosca_tpl))
+ webserver = self._get_node('wordpress',
+ ToscaTemplate(tosca_tpl,
+ parsed_params={
+ 'db_root_pwd': '1234'}))
operation = self._get_operation(webserver.interfaces, 'configure')
wp_endpoint_prot = operation.inputs['wp_endpoint_protocol']
- self.assertTrue(isinstance(wp_endpoint_prot, functions.GetProperty))
+ self.assertIsInstance(wp_endpoint_prot, functions.GetProperty)
self.assertEqual('tcp', wp_endpoint_prot.result())
wp_list_prop = operation.inputs['wp_list_prop']
- self.assertTrue(isinstance(wp_list_prop, functions.GetProperty))
+ self.assertIsInstance(wp_list_prop, functions.GetProperty)
self.assertEqual(3, wp_list_prop.result())
def test_get_property_with_capabilties_inheritance(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/test_capabilties_inheritance.yaml")
- some_node = self._get_node('some_node', ToscaTemplate(tosca_tpl))
+ some_node = self._get_node('some_node',
+ ToscaTemplate(tosca_tpl,
+ parsed_params={
+ 'db_root_pwd': '1234'}))
operation = self._get_operation(some_node.interfaces, 'configure')
some_input = operation.inputs['some_input']
- self.assertTrue(isinstance(some_input, functions.GetProperty))
+ self.assertIsInstance(some_input, functions.GetProperty)
self.assertEqual('someval', some_input.result())
def test_get_property_source_target_keywords(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/test_get_property_source_target_keywords.yaml")
- tosca = ToscaTemplate(tosca_tpl)
+ tosca = ToscaTemplate(tosca_tpl,
+ parsed_params={'db_root_pwd': '1234'})
for node in tosca.nodetemplates:
for relationship, trgt in node.relationships.items():
@@ -171,10 +182,10 @@ class IntrinsicFunctionsTest(TestCase):
operation = self._get_operation(rel_template.interfaces,
'pre_configure_source')
target_test = operation.inputs['target_test']
- self.assertTrue(isinstance(target_test, functions.GetProperty))
+ self.assertIsInstance(target_test, functions.GetProperty)
self.assertEqual(1, target_test.result())
source_port = operation.inputs['source_port']
- self.assertTrue(isinstance(source_port, functions.GetProperty))
+ self.assertIsInstance(source_port, functions.GetProperty)
self.assertEqual(3306, source_port.result())
@@ -184,7 +195,8 @@ class GetAttributeTest(TestCase):
return ToscaTemplate(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'data',
- filename))
+ filename),
+ parsed_params={'db_root_pwd': '1234'})
def _get_operation(self, interfaces, operation):
return [
@@ -283,7 +295,8 @@ class GetAttributeTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/functions/test_get_attribute_source_target_keywords.yaml")
- tosca = ToscaTemplate(tosca_tpl)
+ tosca = ToscaTemplate(tosca_tpl,
+ parsed_params={'db_root_pwd': '12345678'})
for node in tosca.nodetemplates:
for relationship, trgt in node.relationships.items():
@@ -293,14 +306,18 @@ class GetAttributeTest(TestCase):
operation = self._get_operation(rel_template.interfaces,
'pre_configure_source')
target_test = operation.inputs['target_test']
- self.assertTrue(isinstance(target_test, functions.GetAttribute))
+ self.assertIsInstance(target_test, functions.GetAttribute)
source_port = operation.inputs['source_port']
- self.assertTrue(isinstance(source_port, functions.GetAttribute))
+ self.assertIsInstance(source_port, functions.GetAttribute)
def test_get_attribute_with_nested_params(self):
self._load_template(
'functions/test_get_attribute_with_nested_params.yaml')
+ def test_implicit_attribute(self):
+ self.assertIsNotNone(self._load_template(
+ 'functions/test_get_implicit_attribute.yaml'))
+
class ConcatTest(TestCase):
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py b/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py
index fcd1c83..09a24b6 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py
@@ -243,7 +243,7 @@ class GetNumFromScalarUnitSizeNegative(TestCase):
(ScalarUnit_Size(self.InputMemSize).
get_num_from_scalar_unit(self.UserInputUnit))
except Exception as error:
- self.assertTrue(isinstance(error, ValueError))
+ self.assertIsInstance(error, ValueError)
self.assertEqual(_('The unit "qB" is not valid. Valid units are '
'"[\'B\', \'GB\', \'GiB\', \'KiB\', \'MB\', '
'\'MiB\', \'TB\', \'TiB\', \'kB\']".'),
@@ -260,7 +260,7 @@ class GetNumFromScalarUnitFrequencyNegative(TestCase):
(ScalarUnit_Frequency(self.InputFrequency).
get_num_from_scalar_unit(self.UserInputUnit))
except Exception as error:
- self.assertTrue(isinstance(error, ValueError))
+ self.assertIsInstance(error, ValueError)
self.assertEqual(_('The unit "Jz" is not valid. Valid units are '
'"[\'GHz\', \'Hz\', \'MHz\', \'kHz\']".'),
error.__str__())
@@ -276,7 +276,7 @@ class GetNumFromScalarUnitTimeNegative(TestCase):
(ScalarUnit_Time(self.InputTime).
get_num_from_scalar_unit(self.UserInputUnit))
except Exception as error:
- self.assertTrue(isinstance(error, ValueError))
+ self.assertIsInstance(error, ValueError)
self.assertEqual(_('"Jz" is not a valid scalar-unit.'),
error.__str__())
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py b/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py
index e0b5a4e..bb163ff 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py
@@ -29,16 +29,10 @@ class ShellTest(TestCase):
"data/test_multiple_validation_errors.yaml")
def test_missing_arg(self):
- error = self.assertRaises(ValueError, shell.main, '')
- err_msg = _('The program requires a template or a CSAR file as an '
- 'argument. Please refer to the usage documentation.')
- self.assertEqual(err_msg, str(error))
+ self.assertRaises(SystemExit, shell.main, '')
def test_invalid_arg(self):
- error = self.assertRaises(ValueError, shell.main, 'parse me')
- err_msg = _('The program expects "--template-file" as the first '
- 'argument. Please refer to the usage documentation.')
- self.assertEqual(err_msg, str(error))
+ self.assertRaises(SystemExit, shell.main, 'parse me')
def test_template_not_exist(self):
error = self.assertRaises(
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py
index 0c26b67..3aabc9b 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py
@@ -220,48 +220,48 @@ class TopologyTemplateTest(TestCase):
self.assertEqual(expected_message, err.__str__())
def test_invalid_nodetype(self):
- tpl_snippet = '''
- substitution_mappings:
- node_type: example.DatabaseSubsystem1
- capabilities:
- database_endpoint: [ db_app, database_endpoint ]
- requirements:
- receiver1: [ tran_app, receiver1 ]
- '''
- sub_mappings = (toscaparser.utils.yamlparser.
- simple_parse(tpl_snippet))['substitution_mappings']
- custom_defs = self._get_custom_types()
- expected_message = _('Node type "example.DatabaseSubsystem1" '
- 'is not a valid type.')
- err = self.assertRaises(
- exception.InvalidNodeTypeError,
- lambda: SubstitutionMappings(sub_mappings, None, None,
- None, None, custom_defs))
- self.assertEqual(expected_message, err.__str__())
+ tpl_snippet = '''
+ substitution_mappings:
+ node_type: example.DatabaseSubsystem1
+ capabilities:
+ database_endpoint: [ db_app, database_endpoint ]
+ requirements:
+ receiver1: [ tran_app, receiver1 ]
+ '''
+ sub_mappings = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet))['substitution_mappings']
+ custom_defs = self._get_custom_types()
+ expected_message = _('Node type "example.DatabaseSubsystem1" '
+ 'is not a valid type.')
+ err = self.assertRaises(
+ exception.InvalidNodeTypeError,
+ lambda: SubstitutionMappings(sub_mappings, None, None,
+ None, None, custom_defs))
+ self.assertEqual(expected_message, err.__str__())
def test_system_with_input_validation(self):
- tpl_path0 = os.path.join(
- os.path.dirname(os.path.abspath(__file__)),
- "data/topology_template/validate/system_invalid_input.yaml")
- tpl_path1 = os.path.join(
- os.path.dirname(os.path.abspath(__file__)),
- "data/topology_template/validate/"
- "queuingsubsystem_invalid_input.yaml")
- errormsg = _('SubstitutionMappings with node_type '
- 'example.QueuingSubsystem is missing '
- 'required input definition of input "server_port".')
-
- # It's invalid in nested template.
- self.assertRaises(exception.ValidationError,
- lambda: ToscaTemplate(tpl_path0))
- exception.ExceptionCollector.assertExceptionMessage(
- exception.MissingRequiredInputError, errormsg)
-
- # Subtemplate deploy standaolone is also invalid.
- self.assertRaises(exception.ValidationError,
- lambda: ToscaTemplate(tpl_path1))
- exception.ExceptionCollector.assertExceptionMessage(
- exception.MissingRequiredInputError, errormsg)
+ tpl_path0 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/topology_template/validate/system_invalid_input.yaml")
+ tpl_path1 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/topology_template/validate/"
+ "queuingsubsystem_invalid_input.yaml")
+ errormsg = _('SubstitutionMappings with node_type '
+ 'example.QueuingSubsystem is missing '
+ 'required input definition of input "server_port".')
+
+ # It's invalid in nested template.
+ self.assertRaises(exception.ValidationError,
+ lambda: ToscaTemplate(tpl_path0))
+ exception.ExceptionCollector.assertExceptionMessage(
+ exception.MissingRequiredInputError, errormsg)
+
+ # Subtemplate deploy standaolone is also invalid.
+ self.assertRaises(exception.ValidationError,
+ lambda: ToscaTemplate(tpl_path1))
+ exception.ExceptionCollector.assertExceptionMessage(
+ exception.MissingRequiredInputError, errormsg)
def test_system_with_unknown_output_validation(self):
tpl_path0 = os.path.join(
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py
index 358bf28..2e97b0e 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py
@@ -60,7 +60,7 @@ class ToscaDefTest(TestCase):
def test_group(self):
self.assertEqual(group_type.type, "tosca.groups.Root")
- self.assertEqual(group_type.parent_type, None)
+ self.assertIsNone(group_type.parent_type)
self.assertIn(ifaces.LIFECYCLE_SHORTNAME, group_type.interfaces)
def test_capabilities(self):
@@ -71,6 +71,7 @@ class ToscaDefTest(TestCase):
# we SHOULD test symbolic capability names as well
self.assertEqual(
['tosca.capabilities.Container',
+ 'tosca.capabilities.Endpoint.Admin',
'tosca.capabilities.Node',
'tosca.capabilities.OperatingSystem',
'tosca.capabilities.Scalable',
@@ -184,12 +185,12 @@ class ToscaDefTest(TestCase):
relation, node in network_port_type.relationship.items()])
def test_interfaces(self):
- self.assertEqual(compute_type.interfaces, None)
+ self.assertIsNone(compute_type.interfaces)
root_node = NodeType('tosca.nodes.Root')
self.assertIn(ifaces.LIFECYCLE_SHORTNAME, root_node.interfaces)
def test_artifacts(self):
- self.assertEqual(artif_root_type.parent_type, None)
+ self.assertIsNone(artif_root_type.parent_type)
self.assertEqual('tosca.artifacts.Root',
artif_file_type.parent_type.type)
self.assertEqual({}, artif_file_type.parent_artifacts)
@@ -284,7 +285,7 @@ class ToscaDefTest(TestCase):
key=lambda x: str(x)))
def test_policies(self):
- self.assertEqual(policy_root_type.parent_type, None)
+ self.assertIsNone(policy_root_type.parent_type)
self.assertEqual('tosca.policies.Root',
policy_placement_type.parent_type.type)
self.assertEqual({}, policy_placement_type.parent_policies)
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py
index e87b672..77232df 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py
@@ -30,13 +30,15 @@ class ToscaTemplateTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml")
- tosca = ToscaTemplate(tosca_tpl)
+ params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
+ 'db_root_pwd': '12345678'}
+ tosca = ToscaTemplate(tosca_tpl, parsed_params=params)
tosca_elk_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_elk.yaml")
tosca_repo_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/tosca_repositories_test_definition.yaml")
+ "data/repositories/tosca_repositories_test_definition.yaml")
def test_version(self):
self.assertEqual(self.tosca.version, "tosca_simple_yaml_1_0")
@@ -145,8 +147,6 @@ class ToscaTemplateTest(TestCase):
wordpress_node.is_derived_from("tosca.nodes.Root"))
self.assertFalse(
wordpress_node.is_derived_from("tosca.policies.Root"))
- self.assertFalse(
- wordpress_node.is_derived_from("tosca.groups.Root"))
def test_outputs(self):
self.assertEqual(
@@ -174,14 +174,14 @@ class ToscaTemplateTest(TestCase):
self.assertEqual(3, len(interface.inputs))
TestCase.skip(self, 'bug #1440247')
wp_db_port = interface.inputs['wp_db_port']
- self.assertTrue(isinstance(wp_db_port, GetProperty))
+ self.assertIsInstance(wp_db_port, GetProperty)
self.assertEqual('get_property', wp_db_port.name)
self.assertEqual(['SELF',
'database_endpoint',
'port'],
wp_db_port.args)
result = wp_db_port.result()
- self.assertTrue(isinstance(result, GetInput))
+ self.assertIsInstance(result, GetInput)
else:
raise AssertionError(
'Unexpected interface: {0}'.format(interface.name))
@@ -200,6 +200,7 @@ class ToscaTemplateTest(TestCase):
compute_type = NodeType(tpl.type)
self.assertEqual(
sorted(['tosca.capabilities.Container',
+ 'tosca.capabilities.Endpoint.Admin',
'tosca.capabilities.Node',
'tosca.capabilities.OperatingSystem',
'tosca.capabilities.network.Bindable',
@@ -286,7 +287,7 @@ class ToscaTemplateTest(TestCase):
"""
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/test_requirements.yaml")
+ "data/requirements/test_requirements.yaml")
tosca = ToscaTemplate(tosca_tpl)
for node_tpl in tosca.nodetemplates:
if node_tpl.name == 'my_app':
@@ -438,14 +439,17 @@ class ToscaTemplateTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml")
- tosca = ToscaTemplate(tosca_tpl)
+ params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
+ 'db_root_pwd': '12345678'}
+ tosca = ToscaTemplate(tosca_tpl, parsed_params=params)
self.assertTrue(tosca.topology_template.custom_defs)
def test_local_template_with_url_import(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress_with_url_import.yaml")
- tosca = ToscaTemplate(tosca_tpl)
+ tosca = ToscaTemplate(tosca_tpl,
+ parsed_params={'db_root_pwd': '123456'})
self.assertTrue(tosca.topology_template.custom_defs)
def test_url_template_with_local_relpath_import(self):
@@ -576,6 +580,10 @@ class ToscaTemplateTest(TestCase):
exception.ExceptionCollector.assertExceptionMessage(
exception.MissingRequiredFieldError, err9_msg)
+ err10_msg = _('Type "tosca.nodes.XYZ" is not a valid type.')
+ exception.ExceptionCollector.assertExceptionMessage(
+ exception.InvalidTypeError, err10_msg)
+
def test_invalid_section_names(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
@@ -673,9 +681,10 @@ class ToscaTemplateTest(TestCase):
"data/tosca_single_instance_wordpress.yaml")
yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
-
+ params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
+ 'db_root_pwd': '12345678'}
self.assertRaises(exception.ValidationError, ToscaTemplate, None,
- None, False, yaml_dict_tpl)
+ params, False, yaml_dict_tpl)
err_msg = (_('Relative file name "custom_types/wordpress.yaml" '
'cannot be used in a pre-parsed input template.'))
exception.ExceptionCollector.assertExceptionMessage(ImportError,
@@ -747,7 +756,7 @@ class ToscaTemplateTest(TestCase):
def test_node_filter(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/test_node_filter.yaml")
+ "data/node_filter/test_node_filter.yaml")
ToscaTemplate(tosca_tpl)
def test_attributes_inheritance(self):
@@ -759,7 +768,7 @@ class ToscaTemplateTest(TestCase):
def test_repositories_definition(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/test_repositories_definition.yaml")
+ "data/repositories/test_repositories_definition.yaml")
ToscaTemplate(tosca_tpl)
def test_custom_caps_def(self):
@@ -819,5 +828,26 @@ class ToscaTemplateTest(TestCase):
def test_containers(self):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
- "data/test_containers.yaml")
+ "data/containers/test_container_docker_mysql.yaml")
ToscaTemplate(tosca_tpl, parsed_params={"mysql_root_pwd": "12345678"})
+
+ def test_endpoint_on_compute(self):
+ tosca_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/test_endpoint_on_compute.yaml")
+ ToscaTemplate(tosca_tpl)
+
+ def test_nested_dsl_def(self):
+ tosca_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/dsl_definitions/test_nested_dsl_def.yaml")
+ self.assertIsNotNone(ToscaTemplate(tosca_tpl))
+
+ def test_multiple_policies(self):
+ tosca_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/policies/test_tosca_nfv_multiple_policies.yaml")
+ tosca = ToscaTemplate(tosca_tpl)
+ self.assertEqual(
+ ['ALRM1', 'SP1', 'SP2'],
+ sorted([policy.name for policy in tosca.policies]))
diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py
index 5a8f37a..911867f 100644
--- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py
+++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py
@@ -35,8 +35,28 @@ class ToscaTemplateValidationTest(TestCase):
tpl_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_single_instance_wordpress.yaml")
+ params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user',
+ 'db_root_pwd': '12345678'}
+ self.assertIsNotNone(ToscaTemplate(tpl_path, params))
+
+ def test_custom_interface_allowed(self):
+ tpl_path = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/interfaces/test_custom_interface_in_template.yaml")
self.assertIsNotNone(ToscaTemplate(tpl_path))
+ def test_custom_interface_invalid_operation(self):
+ tpl_path = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/interfaces/test_custom_interface_invalid_operation.yaml")
+ self.assertRaises(exception.ValidationError,
+ ToscaTemplate, tpl_path)
+ exception.ExceptionCollector.assertExceptionMessage(
+ exception.UnknownFieldError,
+ _('"interfaces" of template "customInterfaceTest" '
+ 'contains unknown field "CustomOp4". '
+ 'Refer to the definition to verify valid values.'))
+
def test_first_level_sections(self):
tpl_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
@@ -97,6 +117,117 @@ class ToscaTemplateValidationTest(TestCase):
_('Policy "mycompany.mytypes.myScalingPolicy" contains unknown '
'field "derived1_from". Refer to the definition to '
'verify valid values.'))
+ exception.ExceptionCollector.assertExceptionMessage(
+ exception.UnknownFieldError,
+ _('Relationshiptype "test.relation.connects" contains unknown '
+ 'field "derived_from4". Refer to the definition to '
+ 'verify valid values.'))
+
+ def test_getoperation_IncorrectValue(self):
+ # test case 1
+ tpl_snippet = '''
+ node_templates:
+ front_end:
+ type: tosca.nodes.Compute
+ interfaces:
+ Standard:
+ create:
+ implementation: scripts/frontend/create.sh
+ configure:
+ implementation: scripts/frontend/configure.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end,Standard1,
+ create,data_dir]}
+ '''
+ tpl = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet))
+ err = self.assertRaises(ValueError,
+ TopologyTemplate, tpl, None)
+ expectedmessage = _('Enter a valid interface name')
+ self.assertEqual(expectedmessage, err.__str__())
+ # test case 2
+ tpl_snippet2 = '''
+ node_templates:
+ front_end:
+ type: tosca.nodes.Compute
+ interfaces:
+ Standard:
+ create:
+ implementation: scripts/frontend/create.sh
+ configure:
+ implementation: scripts/frontend/configure.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end1,Standard,
+ create,data_dir]}
+ '''
+ tpl2 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet2))
+ err2 = self.assertRaises(KeyError,
+ TopologyTemplate, tpl2, None)
+ expectedmessage2 = _('\'Node template "front_end1" was not found.\'')
+ self.assertEqual(expectedmessage2, err2.__str__())
+ # test case 3
+ tpl_snippet3 = '''
+ node_templates:
+ front_end:
+ type: tosca.nodes.Compute
+ interfaces:
+ Standard:
+ create:
+ implementation: scripts/frontend/create.sh
+ configure:
+ implementation: scripts/frontend/configure.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end,Standard,
+ get_target,data_dir]}
+ '''
+ tpl3 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet3))
+ err3 = self.assertRaises(ValueError,
+ TopologyTemplate, tpl3, None)
+ expectedmessage3 = _('Enter an operation of Standard interface')
+ self.assertEqual(expectedmessage3, err3.__str__())
+ # test case 4
+ tpl_snippet4 = '''
+ node_templates:
+ front_end:
+ type: tosca.nodes.Compute
+ interfaces:
+ Standard:
+ create:
+ implementation: scripts/frontend/create.sh
+ configure:
+ implementation: scripts/frontend/configure.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end,Configure,
+ create,data_dir]}
+ '''
+ tpl4 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet4))
+ err4 = self.assertRaises(ValueError,
+ TopologyTemplate, tpl4, None)
+ expectedmessage4 = _('Enter an operation of Configure interface')
+ self.assertEqual(expectedmessage4, err4.__str__())
+ # test case 5
+ tpl_snippet5 = '''
+ node_templates:
+ front_end:
+ type: tosca.nodes.Compute
+ interfaces:
+ Standard:
+ create:
+ implementation: scripts/frontend/create.sh
+ configure:
+ implementation: scripts/frontend/configure.sh
+ inputs:
+ data_dir: {get_operation_output: [front_end,Standard,
+ create]}
+ '''
+ tpl5 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet5))
+ err5 = self.assertRaises(ValueError,
+ TopologyTemplate, tpl5, None)
+ expectedmessage5 = _('Illegal arguments for function'
+ ' "get_operation_output".'
+ ' Expected arguments: "template_name",'
+ '"interface_name",'
+ '"operation_name","output_variable_name"')
+ self.assertEqual(expectedmessage5, err5.__str__())
def test_unsupported_type(self):
tpl_snippet = '''
@@ -135,6 +266,15 @@ class ToscaTemplateValidationTest(TestCase):
required: yes
status: supported
'''
+ tpl_snippet3 = '''
+ inputs:
+ some_list:
+ type: list
+ description: List of items
+ entry_schema:
+ type: string
+ default: []
+ '''
inputs1 = (toscaparser.utils.yamlparser.
simple_parse(tpl_snippet1)['inputs'])
name1, attrs1 = list(inputs1.items())[0]
@@ -144,14 +284,13 @@ class ToscaTemplateValidationTest(TestCase):
try:
Input(name1, attrs1)
except Exception as err:
- # err=self.assertRaises(exception.UnknownFieldError,
- # input1.validate)
self.assertEqual(_('Input "cpus" contains unknown field '
'"constraint". Refer to the definition to '
'verify valid values.'),
err.__str__())
input2 = Input(name2, attrs2)
self.assertTrue(input2.required)
+ toscaparser.utils.yamlparser.simple_parse(tpl_snippet3)['inputs']
def _imports_content_test(self, tpl_snippet, path, custom_type_def):
imports = (toscaparser.utils.yamlparser.
@@ -366,7 +505,7 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
try:
output.validate()
except Exception as err:
- self.assertTrue(isinstance(err, exception.UnknownFieldError))
+ self.assertIsInstance(err, exception.UnknownFieldError)
self.assertEqual(_('Output "server_address" contains unknown '
'field "descriptions". Refer to the definition '
'to verify valid values.'),
@@ -1456,7 +1595,7 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
requirement: host
capability: Container
condition:
- constraint: utilization greater_than 50%
+ constraint: { greater_than: 50 }
period: 60
evaluations: 1
method : average
@@ -1555,3 +1694,91 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
'unknown field "oss". Refer to the definition '
'to verify valid values.')
self.assertEqual(expectedmessage, err.__str__())
+
+ def test_qualified_name(self):
+ tpl_snippet_full_name = '''
+ node_templates:
+ supported_type:
+ type: tosca.nodes.Compute
+ '''
+ tpl = (
+ toscaparser.utils.yamlparser.simple_parse(
+ tpl_snippet_full_name))
+ TopologyTemplate(tpl, None)
+
+ tpl_snippet_short_name = '''
+ node_templates:
+ supported_type:
+ type: Compute
+ '''
+ tpl = (
+ toscaparser.utils.yamlparser.simple_parse(
+ tpl_snippet_short_name))
+ TopologyTemplate(tpl, None)
+
+ tpl_snippet_qualified_name = '''
+ node_templates:
+ supported_type:
+ type: tosca:Compute
+ '''
+ tpl = (
+ toscaparser.utils.yamlparser.simple_parse(
+ tpl_snippet_qualified_name))
+ TopologyTemplate(tpl, None)
+
+ def test_requirements_as_list(self):
+ """Node template with requirements provided with or without list
+
+ Node template requirements are required to be provided as list.
+ """
+
+ expectedmessage = _('"requirements" of template "my_webserver"'
+ ' must be of type "list".')
+
+ # requirements provided as dictionary
+ tpl_snippet1 = '''
+ node_templates:
+ my_webserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ host: server
+ server:
+ type: tosca.nodes.Compute
+ '''
+ err1 = self.assertRaises(
+ exception.TypeMismatchError,
+ lambda: self._single_node_template_content_test(tpl_snippet1))
+ self.assertEqual(expectedmessage, err1.__str__())
+
+ # requirements provided as string
+ tpl_snippet2 = '''
+ node_templates:
+ my_webserver:
+ type: tosca.nodes.WebServer
+ requirements: server
+ server:
+ type: tosca.nodes.Compute
+ '''
+ err2 = self.assertRaises(
+ exception.TypeMismatchError,
+ lambda: self._single_node_template_content_test(tpl_snippet2))
+ self.assertEqual(expectedmessage, err2.__str__())
+
+ # requirements provided as list
+ tpl_snippet3 = '''
+ node_templates:
+ my_webserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ server:
+ type: tosca.nodes.Compute
+ '''
+ self.assertIsNone(
+ self._single_node_template_content_test(tpl_snippet3))
+
+ def test_properties_override_with_flavor_and_image(self):
+ tpl_path = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/test_normative_type_properties_override.yaml")
+ self.assertIsNotNone(ToscaTemplate(tpl_path))
diff --git a/tosca2heat/tosca-parser/toscaparser/topology_template.py b/tosca2heat/tosca-parser/toscaparser/topology_template.py
index d7fd443..4571fe7 100644
--- a/tosca2heat/tosca-parser/toscaparser/topology_template.py
+++ b/tosca2heat/tosca-parser/toscaparser/topology_template.py
@@ -118,6 +118,7 @@ class TopologyTemplate(object):
def _substitution_mappings(self):
tpl_substitution_mapping = self._tpl_substitution_mappings()
+ # if tpl_substitution_mapping and self.sub_mapped_node_template:
if tpl_substitution_mapping:
return SubstitutionMappings(tpl_substitution_mapping,
self.nodetemplates,
@@ -131,17 +132,17 @@ class TopologyTemplate(object):
for policy in self._tpl_policies():
for policy_name, policy_tpl in policy.items():
target_list = policy_tpl.get('targets')
+ target_objects = []
+ targets_type = "groups"
if target_list and len(target_list) >= 1:
- target_objects = []
- targets_type = "groups"
target_objects = self._get_policy_groups(target_list)
if not target_objects:
targets_type = "node_templates"
target_objects = self._get_group_members(target_list)
- policyObj = Policy(policy_name, policy_tpl,
- target_objects, targets_type,
- self.custom_defs)
- policies.append(policyObj)
+ policyObj = Policy(policy_name, policy_tpl,
+ target_objects, targets_type,
+ self.custom_defs)
+ policies.append(policyObj)
return policies
def _groups(self):
@@ -152,7 +153,7 @@ class TopologyTemplate(object):
if member_names is not None:
DataEntity.validate_datatype('list', member_names)
if len(member_names) < 1 or \
- len(member_names) != len(set(member_names)):
+ len(member_names) != len(set(member_names)):
exception.ExceptionCollector.appendException(
exception.InvalidGroupTargetException(
message=_('Member nodes "%s" should be >= 1 '
@@ -196,16 +197,16 @@ class TopologyTemplate(object):
# topology template can act like node template
# it is exposed by substitution_mappings.
def nodetype(self):
- return (self.substitution_mappings.node_type
- if self.substitution_mappings else None)
+ return self.substitution_mappings.node_type \
+ if self.substitution_mappings else None
def capabilities(self):
- return (self.substitution_mappings.capabilities
- if self.substitution_mappings else None)
+ return self.substitution_mappings.capabilities \
+ if self.substitution_mappings else None
def requirements(self):
- return (self.substitution_mappings.requirements
- if self.substitution_mappings else None)
+ return self.substitution_mappings.requirements \
+ if self.substitution_mappings else None
def _tpl_description(self):
description = self.tpl.get(DESCRIPTION)
@@ -258,7 +259,8 @@ class TopologyTemplate(object):
self,
node_template,
value)
- if node_template.requirements:
+ if node_template.requirements and \
+ isinstance(node_template.requirements, list):
for req in node_template.requirements:
rel = req
for req_name, req_item in req.items():
@@ -291,7 +293,7 @@ class TopologyTemplate(object):
for interface in rel_tpl.interfaces:
if interface.inputs:
for name, value in \
- interface.inputs.items():
+ interface.inputs.items():
interface.inputs[name] = \
functions.get_function(self,
rel_tpl,
diff --git a/tosca2heat/tosca-parser/toscaparser/tosca_template.py b/tosca2heat/tosca-parser/toscaparser/tosca_template.py
index 84d953c..f48078f 100644
--- a/tosca2heat/tosca-parser/toscaparser/tosca_template.py
+++ b/tosca2heat/tosca-parser/toscaparser/tosca_template.py
@@ -36,14 +36,14 @@ SECTIONS = (DEFINITION_VERSION, DEFAULT_NAMESPACE, TEMPLATE_NAME,
TOPOLOGY_TEMPLATE, TEMPLATE_AUTHOR, TEMPLATE_VERSION,
DESCRIPTION, IMPORTS, DSL_DEFINITIONS, NODE_TYPES,
RELATIONSHIP_TYPES, RELATIONSHIP_TEMPLATES,
- CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES,
+ CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, INTERFACE_TYPES,
POLICY_TYPES, GROUP_TYPES, REPOSITORIES) = \
('tosca_definitions_version', 'tosca_default_namespace',
'template_name', 'topology_template', 'template_author',
'template_version', 'description', 'imports', 'dsl_definitions',
'node_types', 'relationship_types', 'relationship_templates',
'capability_types', 'artifact_types', 'data_types',
- 'policy_types', 'group_types', 'repositories')
+ 'interface_types', 'policy_types', 'group_types', 'repositories')
# Sections that are specific to individual template definitions
SPECIAL_SECTIONS = (METADATA) = ('metadata')
@@ -106,6 +106,7 @@ class ToscaTemplate(object):
self.relationship_templates = self._relationship_templates()
self.nodetemplates = self._nodetemplates()
self.outputs = self._outputs()
+ self.policies = self._policies()
self._handle_nested_tosca_templates_with_topology()
self.graph = ToscaGraph(self.nodetemplates)
@@ -162,9 +163,12 @@ class ToscaTemplate(object):
def _tpl_topology_template(self):
return self.tpl.get(TOPOLOGY_TEMPLATE)
+ def _policies(self):
+ return self.topology_template.policies
+
def _get_all_custom_defs(self, imports=None):
types = [IMPORTS, NODE_TYPES, CAPABILITY_TYPES, RELATIONSHIP_TYPES,
- DATA_TYPES, POLICY_TYPES, GROUP_TYPES]
+ DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES]
custom_defs_final = {}
custom_defs = self._get_custom_types(types, imports)
if custom_defs:
@@ -196,9 +200,9 @@ class ToscaTemplate(object):
imports = self._tpl_imports()
if imports:
- custom_service = \
- toscaparser.imports.ImportsLoader(imports, self.path,
- type_defs, self.tpl)
+ custom_service = toscaparser.imports.\
+ ImportsLoader(imports, self.path,
+ type_defs, self.tpl)
nested_tosca_tpls = custom_service.get_nested_tosca_tpls()
self._update_nested_tosca_tpls_with_topology(nested_tosca_tpls)
diff --git a/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py b/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py
index 0d2f1d6..a0c11f0 100644
--- a/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py
+++ b/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py
@@ -20,6 +20,18 @@ log = logging.getLogger('tosca')
class UnsupportedType(object):
+ """Note: TOSCA spec version related
+
+ The tosca.nodes.Storage.ObjectStorage and tosca.nodes.Storage.BlockStorage
+ used here as un_supported_types are part of the name changes in TOSCA spec
+ version 1.1. The original name as specified in version 1.0 are,
+ tosca.nodes.BlockStorage and tosca.nodes.ObjectStorage which are supported
+ by the tosca-parser. Since there are little overlapping in version support
+ currently in the tosca-parser, the names tosca.nodes.Storage.ObjectStorage
+ and tosca.nodes.Storage.BlockStorage are used here to demonstrate the usage
+ of un_supported_types. As tosca-parser move to provide support for version
+ 1.1 and higher, they will be removed.
+ """
un_supported_types = ['tosca.test.invalidtype',
'tosca.nodes.Storage.ObjectStorage',
'tosca.nodes.Storage.BlockStorage']
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
index f5562e2..d631ac8 100644
--- a/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
+++ b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
@@ -19,4 +19,5 @@ _t = gettext.translation('tosca-parser', localedir=_localedir,
def _(msg):
+ # type: (object) -> object
return _t.gettext(msg)
diff --git a/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py
index 43e14d6..b280576 100644
--- a/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py
+++ b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py
@@ -198,7 +198,7 @@ class TOSCAVersionProperty(object):
"""
if self.minor_version is None and self.build_version is None and \
- value != '0':
+ value != '0':
log.warning(_('Minor version assumed "0".'))
self.version = '.'.join([value, '0'])
return value
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..c4b1b0f
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,26 @@
+# this will used to integrate with other components in parser
+# such as verigraph
+[tox]
+minversion = 1.6
+envlist = py27,pep8
+skipsdist = True
+
+[testenv]
+usedevelop = True
+install_command = pip install -U {opts} {packages}
+setenv =
+ VIRTUAL_ENV={envdir}
+deps = -r{toxinidir}/requirements.txt
+
+[testenv:ht]
+whitelist_externals =
+ bash
+commands =
+ bash -c 'cd tosca2heat/heat-translator; tox'
+
+[testenv:tp]
+whitelist_externals =
+ bash
+commands =
+ bash -c 'cd tosca2heat/tosca-parser; tox'
+
diff --git a/verigraph/LICENSE b/verigraph/LICENSE
new file mode 100644
index 0000000..79a7d4f
--- /dev/null
+++ b/verigraph/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2017 Politecnico di Torino and others.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/verigraph/README.rst b/verigraph/README.rst
new file mode 100644
index 0000000..947e893
--- /dev/null
+++ b/verigraph/README.rst
@@ -0,0 +1,258 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+| Let’s look at how to deploy **VeriGraph** on Apache Tomcat. If you’re
+ only interested in creating gRPC API and ``neo4jmanager`` is already
+ deployed, you can skip this section and go straight to the
+ `documentation <https://gitlab.com/serena.spinoso/DP2.2017.SpecialProject2.gRPC/tree/master/src/main/java/it/polito/grpc>`__
+| (though you might find it useful if Tomcat is not yet installed!).
+
+**Windows**
+
+- install ``jdk1.8.X_YY``
+ `here <http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html>`__
+- set ambient variable ``JAVA_HOME`` to where you installed the jdk
+ (e.g. ``C:\Program Files\Java\jdk1.8.X_YY``)
+- install Apache Tomcat 8
+ `here <https://tomcat.apache.org/download-80.cgi>`__
+- install a pre-compiled distribution of Z3 from
+ `here <https://github.com/Z3Prover/bin/tree/master/releases>`__
+ and save the ``[z3_root]/bin`` content under ``[verigraph]/service/build``
+- create the ``mcnet.jar`` of the ``mcnet.*`` packages and put into the ``[verigraph]/service/build`` directory
+- download the qjutils library
+ `here <https://github.com/quanla/classreloading/tree/master/src/main/java/qj/util>`__
+ and create a jar file (i.e. qjutils.jat) in ``[verigrap]/service/build``
+- set ambient variable ``CATALINA_HOME`` to the directory where you
+ installed Apache (e.g.
+ ``C:\Program Files\Java\apache-tomcat-8.0.30``)
+- create ``shared`` folder under ``%CATALINA_HOME%``
+- add previously created folder to the Windows ``Path`` system variable
+ (i.e. append the following string at the end:
+ ``;%CATALINA_HOME%\shared``)
+- copy ``[verigraph]/lib/mcnet.jar``, ``[verigraph]/service/build/com.microsoft.z3.jar`` and ``[verigraph]/service/build/qjutils.jar``
+ to ``%CATALINA_HOME%\shared``
+- to correctly compile the code you have to put the path of ``com.microsoft.z3.jar``
+ and the libraries it refers to as environment variable. i.e. is enough
+ to add the project subfolder ``build`` to the PATH environment variable (i.e., ``[verigraph]/build``)
+- create custom file setenv.bat under ``%CATALINA_HOME%\bin`` with the
+ following content:
+
+ .. code:: bat
+
+ set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\shared\qjutils.jar;%CATALINA_HOME%\shared\mcnet.jar;%CATALINA_HOME%\shared\com.microsoft.z3.jar;.;%CATALINA_HOME%\webapps\verify\WEB-INF\classes\tests
+
+- download ``neo4jmanager.war`` from
+ `here <https://github.com/netgroup-polito/verigraph/tree/master/dist>`__
+ and copy into into ``%CATALINA_HOME%\webapps``
+- export the ``verify.war`` file from the project and copy into ``%CATALINA_HOME%\webapps``
+- (optional) configure Tomcat Manager:
+- open the file ``%CATALINA_HOME%\conf\tomcat-users.xml``
+- under the ``tomcat-users`` tag place the following content:
+ ``xml <role rolename="tomcat"/> <role rolename="role1"/> <user username="tomcat" password="tomcat" roles="tomcat,manager-gui"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/>``
+- launch Tomcat 8 with the startup script
+ ``%CATALINA_HOME%\bin\startup.bat``
+- (optional) if you previously configured Tomcat Manager you can open a
+ browser and navigate to `this link <http://localhost:8080/manager>`__
+ and login using ``tomcat/tomcat`` as username/password
+- (optional) you can deploy/undeploy/redeploy the downloaded WARs
+ through the web interface
+
+**Unix**
+
+- install ``jdk1.8.X_YY`` from the command line:
+- go to `this
+ link <http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html>`__
+ to check the appropriate version for you OS and architecture
+- copy the desired version to the clipboard (e.g.
+ ``http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz``)
+- open a terminal windows and paste the following command (replace
+ ``link`` with the previously copied link):
+ ``wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" 'link'``
+ e.g.
+ ``wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz``
+- untar the archive with the following command (replace 'jdk' to match
+ the name of the downloaded archive):
+ ``tar zxvf 'jdk'.tar.gz``
+ e.g.
+ ``tar zxvf jdk-7u<version>-linux-x64.tar.gz``
+- delete the ``.tar.gz`` file if you want to save disk space
+- install and configure Apache Tomcat 8 with the following commands:
+- go to `this URL <http://it.apache.contactlab.it/tomcat/tomcat-8/>`__
+ and see what the latest available version is
+- download the archive (substitute every occurrence of '8.0.32' in the
+ following command with the latest available version):
+ ``wget http://it.apache.contactlab.it/tomcat/tomcat-8/v8.0.32/bin/apache-tomcat-8.0.32.tar.gz``
+- extract downloaded archive:
+ ``tar xvf apache-tomcat-8.0.32.tar.gz``
+- edit configuration:
+ ``nano ./apache-tomcat-8.0.32/conf/tomcat-users.xml``
+- under the ``tomcat-users`` tag place the following content
+ ``xml <role rolename="tomcat"/> <role rolename="role1"/> <user username="tomcat" password="tomcat" roles="tomcat,manager-gui"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/> </tomcat-users>``
+- set a few environment variables:
+ ``sudo nano ~/.bashrc``
+- paste the following content at the end of the file
+ ``export CATALINA_HOME='/path/to/apache/tomcat/folder'``
+ e.g.
+ ``export CATALINA_HOME=/home/mininet/apache-tomcat-8.0.33``
+ ``export JRE_HOME='/path/to/jdk/folder'``
+ e.g.
+ ``export JRE_HOME=/home/mininet/jdk1.8.0_92/jre``
+ ``export JDK_HOME='/path/to/jdk/folder'``
+ e.g.
+ ``export JDK_HOME=/home/mininet/jdk1.8.0_92``
+ ``export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CATALINA_HOME/shared``
+ ``export JAVA_OPTS="-Djava.library.path=$CATALINA_HOME/shared"``
+- ``exec bash``
+- install a pre-compiled distribution of Z3 from
+ `here <https://github.com/Z3Prover/bin/tree/master/releases>`__
+ and save [z3_root]/bin content under ``[verigraph]/service/build``
+- download the qjutils library
+ `here <https://github.com/quanla/classreloading/tree/master/src/main/java/qj/util>`__
+ and create a jar file (i.e. qjutils.jar) in ``[verigrap]/service/build``
+- create the ``mcnet.jar`` of the ``mcnet.*`` packages and put into the ``[verigraph]/service/build`` directory
+- copy ``[verigraph]/service/build/mcnet.jar``, ``[verigraph]/service/build/com.microsoft.z3.jar``
+ and ``[verigraph]/service/build/qjutils.jar`` to ``$CATALINA_HOME/shared``
+- customize Tomcat classpath
+ ``nano $CATALINA_HOME/bin/setenv.sh``
+- paste the following content and save file:
+ ``bash #!/bin/sh export CLASSPATH=$CLASSPATH:$CATALINA_HOME/shared/qjutils.jar:$CATALINA_HOME/shared/mcnet.jar:$CATALINA_HOME/shared/com.microsoft.z3.jar:.:$CATALINA_HOME/webapps/verify/WEB-INF/classes/tests``
+- save and close the file (``CTRL+O``, ``CTRL+X``)
+ ``sudo chmod +x $CATALINA_HOME/bin/setenv.sh``
+- download ``neo4jmanager.war`` from
+ `here <https://github.com/netgroup-polito/verigraph/tree/master/dist>`__
+ and copy into into ``%CATALINA_HOME%\webapps``
+- export the ``verify.war`` file from the project and copy into ``%CATALINA_HOME%\webapps``
+- launch Tomcat 8 with the startup script
+ ``$CATALINA_HOME/bin/startup.sh``
+- open a browser and navigate to `this
+ link <http://localhost:8080/manager>`__ and login using
+ ``tomcat/tomcat`` as username/password
+- you can deploy/undeploy/redeploy the downloaded WARs through the web
+ interface
+
+**Eclipse**
+
+- clone project onto your hard drive with this command:
+ ``git clone git@github.com:netgroup-polito/verigraph.git``
+- Download Apache Tomcat 8 (see instructions above for Windows and
+ Unix)
+- Download JDK (see instructions above for Windows and Unix)
+- Configure runtime environment in Eclipse with `the following
+ incstructions <http://crunchify.com/step-by-step-guide-to-setup-and-install-apache-tomcat-server-in-eclipse-development-environment-ide/>`__
+- Add new Tomcat server on port ``8080``
+- Configure Tomcat server:
+
+ - double-click on the newly created server in the ``Servers`` tab
+ - make sure under ``Server Locations`` ``Use Tomcat installation``
+ is selected
+ - Open ``Launch Configuration``->``Classpath``
+ - add the required JARS (``mcnet.jar``, ``com.microsoft.z3.jar`` and
+ ``qjutils.jar``) under ``User Entries``
+ - Hit ``Apply`` and ``Ok``
+
+- Run the server
+
+**How to add you own function ``<type>``**
+
+#. under the the ``mcnet.netobjs`` package (i.e. under
+ ``/verify/service/src/mcnet/netobjs``) create a new class
+ ``<Type>.java``, where ``<type>`` is the desired function name (i.e.
+ ``<type>`` will be added to the supported node functional types)
+ which extends ``NetworkObject`` and implement the desired logic
+
+#. regenerate ``mcnet.jar`` selecting the packages ``mcnet.components``
+ and ``mcnet.netobjs`` and exporting the generated JAR to
+ ``/verify/service/build`` (overwrite the existing file)
+
+#. under ``/verify/src/main/webapp/json/`` create a file
+ ``<type>.json``. This file represents a JSON schema (see
+ `here <http://json-schema.org/>`__ the official documentation). For
+ compatibility with the other functions it is mandatory to support an
+ array as the root of the configuration, but feel free to specify all
+ the other constraints as needed. A sample of ``<type>.json`` to
+ describe an empty configuration could be the following:
+
+``json { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Type", "description": "This is a generic type", "type": "array", "items": { "type": "object" }, "minItems": 0, "maxItems": 0, "uniqueItems": true }``
+
+#. in the package ``it.polito.escape.verify.validation`` (i.e. under
+ ``src/main/java/it/polito/escape/verify/validation``) create a new
+ class file named ``<Type>Validator.java`` (please pay attention to
+ the naming convention here: ``<Type>`` is the function type used in
+ the previous step capitalized, followed by the suffix ``Validator``)
+ which implements ``ValidationInterface``. This class represents a
+ custom validator for the newly introduced type and allows for more
+ complex constraints, which is not possible to express through a JSON
+ schema file. The validate method that has to be implemented is given
+ the following objects:
+
+- ``Graph graph`` represents the nffg that the object node belongs to;
+- ``Node node`` represents the node that the object configuration
+ belongs to;
+- ``Configuration configuration`` represents the parsed configuration.
+ It is sufficient to call the method ``getConfiguration`` on the
+ ``configuration`` object to get a ``JsonNode`` (Jackson's class) and
+ iterate over the various fields.
+ In case a configuration is not valid please throw a new
+ ``ValidationException`` passing a descriptive failure message.
+ Adding a custom validator is not strictly necessary whenever a JSON
+ schema is thought to be sufficient. Note though that, other than the
+ mandatory validation against a schema, whenever a custom validator is
+ not found a default validation is triggered, i.e. the value of every
+ JSON property must refer to the name of an existing node in the
+ working graph/nffg. If this is not the desired behavior it is
+ suggested to write a custom validator with looser constraints.
+
+#. customize the class generator and add the support for the newly
+ introduced type:
+
+- open the file
+ ``/verify/service/src/tests/j-verigraph-generator/config.py`` and
+ edit the following dictionaries:
+
+ - ``devices_to_classes`` --> add the following entry:
+ ``"<type>" : "<Type>"``
+ if you followed these instructions carefully the name of the class
+ implementing the function ``<type>`` should be ``<Type>.java``
+ under the package ``mcnet.netobjs``.
+ - ``devices_to_configuration_methods`` --> add the following entry:
+ ``"<type>" : "configurationMethod"``
+ if ``<type>`` is a middlebox it should have a configuration method
+ contained in the implementation ``<Type>.java`` under the package
+ ``mcnet.netobjs``.
+ - ``devices_initialization``: add the following entry:
+ ``"<type>" : ["param1", "param2"]``
+ if ``<type>`` requires any parameter when it gets instanciated
+ please enter them in the form of a list. Make sure that these
+ parameters refer to existing keys contained in the configuration
+ schema file (see step 3). For instance the type ``webclient``
+ requires the name of a webserver it wants to communicate with.
+ This parameter is passed in the configuration of a weblient by
+ setting a property ``webserver`` to the name of the desired
+ webserver. The value of this property gets extracted and used by
+ the test generator automatically.
+ - ``convert_configuration_property_to_ip`` --> add the following
+ entry: ``"<type>" : ["key", "value"]``
+ Note that both ``key`` and ``value`` are optional and it is
+ critical to set them only if needed. Since the Z3 provider used
+ for testing works with IP addresses in this dictionary you have to
+ indicate whether it is needed an automatic convertion from names
+ to IP addresses:
+ - in case the keyword ``key`` is used every key of the JSON
+ configuration parsed will be prepended with the string ``ip_``;
+ - in case the keyword ``value`` is used every value of the JSON
+ configuration parsed will be prepended with the string ``ip_``;
+ - in case the list does not contain neither ``key`` nor ``value``
+ the original configuration won't be touched.
+
+- open the file
+ ``/verify/service/src/tests/j-verigraph-generator/test_class_generator.py``
+ and under the "switch" case in the form of a series of ifs used to
+ configure middle-boxes that starts at line #239 add a branch like the
+ following with the logic to generate the Java code for -->
+ ``elif nodes_types[i] == "<type>":``
+ You can take inspiration from the other branches to see how to
+ serialize Java code. Note that this addition to the "switch"
+ statement is not needed if ``<type>`` is not a middlebox or it does
+ not need to be configured.
+
+#. Restart the web service.
diff --git a/verigraph/buildVeriGraph_gRPC.xml b/verigraph/buildVeriGraph_gRPC.xml
new file mode 100644
index 0000000..d23daa0
--- /dev/null
+++ b/verigraph/buildVeriGraph_gRPC.xml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2017 Politecnico di Torino and others.
+
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Apache License, Version 2.0
+ which accompanies this distribution, and is available at
+ http://www.apache.org/licenses/LICENSE-2.0
+-->
+
+<project name="gRPC-Verigraph" default="run-tests" basedir="." xmlns:artifact="antlib:org.apache.maven.artifact.ant">
+ <description>
+ Script for gRPC-Verigraph
+ </description>
+
+ <!-- The location of this assignment -->
+ <property name="grpc.location" location="." />
+
+ <!-- The location to be used for class files -->
+ <property name="build.dir" location="${grpc.location}/build" />
+ <!-- The location for source files -->
+ <property name="src.dir" location="${grpc.location}/src/main/java" />
+ <!-- The location for solutions -->
+ <property name="grpc.dir" value="src/main/java/it/polito/grpc" />
+ <!-- The location for jar files -->
+ <property name="lib.dir" location="${grpc.location}/lib" />
+ <!-- The location for jar files -->
+ <property name="other_lib.dir" location="${grpc.location}/service/build" />
+ <!-- The location for generated files -->
+ <property name="generated.dir" location="${basedir}/target/generated-sources" />
+ <!-- The default test class -->
+ <property name="test1.class" value="it.polito.grpc.test.GrpcServerTest" />
+ <property name="test2.class" value="it.polito.grpc.test.GrpcTest" />
+ <property name="test3.class" value="it.polito.grpc.test.MultiThreadTest" />
+ <property name="test4.class" value="it.polito.grpc.test.ReachabilityTest" />
+
+ <!-- The name to be given to the final zip -->
+ <property name="sol.zip" value="grpc.zip" />
+
+ <!-- Java compiler settings -->
+ <property name="debug" value="true" />
+ <property name="debuglevel" value="source,lines,vars" />
+ <property name="target" value="1.8" />
+ <property name="source" value="1.8" />
+
+ <!-- The classpath to be used for running the tests -->
+ <path id="test.classpath">
+ <pathelement path="${build.dir}" />
+ <fileset dir="${grpc.location}/lib">
+ <include name="*.jar" />
+ </fileset>
+ <fileset refid="mvn-dependencies" />
+ </path>
+
+ <!-- Here starts part for Maven -->
+ <path id="maven-ant-tasks.classpath" path="lib/maven-ant-tasks-2.1.3.jar" />
+ <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
+ uri="antlib:org.apache.maven.artifact.ant"
+ classpathref="maven-ant-tasks.classpath" />
+ <property file="build.properties"/>
+
+ <!-- Load pom.xml for dependencies -->
+ <artifact:pom id="pomfile" file="pom.xml" />
+ <artifact:dependencies filesetId="mvn-dependencies" pomRefId="pomfile" />
+
+ <!-- Grab the HSQLDB jar and add it to the classpath
+ <artifact:dependencies filesetId="warDeps">
+ <dependency groupId="org.glassfish.jersey" artifactId="jersey-bom" version="2.22.1" />
+ </artifact:dependencies>-->
+
+ <path id="build.classpath">
+ <fileset refid="mvn-dependencies" />
+ </path>
+
+ <target name="init">
+ <mkdir dir="${build.dir}" />
+ </target>
+
+ <!-- The target for compiling the gRPC application -->
+ <target name="build" depends="init" description="Build the sources">
+ <echo>Building gRPC (if needed)...</echo>
+ <javac
+ debug="${debug}"
+ debuglevel="${debuglevel}"
+ source="${source}"
+ target="${target}"
+ destdir="${build.dir}"
+ classpathref="build.classpath"
+ includeantruntime="false">
+ <src path="${generated.dir}" />
+ <src path="${src.dir}" />
+ <compilerarg value="-Xlint:unchecked"/>
+ <classpath>
+ <pathelement path="${other_lib.dir}/qjutils.jar"/>
+ </classpath>
+ </javac>
+ <echo>Done.</echo>
+ </target>
+
+ <!-- The target for running the gRPC application -->
+ <target name="run" depends="build" description="Run gRPC">
+ <parallel>
+ <sequential>
+ <java classname="it.polito.grpc.Service" failonerror="true" classpathref="build.classpath" fork="yes">
+ <classpath>
+ <pathelement path="${build.dir}"/>
+ </classpath>
+ </java>
+ </sequential>
+ <sequential>
+ <sleep milliseconds="500"/>
+ <java classname="it.polito.grpc.Client" failonerror="true" classpathref="build.classpath" fork="yes">
+ <classpath>
+ <pathelement path="${build.dir}"/>
+ </classpath>
+ </java>
+ </sequential>
+ </parallel>
+ </target>
+
+ <target name="run-client" depends="build" description="Run gRPC client">
+ <java classname="it.polito.grpc.Client" failonerror="true" classpathref="build.classpath" fork="yes">
+ <classpath>
+ <pathelement path="${build.dir}"/>
+ </classpath>
+ </java>
+ </target>
+
+ <target name="run-server" depends="build" description="Run gRPC server">
+ <java classname="it.polito.grpc.Service" failonerror="true" classpathref="build.classpath" fork="yes">
+ <classpath>
+ <pathelement path="${build.dir}"/>
+ </classpath>
+ </java>
+ </target>
+
+ <target name="run-tests" description="Run tests for gRPC">
+ <echo>Running functional tests</echo>
+
+ <antcall target="runFuncTest.real">
+ <param name="exit.code1" value="126" />
+ <param name="exit.code2" value="125" />
+ <param name="exit.code3" value="124" />
+ <param name="exit.code4" value="123" />
+ </antcall>
+ </target>
+
+ <!-- Target runFuncTest.real -->
+ <target name="runFuncTest.real" depends="build">
+
+ <echo>Running First set of Junit tests...</echo>
+ <junit printsummary="yes" dir="." fork="yes" haltonfailure="no" showoutput="no" filtertrace="true" timeout="120000">
+ <jvmarg value="-Djava.awt.headless=true" />
+ <formatter type="brief" usefile="false"/>
+ <test haltonfailure="no" failureproperty="test_failed" name="${test1.class}"/>
+ <classpath>
+ <path refid="test.classpath" />
+ </classpath>
+ </junit>
+ <fail if="test_failed" status="${exit.code1}" message="*** First set of Junit tests: Some Tests FAILED ***"/>
+ <echo>*** First set of Junit tests: All Tests PASSED ***</echo>
+
+ <echo>Running Second set of Junit tests...</echo>
+ <junit printsummary="yes" dir="." fork="yes" haltonfailure="no" showoutput="no" filtertrace="true" timeout="120000">
+ <jvmarg value="-Djava.awt.headless=true" />
+ <formatter type="brief" usefile="false"/>
+ <test haltonfailure="no" failureproperty="test_failed" name="${test2.class}"/>
+ <classpath>
+ <path refid="test.classpath" />
+ </classpath>
+ </junit>
+ <fail if="test_failed" status="${exit.code2}" message="*** Second set of Junit tests: Some Tests FAILED ***"/>
+ <echo>*** Second set of Junit tests: All Tests PASSED ***</echo>
+
+ <echo>Running Third set of Junit tests...</echo>
+ <junit printsummary="yes" dir="." fork="yes" haltonfailure="no" showoutput="no" filtertrace="true" timeout="120000">
+ <jvmarg value="-Djava.awt.headless=true" />
+ <formatter type="brief" usefile="false"/>
+ <test haltonfailure="no" failureproperty="test_failed" name="${test3.class}"/>
+ <classpath>
+ <path refid="test.classpath" />
+ </classpath>
+ </junit>
+ <fail if="test_failed" status="${exit.code3}" message="*** Third set of Junit tests: Some Tests FAILED ***"/>
+ <echo>*** Third set of Junit tests: All Tests PASSED ***</echo>
+
+ <echo>Running Fourth set of Junit tests...</echo>
+ <junit printsummary="yes" dir="." fork="yes" haltonfailure="no" showoutput="no" filtertrace="true" timeout="120000">
+ <jvmarg value="-Djava.awt.headless=true" />
+ <jvmarg value="-Djava.library.path=${other_lib.dir}" />
+ <formatter type="brief" usefile="false"/>
+ <test haltonfailure="no" failureproperty="test_failed" name="${test4.class}"/>
+ <classpath>
+ <path refid="test.classpath" />
+ <fileset dir="${other_lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+ </classpath>
+ </junit>
+ <fail if="test_failed" status="${exit.code4}" message="*** Fourth set of Junit tests: Some Tests FAILED ***"/>
+ <echo>*** Fourth set of Junit tests: All Tests PASSED ***</echo>
+ <echo>***************************************************</echo>
+ <echo>*************** All Tests PASSED *****************</echo>
+ </target>
+
+ <!-- target for cleaning -->
+ <target name="clean">
+ <delete dir="${build.dir}" />
+ </target>
+</project>
diff --git a/verigraph/pom.xml b/verigraph/pom.xml
new file mode 100644
index 0000000..63603a7
--- /dev/null
+++ b/verigraph/pom.xml
@@ -0,0 +1,213 @@
+<!-- Copyright (c) 2017 Politecnico di Torino and others. All rights reserved.
+ This program and the accompanying materials are made available under the
+ terms of the Apache License, Version 2.0 which accompanies this distribution,
+ and is available at http://www.apache.org/licenses/LICENSE-2.0 -->
+
+<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/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>it.polito.escape</groupId>
+ <artifactId>verify</artifactId>
+ <packaging>war</packaging>
+ <version>0.0.1-SNAPSHOT</version>
+ <name>verify</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <grpc.version>1.0.3</grpc.version><!-- CURRENT_GRPC_VERSION -->
+ <jersey.version>2.22.1</jersey.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <build>
+ <finalName>verify</finalName>
+ <extensions>
+ <extension>
+ <groupId>kr.motd.maven</groupId>
+ <artifactId>os-maven-plugin</artifactId>
+ <version>1.4.1.Final</version>
+ </extension>
+ </extensions>
+ <plugins>
+ <plugin>
+ <groupId>org.xolstice.maven.plugins</groupId>
+ <artifactId>protobuf-maven-plugin</artifactId>
+ <version>0.5.0</version>
+ <configuration>
+ <protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact>
+ <pluginId>grpc-java</pluginId>
+ <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>compile-custom</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <inherited>true</inherited>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <versionRange>[1.0.0,)</versionRange>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey</groupId>
+ <artifactId>jersey-bom</artifactId>
+ <version>${jersey.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet-core</artifactId>
+ <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
+ <!-- artifactId>jersey-container-servlet</artifactId -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.bundles</groupId>
+ <artifactId>jaxrs-ri</artifactId>
+ </dependency>
+
+ <!-- <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId>
+ </dependency> -->
+
+ <dependency>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <artifactId>jersey-media-json-jackson</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>io.swagger</groupId>
+ <artifactId>swagger-jersey2-jaxrs</artifactId>
+ <version>1.5.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.googlecode.json-simple</groupId>
+ <artifactId>json-simple</artifactId>
+ <version>1.1</version>
+ </dependency>
+
+ <!-- added to retrieve server path -->
+ <!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version> <scope>provided</scope> </dependency> -->
+
+ <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.5.6</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>com.github.fge</groupId>
+ <artifactId>json-schema-validator</artifactId>
+ <version>2.2.6</version>
+ </dependency>
+
+ <!-- http://mvnrepository.com/artifact/org.json/json -->
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20160212</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/junit/junit -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- here start dependencies for grpc -->
+ <dependency>
+ <groupId>org.apache.thrift</groupId>
+ <artifactId>libthrift</artifactId>
+ <version>0.9.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-netty</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-protobuf</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>3.0.2</version>
+ </dependency>
+
+
+
+ </dependencies>
+
+</project>
diff --git a/verigraph/service/src/mcnet/components/Checker.java b/verigraph/service/src/mcnet/components/Checker.java
new file mode 100644
index 0000000..3c13d28
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/Checker.java
@@ -0,0 +1,363 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Model;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Status;
+
+/**Various checks for specific properties in the network.
+ *
+ */
+public class Checker {
+
+ Context ctx;
+ Network net;
+ NetContext nctx;
+ Solver solver;
+ ArrayList<BoolExpr> constraints;
+ public BoolExpr [] assertions;
+ public Status result;
+ public Model model;
+
+
+ public Checker(Context context,NetContext nctx,Network network){
+ this.ctx = context;
+ this.net = network;
+ this.nctx = nctx;
+ this.solver = ctx.mkSolver();
+ this.constraints = new ArrayList<BoolExpr>();
+ }
+
+ /**Resets the constraints
+ *
+ */
+ public void clearState (){
+ this.solver.reset();
+ this.constraints = new ArrayList<BoolExpr>();
+ }
+
+ /**Checks whether the source provided can reach the destination
+ *
+ * @param src
+ * @param dest
+ * @return
+ */
+ public IsolationResult checkIsolationProperty (NetworkObject src, NetworkObject dest){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ solver.push ();
+ addConstraints();
+
+ Expr p0 = ctx.mkConst("check_isolation_p0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+ Expr p1 = ctx.mkConst("check_isolation_p1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_1 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ IntExpr t_0 = ctx.mkIntConst("check_isolation_t0_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_1 = ctx.mkIntConst("check_isolation_t1_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p0,t_0)
+ this.solver.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p0, t_0));
+
+ // Constraint2 send(srcNode,n_1,p1,t_1)
+ this.solver.add((BoolExpr)nctx.send.apply(src.getZ3Node(), n_1, p1, t_1));
+
+ // Constraint3 nodeHasAddr(srcNode,p1.srcAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(src.getZ3Node(), nctx.pf.get("src").apply(p1)));
+
+ // Constraint4 p1.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p1), src.getZ3Node()));
+
+ // Constraint5 nodeHasAddr(destNode,p1.destAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(dest.getZ3Node(), nctx.pf.get("dest").apply(p1)));
+
+ //NON sembrano necessari
+ // this.solver.add(z3.Or(this.ctx.nodeHasAddr(src.getZ3Node(), this.ctx.packet.src(p0)),\
+ // this.ctx.nodeHasAddr(n_0, this.ctx.packet.src(p0)),\
+ // this.ctx.nodeHasAddr(n_1, this.ctx.packet.src(p0))))
+ //this.solver.add(this.ctx.packet.dest(p1) == this.ctx.packet.dest(p0))
+
+ // Constraint6 p1.origin == p0.origin
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p1),nctx.pf.get("origin").apply(p0)));
+
+ // Constraint7 nodeHasAddr(destNode, p0.destAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(dest.getZ3Node(), nctx.pf.get("dest").apply(p0)));
+
+ result = this.solver.check();
+ model = null;
+ assertions = this.solver.getAssertions();
+ if (result == Status.SATISFIABLE){
+ model = this.solver.getModel();
+ }
+ this.solver.pop();
+ return new IsolationResult(ctx,result, p0, n_0, t_1, t_0, nctx, assertions, model);
+ }
+
+
+
+ public IsolationResult CheckIsolationFlowProperty (NetworkObject src, NetworkObject dest){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ solver.push ();
+ addConstraints();
+
+ Expr p = ctx.mkConst("check_isolation_p_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_1 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_2 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+
+ IntExpr t_0 = ctx.mkIntConst("check_isolation_t0_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_1 = ctx.mkIntConst("check_isolation_t1_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_2 = ctx.mkIntConst("check_isolation_t2_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p,t_0)
+ this.solver.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p, t_0));
+
+ // Constraint2 send(srcNode,n_1,p1,t_1)
+ this.solver.add((BoolExpr)nctx.send.apply(src.getZ3Node(), n_1, p, t_1));
+
+ // Constraint3 nodeHasAddr(srcNode,p.srcAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(src.getZ3Node(), nctx.pf.get("src").apply(p)));
+
+ // Constraint4 p.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p), src.getZ3Node()));
+
+
+ Expr p_2 = ctx.mkConst("check_isolation_p_flow_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+
+ // Constraint5 there does not exist p_2, n_2, t_2 :
+ // send(destNode,n_2,p_2,t_2) &&
+ // p_2.srcAddr == p. destAddr &&
+ // p_2.srcPort == p.destPort &&
+ // p_2.destPort == p.srcPort &&
+ // p_2.destt == p.src &&
+ // t_2 < t_0
+ this.solver.add(ctx.mkNot(ctx.mkExists(new Expr[]{p_2,n_2,t_2},
+ ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(dest.getZ3Node(), n_2, p_2, t_2),
+ ctx.mkEq(nctx.pf.get("src").apply(p_2), nctx.pf.get("dest").apply(p)),
+ ctx.mkEq(nctx.pf.get("src_port").apply(p_2), nctx.pf.get("dest_port").apply(p)),
+ ctx.mkEq(nctx.pf.get("dest_port").apply(p_2), nctx.pf.get("src_port").apply(p)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_2), nctx.pf.get("src").apply(p)),
+ ctx.mkLt(t_2,t_0)),1,null,null,null,null)));
+
+
+ result = this.solver.check();
+ model = null;
+ assertions = this.solver.getAssertions();
+ if (result == Status.SATISFIABLE){
+ model = this.solver.getModel();
+ }
+ this.solver.pop();
+ return new IsolationResult(ctx,result, p, n_0, t_1, t_0, nctx, assertions, model);
+ }
+
+
+
+ public IsolationResult CheckNodeTraversalProperty (NetworkObject src, NetworkObject dest, NetworkObject node){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ solver.push ();
+ addConstraints();
+
+ Expr p = ctx.mkConst("check_isolation_p_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_1 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_2 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+
+ IntExpr t_0 = ctx.mkIntConst("check_isolation_t0_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_1 = ctx.mkIntConst("check_isolation_t1_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_2 = ctx.mkIntConst("check_isolation_t2_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p,t_0)
+ this.solver.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p, t_0));
+
+ // Constraint2 send(srcNode,n_1,p1,t_1)
+ this.solver.add((BoolExpr)nctx.send.apply(src.getZ3Node(), n_1, p, t_1));
+
+ // Constraint3 nodeHasAddr(srcNode,p.srcAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(src.getZ3Node(), nctx.pf.get("src").apply(p)));
+
+ // Constraint4 p.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p), src.getZ3Node()));
+
+
+ // Constraint5 there does not exist n_2, t_2 : recv(n_2,node,p,t_2) && t_2 < t_0
+ this.solver.add(ctx.mkNot(ctx.mkExists(new Expr[]{n_2,t_2},
+ ctx.mkAnd(
+ (BoolExpr)nctx.recv.apply(n_2, node.getZ3Node(), p, t_2),
+ ctx.mkLt(t_2,t_0)),1,null,null,null,null)));
+
+ // Constraint 6 there does not exist n_2, t_2 : send(node,n_2,p,t_2) && t_2 < t_0
+ this.solver.add(ctx.mkNot(ctx.mkExists(new Expr[]{n_2,t_2},
+ ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(node.getZ3Node(), n_2, p, t_2),
+ ctx.mkLt(t_2,t_0)),1,null,null,null,null)));
+
+
+ result = this.solver.check();
+ model = null;
+ assertions = this.solver.getAssertions();
+ if (result == Status.SATISFIABLE){
+ model = this.solver.getModel();
+ }
+ this.solver.pop();
+ return new IsolationResult(ctx,result, p, n_0, t_1, t_0, nctx, assertions, model);
+
+ }
+
+ public IsolationResult CheckLinkTraversalProperty (NetworkObject src, NetworkObject dest, NetworkObject le0, NetworkObject le1){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ solver.push ();
+ addConstraints();
+
+ Expr p = ctx.mkConst("check_isolation_p_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ Expr n_1 =ctx.mkConst("check_isolation_n_1_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+
+ IntExpr t_0 = ctx.mkIntConst("check_isolation_t0_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_1 = ctx.mkIntConst("check_isolation_t1_"+src.getZ3Node()+"_"+dest.getZ3Node());
+ IntExpr t_2 = ctx.mkIntConst("check_isolation_t2_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p,t_0)
+ this.solver.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p, t_0));
+
+ // Constraint2 send(srcNode,n_1,p1,t_1)
+ this.solver.add((BoolExpr)nctx.send.apply(src.getZ3Node(), n_1, p, t_1));
+
+ // Constraint3 nodeHasAddr(srcNode,p.srcAddr)
+ this.solver.add((BoolExpr)nctx.nodeHasAddr.apply(src.getZ3Node(), nctx.pf.get("src").apply(p)));
+
+ // Constraint4 p.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p), src.getZ3Node()));
+
+ // Constraint5 ∃ t_1, t_2 :
+ // send(linkNode0,linkNode1,p,t_1) &&
+ // recv(linkNode0,linkNode1,p,t_2) &&
+ // t_1 < t_0 &&
+ // t_2 < t_0
+ this.solver.add(ctx.mkExists(new Expr[]{t_1,t_2},
+ ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(le0.getZ3Node(), le1.getZ3Node(), p, t_1),
+ (BoolExpr)nctx.recv.apply(le0.getZ3Node(), le1.getZ3Node(), p, t_2),
+ ctx.mkLt(t_1,t_0),
+ ctx.mkLt(t_2,t_0)),1,null,null,null,null));
+
+
+ result = this.solver.check();
+ model = null;
+ assertions = this.solver.getAssertions();
+ if (result == Status.SATISFIABLE){
+ model = this.solver.getModel();
+ }
+ this.solver.pop();
+ return new IsolationResult(ctx,result, p, n_0, t_1, t_0, nctx, assertions, model);
+
+ }
+
+ public Result CheckDataIsolationPropertyCore (NetworkObject src, NetworkObject dest){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ List<BoolExpr> constr = this.getConstraints();
+ Expr p = ctx.mkConst("check_isolation_p_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ IntExpr t = ctx.mkIntConst("check_isolation_t_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p,t)
+ constr.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p, t));
+
+ // Constraint2 p.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p), src.getZ3Node()));
+
+ this.solver.push();
+
+ // Constraint3 for each constraint( n -> constraint)
+ ArrayList<BoolExpr> names =new ArrayList<BoolExpr>();
+ for(BoolExpr con : constr){
+ BoolExpr n = ctx.mkBoolConst(""+con);
+ names.add(n);
+ this.solver.add(ctx.mkImplies(n, con));
+ }
+
+ BoolExpr[] nam = new BoolExpr[names.size()];
+ result = this.solver.check(names.toArray(nam));
+ Result ret =null;
+
+ if (result == Status.SATISFIABLE){
+ System.out.println("SAT");
+ ret = new Result(ctx,this.solver.getModel());
+ }else if(result == Status.UNSATISFIABLE){
+ System.out.println("unsat");
+ ret = new Result(ctx,this.solver.getUnsatCore());
+ }
+ this.solver.pop();
+ return ret;
+ }
+
+ public DataIsolationResult CheckDataIsolationProperty(NetworkObject src, NetworkObject dest){
+ assert(net.elements.contains(src));
+ assert(net.elements.contains(dest));
+ solver.push ();
+ addConstraints();
+
+ Expr p = ctx.mkConst("check_isolation_p_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.packet);
+
+ Expr n_0 =ctx.mkConst("check_isolation_n_0_"+src.getZ3Node()+"_"+dest.getZ3Node(), nctx.node);
+ IntExpr t = ctx.mkIntConst("check_isolation_t_"+src.getZ3Node()+"_"+dest.getZ3Node());
+
+ // Constraint1 recv(n_0,destNode,p,t)
+ this.solver.add((BoolExpr)nctx.recv.apply(n_0, dest.getZ3Node(), p, t));
+
+ // Constraint2 p.origin == srcNode
+ this.solver.add(ctx.mkEq(nctx.pf.get("origin").apply(p), src.getZ3Node()));
+
+ result = this.solver.check();
+ model = null;
+ assertions = this.solver.getAssertions();
+ if (result == Status.SATISFIABLE){
+ model = this.solver.getModel();
+ }
+ this.solver.pop();
+ return new DataIsolationResult(ctx,result, p, n_0, t, nctx, assertions, model);
+ }
+
+
+
+
+ public void addConstraints(){
+ nctx.addConstraints(solver);
+ net.addConstraints(solver);
+ for (NetworkObject el : net.elements)
+ el.addConstraints(solver);
+ }
+
+
+ public List<BoolExpr> getConstraints(){
+ Solver l = ctx.mkSolver();
+ nctx.addConstraints(l);
+ net.addConstraints(l);
+ for (NetworkObject el : net.elements)
+ el.addConstraints(l);
+ return Arrays.asList(l.getAssertions());
+ }
+}
diff --git a/verigraph/service/src/mcnet/components/Core.java b/verigraph/service/src/mcnet/components/Core.java
new file mode 100644
index 0000000..c72b9e3
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/Core.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.Solver;
+
+/**Core component for everything that matters
+ *
+ */
+public abstract class Core{
+
+ final int MAX_PORT = 512;
+
+ /**
+ * Base class for all objects in the modeling framework
+ * @param ctx
+ * @param args
+ */
+ public Core(Context ctx, Object[]... args){ // Object[]... -> The nearest way to implement variable length argument lists
+ //in Java, in the most generic way.
+ init(ctx,args);
+ }
+ /**
+ * Override _init for any constructor initialization. Avoids having to explicitly call super.__init__ every Time.class
+ * @param ctx
+ * @param args
+ */
+ abstract protected void init(Context ctx,Object[]... args);
+
+ /**
+ * Add constraints to solver
+ * @param solver
+ */
+ abstract protected void addConstraints(Solver solver);
+}
+
+
diff --git a/verigraph/service/src/mcnet/components/DataIsolationResult.java b/verigraph/service/src/mcnet/components/DataIsolationResult.java
new file mode 100644
index 0000000..b90a47f
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/DataIsolationResult.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.Model;
+import com.microsoft.z3.Status;
+
+
+/**Data structure for the response to a check request for data isolation property
+ *
+ */
+public class DataIsolationResult {
+
+ Context ctx;
+ public NetContext nctx;
+ public Status result;
+ public Model model;
+ public Expr violating_packet,last_hop,last_time,t_1;
+ public BoolExpr [] assertions;
+
+ public DataIsolationResult(Context ctx,Status result, Expr violating_packet, Expr last_hop, Expr last_time, NetContext nctx, BoolExpr[] assertions, Model model){
+ this.ctx = ctx;
+ this.result = result;
+ this.violating_packet = violating_packet;
+ this.last_hop = last_hop;
+ this.model = model;
+ this.last_time = last_time;
+ this.assertions = assertions;
+ }
+}
+
diff --git a/verigraph/service/src/mcnet/components/IsolationResult.java b/verigraph/service/src/mcnet/components/IsolationResult.java
new file mode 100644
index 0000000..1ecaccc
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/IsolationResult.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.Model;
+import com.microsoft.z3.Status;
+
+/**
+ * Data structure for the response to check requests for isolation properties
+ *
+ */
+public class IsolationResult {
+
+ Context ctx;
+ public NetContext nctx;
+ public Status result;
+ public Model model;
+ public Expr violating_packet,last_hop,last_send_time,last_recv_time,t_1;
+ public BoolExpr [] assertions;
+
+ public IsolationResult(Context ctx,Status result, Expr violating_packet, Expr last_hop, Expr last_send_time, Expr last_recv_time,NetContext nctx, BoolExpr[] assertions, Model model){
+ this.ctx = ctx;
+ this.result = result;
+ this.violating_packet = violating_packet;
+ this.last_hop = last_hop;
+ this.model = model;
+ this.last_send_time = last_send_time;
+ this.last_recv_time = last_recv_time;
+ this.assertions = assertions;
+ }
+}
+
diff --git a/verigraph/service/src/mcnet/components/NetContext.java b/verigraph/service/src/mcnet/components/NetContext.java
new file mode 100644
index 0000000..ece31c5
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/NetContext.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Constructor;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.DatatypeSort;
+import com.microsoft.z3.EnumSort;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Sort;
+
+import mcnet.netobjs.DumbNode;
+
+/**
+ * Basic fields and other things required for model checking.
+ *
+ */
+public class NetContext extends Core{
+
+
+ List<BoolExpr> constraints;
+ List<Core> policies;
+
+ public HashMap<String,NetworkObject> nm; //list of nodes, callable by node name
+ public HashMap<String,DatatypeExpr> am; // list of addresses, callable by address name
+ public HashMap<String,FuncDecl> pf;
+ Context ctx;
+ public EnumSort node,address;
+ public FuncDecl src_port,dest_port,nodeHasAddr,addrToNode,send,recv;
+ public DatatypeSort packet;
+
+ /* Constants definition
+ - used in the packet proto field */
+ public final int HTTP_REQUEST = 1;
+ public final int HTTP_RESPONSE = 2;
+ public final int POP3_REQUEST = 3;
+ public final int POP3_RESPONSE = 4;
+
+ /**
+ * Context for all of the rest that follows. Every network needs one of these
+ * @param ctx
+ * @param args
+ */
+ public NetContext(Context ctx,Object[]... args ){
+ super(ctx,args);
+
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ nm = new HashMap<String,NetworkObject>(); //list of nodes, callable by node name
+ am = new HashMap<String,DatatypeExpr>(); // list of addresses, callable by address name
+ pf= new HashMap<String,FuncDecl>() ;
+
+ mkTypes((String[])args[0],(String[])args[1]);
+
+ constraints = new ArrayList<BoolExpr>();
+ policies = new ArrayList<Core>();
+
+ baseCondition();
+ }
+
+ /**
+ * A policy is a collection of shared algorithms or functions used by multiple components
+ * (for instance compression or DPI policies etc).
+ * @param policy
+ */
+ public void AddPolicy (NetworkObject policy){
+ policies.add(policy);
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ for (Core policy : policies){
+ policy.addConstraints(solver);
+ }
+ }
+
+ private void mkTypes (String[] nodes, String[] addresses){
+ //Nodes in a network
+ node = ctx.mkEnumSort("Node", nodes);
+ for(int i=0;i<node.getConsts().length;i++){
+ DatatypeExpr fd = (DatatypeExpr)node.getConst(i);
+ DumbNode dn =new DumbNode(ctx,new Object[]{fd});
+ nm.put(fd.toString(),dn);
+ }
+
+ //Addresses for this network
+ String[] new_addr = new String[addresses.length+1];
+ for(int k=0;k<addresses.length;k++)
+ new_addr[k] = addresses[k];
+
+ new_addr[new_addr.length-1] = "null";
+ address = ctx.mkEnumSort("Address", new_addr);
+ for(int i=0;i<address.getConsts().length;i++){
+ DatatypeExpr fd = (DatatypeExpr)address.getConst(i);
+ am.put(fd.toString(),fd);
+ }
+
+ // Type for packets, contains (some of these are currently represented as relations):
+ // - src: Source address
+ // - dest: Destination address
+ // - origin: Node where the data originated. (Node)
+ // - body: Packet contents. (Integer)
+ // - seq: Sequence number for packets. (Integer)
+ // - options: A representation for IP options. (Integer)
+
+ String[] fieldNames = new String[]{
+ "src","dest","inner_src","inner_dest","origin","orig_body","body","seq","proto","emailFrom","url","options","encrypted"};
+ Sort[] srt = new Sort[]{
+ address,address,address,address,node,ctx.mkIntSort(),ctx.mkIntSort(),ctx.mkIntSort(),
+ ctx.mkIntSort(),ctx.mkIntSort(),ctx.mkIntSort(),ctx.mkIntSort(),ctx.mkBoolSort()};
+ Constructor packetcon = ctx.mkConstructor("packet", "is_packet", fieldNames, srt, null);
+ packet = ctx.mkDatatypeSort("packet", new Constructor[] {packetcon});
+
+ for(int i=0;i<fieldNames.length;i++){
+ pf.put(fieldNames[i], packet.getAccessors()[0][i]); // pf to get packet's function declarations by name
+ }
+
+ src_port = ctx.mkFuncDecl("sport", packet, ctx.mkIntSort());
+ dest_port = ctx.mkFuncDecl("dport", packet, ctx.mkIntSort());
+
+ // Some commonly used relations
+
+ // nodeHasAddr: node -> address -> boolean
+ nodeHasAddr = ctx.mkFuncDecl("nodeHasAddr", new Sort[]{node, address},ctx.mkBoolSort());
+
+ // addrToNode: address -> node
+ addrToNode = ctx.mkFuncDecl("addrToNode", address, node);
+
+ // Send and receive both have the form:
+ // source-> destination -> packet-> int-> bool
+
+ // send: node -> node -> packet-> int-> bool
+ send = ctx.mkFuncDecl("send", new Sort[]{ node, node, packet, ctx.mkIntSort()},ctx.mkBoolSort());
+
+ // recv: node -> node -> packet-> int-> bool
+ recv = ctx.mkFuncDecl("recv", new Sort[]{ node, node, packet, ctx.mkIntSort()},ctx.mkBoolSort());
+
+ }
+
+ /**
+ * Set up base conditions for the network
+ */
+ private void baseCondition(){
+ // Basic constraints for the overall model
+ Expr n_0 = ctx.mkConst("ctx_base_n_0", node);
+ Expr n_1 = ctx.mkConst("ctx_base_n_1", node);
+ Expr n_2 = ctx.mkConst("ctx_base_n_2", node);
+ Expr p_0 = ctx.mkConst("ctx_base_p_0", packet);
+ Expr p_1 = ctx.mkConst("ctx_base_p_1", packet);
+ IntExpr t_0 = ctx.mkIntConst("ctx_base_t_0");
+ IntExpr t_1 = ctx.mkIntConst("ctx_base_t_1");
+
+ // Constraint1 send(n_0, n_1, p_0, t_0) -> n_0 != n_1
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)send.apply(n_0, n_1, p_0, t_0),ctx.mkNot(ctx.mkEq( n_0, n_1))),1,null,null,null,null));
+
+ // Constraint2 recv(n_0, n_1, p_0, t_0) -> n_0 != n_1
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),ctx.mkNot(ctx.mkEq( n_0, n_1))),1,null,null,null,null));
+
+ // Constraint3 send(n_0, n_1, p_0, t_0) -> p_0.src != p_0.dest
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkNot(ctx.mkEq( pf.get("src").apply(p_0), pf.get("dest").apply(p_0)))),1,null,null,null,null));
+
+ // Constraint4 recv(n_0, n_1, p_0, t_0) -> p_0.src != p_0.dest
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkNot(ctx.mkEq(pf.get("src").apply(p_0),pf.get("dest").apply(p_0)))),1,null,null,null,null));
+
+ // Constraint5 recv(n_0, n_1, p, t_0) -> send(n_0, n_1, p, t_1) && t_1 < t_0
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkExists(new Expr[]{t_1},
+ ctx.mkAnd((BoolExpr)send.apply(n_0, n_1, p_0, t_1),
+ ctx.mkLt(t_1, t_0)),1,null,null,null,null)),1,null,null,null,null));
+
+ // Constraint6 send(n_0, n_1, p, t_0) -> p.src_port > 0 && p.dest_port < MAX_PORT
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkAnd( ctx.mkGe((IntExpr)src_port.apply(p_0),(IntExpr)ctx.mkInt(0)),
+ ctx.mkLt((IntExpr)src_port.apply(p_0),(IntExpr) ctx.mkInt(MAX_PORT)))),1,null,null,null,null));
+
+ // Constraint7 recv(n_0, n_1, p, t_0) -> p.src_port > 0 && p.dest_port < MAX_PORT
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkAnd( ctx.mkGe((IntExpr)dest_port.apply(p_0),(IntExpr)ctx.mkInt(0)),
+ ctx.mkLt((IntExpr)dest_port.apply(p_0),(IntExpr) ctx.mkInt(MAX_PORT)))),1,null,null,null,null));
+
+ // Constraint8 recv(n_0, n_1, p_0, t_0) -> t_0 > 0
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkGt(t_0,ctx.mkInt(0))),1,null,null,null,null));
+
+ // Constraint9 send(n_0, n_1, p_0, t_0) -> t_0 > 0
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkGt(t_0,ctx.mkInt(0))),1,null,null,null,null));
+
+ // Extra constriants for supporting the VPN gateway
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkNot(ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.am.get("null")))),
+ ctx.mkNot(ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0)))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.am.get("null"))),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ ctx.mkEq(this.pf.get("inner_dest").apply(p_0), this.am.get("null"))),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkNot(ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.am.get("null")))),
+ ctx.mkNot(ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0)))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.am.get("null"))),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)recv.apply(n_0, n_1, p_0, t_0),
+ ctx.mkEq(this.pf.get("inner_dest").apply(p_0), this.am.get("null"))),
+ ctx.mkEq(this.pf.get("inner_src").apply(p_0), this.pf.get("inner_dest").apply(p_0))),1,null,null,null,null));
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, n_1, p_0, t_0, n_2, p_1, t_1},
+ ctx.mkImplies(
+ ctx.mkAnd(
+ ctx.mkLt(t_1, t_0),
+ (BoolExpr)send.apply(n_0, n_1, p_0, t_0),
+ (BoolExpr)this.pf.get("encrypted").apply(p_1),
+ (BoolExpr)recv.apply(n_2, n_0, p_1, t_1),
+ (BoolExpr)this.pf.get("encrypted").apply(p_0)),
+ ctx.mkAnd(
+ ctx.mkEq(this.pf.get("inner_src").apply(p_1), this.pf.get("inner_src").apply(p_0)),
+ ctx.mkEq(this.pf.get("inner_dest").apply(p_1), this.pf.get("inner_dest").apply(p_0)),
+ ctx.mkEq(this.pf.get("origin").apply(p_1), this.pf.get("origin").apply(p_0)),
+ ctx.mkEq(this.pf.get("orig_body").apply(p_1), this.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(this.pf.get("body").apply(p_1), this.pf.get("body").apply(p_0)),
+ ctx.mkEq(this.pf.get("seq").apply(p_1), this.pf.get("seq").apply(p_0)),
+ ctx.mkEq(this.pf.get("proto").apply(p_1), this.pf.get("proto").apply(p_0)),
+ ctx.mkEq(this.pf.get("emailFrom").apply(p_1), this.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(this.pf.get("url").apply(p_1), this.pf.get("url").apply(p_0)),
+ ctx.mkEq(this.pf.get("options").apply(p_1), this.pf.get("options").apply(p_0)))),1,null,null,null,null)
+ );
+ }
+
+ /**
+ * Two packets have equal headers
+ * @param p1
+ * @param p2
+ * @return
+ */
+ public BoolExpr PacketsHeadersEqual(Expr p1, Expr p2){
+ return ctx.mkAnd(new BoolExpr[]{
+ ctx.mkEq(pf.get("src").apply(p1), pf.get("src").apply(p2)),
+ ctx.mkEq(pf.get("dest").apply(p1), pf.get("dest").apply(p2)),
+ ctx.mkEq(pf.get("origin").apply(p1), pf.get("origin").apply(p2)),
+ ctx.mkEq(pf.get("seq").apply(p1), pf.get("seq").apply(p2)),
+ ctx.mkEq(src_port.apply(p1), src_port.apply(p2)),
+ ctx.mkEq(dest_port.apply(p1), dest_port.apply(p2)),
+ ctx.mkEq(pf.get("options").apply(p1), pf.get("options").apply(p2))});
+ }
+
+ /**
+ * Two packets have equal bodies
+ * @param p1
+ * @param p2
+ * @return
+ */
+ public BoolExpr PacketContentEqual(Expr p1, Expr p2){
+ return ctx.mkEq(pf.get("body").apply(p1), pf.get("body").apply(p2));
+ }
+
+
+ /* seems to be useless
+ *
+ public Function failurePredicate (NetContext context)
+ {
+ return (NetworkObject node) -> ctx.mkNot(context.failed (node.z3Node));
+
+ }*/
+
+ public BoolExpr destAddrPredicate (Expr p, DatatypeExpr address){
+ return ctx.mkEq(pf.get("dest").apply(p),address);
+ }
+
+ public BoolExpr srcAddrPredicate (Expr p, DatatypeExpr address){
+ return ctx.mkEq(pf.get("src").apply(p),address);
+ }
+
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/components/Network.java b/verigraph/service/src/mcnet/components/Network.java
new file mode 100644
index 0000000..c04f771
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/Network.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Z3Exception;
+
+/**Model for a network, encompasses routing and wiring
+ *
+ */
+public class Network extends Core{
+
+ Context ctx;
+ NetContext nctx;
+ List<BoolExpr> constraints;
+ List<NetworkObject> elements;
+
+
+
+ public Network(Context ctx,Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ this.nctx = (NetContext) args[0][0];
+ constraints = new ArrayList<BoolExpr>();
+ elements = new ArrayList<NetworkObject>();
+
+ }
+
+ /**Composes the network linking the configured network objects
+ *
+ * @param elements
+ */
+ public void attach (NetworkObject ... elements){
+ for(NetworkObject el : elements)
+ this.elements.add(el);
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ try {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ } catch (Z3Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Specify host to address mapping.
+ * Handles the case in which we have more than one address for a node
+ * @param addrmap
+ */
+ public void setAddressMappings(ArrayList<Tuple<NetworkObject,ArrayList<DatatypeExpr>>> addrmap){
+ // Set address mapping for nodes.
+ for (Tuple<NetworkObject,ArrayList<DatatypeExpr>> entry : addrmap) {
+ NetworkObject node=entry._1;
+ List<DatatypeExpr> addr=entry._2;
+ Expr a_0 = ctx.mkConst(node+"_address_mapping_a_0",nctx.address);
+ ArrayList<BoolExpr> or_clause = new ArrayList<BoolExpr>();
+
+ // Constraint 1 addrToNode(foreach ad in addr) = node
+ for (DatatypeExpr ad : addr){
+ constraints.add(ctx.mkEq(nctx.addrToNode.apply(ad), node.getZ3Node()));
+ or_clause.add(ctx.mkEq(a_0,ad));
+ }
+ BoolExpr[] orClause = new BoolExpr[or_clause.size()];
+
+ // Constraint 2 nodeHasAddr(node, a_0) == Or(foreach ad in addr (a_0 == ad))
+ // Note we need the iff here to make sure that we set nodeHasAddr to false
+ // for other addresses.
+ constraints.add(ctx.mkForall(new Expr[]{a_0},
+ ctx.mkEq(ctx.mkOr(or_clause.toArray(orClause)), nctx.nodeHasAddr.apply(node.getZ3Node(), a_0)),1,null,null,null,null));
+ }
+ }
+
+
+
+ /**
+ * Don't forward packets addressed to node
+ * @param node
+ */
+ public void saneSend(NetworkObject node){
+ Expr n_0 = ctx.mkConst(node+"_saneSend_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst(node+"_saneSend_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst(node+"_saneSend_t_0");
+ // Constant: node
+ //Constraint send(node, n_0, p, t_0) -> !nodeHasAddr(node, p.dest)
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node.getZ3Node(),n_0, p_0, t_0),
+ ctx.mkNot((BoolExpr)nctx.nodeHasAddr.apply( node.getZ3Node(),
+ nctx.pf.get("dest").apply(p_0)))),1,null,null,null,null));
+ }
+
+ /**
+ * Node sends all traffic through gateway
+ * @param node
+ * @param gateway
+ */
+ public void setGateway (NetworkObject node, NetworkObject gateway){
+ // SetGateway(self, node, gateway): All packets from node are sent through gateway
+ Expr n_0 = ctx.mkConst(node+"_gateway_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst(node+"_gateway_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst(node+"_gateway_t_0");
+
+ //Constraint send(node, n_0, p_0, t_0) -> n_0 = gateway
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.send.apply(node.getZ3Node(), n_0, p_0, t_0),
+ ctx.mkEq(n_0,gateway.getZ3Node())),1,null,null,null,null));
+
+// constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0, node.getZ3Node(), p_0, t_0),
+// ctx.mkEq(n_0,gateway.getZ3Node())),1,null,null,null,null));
+ }
+
+ /**
+ * Assigns a specific routing table to a network object. Routing entries in the form: address -> node
+ * @param node
+ * @param routing_table
+ */
+ public void routingTable (NetworkObject node,ArrayList<Tuple<DatatypeExpr,NetworkObject>> routing_table){
+ compositionPolicy(node,routing_table);
+ }
+
+ /**
+ * Composition policies steer packets between middleboxes.
+ * @param node
+ * @param policy
+ */
+ public void compositionPolicy (NetworkObject node,ArrayList<Tuple<DatatypeExpr,NetworkObject>> policy){
+ //Policy is of the form predicate -> node
+ Expr p_0 = ctx.mkConst(node+"_composition_p_0", nctx.packet);
+ Expr n_0 = ctx.mkConst(node+"_composition_n_0", nctx.node);
+ Expr t_0 = ctx.mkIntConst(node+"_composition_t_0");
+
+ HashMap<String,ArrayList<BoolExpr>> collected = new HashMap<String,ArrayList<BoolExpr>>();
+ HashMap<String,NetworkObject> node_dict = new HashMap<String,NetworkObject>();
+ BoolExpr predicates;
+ for(int y=0;y<policy.size();y++){
+ Tuple<DatatypeExpr,NetworkObject> tp = policy.get(y);
+ if(collected.containsKey(""+tp._2)) collected.get(""+tp._2).add(nctx.destAddrPredicate(p_0,tp._1));
+ else{
+ ArrayList<BoolExpr> alb = new ArrayList<BoolExpr>();
+ alb.add(nctx.destAddrPredicate(p_0,tp._1));
+ collected.put(""+tp._2,alb);
+ }
+ node_dict.put(""+tp._2, tp._2);
+ }
+
+ //Constraint foreach rtAddr,rtNode in rt( send(node, n_0, p_0, t_0) &&
+ // Or(foreach rtAddr in rt destAddrPredicate(p_0,rtAddr)) -> n_0 == rtNode )
+ for (Map.Entry<String,ArrayList<BoolExpr>> entry : collected.entrySet()) {
+ BoolExpr[] pred = new BoolExpr[entry.getValue().size()];
+ predicates = ctx.mkOr(entry.getValue().toArray(pred));
+
+ constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(node.getZ3Node(), n_0, p_0, t_0), predicates),
+ ctx.mkEq(n_0, node_dict.get(entry.getKey()).getZ3Node())),1,null,null,null,null));
+ }
+ }
+
+ /**
+ * Routing entries are in the form: address -> node. Also allows packet to be sent to another box for further processing
+ * @param node
+ * @param routing_table
+ * @param shunt_node
+ */
+ public void routingTableShunt (NetworkObject node,ArrayList<Tuple<DatatypeExpr,NetworkObject>> routing_table,NetworkObject shunt_node){
+ compositionPolicyShunt(node,routing_table,shunt_node);
+ }
+
+ /**
+ * Composition policies steer packets between middleboxes.Policy is in the form: predicate -> node
+ * @param node
+ * @param routing_table
+ * @param shunt_node
+ */
+ public void compositionPolicyShunt (NetworkObject node,ArrayList<Tuple<DatatypeExpr,NetworkObject>> routing_table,NetworkObject shunt_node){
+ Expr p_0 = ctx.mkConst(node+"_composition_p_0", nctx.packet);
+ Expr n_0 = ctx.mkConst(node+"_composition_n_0", nctx.node);
+ Expr t_0 = ctx.mkIntConst(node+"_composition_t_0");
+
+ HashMap<String,ArrayList<BoolExpr>> collected = new HashMap<String,ArrayList<BoolExpr>>();
+ HashMap<String,NetworkObject> node_dict = new HashMap<String,NetworkObject>();
+ BoolExpr predicates;
+ for(int y=0;y<routing_table.size();y++){
+ Tuple<DatatypeExpr,NetworkObject> tp = routing_table.get(y);
+ if(collected.containsKey(""+tp._2)) collected.get(""+tp._2).add(nctx.destAddrPredicate(p_0,tp._1));
+ else{
+ ArrayList<BoolExpr> alb = new ArrayList<BoolExpr>();
+ alb.add(nctx.destAddrPredicate(p_0,tp._1));
+ collected.put(""+tp._2,alb);
+ }
+ node_dict.put(""+tp._2, tp._2);
+ }
+
+ //Constraint foreach rtAddr,rtNode in rt( send(node, n_0, p_0, t_0) &&
+ // Or(foreach rtAddr in rt destAddrPredicate(p_0,rtAddr)) -> n_0 == rtNode )
+ for (Map.Entry<String,ArrayList<BoolExpr>> entry : collected.entrySet()) {
+ BoolExpr[] pred = new BoolExpr[entry.getValue().size()];
+ predicates = ctx.mkOr(entry.getValue().toArray(pred));
+
+ constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(node.getZ3Node(), n_0, p_0, t_0), predicates),
+ ctx.mkOr(ctx.mkEq(n_0, node_dict.get(entry.getKey()).getZ3Node()),ctx.mkEq(n_0, shunt_node.getZ3Node()))),1,null,null,null,null));
+ }
+
+ }
+
+// public void SimpleIsolation (NetworkObject node, ArrayList<DatatypeExpr> addresses){
+// Expr p = ctx.mkConst(node+"_s_p", nctx.packet);
+// Expr n = ctx.mkConst(node+"_s_n", nctx.node);
+// IntExpr t = ctx.mkInt(node+"_s_t");
+//
+// BoolExpr[] a_pred= new BoolExpr[addresses.size()];
+// for(int y=0;y<addresses.size();y++){
+// DatatypeExpr de = addresses.get(y);
+// a_pred[y] = ctx.mkOr(ctx.mkEq(nctx.pf.get("src").apply(p), de),ctx.mkEq(nctx.pf.get("dest").apply(p), de));
+// }
+//
+// constraints.add(
+// ctx.mkForall(new Expr[]{p, n, t},
+// ctx.mkImplies((BoolExpr)nctx.recv.apply(n, node.getZ3Node(), p, t),
+// ctx.mkOr(a_pred)),1,null,null,null,null));
+// constraints.add(
+// ctx.mkForall(new Expr[]{p, n, t},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(node.getZ3Node(), n, p, t),
+// ctx.mkOr(a_pred)),1,null,null,null,null));
+// }
+
+
+ /**
+ * Set isolation constraints on a node.
+ * Doesn't need to be set but useful when interfering policies are in play.
+ * @param node
+ * @param adjacencies
+ *
+ */
+ public void SetIsolationConstraint ( NetworkObject node, ArrayList<NetworkObject> adjacencies){
+
+ Expr n_0 = ctx.mkConst(node+"_isolation_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst(node+"_isolation_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkInt(node+"_isolation_t_0");
+
+ BoolExpr[] adj = new BoolExpr[adjacencies.size()];
+ for(int y=0;y<adjacencies.size();y++){
+ NetworkObject no = adjacencies.get(y);
+ adj[y] = ctx.mkEq(n_0,no.getZ3Node());
+ }
+ BoolExpr clause = ctx.mkOr(adj);
+
+ constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node.getZ3Node(), n_0, p_0, t_0),
+ clause),1,null,null,null,null));
+ constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0, node.getZ3Node(), p_0, t_0),
+ clause),1,null,null,null,null));
+ }
+
+ /**
+ * Return all currently attached endhosts
+ * @return NetworkObject
+ */
+ public List<String> EndHosts(){
+ List<String> att_nos = new ArrayList<String>();
+ for(NetworkObject el :elements){
+ if(el.isEndHost){
+ System.out.println("el: "+el);
+ att_nos.add(el.getZ3Node().toString());
+ }
+ }
+ return att_nos;
+ }
+}
diff --git a/verigraph/service/src/mcnet/components/NetworkObject.java b/verigraph/service/src/mcnet/components/NetworkObject.java
new file mode 100644
index 0000000..0de3937
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/NetworkObject.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+
+/** Represents a generic network object.
+ *
+ */
+public abstract class NetworkObject extends Core{
+
+ public NetworkObject(Context ctx,Object[]... args) {
+ super(ctx,args);
+ }
+
+ protected DatatypeExpr z3Node;
+ protected boolean isEndHost;
+ /**
+ * Get a reference to the z3 node this class wraps around
+ * @return
+ */
+ abstract public DatatypeExpr getZ3Node();
+
+ public String toString(){
+ return z3Node.toString();
+ }
+
+ //There is probably an error: z3Node.hashCode = 0 because AST.hashCode() has always hash=0
+ /*public int hashCode(){
+ return z3Node.hashCode();
+ }*/
+
+ /**
+ * A simple way to determine the set of endhosts
+ * @return
+ */
+ public boolean isEndHost(){
+ return isEndHost;
+ }
+
+ /**
+ * Wrap methods to set policy
+ * @param policy
+ * @throws UnsupportedOperationException
+ */
+ void setPolicy (Object policy) throws UnsupportedOperationException{
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/verigraph/service/src/mcnet/components/Result.java b/verigraph/service/src/mcnet/components/Result.java
new file mode 100644
index 0000000..acb23f1
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/Result.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.Model;
+
+/**Data structure for the core of the response to a check request for data isolation property
+ *
+ */
+public class Result {
+ Context ctx;
+ public Model model;
+ public BoolExpr[] unsat_core;
+
+/**
+ *
+ * @param ctx
+ * @param model
+ */
+ public Result(Context ctx, Model model){
+ this.ctx = ctx;
+ this.model = model;
+ }
+
+/**
+ *
+ * @param ctx
+ * @param unsat_core
+ */
+ public Result(Context ctx, BoolExpr[] unsat_core){
+ this.ctx = ctx;
+ this.unsat_core = unsat_core;
+}
+}
diff --git a/verigraph/service/src/mcnet/components/Tuple.java b/verigraph/service/src/mcnet/components/Tuple.java
new file mode 100644
index 0000000..849d607
--- /dev/null
+++ b/verigraph/service/src/mcnet/components/Tuple.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.components;
+
+/** A data structure which is an utility to make a generic couple of objects with different types in Java
+ *
+ */
+public class Tuple<T, U> {
+ public final T _1;
+ public final U _2;
+
+
+ public Tuple(T arg1,U arg2) {
+ super();
+ this._1 = arg1;
+ this._2 = arg2;
+ }
+
+ public Tuple(){
+ this._1 = null;
+ this._2 = null;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(%s, %s)", _1, _2);
+ }
+ } \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/AclFirewall.java b/verigraph/service/src/mcnet/netobjs/AclFirewall.java
new file mode 100644
index 0000000..4ae3421
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/AclFirewall.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Sort;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+import mcnet.components.Tuple;
+
+/** Represents a Firewall with the associated Access Control List
+ *
+ */
+public class AclFirewall extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr fw;
+ ArrayList<Tuple<DatatypeExpr,DatatypeExpr>> acls;
+ Network net;
+ NetContext nctx;
+ FuncDecl acl_func;
+
+ public AclFirewall(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ acls = new ArrayList<Tuple<DatatypeExpr,DatatypeExpr>>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ fw = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ net.saneSend(this);
+ firewallSendRules();
+ }
+
+ /**
+ * Wrap add acls
+ * @param policy
+ */
+ public void setPolicy(ArrayList<Tuple<DatatypeExpr, DatatypeExpr>> policy){
+ addAcls(policy);
+ }
+
+ public void addAcls(ArrayList<Tuple<DatatypeExpr,DatatypeExpr>> acls){
+ this.acls.addAll(acls);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return fw;
+ }
+
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ aclConstraints(solver);
+ }
+
+ private void firewallSendRules (){
+ Expr p_0 = ctx.mkConst(fw+"_firewall_send_p_0", nctx.packet);
+ Expr n_0 = ctx.mkConst(fw+"_firewall_send_n_0", nctx.node);
+ Expr n_1 = ctx.mkConst(fw+"_firewall_send_n_1", nctx.node);
+ IntExpr t_0 = ctx.mkIntConst(fw+"_firewall_send_t_0");
+ IntExpr t_1 = ctx.mkIntConst(fw+"_firewall_send_t_1");
+ acl_func = ctx.mkFuncDecl(fw+"_acl_func", new Sort[]{nctx.address, nctx.address},ctx.mkBoolSort());
+
+ //Constraint1 send(fw, n_0, p, t_0) -> (exist n_1,t_1 : (recv(n_1, fw, p, t_1) &&
+ // t_1 < t_0 && !acl_func(p.src,p.dest))
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.send.apply(new Expr[]{ fw, n_0, p_0, t_0}),
+ ctx.mkExists(new Expr[]{t_1},
+ ctx.mkAnd(ctx.mkLt(t_1,t_0),
+ ctx.mkExists(new Expr[]{n_1},
+ nctx.recv.apply(n_1, fw, p_0, t_1),1,null,null,null,null),
+ ctx.mkNot((BoolExpr)acl_func.apply(nctx.pf.get("src").apply(p_0), nctx.pf.get("dest").apply(p_0)))),1,null,null,null,null)),1,null,null,null,null));
+
+ }
+
+ private void aclConstraints(Solver solver){
+ if (acls.size() == 0)
+ return;
+ Expr a_0 = ctx.mkConst(fw+"_firewall_acl_a_0", nctx.address);
+ Expr a_1 = ctx.mkConst(fw+"_firewall_acl_a_1", nctx.address);
+ BoolExpr[] acl_map = new BoolExpr[acls.size()];
+ for(int y=0;y<acls.size();y++){
+ Tuple<DatatypeExpr,DatatypeExpr> tp = acls.get(y);
+ acl_map[y] = ctx.mkOr(ctx.mkAnd(ctx.mkEq(a_0,tp._1),ctx.mkEq(a_1,tp._2)), ctx.mkAnd(ctx.mkEq(a_0,tp._2),ctx.mkEq(a_1,tp._1)));
+ }
+ //Constraint2 acl_func(a_0,a_1) == or(foreach ip1,ip2 in acl_map ((a_0 == ip1 && a_1 == ip2)||(a_0 == ip2 && a_1 == ip1)))
+ solver.add(ctx.mkForall(new Expr[]{a_0, a_1},
+ ctx.mkEq(
+ acl_func.apply(a_0, a_1),
+ ctx.mkOr(acl_map)),1,null,null,null,null));
+ }
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/DumbNode.java b/verigraph/service/src/mcnet/netobjs/DumbNode.java
new file mode 100644
index 0000000..012ff40
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/DumbNode.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetworkObject;
+
+/**
+ * This is just a wrapper around z3 instances. The idea is that by using this we perhaps need to have
+ * fewer (or no) ifs to deal with the case where we don't instantiate an object for a node
+ *
+ */
+public class DumbNode extends NetworkObject {
+ public DumbNode(Context ctx, Object[]... args){
+ super(ctx,args);
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ return;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ isEndHost=true;
+ this.z3Node = (DatatypeExpr)args[0][0];
+ }
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return z3Node;
+ }
+}
diff --git a/verigraph/service/src/mcnet/netobjs/EndHost.java b/verigraph/service/src/mcnet/netobjs/EndHost.java
new file mode 100644
index 0000000..99cf732
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/EndHost.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**
+ * End host network objects
+ *
+ */
+public class EndHost extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr node;
+ Network net;
+ NetContext nctx;
+
+ public EndHost(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=true;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ node = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ endHostRules();
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return node;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void endHostRules (){
+ Expr n_0 = ctx.mkConst("eh_"+node+"_n_0", nctx.node);
+ IntExpr t_0 = ctx.mkIntConst("eh_"+node+"_t_0");
+ Expr p_0 = ctx.mkConst("eh_"+node+"_p_0", nctx.packet);
+
+ //Constraint1 send(node, n_0, p, t_0) -> nodeHasAddr(node,p.src)
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.send.apply( new Expr[]{ node, n_0, p_0, t_0}),
+ (BoolExpr)nctx.nodeHasAddr.apply(new Expr[]{node, nctx.pf.get("src").apply(p_0)})),1,null,null,null,null));
+ //Constraint2 send(node, n_0, p, t_0) -> p.origin == node
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.send.apply( new Expr[]{ node, n_0, p_0, t_0}),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),node)),1,null,null,null,null));
+ //Constraint3 send(node, n_0, p, t_0) -> p.orig_body == p.body
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.send.apply(new Expr[]{ node, n_0, p_0, t_0}),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),1,null,null,null,null));
+ //Constraint4 recv(n_0, node, p, t_0) -> nodeHasAddr(node,p.dest)
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(
+ (BoolExpr)nctx.recv.apply( new Expr[]{ n_0, node, p_0, t_0}),
+ (BoolExpr)nctx.nodeHasAddr.apply(new Expr[]{node, nctx.pf.get("dest").apply(p_0)})),1,null,null,null,null));
+
+// Just a try: here we state that an endhost is not able to issue a HTTP response traffic
+// See PolitoCache.py model for constants definition (2 means HTTP_RESPONSE, 1 means HTTP_REQUEST)
+// constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(node, n_0, p_0, t_0),
+// ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(1))),1,null,null,null,null));
+ }
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PacketModel.java b/verigraph/service/src/mcnet/netobjs/PacketModel.java
new file mode 100644
index 0000000..5761861
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PacketModel.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import com.microsoft.z3.DatatypeExpr;
+
+/*
+ * Fields that can be configured -> "dest","body","seq","proto","emailFrom","url","options"
+ */
+public class PacketModel {
+
+ private DatatypeExpr ip_dest;
+ private Integer body;
+ private Integer seq;
+ private Integer proto;
+ private Integer emailFrom;
+ private Integer url;
+ private Integer options;
+
+ public DatatypeExpr getIp_dest() {
+ return ip_dest;
+ }
+ public void setIp_dest(DatatypeExpr ip_dest) {
+ this.ip_dest = ip_dest;
+ }
+ public Integer getBody() {
+ return body;
+ }
+ public void setBody(Integer body) {
+ this.body = body;
+ }
+ public Integer getSeq() {
+ return seq;
+ }
+ public void setSeq(Integer seq) {
+ this.seq = seq;
+ }
+ public Integer getProto() {
+ return proto;
+ }
+ public void setProto(Integer proto) {
+ this.proto = proto;
+ }
+ public Integer getEmailFrom() {
+ return emailFrom;
+ }
+ public void setEmailFrom(Integer emailFrom) {
+ this.emailFrom = emailFrom;
+ }
+ public Integer getUrl() {
+ return url;
+ }
+ public void setUrl(Integer url) {
+ this.url = url;
+ }
+ public Integer getOptions() {
+ return options;
+ }
+ public void setOptions(Integer options) {
+ this.options = options;
+ }
+
+}
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoAntispam.java b/verigraph/service/src/mcnet/netobjs/PolitoAntispam.java
new file mode 100644
index 0000000..abb4615
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoAntispam.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+/**
+ * Model of an anti-spam node
+ *
+ */
+public class PolitoAntispam extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoAntispam;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoAntispam(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoAntispam = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ //net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoAntispam;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void installAntispam (int[] blackList){
+ Expr n_0 = ctx.mkConst(politoAntispam+"_n_0", nctx.node);
+ Expr n_1 = ctx.mkConst(politoAntispam+"_n_1", nctx.node);
+ Expr p_0 = ctx.mkConst(politoAntispam+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst(politoAntispam+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst(politoAntispam+"_t_1");
+ IntExpr ef_0 = ctx.mkIntConst(politoAntispam+"_ef_0");
+
+ isInBlacklist = ctx.mkFuncDecl(politoAntispam+"_isInBlacklist", ctx.mkIntSort(), ctx.mkBoolSort());
+ BoolExpr[] blConstraint = new BoolExpr[blackList.length];
+ if(blackList.length != 0){
+ for (int i=0;i<blackList.length;i++)
+ blConstraint[i]=(ctx.mkEq(ef_0,ctx.mkInt(blackList[i])));
+ //Constraint1a if(isInBlackList(ef_0) == or(for bl in blacklist (ef_0==bl)) ? true : false
+ constraints.add(ctx.mkForall(new Expr[]{ef_0}, ctx.mkIff((BoolExpr)isInBlacklist.apply(ef_0),ctx.mkOr(blConstraint)),1,null,null,null,null));
+ }else{
+ //Constraint1b isInblackList(ef_0) == false
+ constraints.add(ctx.mkForall(new Expr[]{ef_0}, ctx.mkEq((BoolExpr)isInBlacklist.apply(ef_0), ctx.mkBool(false)),1,null,null,null,null));
+ }
+
+ //Constraint2 send(politoAntispam, n_0, p, t_0) && p.proto(POP3_RESP) ->
+ // (exist n_1,t_1 : (recv(n_1, politoAntispam, p, t_1) && t_1 < t_0)) && !isInBlackList(p.emailFrom)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(politoAntispam, n_0, p_0, t_0), ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_RESPONSE))),
+ ctx.mkAnd( ctx.mkExists(new Expr[]{n_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1, politoAntispam, p_0, t_1), ctx.mkLt(t_1 , t_0)),1,null,null,null,null),
+ ctx.mkNot((BoolExpr)isInBlacklist.apply(nctx.pf.get("emailFrom").apply(p_0))))),1,null,null,null,null));
+
+ //Constraint3 send(politoAntispam, n_0, p, t_0) && p.proto(POP3_REQ) ->
+ // (exist n_1,t_1 : (recv(n_1, politoAntispam, p, t_1) && t_1 < t_0))
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(politoAntispam, n_0, p_0, t_0), ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_REQUEST))),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{n_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1, politoAntispam, p_0, t_1),
+ ctx.mkLt(t_1 , t_0)),1,null,null,null,null))),1,null,null,null,null));
+
+ //Constraint4 send(politoAntispam, politoErrFunction, p, t_0) ->
+ // (exist n_1,t_1 : (recv(n_1, politoAntispam, p, t_1) && t_1 < t_0 && p.emailFrom ==1))
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoAntispam, nctx.nm.get("politoErrFunction").getZ3Node(), p_0, t_0),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{n_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1, politoAntispam, p_0, t_1),
+ ctx.mkLt(t_1 , t_0),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_0),ctx.mkInt(1))),1,null,null,null,null))),1,null,null,null,null));
+
+ //Constraint5 send(politoAntispam, n_0, p, t_0) -> p.proto == POP_REQ || p.protpo == POP_RESP
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoAntispam, n_0, p_0, t_0),
+ ctx.mkOr( ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_REQUEST)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_RESPONSE)))),1,null,null,null,null));
+
+ //Constraint6 send(politoAntispam, n_0, p, t_0) -> nodeHasAddr(politoAntispam,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoAntispam, n_0, p_0, t_0),
+ ctx.mkNot((BoolExpr)nctx.nodeHasAddr.apply(politoAntispam,nctx.pf.get("src").apply(p_0)))),1,null,null,null,null));
+ }
+ } \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoCache.java b/verigraph/service/src/mcnet/netobjs/PolitoCache.java
new file mode 100644
index 0000000..948915c
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoCache.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Sort;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**Cache Model
+ *
+ */
+public class PolitoCache extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoCache;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoCache(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoCache = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ //net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoCache;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void installCache (NetworkObject[] internalNodes){
+ Expr n_0 = ctx.mkConst("politoCache_"+politoCache+"_n_0", nctx.node);
+ Expr n_1 = ctx.mkConst("politoCache_"+politoCache+"_n_1", nctx.node);
+ Expr n_2 = ctx.mkConst("politoCache_"+politoCache+"_n_2", nctx.node);
+ Expr p_0 = ctx.mkConst("politoCache_"+politoCache+"_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("politoCache_"+politoCache+"_p_1", nctx.packet);
+ Expr p_2 = ctx.mkConst("politoCache_"+politoCache+"_p_2", nctx.packet);
+
+ IntExpr t_0 = ctx.mkIntConst("politoCache_"+politoCache+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst("politoCache_"+politoCache+"_t_1");
+ IntExpr t_2 = ctx.mkIntConst("politoCache_"+politoCache+"_t_2");
+
+ Expr a_0 = ctx.mkConst(politoCache+"politoCache_a_0", nctx.node);
+ IntExpr u_0 = ctx.mkIntConst("politoCache_"+politoCache+"_u_0");
+
+ FuncDecl isInternalNode = ctx.mkFuncDecl(politoCache+"_isInternalNode", nctx.node, ctx.mkBoolSort());
+ FuncDecl isInCache = ctx.mkFuncDecl(politoCache+"_isInCache", new Sort[]{ctx.mkIntSort(),ctx.mkIntSort()}, ctx.mkBoolSort());
+
+ assert(internalNodes.length!=0); //No internal nodes => Should never happen
+
+ //Modeling the behavior of the isInternalNode() and isInCache() functions
+ BoolExpr[] internalNodesConstraint = new BoolExpr[internalNodes.length];
+ for(int w=0;w<internalNodesConstraint.length;w++)
+ internalNodesConstraint[w]= (ctx.mkEq(a_0,internalNodes[w].getZ3Node()));
+
+ //Constraint1 if(isInternalNode(a_0) == or(listadeinodiinterni) ? True : false
+ constraints.add(
+ ctx.mkForall(new Expr[]{a_0},
+ ctx.mkIff((BoolExpr)isInternalNode.apply(a_0), ctx.mkOr(internalNodesConstraint)),1,null,null,null,null));
+
+// constraints.add(ctx.mkForall(new Expr[]{a_0}, ctx.mkEq(isInternalNode.apply(a_0),ctx.mkOr(internalNodesConstraint)),1,null,null,null,null));
+
+// constraints.add(ctx.mkForall(new Expr[]{u_0, t_0},
+// ctx.mkITE(ctx.mkExists(new Expr[]{t_1, t_2, p_1, p_2, n_1, n_2},
+// ctx.mkAnd(ctx.mkLt(t_1, t_2),
+// ctx.mkLt(t_1, t_0),
+// ctx.mkLt(t_2, t_0),
+// (BoolExpr)nctx.recv.apply(n_1, politoCache, p_1, t_1),
+// (BoolExpr)nctx.recv.apply(n_2, politoCache, p_2, t_2),
+// ctx.mkEq(nctx.pf.get("proto").apply(p_1),ctx.mkInt(nctx.HTTP_REQUEST)),
+// ctx.mkEq(nctx.pf.get("proto").apply(p_2),ctx.mkInt(nctx.HTTP_RESPONSE)),
+// (BoolExpr)isInternalNode.apply(n_1),
+// ctx.mkNot((BoolExpr)isInternalNode.apply(n_2)),
+// ctx.mkEq(nctx.pf.get("url").apply(p_1),u_0),
+// ctx.mkEq(nctx.pf.get("url").apply(p_2),u_0)),1,null,null,null,null),
+// ctx.mkEq(isInCache.apply(u_0,t_0),ctx.mkBool(true)),ctx.mkEq(isInCache.apply(u_0,t_0),ctx.mkBool(false))),1,null,null,null,null));
+//
+
+ //Constraint2 isInCache(u_0,t_0), exist t_1, t_2, p_1, p_2, n_1, n_2 :
+ // ( t_1< t_2 < t_0 && recv(n_1, politoCache, p_1, t_1) && recv(n_2, politoCache, p_2, t_2))) &&
+ // p_1.proto == HTTP_REQ && p_2.proto == HTTP_RESP &&
+ // isInternalNode(n_1) && !isInternalNode(n_2) &&
+ // p_1.url == u_0 && p_2.url == u_0 )
+ constraints.add(
+ ctx.mkForall(new Expr[]{u_0, t_0},
+ ctx.mkImplies((BoolExpr)isInCache.apply(u_0, t_0),
+ ctx.mkExists(new Expr[]{t_1,t_2,p_1,p_2,n_1, n_2},
+ ctx.mkAnd(
+ ctx.mkLt(t_1, t_2),
+ ctx.mkLt(t_1, t_0),
+ ctx.mkLt(t_2, t_0),
+ (BoolExpr)nctx.recv.apply(n_1, politoCache, p_1, t_1),
+ (BoolExpr)nctx.recv.apply(n_2, politoCache, p_2, t_2),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), ctx.mkInt(nctx.HTTP_REQUEST)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_2), ctx.mkInt(nctx.HTTP_RESPONSE)),
+ (BoolExpr)isInternalNode.apply(n_1),
+ ctx.mkNot((BoolExpr)isInternalNode.apply(n_2)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), u_0),
+ ctx.mkEq(nctx.pf.get("url").apply(p_2), u_0)),1,null,null,null,null)),1,null,null,null,null));
+// //Always in cache
+// constraints.add(ctx.mkForall(new Expr[]{u_0, t_0},ctx.mkEq(isInCache.apply(u_0,t_0),ctx.mkBool(true)),1,null,null,null,null));
+
+ //Constraint3 Modeling the behavior of the cache
+ // send(politoCache, n_0, p, t_0) && !isInternalNode(n_0) ->
+ // (exist t_1,n_1 :
+ // (t_1 < t_0 && recv(n_1, politoCache, p, t_1) &&
+ // p.proto == HTTP_REQ && !isInCache(p.url,t_0))
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0,p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)nctx.send.apply(politoCache,n_0,p_0,t_0),ctx.mkNot((BoolExpr)isInternalNode.apply(n_0))),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{t_1, n_1},
+ ctx.mkAnd(
+ ctx.mkLt(t_1, t_0),
+ (BoolExpr)isInternalNode.apply(n_1),
+ (BoolExpr)nctx.recv.apply(n_1, politoCache, p_0, t_1)),1,null,null,null,null),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_REQUEST)),
+ ctx.mkNot((BoolExpr)isInCache.apply(nctx.pf.get("url").apply(p_0), t_0)))),1,null,null,null,null));
+
+ //Constraint4 send(politoCache, n_0, p, t_0) && isInternalNode(n_0) ->
+ // (exist p_1,t_1 :
+ // (t_1 < t_0 && recv(n_0, politoCache, p_1, t_1) &&
+ // p_1.proto == HTTP_REQ && p.proto == HTTP_RESP &&
+ // p_1.url == p.url && p.src == p_1.dest && p.dest==p_1.src
+ // && isInCache(p.url,t_0))
+ constraints.add(
+ ctx.mkForall(new Expr[]{n_0,p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)nctx.send.apply(politoCache,n_0,p_0,t_0),(BoolExpr)isInternalNode.apply(n_0)),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{p_1, t_1},
+ ctx.mkAnd(
+ ctx.mkLt(t_1, t_0),
+ (BoolExpr)nctx.recv.apply(n_0, politoCache, p_1, t_1),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), ctx.mkInt(nctx.HTTP_REQUEST)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), nctx.pf.get("url").apply(p_0))),1,null,null,null,null),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_RESPONSE)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_0), nctx.pf.get("dest").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), nctx.pf.get("src").apply(p_1)),
+ (BoolExpr)isInCache.apply(nctx.pf.get("url").apply(p_0), t_0))),1,null,null,null,null));
+ }
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoEndHost.java b/verigraph/service/src/mcnet/netobjs/PolitoEndHost.java
new file mode 100644
index 0000000..e12579f
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoEndHost.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+public class PolitoEndHost extends NetworkObject {
+
+ List<BoolExpr> constraints = new ArrayList<BoolExpr>();
+ Context ctx;
+ DatatypeExpr politoEndHost;
+ Network net;
+ NetContext nctx;
+
+ public PolitoEndHost(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoEndHost;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ this.isEndHost = true;
+ this.politoEndHost = this.z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ this.net = (Network)args[0][1];
+ this.nctx = (NetContext)args[0][2];
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ /*
+ * Fields that can be configured -> "dest","body","seq","proto","emailFrom","url","options"
+ */
+ public void installEndHost (PacketModel packet){
+ System.out.println("Installing PolitoEndHost...");
+ Expr n_0 = ctx.mkConst("PolitoEndHost_"+politoEndHost+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst("PolitoEndHost_"+politoEndHost+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("PolitoEndHost_"+politoEndHost+"_t_0");
+ BoolExpr predicatesOnPktFields = ctx.mkTrue();
+
+ if(packet.getIp_dest() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("dest").apply(p_0), packet.getIp_dest()));
+ if(packet.getBody() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("body").apply(p_0), ctx.mkInt(packet.getBody())));
+ if(packet.getEmailFrom() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("emailFrom").apply(p_0), ctx.mkInt(packet.getEmailFrom())));
+ if(packet.getOptions() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("options").apply(p_0), ctx.mkInt(packet.getOptions())));
+ if(packet.getProto() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(packet.getProto())));
+ if(packet.getSeq() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("seq").apply(p_0), ctx.mkInt(packet.getSeq())));
+ if(packet.getUrl() != null)
+ predicatesOnPktFields = ctx.mkAnd(predicatesOnPktFields, ctx.mkEq(nctx.pf.get("url").apply(p_0), ctx.mkInt(packet.getUrl())));
+
+ //Constraint1 send(politoWebClient, n_0, p, t_0) -> p.origin == politoWebClient && p.orig_body == p.body && nodeHasAddr(politoWebClient,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoEndHost, n_0, p_0, t_0),
+ ctx.mkAnd(predicatesOnPktFields,
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),politoEndHost),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoEndHost,nctx.pf.get("src").apply(p_0)))),1,null,null,null,null));
+
+ //Constraint2 recv(n_0, politoWebClient, p, t_0) -> nodeHasAddr(politoWebClient,p.dest)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0,politoEndHost, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoEndHost,nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+ System.out.println("Done.");
+ return;
+ }
+
+}
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoErrFunction.java b/verigraph/service/src/mcnet/netobjs/PolitoErrFunction.java
new file mode 100644
index 0000000..5f84b9f
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoErrFunction.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**Error Function objects
+ *
+ */
+public class PolitoErrFunction extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoErrFunction;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoErrFunction(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=true;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoErrFunction = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ errFunctionRules();
+ //net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoErrFunction;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+// System.out.println("[ERR FUNC] Installing rules.");
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ private void errFunctionRules (){
+ Expr n_0 = ctx.mkConst("PolitoErrFunction_"+politoErrFunction+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst("PolitoErrFunction_"+politoErrFunction+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("PolitoErrFunction_"+politoErrFunction+"_t_0");
+
+// constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(politoErrFunction, n_0, p_0, t_0),
+// (BoolExpr)nctx.nodeHasAddr.apply(politoErrFunction, nctx.pf.get("src").apply(p_0))),1,null,null,null,null));
+// constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(politoErrFunction, n_0, p_0, t_0),
+// ctx.mkEq(nctx.pf.get("origin").apply(p_0), politoErrFunction)),1,null,null,null,null));
+//
+// constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(politoErrFunction, n_0, p_0, t_0),
+// ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),1,null,null,null,null));
+
+
+// Constraint1 We want the ErrFunction not to send out any packet
+// send(politoErrFunction, n_0, p, t_0) -> 1 == 2
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoErrFunction, n_0, p_0, t_0),
+ ctx.mkEq(ctx.mkInt(1),ctx.mkInt(2))),1,null,null,null,null));
+
+// constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies( (BoolExpr)nctx.send.apply(n_0, politoErrFunction, p_0, t_0),
+// (BoolExpr)nctx.nodeHasAddr.apply(politoErrFunction, nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+ }
+ } \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoFieldModifier.java b/verigraph/service/src/mcnet/netobjs/PolitoFieldModifier.java
new file mode 100644
index 0000000..6d8d8fe
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoFieldModifier.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+public class PolitoFieldModifier extends NetworkObject {
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoFieldModifier;
+ Network net;
+ NetContext nctx;
+
+ public PolitoFieldModifier(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoFieldModifier;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoFieldModifier = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void installFieldModifier (){
+ Expr x = ctx.mkConst("politoFieldModifier_"+politoFieldModifier+"_x", nctx.node);
+ Expr y = ctx.mkConst("politoFieldModifier_"+politoFieldModifier+"_y", nctx.node);
+ Expr p_0 = ctx.mkConst("politoFieldModifier_"+politoFieldModifier+"_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("politoFieldModifier_"+politoFieldModifier+"_p_1", nctx.packet);
+
+ IntExpr t_0 = ctx.mkIntConst("politoFieldModifier_"+politoFieldModifier+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst("politoFieldModifier_"+politoFieldModifier+"_t_1");
+
+ constraints.add(
+ ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoFieldModifier,x,p_0,t_0),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd(ctx.mkLt(t_1, t_0),
+ (BoolExpr)nctx.recv.apply(y, politoFieldModifier, p_1, t_1),
+ ctx.mkEq(nctx.pf.get("encrypted").apply(p_0), nctx.pf.get("encrypted").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_0), nctx.pf.get("src").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), nctx.pf.get("dest").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_0), nctx.pf.get("inner_src").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("inner_dest").apply(p_0), nctx.pf.get("inner_dest").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0), nctx.pf.get("origin").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0), nctx.pf.get("orig_body").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_0), nctx.pf.get("body").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_0), nctx.pf.get("seq").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), nctx.pf.get("proto").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_0), nctx.pf.get("emailFrom").apply(p_1)),
+ ctx.mkNot(ctx.mkEq(nctx.pf.get("url").apply(p_0), nctx.pf.get("url").apply(p_1))),
+ ctx.mkEq(nctx.pf.get("options").apply(p_0), nctx.pf.get("options").apply(p_1))),1,null,null,null,null)),
+ 1,null,null,null,null));
+ }
+
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoIDS.java b/verigraph/service/src/mcnet/netobjs/PolitoIDS.java
new file mode 100644
index 0000000..6f2cddf
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoIDS.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+public class PolitoIDS extends NetworkObject {
+
+ public static final int DROGA = 1; //no go
+ public static final int GATTINI = 2; //go
+
+ Context ctx;
+ List<BoolExpr> constraints = new ArrayList<BoolExpr>();
+ DatatypeExpr politoIDS;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+
+ public PolitoIDS(Context ctx, Object[]...args){
+ super(ctx, args);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoIDS;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+
+ this.ctx = ctx;
+ this.isEndHost = false;
+ this.politoIDS = this.z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ this.net = (Network)args[0][1];
+ this.nctx = (NetContext)args[0][2];
+
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+
+ }
+
+ public void installIDS(int[] blackList){
+ Expr n_0 = ctx.mkConst(politoIDS + "_n_0", nctx.node);
+ Expr n_1 = ctx.mkConst(politoIDS + "_n_1", nctx.node);
+ Expr p_0 = ctx.mkConst(politoIDS + "_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst(politoIDS + "_t_0");
+ IntExpr t_1 = ctx.mkIntConst(politoIDS + "_t_1");
+ Expr b_0 = ctx.mkIntConst(politoIDS + "_b_0");
+
+ isInBlacklist = ctx.mkFuncDecl(politoIDS + "_isInBlacklist", ctx.mkIntSort(), ctx.mkBoolSort());
+
+
+ BoolExpr[] blConstraints = new BoolExpr[blackList.length];
+ if(blackList.length != 0){
+
+ for(int i = 0; i<blackList.length; i++)
+ blConstraints[i] = ctx.mkEq(b_0, ctx.mkInt(blackList[i]));
+
+ this.constraints.add(ctx.mkForall(new Expr[]{b_0},
+ ctx.mkIff((BoolExpr)isInBlacklist.apply(b_0), ctx.mkOr(blConstraints)),
+ 1,
+ null, null, null, null));
+ }else{
+ this.constraints.add(ctx.mkForall(new Expr[]{b_0},
+ ctx.mkEq(isInBlacklist.apply(b_0), ctx.mkBool(false)),
+ 1,
+ null, null, null, null));
+ }
+
+ //Constraint2 send(politoIDS, n_0, p, t_0) && (p.proto(HTTP_RESPONSE) || p.proto(HTTP_REQUEST)) ->
+ // (exist n_1,t_1 : (recv(n_1, politoIDS, p, t_1) && t_1 < t_0)) && !isInBlackList(p.body)
+
+ this.constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(politoIDS, n_0, p_0, t_0), ctx.mkOr(ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_RESPONSE)), ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_REQUEST)))),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{n_1,t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1,politoIDS,p_0,t_1),ctx.mkLt(t_1, t_0)),
+ 1,
+ null, null, null, null),
+ ctx.mkNot((BoolExpr)isInBlacklist.apply(nctx.pf.get("body").apply(p_0))))),
+ 1,
+ null, null, null, null));
+
+ //Constraint3 send(politoIDS, n_0, p, t_0) && p.proto(HTTP_REQUEST) ->
+ // (exist n_1,t_1 : (recv(n_1, politoIDS, p, t_1) && t_1 < t_0)) Constraint not needed anymore (included in contr. 2)
+ /*
+ this.constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies(ctx.mkAnd((BoolExpr)nctx.send.apply(politoIDS, n_0, p_0, t_0), ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_REQUEST))),
+ ctx.mkAnd(ctx.mkExists(new Expr[]{n_1,t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1,politoIDS,p_0,t_1),ctx.mkLt(t_1, t_0)),
+ 1,
+ null, null, null, null))),
+ 1,
+ null, null, null, null));
+ */
+
+ //Constraint5 send(politoIDS, n_0, p, t_0) -> p.proto == HTTP_REQ || p.protpo == HTTP_RESP
+
+ this.constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoIDS, n_0, p_0, t_0),
+ ctx.mkOr(ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_REQUEST)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_RESPONSE)))),
+ 1,
+ null,null,null,null));
+
+ //Constraint6 send(politoIDS, n_0, p, t_0) -> nodeHasAddr(politoIDS,p.src)
+
+ this.constraints.add(ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoIDS, n_0, p_0, t_0),
+ ctx.mkNot((BoolExpr)nctx.nodeHasAddr.apply(politoIDS,nctx.pf.get("src").apply(p_0)))),
+ 1,
+ null,null,null,null));
+
+ }
+
+}
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoMailClient.java b/verigraph/service/src/mcnet/netobjs/PolitoMailClient.java
new file mode 100644
index 0000000..6925258
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoMailClient.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**
+ * MailClient objects
+ *
+ */
+public class PolitoMailClient extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoMailClient;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoMailClient(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=true;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoMailClient = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ DatatypeExpr ipServer = (DatatypeExpr) args[0][3];
+ mailClientRules(ipServer);
+ //net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoMailClient;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+// System.out.println("[MailClient] Installing rules.");
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ private void mailClientRules (DatatypeExpr ipServer){
+ Expr n_0 = ctx.mkConst("PolitoMailClient_"+politoMailClient+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst("PolitoMailClient_"+politoMailClient+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("PolitoMailClient_"+politoMailClient+"_t_0");
+
+// Constraint1 send(politoMailClient, n_0, p, t_0) -> nodeHasAddr(politoMailClient,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailClient, n_0, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoMailClient,nctx.pf.get("src").apply(p_0))),1,null,null,null,null));
+
+// Constraint2 send(politoMailClient, n_0, p, t_0) -> p.origin == politoMailClient
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),politoMailClient)),1,null,null,null,null));
+
+// Constraint3 send(politoMailClient, n_0, p, t_0) -> p.orig_body == p.body
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),1,null,null,null,null));
+
+// Constraint4 recv(n_0, politoMailClient, p, t_0) -> nodeHasAddr(politoMailClient,p.dest)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0,politoMailClient, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoMailClient,nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+// Constraint5 This client is only able to produce POP3 requests
+// send(politoMailClient, n_0, p, t_0) -> p.proto == POP3_REQ
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_REQUEST))),1,null,null,null,null));
+
+// Constraint6 send(politoMailClient, n_0, p, t_0) -> p.dest == ip_mailServer
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), ipServer)),1,null,null,null,null));
+ }
+}
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoMailServer.java b/verigraph/service/src/mcnet/netobjs/PolitoMailServer.java
new file mode 100644
index 0000000..c464195
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoMailServer.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/** Mail server objects
+ *
+ */
+public class PolitoMailServer extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoMailServer;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoMailServer(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoMailServer = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ mailServerRules();
+ net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoMailServer;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ private void mailServerRules (){
+ Expr n_0 = ctx.mkConst(politoMailServer+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst(politoMailServer+"_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst(politoMailServer+"_p_1", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst(politoMailServer+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst(politoMailServer+"_t_1");
+
+// Constraint1 send(politoMailServer, n_0, p, t_0) -> nodeHasAddr(politoMailServer,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoMailServer,nctx.pf.get("src").apply(p_0))),1,null,null,null,null));
+
+// Constraint2 send(politoMailServer, n_0, p, t_0) -> p.origin == politoMailServer
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),politoMailServer)),1,null,null,null,null));
+
+// Constraint3 send(politoMailServer, n_0, p, t_0) -> p.orig_body == p.body
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),1,null,null,null,null));
+
+// Constraint4 recv(n_0, politoMailServer, p, t_0) -> nodeHasAddr(politoMailServer,p.dest)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0,politoMailServer, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoMailServer,nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+// Constraint5 send(politoMailServer, n_0, p, t_0) -> p.proto == POP3_RESP && p.emailFrom == 1
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+ ctx.mkAnd( ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_RESPONSE)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_0), ctx.mkInt(1)))),1,null,null,null,null));
+
+// Constraint6 send(politoMailServer, n_0, p, t_0) ->
+// (exist p_1, t_1 : (t_1 < t_0 && recv(n_0, politoMailServer, p_1, t_1) &&
+// p_0.proto == POP3_RESP && p_1.proto == POP3_REQ && p_0.dest == p_1.src )
+
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+ ctx.mkExists(new Expr[]{p_1, t_1},
+ ctx.mkAnd(ctx.mkLt(t_1, t_0),
+ (BoolExpr)nctx.recv.apply(n_0, politoMailServer, p_1, t_1),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.POP3_RESPONSE)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), ctx.mkInt(nctx.POP3_REQUEST)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), nctx.pf.get("src").apply(p_1))),1,null,null,null,null)),1,null,null,null,null));
+
+// constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+// ctx.mkImplies((BoolExpr)nctx.send.apply(politoMailServer, n_0, p_0, t_0),
+// ctx.mkEq(nctx.pf.get("emailFrom").apply(p_0),ctx.mkInt(2))),1,null,null,null,null));
+ }
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoNF.java b/verigraph/service/src/mcnet/netobjs/PolitoNF.java
new file mode 100644
index 0000000..53cae28
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoNF.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+import com.microsoft.z3.Sort;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+/** First example of custom network function: a simple filter
+ *
+ */
+public class PolitoNF extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoNF;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+
+ public PolitoNF(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoNF = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ //net.saneSend(this);
+ }
+
+ public void politoNFRules (DatatypeExpr ipA,DatatypeExpr ipB){
+// System.out.println("[PolitoNf] Installing rules");
+ Expr n_0 = ctx.mkConst("politoNF_"+politoNF+"_n_0", nctx.node);
+ Expr n_1 = ctx.mkConst("politoNF_"+politoNF+"_n_1", nctx.node);
+ Expr p_0 = ctx.mkConst("politoNF_"+politoNF+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("politoNF_"+politoNF+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst("politoNF_"+politoNF+"_t_1");
+ Expr a_0 = ctx.mkConst(politoNF+"_politoNF_a_0", nctx.address);
+ Expr a_1 = ctx.mkConst(politoNF+"_politoNF_a_1", nctx.address);
+
+ FuncDecl myFunction = ctx.mkFuncDecl(politoNF+"_myFunction", new Sort[]{nctx.address,nctx.address}, ctx.mkBoolSort());
+
+ BoolExpr myConstraint = ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoNF, n_0, p_0, t_0),
+ ctx.mkExists(new Expr[]{n_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(n_1, politoNF, p_0, t_1),
+ ctx.mkLt(t_1 , t_0),
+ (BoolExpr)myFunction.apply(nctx.pf.get("src").apply(p_0), nctx.pf.get("dest").apply(p_0))),1,null,null,null,null)),1,null,null,null,null);
+
+ BoolExpr funcConstraint = ctx.mkOr(ctx.mkAnd(ctx.mkEq(a_0, ipA), ctx.mkEq(a_1, ipB)), ctx.mkAnd(ctx.mkEq(a_0,ipB), ctx.mkEq(a_1,ipA)));
+
+ // Constraint1 myFunction(a_0,a_1) == ((a_0 == ipA && a_1 == ipB) || (a_0 == ipB && a_1 == ipA))
+ constraints.add(
+ ctx.mkForall(new Expr[]{a_0,a_1},
+ ctx.mkEq(myFunction.apply(a_0, a_1), funcConstraint),1,null,null,null,null));
+
+ //Constraint2 send(politoNF, n_0, p, t_0) ->
+ // (exist n_1,t_1 : (t_1 < t_0 && recv(n_1, politoNF, p, t_1) && myFunction(p.src,p.dest))
+ constraints.add(myConstraint);
+
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoNF;
+ }
+
+ } \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoNat.java b/verigraph/service/src/mcnet/netobjs/PolitoNat.java
new file mode 100644
index 0000000..6d8a36d
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoNat.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**
+ * NAT Model object
+ *
+ */
+public class PolitoNat extends NetworkObject{
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr nat;
+ List<DatatypeExpr> private_addresses;
+ List<NetworkObject> private_node;
+ Network net;
+ NetContext nctx;
+ FuncDecl private_addr_func ;
+
+ public PolitoNat(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=false;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ nat = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ private_addresses = new ArrayList<DatatypeExpr>();
+ private_node = new ArrayList<NetworkObject>();
+ net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return nat;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ /*
+ private void addPrivateAdd(List<DatatypeExpr> address){
+ private_addresses.addAll(address);
+ }
+ */
+
+ public List<DatatypeExpr> getPrivateAddress(){
+ return private_addresses;
+ }
+
+ public void natModel(DatatypeExpr natIp){
+ Expr x = ctx.mkConst("x", nctx.node);
+ Expr y = ctx.mkConst("y", nctx.node);
+ Expr z = ctx.mkConst("z", nctx.node);
+
+ Expr p_0 = ctx.mkConst("p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("p_1", nctx.packet);
+ Expr p_2 = ctx.mkConst("p_2", nctx.packet);
+
+ IntExpr t_0 = ctx.mkIntConst("t_0");
+ IntExpr t_1 = ctx.mkIntConst("t_1");
+ IntExpr t_2 = ctx.mkIntConst("t_2");
+
+// private_addr_func = ctx.mkFuncDecl("private_addr_func", nctx.address, ctx.mkBoolSort());
+ private_addr_func = ctx.mkFuncDecl(nat + "_nat_func", nctx.address, ctx.mkBoolSort());
+
+ //Constraint1
+// "send(nat, x, p_0, t_0) && !private_addr_func(p_0.dest) ->
+// p_0.src == ip_politoNat &&
+// (exist y, p_1,t_1 :
+// (recv(y, nat, p_1, t_1) && t_1 < t_0 &&
+// private_addr_func(p1.src) &&
+// p_1.origin == p_0.origin &&
+// same for p_1.<dest,orig_body,body,seq,proto,emailFrom,url,options> == p_0.<...>) "
+ constraints.add( ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)nctx.send.apply(nat, x, p_0, t_0),
+ ctx.mkNot((BoolExpr)private_addr_func.apply(nctx.pf.get("dest").apply(p_0)))),
+ ctx.mkAnd(
+ ctx.mkEq(nctx.pf.get("src").apply(p_0),natIp),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd(
+ (BoolExpr)nctx.recv.apply(y, nat, p_1, t_1),
+ ctx.mkLt(t_1 , t_0),
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("src").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_1),nctx.pf.get("origin").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1),nctx.pf.get("dest").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1),nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1),nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1),nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1),nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1),nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1),nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1),nctx.pf.get("options").apply(p_0))),1,null,null,null,null))),1,null,null,null,null));
+
+ //Constraint2
+// send(nat, x, p_0, t_0) && private_addr_func(p_0.dest) ->
+// !private_addr_func(p_0.src) &&
+// (exist y, p_1,t_1 :
+// (recv(y, nat, p_1, t_1) && t_1 < t_0 &&
+// !private_addr_func(p1.src) &&
+// p_1.dest == ip_politoNat &&
+// p_1.origin == p_0.origin &&
+// same for p_1.<src,orig_body,body,seq,proto,emailFrom,url,options> == p_0.<...>)
+ constraints.add( ctx.mkForall(new Expr[]{x, p_0, t_0},
+ ctx.mkImplies(
+ ctx.mkAnd((BoolExpr)nctx.send.apply(nat, x, p_0, t_0),
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("dest").apply(p_0))),
+ ctx.mkAnd(
+ ctx.mkNot((BoolExpr)private_addr_func.apply(nctx.pf.get("src").apply(p_0))),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd(
+ ctx.mkLt(t_1 , t_0),
+ (BoolExpr)nctx.recv.apply(y, nat, p_1, t_1),
+ ctx.mkNot((BoolExpr)private_addr_func.apply(nctx.pf.get("src").apply(p_1))),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1),natIp),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1),nctx.pf.get("src").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),nctx.pf.get("origin").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1),nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1),nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1),nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1),nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1),nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1),nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1),nctx.pf.get("options").apply(p_0)),
+ ctx.mkExists(new Expr[]{z, p_2, t_2},
+ ctx.mkAnd(
+ ctx.mkLt(t_2 , t_1),
+ (BoolExpr)nctx.recv.apply(z, nat, p_2, t_2),
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("src").apply(p_2)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1),nctx.pf.get("dest").apply(p_2)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_0),nctx.pf.get("dest").apply(p_2)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_2),nctx.pf.get("dest").apply(p_0))),1,null,null,null,null)),1,null,null,null,null))),1,null,null,null,null));
+ }
+
+ public void setInternalAddress(ArrayList<DatatypeExpr> internalAddress){
+ List<BoolExpr> constr = new ArrayList<BoolExpr>();
+ Expr n_0 = ctx.mkConst("nat_node", nctx.address);
+
+ for(DatatypeExpr n : internalAddress){
+ constr.add(ctx.mkEq(n_0,n));
+ }
+ BoolExpr[] constrs = new BoolExpr[constr.size()];
+ //Constraint private_addr_func(n_0) == or(n_0==n foreach internal address)
+ constraints.add(ctx.mkForall(new Expr[]{n_0}, ctx.mkEq(private_addr_func.apply(n_0),ctx.mkOr(constr.toArray(constrs))),1,null,null,null,null));
+ }
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoVpnAccess.java b/verigraph/service/src/mcnet/netobjs/PolitoVpnAccess.java
new file mode 100644
index 0000000..e6fc5fe
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoVpnAccess.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+public class PolitoVpnAccess extends NetworkObject {
+
+ List<BoolExpr> constraints = new ArrayList<BoolExpr>();
+ DatatypeExpr politoVpnAccess;
+ FuncDecl private_addr_func;
+ NetContext nctx;
+ Context ctx;
+ Network net;
+
+ public PolitoVpnAccess(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoVpnAccess;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ this.isEndHost = false;
+ this.politoVpnAccess = this.z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ this.net = (Network)args[0][1];
+ this.nctx = (NetContext)args[0][2];
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void vpnAccessModel(DatatypeExpr vpnAccessIp, DatatypeExpr vpnExitIp) {
+ Expr x = ctx.mkConst("vpn_x", nctx.node);
+ Expr y = ctx.mkConst("vpn_y", nctx.node);
+
+ Expr p_0 = ctx.mkConst("vpn_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("vpn_p_1", nctx.packet);
+
+ IntExpr t_0 = ctx.mkIntConst("vpn_t_0");
+ IntExpr t_1 = ctx.mkIntConst("vpn_t_1");
+
+ private_addr_func = ctx.mkFuncDecl("vpn_private_addr_func", nctx.address, ctx.mkBoolSort());
+
+ BoolExpr constraint1 = ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies(ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(politoVpnAccess, x, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_0), nctx.am.get("null"))),
+ ctx.mkAnd(
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("dest").apply(p_0)),
+ ctx.mkNot((BoolExpr)nctx.pf.get("encrypted").apply(p_0)),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(y, politoVpnAccess, p_1, t_1),
+ ctx.mkLt(t_1, t_0),
+ (BoolExpr)nctx.pf.get("encrypted").apply(p_1),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1), vpnExitIp),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1), vpnAccessIp),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_1), nctx.pf.get("src").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("inner_dest").apply(p_1), nctx.pf.get("dest").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_1), nctx.pf.get("origin").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1), nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1), nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1), nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1), nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1), nctx.pf.get("options").apply(p_0))), 1, null, null, null, null))),
+ 1,null,null,null,null);
+
+ constraints.add(constraint1);
+
+ BoolExpr constraint2 = ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies(ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(politoVpnAccess, x, p_0, t_0),
+ ctx.mkNot(ctx.mkEq(nctx.pf.get("inner_src").apply(p_0), nctx.am.get("null")))),
+ ctx.mkAnd(
+ ctx.mkEq(nctx.pf.get("src").apply(p_0), vpnAccessIp),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), vpnExitIp),
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("inner_src").apply(p_0)),
+ ctx.mkNot(ctx.mkEq(nctx.pf.get("inner_dest").apply(p_0), vpnAccessIp)),
+ (BoolExpr)nctx.pf.get("encrypted").apply(p_0),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(y, politoVpnAccess, p_1, t_1),
+ ctx.mkLt(t_1, t_0),
+ ctx.mkNot((BoolExpr)nctx.pf.get("encrypted").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1), nctx.pf.get("inner_src").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1), nctx.pf.get("inner_dest").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_1), nctx.am.get("null")),
+ ctx.mkEq(nctx.pf.get("inner_dest").apply(p_1), nctx.am.get("null")),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_1), nctx.pf.get("origin").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1), nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1), nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1), nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1), nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1), nctx.pf.get("options").apply(p_0))), 1, null, null, null, null))),
+ 1,null,null,null,null);
+
+ constraints.add(constraint2);
+ }
+
+ public void setInternalAddress(ArrayList<DatatypeExpr> internalAddress){
+ List<BoolExpr> constr = new ArrayList<BoolExpr>();
+ Expr n_0 = ctx.mkConst("vpn_node", nctx.address);
+
+ for(DatatypeExpr n : internalAddress){
+ constr.add(ctx.mkEq(n_0,n));
+ }
+ BoolExpr[] constrs = new BoolExpr[constr.size()];
+ //Constraint private_addr_func(n_0) == or(n_0==n foreach internal address)
+ constraints.add(ctx.mkForall(new Expr[]{n_0}, ctx.mkEq(private_addr_func.apply(n_0),ctx.mkOr(constr.toArray(constrs))),1,null,null,null,null));
+ }
+
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoVpnExit.java b/verigraph/service/src/mcnet/netobjs/PolitoVpnExit.java
new file mode 100644
index 0000000..fb2341f
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoVpnExit.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+public class PolitoVpnExit extends NetworkObject {
+
+ List<BoolExpr> constraints = new ArrayList<BoolExpr>();
+ DatatypeExpr politoVpnExit;
+ FuncDecl private_addr_func;
+ NetContext nctx;
+ Context ctx;
+ Network net;
+
+ public PolitoVpnExit(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoVpnExit;
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ this.isEndHost = false;
+ this.politoVpnExit = this.z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ this.net = (Network)args[0][1];
+ this.nctx = (NetContext)args[0][2];
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ public void vpnAccessModel(DatatypeExpr vpnAccessIp, DatatypeExpr vpnExitIp) {
+ Expr x = ctx.mkConst("vpn_x", nctx.node);
+ Expr y = ctx.mkConst("vpn_y", nctx.node);
+
+ Expr p_0 = ctx.mkConst("vpn_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("vpn_p_1", nctx.packet);
+
+ IntExpr t_0 = ctx.mkIntConst("vpn_t_0");
+ IntExpr t_1 = ctx.mkIntConst("vpn_t_1");
+
+ private_addr_func = ctx.mkFuncDecl("vpn_private_addr_func", nctx.address, ctx.mkBoolSort());
+
+ BoolExpr constraint1 = ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies(ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(politoVpnExit, x, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_0), nctx.am.get("null"))),
+ ctx.mkAnd(
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("src").apply(p_0)),
+ ctx.mkNot((BoolExpr)nctx.pf.get("encrypted").apply(p_0)),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(y, politoVpnExit, p_1, t_1),
+ ctx.mkLt(t_1, t_0),
+ (BoolExpr)nctx.pf.get("encrypted").apply(p_1),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1), vpnAccessIp),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1), vpnExitIp),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_1), nctx.pf.get("src").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("inner_dest").apply(p_1), nctx.pf.get("dest").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_1), nctx.pf.get("origin").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1), nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1), nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1), nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1), nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1), nctx.pf.get("options").apply(p_0))), 1, null, null, null, null))),
+ 1,null,null,null,null);
+
+ constraints.add(constraint1);
+
+ BoolExpr constraint2 = ctx.mkForall(new Expr[]{t_0, p_0, x},
+ ctx.mkImplies(ctx.mkAnd(
+ (BoolExpr)nctx.send.apply(politoVpnExit, x, p_0, t_0),
+ ctx.mkNot(ctx.mkEq(nctx.pf.get("inner_src").apply(p_0), nctx.am.get("null")))),
+ ctx.mkAnd(
+ ctx.mkEq(nctx.pf.get("src").apply(p_0), vpnExitIp),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), vpnAccessIp),
+ (BoolExpr)private_addr_func.apply(nctx.pf.get("dest").apply(p_0)),
+ ctx.mkNot(ctx.mkEq(nctx.pf.get("inner_dest").apply(p_1), vpnExitIp)),
+ (BoolExpr)nctx.pf.get("encrypted").apply(p_0),
+ ctx.mkExists(new Expr[]{y, p_1, t_1},
+ ctx.mkAnd((BoolExpr)nctx.recv.apply(y, politoVpnExit, p_1, t_1),
+ ctx.mkLt(t_1, t_0),
+ ctx.mkNot((BoolExpr)nctx.pf.get("encrypted").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_1), nctx.pf.get("inner_src").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_1), nctx.pf.get("inner_dest").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("inner_src").apply(p_1), nctx.am.get("null")),
+ ctx.mkEq(nctx.pf.get("inner_dest").apply(p_1), nctx.am.get("null")),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_1), nctx.pf.get("origin").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_1), nctx.pf.get("orig_body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("body").apply(p_1), nctx.pf.get("body").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("seq").apply(p_1), nctx.pf.get("seq").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), nctx.pf.get("proto").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("emailFrom").apply(p_1), nctx.pf.get("emailFrom").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("url").apply(p_1), nctx.pf.get("url").apply(p_0)),
+ ctx.mkEq(nctx.pf.get("options").apply(p_1), nctx.pf.get("options").apply(p_0))), 1, null, null, null, null))),
+ 1,null,null,null,null);
+
+ constraints.add(constraint2);
+ }
+
+ public void setInternalAddress(ArrayList<DatatypeExpr> internalAddress){
+ List<BoolExpr> constr = new ArrayList<BoolExpr>();
+ Expr n_0 = ctx.mkConst("vpn_node", nctx.address);
+
+ for(DatatypeExpr n : internalAddress){
+ constr.add(ctx.mkEq(n_0,n));
+ }
+ BoolExpr[] constrs = new BoolExpr[constr.size()];
+ //Constraint private_addr_func(n_0) == or(n_0==n foreach internal address)
+ constraints.add(ctx.mkForall(new Expr[]{n_0}, ctx.mkEq(private_addr_func.apply(n_0),ctx.mkOr(constr.toArray(constrs))),1,null,null,null,null));
+ }
+
+} \ No newline at end of file
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoWebClient.java b/verigraph/service/src/mcnet/netobjs/PolitoWebClient.java
new file mode 100644
index 0000000..28e2cf2
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoWebClient.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+
+/**
+ * WebClient
+ */
+public class PolitoWebClient extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr politoWebClient;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoWebClient(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=true;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ politoWebClient = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ DatatypeExpr ipServer = (DatatypeExpr) args[0][3];
+ webClientRules(ipServer);
+ //net.saneSend(this);
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return politoWebClient;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+// System.out.println("[MailClient] Installing rules.");
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ private void webClientRules (DatatypeExpr ipServer){
+ Expr n_0 = ctx.mkConst("PolitoWebClient_"+politoWebClient+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst("PolitoWebClient_"+politoWebClient+"_p_0", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("PolitoWebClient_"+politoWebClient+"_t_0");
+
+ //Constraint1 send(politoWebClient, n_0, p, t_0) -> nodeHasAddr(politoWebClient,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoWebClient, n_0, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoWebClient,nctx.pf.get("src").apply(p_0))),1,null,null,null,null));
+
+ //Constraint2 send(politoWebClient, n_0, p, t_0) -> p.origin == politoWebClient
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoWebClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),politoWebClient)),1,null,null,null,null));
+
+ //Constraint3 send(politoWebClient, n_0, p, t_0) -> p.orig_body == p.body
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoWebClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),1,null,null,null,null));
+
+ //Constraint4 recv(n_0, politoWebClient, p, t_0) -> nodeHasAddr(politoWebClient,p.dest)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0,politoWebClient, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(politoWebClient,nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+
+ //Constraint5 This client is only able to produce HTTP requests
+ // send(politoWebClient, n_0, p, t_0) -> p.proto == HTTP_REQ
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoWebClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_REQUEST))),1,null,null,null,null));
+
+ //Constraint6 send(politoWebClient, n_0, p, t_0) -> p.dest == ipServer
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(politoWebClient, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), ipServer)),1,null,null,null,null));
+ }
+ }
diff --git a/verigraph/service/src/mcnet/netobjs/PolitoWebServer.java b/verigraph/service/src/mcnet/netobjs/PolitoWebServer.java
new file mode 100644
index 0000000..54710d9
--- /dev/null
+++ b/verigraph/service/src/mcnet/netobjs/PolitoWebServer.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package mcnet.netobjs;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.z3.BoolExpr;
+import com.microsoft.z3.Context;
+import com.microsoft.z3.DatatypeExpr;
+import com.microsoft.z3.Expr;
+import com.microsoft.z3.FuncDecl;
+import com.microsoft.z3.IntExpr;
+import com.microsoft.z3.Solver;
+
+import mcnet.components.NetContext;
+import mcnet.components.Network;
+import mcnet.components.NetworkObject;
+/**
+ * WebServer object
+ *
+ */
+public class PolitoWebServer extends NetworkObject{
+
+ List<BoolExpr> constraints;
+ Context ctx;
+ DatatypeExpr node;
+ Network net;
+ NetContext nctx;
+ FuncDecl isInBlacklist;
+
+ public PolitoWebServer(Context ctx, Object[]... args) {
+ super(ctx, args);
+ }
+
+ @Override
+ protected void init(Context ctx, Object[]... args) {
+ this.ctx = ctx;
+ isEndHost=true;
+ constraints = new ArrayList<BoolExpr>();
+ z3Node = ((NetworkObject)args[0][0]).getZ3Node();
+ node = z3Node;
+ net = (Network)args[0][1];
+ nctx = (NetContext)args[0][2];
+ webServerRules();
+ }
+
+ @Override
+ public DatatypeExpr getZ3Node() {
+ return node;
+ }
+
+ @Override
+ protected void addConstraints(Solver solver) {
+ BoolExpr[] constr = new BoolExpr[constraints.size()];
+ solver.add(constraints.toArray(constr));
+ }
+
+ private void webServerRules (){
+ Expr n_0 = ctx.mkConst("webserver_"+node+"_n_0", nctx.node);
+ Expr p_0 = ctx.mkConst("webserver_"+node+"_p_0", nctx.packet);
+ Expr p_1 = ctx.mkConst("webserver_"+node+"_p_1", nctx.packet);
+ IntExpr t_0 = ctx.mkIntConst("webserver_"+node+"_t_0");
+ IntExpr t_1 = ctx.mkIntConst("webserver_"+node+"_t_1");
+
+ //Constraint1 send(politoWebServer, n_0, p, t_0) -> nodeHasAddr(politoWebServer,p.src)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node, n_0, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(node,nctx.pf.get("src").apply(p_0))),1,null,null,null,null));
+
+ //Constraint2 send(politoWebServer, n_0, p, t_0) -> p.origin == politoWebServer
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("origin").apply(p_0),node)),1,null,null,null,null));
+
+ //Constraint3 send(politoWebServer, n_0, p, t_0) -> p.orig_body == p.body
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node, n_0, p_0, t_0),
+ ctx.mkEq(nctx.pf.get("orig_body").apply(p_0),nctx.pf.get("body").apply(p_0))),
+ 1,null,null,null,null));
+
+ //Constraint4 recv(n_0, politoWebServer, p, t_0) -> nodeHasAddr(politoWebServer,p.dest)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.recv.apply(n_0,node, p_0, t_0),
+ (BoolExpr)nctx.nodeHasAddr.apply(node,nctx.pf.get("dest").apply(p_0))),1,null,null,null,null));
+
+ //Constraint5
+ // send(politoWebServer, n_0, p, t_0) ->
+ // (exist p_1,t_1 :
+ // (t_1 < t_0 && recv(n_0, politoWebServer, p_1, t_1) &&
+ // p_0.proto == HTTP_RESP && p_1.proto == HTTP_REQ &&
+ // p_0.dest == p_1.src && p_0.src == p_1.dest && p_0.url == p_1.url)
+ constraints.add( ctx.mkForall(new Expr[]{n_0, p_0, t_0},
+ ctx.mkImplies((BoolExpr)nctx.send.apply(node, n_0, p_0, t_0),
+ ctx.mkExists(new Expr[]{p_1, t_1},
+ ctx.mkAnd(
+ ctx.mkLt(t_1, t_0),
+ ctx.mkEq(nctx.pf.get("url").apply(p_0), nctx.pf.get("url").apply(p_1)),
+ (BoolExpr)nctx.recv.apply(n_0, node, p_1, t_1),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_0), ctx.mkInt(nctx.HTTP_RESPONSE)),
+ ctx.mkEq(nctx.pf.get("proto").apply(p_1), ctx.mkInt(nctx.HTTP_REQUEST)),
+ ctx.mkEq(nctx.pf.get("dest").apply(p_0), nctx.pf.get("src").apply(p_1)),
+ ctx.mkEq(nctx.pf.get("src").apply(p_0), nctx.pf.get("dest").apply(p_1))),
+ 1,null,null,null,null)),1,null,null,null,null));
+ }
+}
diff --git a/verigraph/service/src/tests/j-verigraph-generator/README.rst b/verigraph/service/src/tests/j-verigraph-generator/README.rst
new file mode 100644
index 0000000..c796af7
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/README.rst
@@ -0,0 +1,54 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+CODE\_GENERATOR Java serializer and formatter
+
+UTILITY Contains utility methods used by other modules
+
+JSON\_GENERATOR Interactive module to generate the configuration files
+(default names are "chains.json" and "config.json") "chains.json"
+describes all the chains of nodes belonging to a certain scenario
+
+TEST\_CLASS\_GENERATOR Generates one or multiple test scenarios given
+the two configuration files above (default names are "chains.json" and
+"config.json") All the test scenarios have to be placed in the examples
+folder (i. e. under "j-verigraph/service/src/tests/examples"). Here is
+the script help:
+
+test\_class\_generator.py -c -f -o
+
+Supposing the module gets executed from the project root directory (i.e.
+"j-verigraph"), a sample command is the following:
+
+service/src/tests/j-verigraph-generator/test\_class\_generator.py -c
+"service/src/tests/j-verigraph-generator/examples/budapest/chains.json"
+-f
+"service/src/tests/j-verigraph-generator/examples/budapest/config.json"
+-o "service/src/tests/examples/Scenario"
+
+Keep in mind that in the previous command "Scenario" represents a prefix
+which will be followed by an underscore and an incremental number
+starting from 1, which represents the n-th scenario starting from the
+previously mentioned "chains.json" file (this file can indeed contain
+multiple chains).
+
+TEST\_GENERATOR Generates a file which performs the verification test
+through Z3 (theorem prover from Microsoft Research) given a certain
+scenario generated with the above snippet. All the test modules have to
+be placed under the "tests" directory (i.e. under
+"j-verigraph/service/src/tests"). Here is the module help:
+
+test\_generator.py -i -o -s -d
+
+Supposing the module gets executed from the project root directory (i.e.
+"j-verigraph") a sample command given the previously generated scenario
+is the following:
+
+service/src/tests/j-verigraph-generator/test\_generator.py -i
+service/src/tests/examples/Scenario\_1.java -o
+service/src/tests/Test.java -s user1 -d webserver
+
+The aforementioned "Test.java" file can be compiled and executed
+normally. Its output will be either "SAT" or "UNSAT". For possible
+statistics the test is repeated 10 times and the average execution time
+in seconds is printed to the console.
diff --git a/verigraph/service/src/tests/j-verigraph-generator/__init__.py b/verigraph/service/src/tests/j-verigraph-generator/__init__.py
new file mode 100644
index 0000000..d8a620f
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/__init__.py
@@ -0,0 +1,8 @@
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
diff --git a/verigraph/service/src/tests/j-verigraph-generator/batch_generator.py b/verigraph/service/src/tests/j-verigraph-generator/batch_generator.py
new file mode 100644
index 0000000..517bdf7
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/batch_generator.py
@@ -0,0 +1,186 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import json
+from pprint import pprint
+import sys, getopt
+import commands
+import os
+from config import *
+from utility import *
+import subprocess
+
+#global variables
+chains = {}
+chains["chains"] = []
+routing = {}
+routing["routing_table"] = []
+configuration = {}
+configuration["nodes"] = []
+#end of global variables
+
+
+#generates json file describing the chains (default chains.json)
+def generate_chains(curr_dir, multiplier, flowspace):
+ filename = "chains.json"
+
+ multiplier = int(multiplier)
+ number_of_chains = multiplier*multiplier
+ for i in range(0, int(number_of_chains)):
+ chains["chains"].insert(i, {})
+ chains["chains"][i]["id"] = i+1
+ chains["chains"][i]["flowspace"] = flowspace
+ chain_nodes = multiplier
+ chains["chains"][i]["nodes"] = []
+ #set attributes for nth client
+ chains["chains"][i]["nodes"].insert(0, {})
+ node_name = "client_" + str((i%multiplier)+1)
+ chains["chains"][i]["nodes"][0]["name"] = node_name
+ node_type = "web_client"
+ chains["chains"][i]["nodes"][0]["functional_type"] = node_type
+ node_address = "ip_web_client_" + str((i%multiplier)+1)
+ chains["chains"][i]["nodes"][0]["address"] = node_address
+ #set attributes for chain of firewalls
+ for j in range(1, chain_nodes+1):
+ chains["chains"][i]["nodes"].insert(j, {})
+ node_name = "firewall_" + str(j)
+ chains["chains"][i]["nodes"][j]["name"] = node_name
+ node_type = "firewall"
+ chains["chains"][i]["nodes"][j]["functional_type"] = node_type
+ node_address = "ip_firewall_" + str(j)
+ chains["chains"][i]["nodes"][j]["address"] = node_address
+ #set attributes for nth web server
+ chains["chains"][i]["nodes"].insert(chain_nodes+1, {})
+ node_name = "server_" + str((i%multiplier)+1)
+ chains["chains"][i]["nodes"][chain_nodes+1]["name"] = node_name
+ node_type = "web_server"
+ chains["chains"][i]["nodes"][chain_nodes+1]["functional_type"] = node_type
+ node_address = "ip_web_server_" + str((i%multiplier)+1)
+ chains["chains"][i]["nodes"][chain_nodes+1]["address"] = node_address
+ #pprint(chains)
+ with smart_open(curr_dir + "/" + filename) as f:
+ print >>f, json.dumps(chains)
+ return filename
+
+#generates json file describing the node configurations (default config.json)
+def generate_config(curr_dir):
+ chains_file = "chains.json"
+
+ chains = parse_chains(curr_dir + "/" + chains_file)
+
+ print "Chains read from file:"
+ pprint(chains)
+ chains_id = []
+
+ for chain_id, chain in chains.items():
+ chains_id.append(chain_id)
+ print "Chain #" + str(chain_id) + " has " + str(len(chain)) + " elements"
+ for node_name in chain.keys():
+ print node_name + " ",
+ print ""
+
+
+ filename = "config.json"
+
+ config_names = []
+
+ i = -1
+
+ for number_of_chain in chains_id:
+ number_of_nodes = len(chains[number_of_chain].keys())
+
+ # for i in range(0, number_of_nodes):
+
+ for node_name, node_map in chains[number_of_chain].items():
+ if node_name in config_names:
+ continue
+ config_names.append(node_name)
+ i += 1
+ configuration["nodes"].insert(i, {})
+ # node_id = raw_input("Node #" + str(i+1) + " id? -->")
+ # configuration["nodes"][i]["id"] = node_id
+ configuration["nodes"][i]["id"] = node_name
+
+ name_split = node_name.split("_")
+
+ #init = raw_input("Any parameter for inizialization of node " + node_name + "? (N/Y)-->")
+ init_list = devices_initialization[node_map["functional_type"]]
+ if init_list != []:
+ for init_item in init_list:
+ init_param = "ip_" + init_item + "_" + name_split[1]
+ configuration["nodes"][i][init_item] = init_param
+
+ node_description = name_split[0] + " denies any traffic from web_client #" + name_split[1] + " to web_server #" + name_split[1]
+ configuration["nodes"][i]["description"] = node_description
+ while(True):
+ #node_configuration_type = raw_input("Node " + node_id +"'s configuration type (list, maps)? (L/M) -->")
+ #n = search_node_in_chains(node_id)
+
+ node_configuration_type = devices_configuration_methods[node_map["functional_type"]]
+ if node_configuration_type == "list":
+ #list
+ configuration["nodes"][i]["configuration"] = []
+
+ break
+ if node_configuration_type == "maps":
+ #maps
+ configuration["nodes"][i]["configuration"] = []
+ n_entries = 1
+
+ for m in range(0, n_entries):
+ configuration["nodes"][i]["configuration"].insert(m, {})
+
+ map_elements = 1
+
+ for n in range(0, map_elements):
+ key = "ip_web_server_" + name_split[1]
+ value = "ip_web_client_" + name_split[1]
+ configuration["nodes"][i]["configuration"][m][key] = value
+ break
+ else:
+ print "Invalid config, please edit the config file"
+ #pprint(configuration)
+ with smart_open(curr_dir + "/" + filename) as f:
+ print >>f, json.dumps(configuration)
+ return filename
+
+def main(argv):
+ #exit if any command line argument is missing
+ if len(argv) < 4:
+ print 'batch_generator.py -m <multiplier> -o <output_directory>'
+ sys.exit(2)
+ #initialize json file names
+ chains_file = ''
+ configuration_file = ''
+ output_dir = ''
+ multiplier = ''
+ #parse command line arguments and exit if there is an error
+ try:
+ opts, args = getopt.getopt(argv,"hm:o:",["mutliplier=","help","odir="])
+ except getopt.GetoptError as err:
+ print str(err)
+ print 'batch_generator.py -m <multiplier> -o <output_directory>'
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print 'batch_generator.py -m <multiplier> -o <output_directory>'
+ sys.exit()
+ elif opt in ("-o", "--output"):
+ output_dir = arg
+ elif opt in ("-m", "--multiplier"):
+ multiplier = arg
+
+ generate_chains(output_dir, multiplier, "tcp=80")
+ generate_config(output_dir)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/verigraph/service/src/tests/j-verigraph-generator/code_generator.py b/verigraph/service/src/tests/j-verigraph-generator/code_generator.py
new file mode 100644
index 0000000..5b9834f
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/code_generator.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import sys, string
+
+class CodeGeneratorBackend:
+
+ def begin(self, tab="\t"):
+ self.code = []
+ self.tab = tab
+ self.level = 0
+
+ def end(self):
+ return string.join(self.code, "")
+
+ def write(self, string):
+ self.code.append(self.tab * self.level + string)
+
+ def writeln(self, string):
+ self.code.append(self.tab * self.level + string + "\n")
+
+ def append(self, string):
+ self.code.append(string)
+
+ def indent(self):
+ self.level = self.level + 1
+
+ def dedent(self):
+ if self.level == 0:
+ raise SyntaxError, "internal error in code generator"
+ self.level = self.level - 1
+
+ def write_list(self, data, delimiter=True, wrapper="'"):
+ if delimiter == True:
+ self.code.append("{")
+ first = True
+ for element in data:
+ if (first == False):
+ self.code.append(", ")
+ else:
+ first = False
+ if wrapper == "'":
+ self.code.append("'" + str(element) + "'")
+ elif wrapper == "\"":
+ self.code.append("\"" + str(element) + "\"")
+ elif wrapper == "b":
+ self.code.append("(" + str(element) + ")")
+ else:
+ self.code.append(str(element))
+ if delimiter == True:
+ self.code.append("}")
diff --git a/verigraph/service/src/tests/j-verigraph-generator/config.py b/verigraph/service/src/tests/j-verigraph-generator/config.py
new file mode 100644
index 0000000..3fe5d6c
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/config.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+devices_to_classes = { "webclient" : "PolitoWebClient",
+ "webserver" : "PolitoWebServer",
+ "cache" : "PolitoCache",
+ "nat" : "PolitoNat",
+ "firewall" : "AclFirewall",
+ "mailclient" : "PolitoMailClient",
+ "mailserver" : "PolitoMailServer",
+ "antispam" : "PolitoAntispam",
+ "endpoint": "EndHost",
+ "dpi": "PolitoIDS",
+ "endhost": "PolitoEndHost",
+ "vpnaccess":"PolitoVpnAccess",
+ "vpnexit":"PolitoVpnExit",
+ "fieldmodifier":"PolitoFieldModifier"
+ }
+devices_to_configuration_methods = {"webclient" : "",
+ "webserver" : "",
+ "cache" : "installCache",
+ "nat" : "setInternalAddress",
+ "firewall" : "addAcls",
+ "mailclient" : "",
+ "mailserver" : "",
+ "antispam" : "",
+ "endpoint": "",
+ "dpi": "installIDS",
+ "endhost": "installEndHost",
+ "vpnaccess":"vpnAccessModel",
+ "vpnexit":"vpnAccessModel",
+ "fieldmodifier":"installFieldModifier"
+ }
+devices_initialization = { "webclient" : ["webserver"],
+ "webserver" : [],
+ "cache" : [],
+ "nat" : [],
+ "firewall" : [],
+ "mailclient" : ["mailserver"],
+ "mailserver" : [],
+ "antispam" : [],
+ "endpoint": [],
+ "dpi":[] ,
+ "endhost":[],
+ "vpnaccess":[],
+ "vpnexit":[],
+ "fieldmodifier":[]
+ }
+
+convert_configuration_property_to_ip = { "webclient" : ["value"],
+ "webserver" : [],
+ "cache" : ["value"],
+ "nat" : ["value"],
+ "firewall" : ["key", "value"],
+ "mailclient" : ["value"],
+ "mailserver" : [],
+ "antispam" : [],
+ "endpoint": [],
+ "dpi": [],
+ "endhost": [],
+ "vpnaccess": ["value"],
+ "vpnexit": ["value"],
+ "fieldmodifier": []
+ }
+
+devices_configuration_fields = { "webclient" : "",
+ "webserver" : "",
+ "cache" : "cached address",
+ "nat" : "natted address",
+ "firewall" : "acl entry",
+ "mailclient" : "",
+ "mailserver" : "",
+ "antispam" : "",
+ "endpoint": "",
+ "dpi":"words blacklist",
+ "endhost":"",
+ "vpnaccess":"vpn access",
+ "vpnexit":"vpn exit",
+ "fieldmodifier":"field modifier"
+ }
diff --git a/verigraph/service/src/tests/j-verigraph-generator/json_generator.py b/verigraph/service/src/tests/j-verigraph-generator/json_generator.py
new file mode 100644
index 0000000..d65ea43
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/json_generator.py
@@ -0,0 +1,261 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import json
+from pprint import pprint
+import sys
+import commands
+import os
+from config import *
+from utility import *
+import batch_generator
+import subprocess
+
+#global variables
+chains = {}
+chains["chains"] = []
+routing = {}
+routing["routing_table"] = []
+configuration = {}
+configuration["nodes"] = []
+#end of global variables
+
+
+
+#generates json file describing the chains (default chains.json)
+def generate_chains(curr_dir):
+ filename = "chains.json"
+ fn = raw_input("Please enter a file name for the json file describing the nodes chains (default \"chains.json\") -->")
+ if fn != "":
+ filename = fn
+
+ number_of_chains = check_input_is_int("Please enter the number of chains you wish to simulate: -->")
+ for i in range(0, int(number_of_chains)):
+ chains["chains"].insert(i, {})
+ #decomment the following 2 lines to make chain id an arbitrary integer
+ #chain_id = check_input_is_int("Chain #" + str(i+1) + " id? -->")
+ #chains["chains"][i]["id"] = chain_id
+ chains["chains"][i]["id"] = i+1
+ flowspace = raw_input("Chain #" + str(i+1) + " flowspace? -->")
+ chains["chains"][i]["flowspace"] = flowspace
+ chain_nodes = check_input_is_int("How many nodes does the chain #" + str(i+1) + " have? -->")
+ chains["chains"][i]["nodes"] = []
+ for j in range(0, chain_nodes):
+ chains["chains"][i]["nodes"].insert(j, {})
+ node_name = raw_input("Node #" + str(j+1) + " name? -->")
+ chains["chains"][i]["nodes"][j]["name"] = node_name
+ print "Available functional types are:"
+ for device in devices_to_classes.keys():
+ print device + " ",
+ while True:
+ node_type = raw_input("Node #" + str(j+1) + " functional_type (see valid options above)? -->")
+ if node_type in devices_to_classes.keys():
+ break
+ chains["chains"][i]["nodes"][j]["functional_type"] = node_type
+ node_address = raw_input("Node #" + str(j+1) + " address? -->")
+ chains["chains"][i]["nodes"][j]["address"] = node_address
+ #pprint(chains)
+ with smart_open(curr_dir + "/" + filename) as f:
+ print >>f, json.dumps(chains)
+ return filename
+
+#generates json file describing the node configurations (default config.json)
+def generate_config(curr_dir):
+ chains_file = "chains.json"
+ while True:
+ list_files(curr_dir)
+ fn = raw_input("Please enter the file name of the json file containing the chains (default \"chains.json\") -->")
+ if fn != "":
+ chains_file = fn
+ try:
+ chains = parse_chains(curr_dir + "/" + chains_file)
+ except:
+ print "Chains file is not valid"
+ continue
+ break
+ print "Chains read from file:"
+ pprint(chains)
+ chains_id = []
+
+ for chain_id, chain in chains.items():
+ chains_id.append(chain_id)
+ print "Chain #" + str(chain_id) + " has " + str(len(chain)) + " elements"
+ for node_name in chain.keys():
+ print node_name + " ",
+ print ""
+
+ while True:
+ number_of_chain = check_input_is_int("Please enter the number of the chain you wish to configure: -->")
+ if number_of_chain in chains_id:
+ break
+ else:
+ print "Please enter a valid chain id (see options above)"
+
+ filename = "config.json"
+ fn = raw_input("Please enter a file name for the json file describing the nodes configuration (default \"config.json\") -->")
+ if fn != "":
+ filename = fn
+
+ number_of_nodes = len(chains[number_of_chain].keys())
+
+# for i in range(0, number_of_nodes):
+ i = -1
+ for node_name, node_map in chains[number_of_chain].items():
+ i += 1
+ configuration["nodes"].insert(i, {})
+# node_id = raw_input("Node #" + str(i+1) + " id? -->")
+# configuration["nodes"][i]["id"] = node_id
+ configuration["nodes"][i]["id"] = node_name
+ #init = raw_input("Any parameter for inizialization of node " + node_name + "? (N/Y)-->")
+ init_list = devices_initialization[node_map["functional_type"]]
+ if init_list != []:
+ for init_item in init_list:
+ init_param = raw_input("Please enter the IP address of parameter \"" + init_item + "\" for node " + node_name + ": -->")
+ configuration["nodes"][i][init_item] = init_param
+
+ node_description = raw_input("Node " + node_name +"'s configuration description? -->")
+ configuration["nodes"][i]["description"] = node_description
+ while(True):
+ #node_configuration_type = raw_input("Node " + node_id +"'s configuration type (list, maps)? (L/M) -->")
+ #n = search_node_in_chains(node_id)
+
+ node_configuration_type = devices_configuration_methods[node_map["functional_type"]]
+ if node_configuration_type == "list":
+ #list
+ configuration["nodes"][i]["configuration"] = []
+ config_elements = check_input_is_int("How many configuration elements for node " + node_name + "? (type 0 to skip configuration) -->")
+ for e in range(0, config_elements):
+ element = raw_input("\tPlease enter " + devices_configuration_fields[node_map["functional_type"]] + "#" + str(e+1) + " -->")
+ configuration["nodes"][i]["configuration"].append(element)
+ break
+ elif node_configuration_type == "maps":
+ #maps
+ configuration["nodes"][i]["configuration"] = []
+ n_entries = check_input_is_int("How many maps for the configuration of node " + node_name + "? (type 0 to skip configuration) -->")
+
+ for m in range(0, n_entries):
+ configuration["nodes"][i]["configuration"].insert(m, {})
+
+ map_elements = check_input_is_int("How many elements for map #" + str(m+1) + "? -->")
+
+ for n in range(0, map_elements):
+ key = raw_input("\tKey for " + devices_configuration_fields[node_map["functional_type"]] + "#" + str(n+1) + ": -->")
+ value = raw_input("\tValue for " + devices_configuration_fields[node_map["functional_type"]] + "#" + str(n+1) + ": -->")
+ configuration["nodes"][i]["configuration"][m][key] = value
+ break
+ else:
+ print "Invalid config, please edit the config file"
+ #pprint(configuration)
+ with smart_open(curr_dir + "/" + filename) as f:
+ print >>f, json.dumps(configuration)
+ return filename
+
+
+def main():
+
+ chains_file = ""
+ configuration_file = ""
+ routing_file = ""
+ curr_dir = os.getcwd()
+ current_path = curr_dir
+
+ set_dir = raw_input("Change working directory? (" + curr_dir + ") (N/Y) -->")
+ if set_dir == "Y" or set_dir == "y":
+ print "List of subdirectories:"
+ print list_directories(curr_dir)
+ while True:
+ curr_dir = os.path.abspath(raw_input("Enter working path (relative or absolute path are supported) -->"))
+ if os.path.exists(curr_dir):
+ current_path = curr_dir
+ break
+ else:
+ print "Please enter a valid path!"
+
+ directory = raw_input("Do you want to create a new test directory? (N/Y) -->")
+ if directory == "Y" or directory =="y":
+ directory_name = raw_input("Directory name? -->")
+ print commands.getoutput("mkdir -v " + curr_dir + "/" + directory_name)
+ current_path = curr_dir + "/" + directory_name
+
+ print "Files will be created at " + current_path
+
+ firewall_chain = False
+
+ while True:
+ choice = raw_input("""CHAINS?\n
+ Choose one of the following options:\n
+ 1) Automatic generation of chains.json and config.json for an N-firewall chain
+ 2) Generate step-by-step
+ 3) Verify the integrity of an existing json file
+ 4) Skip step\n-->""")
+ try:
+ if int(choice) == 1:
+ multiplier = check_input_is_int("Please enter N -->")
+ arguments = ["-m", str(multiplier), "-o", current_path]
+ batch_generator.main(arguments)
+ firewall_chain = True
+ break
+ elif int(choice) == 2:
+ chains_file = generate_chains(current_path)
+ break
+ elif int(choice) == 3:
+ chains_file = raw_input("Input file for CHAINS? -->")
+ if(check_chains_integrity(current_path + "/" + chains_file)) == True:
+ break
+ else:
+ print "Input json file for CHAINS not well formed, please try again!"
+ elif int(choice) == 4:
+ break
+ else:
+ print "Invalid choice, please try again!"
+ except ValueError, e:
+ print "Invalid choice, please try again!"
+ continue
+
+ while True:
+
+ if firewall_chain == True:
+ chains_file = "chains.json"
+ configuration_file = "config.json"
+ routing_file = ""
+ break
+
+ choice = raw_input("""CONFIGURATION?\n
+ Choose one of the following options:\n
+ 1) Generate step-by-step
+ 2) Verify the integrity of an existing json file
+ 3) Skip step\n-->""")
+ try:
+ if int(choice) == 1:
+ configuration_file = generate_config(current_path)
+ break
+ elif int(choice) == 2:
+ configuration_file = raw_input("Input file for CONFIGURATION? -->")
+ if(check_config_integrity(current_path + "/" + configuration_file)) == True:
+ break
+ else:
+ print "Input json file for CONFIGURATION not well formed, please try again!"
+ elif int(choice) == 3:
+ break
+ else:
+ print "Invalid choice, please try again!"
+ except ValueError, e:
+ print "Invalid choice, please try again!"
+ continue
+
+ print "All done, you are ready to launch the test generator like so:"
+ print "test_class_generator.py -c " + chains_file + " -f " + configuration_file + " -o <output_file>"
+
+ return chains_file, configuration_file, routing_file, current_path
+
+
+if __name__ == "__main__":
+ main()
diff --git a/verigraph/service/src/tests/j-verigraph-generator/routing_generator.py b/verigraph/service/src/tests/j-verigraph-generator/routing_generator.py
new file mode 100644
index 0000000..c8956f2
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/routing_generator.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from pprint import pprint
+import sys, getopt
+import os
+from utility import *
+
+# used by test_class_generator
+def generate_routing_from_chain(chain):
+ routing = {}
+ routing["routing_table"] = {}
+
+ chain = chain["nodes"]
+ for i in range(0, len(chain)):
+ routing["routing_table"][chain[i]["name"]] = {}
+ for j in range(i-1, -1, -1):
+ routing["routing_table"][chain[i]["name"]][chain[j]["address"]] = chain[i-1]["name"]
+ for k in range (i+1, len(chain)):
+ routing["routing_table"][chain[i]["name"]][chain[k]["address"]] = chain[i+1]["name"]
+ pprint(routing)
+ return routing
+
+def generate_routing_from_chains_file(chains_file, chain_number):
+ routing = {}
+ routing["routing_table"] = {}
+
+ chains = convert_unicode_to_ascii(parse_json_file(chains_file))
+ chain = None
+ for chn in chains["chains"]:
+ if chn["id"] == chain_number:
+ chain = chn["nodes"]
+ break
+ if chain == None:
+ return routing
+
+ for i in range(0, len(chain)):
+ routing["routing_table"][chain[i]["name"]] = {}
+ for j in range(i-1, -1, -1):
+ routing["routing_table"][chain[i]["name"]][chain[j]["address"]] = chain[i-1]["name"]
+ for k in range (i+1, len(chain)):
+ routing["routing_table"][chain[i]["name"]][chain[k]["address"]] = chain[i+1]["name"]
+ pprint(routing)
+ return routing
+
+def main(argv):
+ if len(argv) < 4:
+ print 'routing_generator.py -c <chains_file> -n <chain_number>'
+ sys.exit(2)
+ chains_file = ""
+ chain_number = ""
+ try:
+ opts, args = getopt.getopt(argv,"hc:n:",["chains=","id="])
+ except getopt.GetoptError:
+ print 'routing_generator.py -c <chains_file> -n <chain_number>'
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt == '-h':
+ print 'routing_generator.py -c <chains_file> -n <chain_number>'
+ sys.exit()
+ elif opt in ("-c", "--chains"):
+ chains_file = arg
+ elif opt in ("-n", "--id"):
+ chain_number = arg
+
+ print "Chains file is " + chains_file
+ print "Chain id is " + chain_number
+
+ return generate_routing_from_chains_file(chains_file, chain_number)
+
+if __name__ == '__main__':
+ main(sys.argv[1:]) \ No newline at end of file
diff --git a/verigraph/service/src/tests/j-verigraph-generator/test_class_generator.py b/verigraph/service/src/tests/j-verigraph-generator/test_class_generator.py
new file mode 100644
index 0000000..7bf446c
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/test_class_generator.py
@@ -0,0 +1,399 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from pprint import pprint
+from pprint import pformat
+import sys, getopt
+from code_generator import CodeGeneratorBackend
+import os, errno
+from config import *
+from utility import *
+from routing_generator import *
+import logging
+from pip._vendor.pkg_resources import null_ns_handler
+
+#generates a custom test file
+def generate_test_file(chain, number, configuration, output_file="test_class"):
+
+ route = {}
+ config = {}
+ chn = {}
+
+ #initiatlize the config dictionary for each node
+ for node in chain["nodes"]:
+ config[node["name"]] = {}
+
+ #initiatlize the route dictionary for each node
+ for node in chain["nodes"]:
+ route[node["name"]] = {}
+
+ #initiatlize the chn dictionary for each node
+ for node in chain["nodes"]:
+ chn[node["name"]] = {}
+
+ #set chn values: chn[name][key] = value
+ for node in chain["nodes"]:
+ for key, value in node.items():
+ try:
+ #name key is redundant in map
+ if key != "name":
+ chn[node["name"]][key] = value
+ except KeyError, e:
+ logging.debug("Field " + str(key) + " not found for node " + str(node["name"]))
+ logging.debug("Cotinuing...")
+ continue
+
+ #debug print of chn
+ logging.debug(pformat((chn)))
+
+ routing = generate_routing_from_chain(chain)
+
+ for node_name, node_rt in routing["routing_table"].items():
+ route[node_name] = node_rt
+
+ #debug print of route
+ logging.debug(pformat((route)))
+
+ #set config: config[node_name][key] = value
+ for node in configuration["nodes"]:
+ for key, value in node.items():
+ #id field is redundant
+ if key != "id":
+ try:
+ if key == "configuration":
+ #init config[node_name][key] with an empty array
+ config[node["id"]][key] = []
+
+ for value_item in value:
+ change_key = "key" in convert_configuration_property_to_ip[chn[node["id"]]["functional_type"]]
+ change_value = "value" in convert_configuration_property_to_ip[chn[node["id"]]["functional_type"]]
+ if (change_key==False and change_value==False):
+ config[node["id"]][key].append(value_item)
+ continue
+ # config[node_name][configuration] is a dictionary
+ if isinstance(value_item, dict):
+ for config_item_key, config_item_value in value_item.items():
+ new_key = config_item_key
+ changed_key = False
+ changed_value = False
+ if change_key and config_item_key in chn.keys():
+ changed_key = True
+ new_key = "ip_" + str(config_item_key)
+ value_item[new_key] = str(config_item_value)
+ del value_item[config_item_key]
+ if change_value and config_item_value in chn.keys():
+ changed_value = True
+ new_value = "ip_" + str(config_item_value)
+ value_item[new_key] = new_value
+ if(change_key==changed_key) and (change_value==changed_value):
+ config[node["id"]][key].append(value_item)
+ else:
+ if change_value:
+ if value_item in chn.keys():
+ new_value = "ip_" + str(value_item)
+ config[node["id"]][key].append(new_value)
+ else:
+ config[node["id"]][key].append(str(value_item))
+ else:
+ config[node["id"]][key] = value
+ except KeyError, e:
+ #node not found in current chain
+ logging.debug("Field '" + key + "' not found for node '" + str(node["id"]) + "'")
+ logging.debug(key + " probably doesn't belong to the current chain, thus it will be skipped")
+ #sys.exit(1)
+ continue
+
+ # debug print of config
+ logging.debug(pformat((config)))
+
+ #prepare a few more helpful data structures
+ nodes_names = []
+ nodes_types = []
+ nodes_addresses = []
+ nodes_ip_mappings = []
+ nodes_rt = {}
+
+ #initialize vectors for node names and routing tables
+ for name in chn.keys():
+ nodes_names.append(name)
+ nodes_rt[name] = []
+
+ #add functional types, addresses and ip mapping to vectors
+ for node, field in chn.items():
+ nodes_types.append(field["functional_type"])
+ nodes_addresses.append(field["address"])
+ nodes_ip_mappings.append(field["address"])
+
+ for node, rt in route.items():
+ for dest, next_hop in rt.items():
+ row = "nctx.am.get(\"" + dest + "\"), " + next_hop
+ try:
+ nodes_rt[node].append(row)
+ except KeyError, e:
+ #node not found, notify and exit
+ logging.debug("Node " + node + " not found!")
+ sys.exit(1)
+
+ #begin file generation
+ logging.debug("* instantiating chain #" + str(number))
+ dirname = os.path.dirname(output_file)
+ basename = os.path.basename(output_file)
+ basename = os.path.splitext(basename)[0]
+ basename = basename[0].upper() + basename[1:]
+ with smart_open(dirname + "/" + basename + "_" + str(number) + ".java") as f:
+ c = CodeGeneratorBackend()
+ c.begin(tab=" ")
+
+ c.writeln("package tests.scenarios;")
+
+ #imports here
+ c.writeln("import java.util.ArrayList;")
+ c.writeln("import com.microsoft.z3.Context;")
+ c.writeln("import com.microsoft.z3.DatatypeExpr;")
+
+ c.writeln("import mcnet.components.Checker;")
+ c.writeln("import mcnet.components.NetContext;")
+ c.writeln("import mcnet.components.Network;")
+ c.writeln("import mcnet.components.NetworkObject;")
+ c.writeln("import mcnet.components.Tuple;")
+ c.writeln("import mcnet.netobjs.PacketModel;")
+
+ #import components
+ #for i in range(0, len(nodes_names)):
+ # c.writeln("import mcnet.netobjs." + devices_to_classes[str(nodes_types[i])] + ";")
+
+ for key, value in devices_to_classes.items():
+ c.writeln("import mcnet.netobjs." + value + ";")
+
+ c.writeln("public class " + basename + "_" + str(number) + "{")
+
+ c.indent()
+ c.writeln("public Checker check;")
+ # declare components
+ for i in range(0, len(nodes_names)):
+ c.writeln("public " + devices_to_classes[str(nodes_types[i])] + " " + str(nodes_names[i]) + ";")
+
+ # method setDevices
+ c.writeln("private void setDevices(Context ctx, NetContext nctx, Network net){")
+ c.indent()
+ for i in range(0, len(nodes_names)):
+ c.write(str(nodes_names[i]) + " = new " + devices_to_classes[str(nodes_types[i])] + "(ctx, new Object[]{nctx.nm.get(\"" + nodes_names[i] + "\"), net, nctx")
+ if devices_initialization[nodes_types[i]] != [] :
+ for param in devices_initialization[nodes_types[i]]:
+ print "configuring node " + nodes_names[i]
+ for config_param in config[nodes_names[i]]["configuration"]:
+ if param in config_param:
+ c.append(", nctx.am.get(\"" + config_param[param] + "\")")
+ c.append("});\n")
+ c.dedent()
+ c.writeln("}")
+ # end method setDevices
+
+ # method doMappings
+ c.writeln("private void doMappings(NetContext nctx, ArrayList<Tuple<NetworkObject,ArrayList<DatatypeExpr>>> adm){")
+ c.indent()
+ for i in range(0, len(nodes_names)):
+ c.writeln("ArrayList<DatatypeExpr> al" + str(i) + " = new ArrayList<DatatypeExpr>();")
+ c.writeln("al" + str(i) + ".add(nctx.am.get(\"" + nodes_ip_mappings[i] + "\"));")
+ c.writeln("adm.add(new Tuple<>((NetworkObject)" + nodes_names[i] + ", al" + str(i) + "));")
+ c.dedent()
+ c.writeln("}")
+ # end method doMappings
+
+ # for each node methods setRouting and configureDevice
+ for i in range(0, len(nodes_names)):
+ # method setRouting
+ c.writeln("private void setRouting" + nodes_names[i] + "(NetContext nctx, Network net, ArrayList<Tuple<DatatypeExpr,NetworkObject>> rt_" + nodes_names[i] + "){")
+ c.indent()
+ for row in nodes_rt[nodes_names[i]]:
+ c.writeln("rt_" + nodes_names[i] + ".add(new Tuple<DatatypeExpr,NetworkObject>(" + row + "));")
+ c.writeln("net.routingTable(" + nodes_names[i] + ", rt_" + nodes_names[i] + ");")
+ c.dedent()
+ c.writeln("}")
+ # end method setRouting
+ # method configureDevice
+ c.writeln("private void configureDevice" + nodes_names[i] + "(NetContext nctx) {")
+ c.indent()
+ #configure middle-box only if its configuration is not empty
+ if config[nodes_names[i]]["configuration"] != [] :
+ if nodes_types[i] == "cache":
+ c.write(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(new NetworkObject[]")
+ cache_ips = config[nodes_names[i]]["configuration"]
+ cache_hosts = []
+ for cache_ip in cache_ips:
+ i = -1
+ for host in nodes_addresses:
+ i += 1
+ if host == cache_ip:
+ cache_hosts.append(nodes_names[i])
+ c.write_list(formatted_list_from_list_of_maps(cache_hosts), wrapper="")
+ c.append(");\n")
+ elif nodes_types[i] == "nat":
+ c.writeln("ArrayList<DatatypeExpr> ia" + str(i) +" = new ArrayList<DatatypeExpr>();")
+ config_elements = []
+ config_elements = formatted_list_from_list_of_maps(config[nodes_names[i]]["configuration"])
+ for address in config_elements:
+ c.writeln("ia" + str(i) + ".add(nctx.am.get(\"" + address + "\"));")
+ c.writeln(nodes_names[i] + ".natModel(nctx.am.get(\"ip_" + nodes_names[i] + "\"));")
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(ia" + str(i) +");")
+ elif nodes_types[i] == "firewall":
+ c.writeln("ArrayList<Tuple<DatatypeExpr,DatatypeExpr>> acl" + str(i) + " = new ArrayList<Tuple<DatatypeExpr,DatatypeExpr>>();")
+ for config_element in config[nodes_names[i]]["configuration"]:
+ if isinstance(config_element,dict):
+ for key, value in config_element.items():
+ if key in nodes_addresses and value in nodes_addresses:
+ c.writeln("acl" + str(i) + ".add(new Tuple<DatatypeExpr,DatatypeExpr>(nctx.am.get(\"" + key + "\"),nctx.am.get(\"" + value + "\")));")
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(acl" + str(i) + ");")
+ elif nodes_types[i] == "antispam":
+ c.write(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(new int[]")
+ c.write_list(formatted_list_from_list_of_maps(config[nodes_names[i]]["configuration"]))
+ c.append(");\n")
+ elif nodes_types[i] == "dpi":
+ for index in range(0, len(config[nodes_names[i]]["configuration"])):
+ config[nodes_names[i]]["configuration"][index] = "String.valueOf(\"" + str(config[nodes_names[i]]["configuration"][index]) + "\").hashCode()"
+ c.write(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(new int[]")
+ c.write_list(formatted_list_from_list_of_maps(config[nodes_names[i]]["configuration"]), wrapper="")
+ c.append(");\n")
+ elif nodes_types[i] == "endhost":
+ c.writeln("PacketModel pModel" + str(i) + " = new PacketModel();")
+ if "body" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setBody(String.valueOf(\"" + config[nodes_names[i]]["configuration"][0]["body"] + "\").hashCode());")
+ if "sequence" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setSeq(" + config[nodes_names[i]]["configuration"][0]["sequence"] + ");")
+ if "protocol" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setProto(nctx." + config[nodes_names[i]]["configuration"][0]["protocol"] + ");")
+ if "email_from" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setEmailFrom(String.valueOf(\"" + config[nodes_names[i]]["configuration"][0]["email_from"] + "\").hashCode());")
+ if "url" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setUrl(String.valueOf(\"" + config[nodes_names[i]]["configuration"][0]["url"] + "\").hashCode());")
+ if "options" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setOptions(String.valueOf(\"" + config[nodes_names[i]]["configuration"][0]["options"] + "\").hashCode());")
+ if "destination" in config[nodes_names[i]]["configuration"][0]:
+ c.writeln("pModel" + str(i) + ".setIp_dest(nctx.am.get(\"" + config[nodes_names[i]]["configuration"][0]["destination"] + "\"));")
+
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(pModel" + str(i) + ");")
+ elif nodes_types[i] == "vpnaccess":
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(nctx.am.get(\"" + nodes_addresses[i] + "\"), nctx.am.get(\"" + config[nodes_names[i]]["configuration"][0]["vpnexit"] + "\"));")
+ elif nodes_types[i] == "vpnexit":
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "(nctx.am.get(\"" + config[nodes_names[i]]["configuration"][0]["vpnaccess"] + "\"), nctx.am.get(\"" + nodes_addresses[i] + "\"));")
+
+ # config is empty but configure device anyway
+ elif nodes_types[i] == "fieldmodifier":
+ c.writeln(nodes_names[i] + "." + devices_to_configuration_methods[nodes_types[i]] + "();")
+ c.dedent()
+ c.writeln("}")
+ # end method configureDevice
+
+
+ c.writeln("public " + basename + "_" + str(number) + "(Context ctx){")
+ c.indent()
+ c.write("NetContext nctx = new NetContext (ctx,new String[]")
+ c.write_list(nodes_names, wrapper="\"")
+ c.append(", new String[]")
+ c.write_list(nodes_addresses, wrapper="\"")
+ c.append(");\n")
+ c.writeln("Network net = new Network (ctx,new Object[]{nctx});")
+ # call method setDevices
+ c.writeln("setDevices(ctx, nctx, net);")
+
+ #SET ADDRESS MAPPINGS
+ c.writeln("ArrayList<Tuple<NetworkObject,ArrayList<DatatypeExpr>>> adm = new ArrayList<Tuple<NetworkObject,ArrayList<DatatypeExpr>>>();")
+ # call doMappings
+ c.writeln("doMappings(nctx, adm);")
+ c.writeln("net.setAddressMappings(adm);")
+
+ #CONFIGURE ROUTING TABLE
+ for i in range(0, len(nodes_names)):
+ c.writeln("ArrayList<Tuple<DatatypeExpr,NetworkObject>> rt_" + nodes_names[i] + " = new ArrayList<Tuple<DatatypeExpr,NetworkObject>>(); ")
+ c.writeln("setRouting" + nodes_names[i] + "(nctx, net, rt_" + nodes_names[i] + ");")
+
+ #ATTACH DEVICES
+ c.write("net.attach(")
+ c.write_list(nodes_names, delimiter = False, wrapper="")
+ c.append(");\n")
+
+ #CONFIGURE MIDDLE-BOXES
+ for i in range(0, len(nodes_names)):
+ c.writeln("configureDevice" + nodes_names[i] + "(nctx);")
+
+ c.writeln("check = new Checker(ctx,nctx,net);")
+
+ c.dedent()
+ c.writeln("}")
+
+ c.dedent()
+ c.writeln("}")
+
+ #write c object to file
+ print >>f, c.end()
+
+ logging.debug("wrote test file " + os.path.abspath(dirname + "/" + basename + "_" + str(number)) + ".java" + " successfully!")
+
+
+def main(argv):
+ #exit if any command line argument is missing
+ if len(argv) < 6:
+ print 'test_class_generator.py -c <chain_file> -f <conf_file> -o <output_name>'
+ sys.exit(1)
+
+ #initialize json file names
+ chains_file = ''
+ configuration_file = ''
+ output_file = ''
+
+ #parse command line arguments and exit in case of any error
+ try:
+ opts, args = getopt.getopt(argv,"hc:f:r:o:",["help","chain=","config=","route=","ofile="])
+ except getopt.GetoptError as err:
+ print str(err)
+ print 'test_class_generator.py -c <chain_file> -f <conf_file> -o <output_name>'
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print 'test_class_generator.py -c <chain_file> -f <conf_file> -o <output_name'
+ sys.exit()
+ elif opt in ("-c", "--chain"):
+ chains_file = arg
+ elif opt in ("-f", "--config"):
+ configuration_file = arg
+ elif opt in ("-o", "--ofile"):
+ output_file = arg
+
+ #set logging
+ logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
+
+ #parse chains file
+ chains = convert_unicode_to_ascii(parse_json_file(chains_file))
+
+ #parse configuration file
+ configuration = convert_unicode_to_ascii(parse_json_file(configuration_file))
+
+ logging.debug(pformat((chains)))
+ logging.debug(pformat((configuration)))
+
+ #custom formatted prints
+ print_chains(chains)
+ print_configuration(configuration)
+
+ #counter for the number of chains
+ number_of_chains = 0
+
+ #generate test classes
+ for chain in chains["chains"]:
+ #increment the number of chains
+ number_of_chains += 1;
+ #generate test files
+ generate_test_file(chain, number_of_chains, configuration, output_file)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
+
diff --git a/verigraph/service/src/tests/j-verigraph-generator/test_generator.py b/verigraph/service/src/tests/j-verigraph-generator/test_generator.py
new file mode 100644
index 0000000..f4629bb
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/test_generator.py
@@ -0,0 +1,160 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from pprint import pprint
+from code_generator import CodeGeneratorBackend
+import sys, getopt
+import contextlib
+import os
+from utility import *
+import logging
+
+def main(argv):
+ if len(argv) < 8:
+ print 'test_generator.py -i <inputfile> -o <outputfile> -s <source> -d <destination>'
+ sys.exit(2)
+ #initialize command line arguments values
+ inputfile = ''
+ outputfile = ''
+ source = ''
+ destination = ''
+ #parse command line arguments and exit if there is an error
+ try:
+ opts, args = getopt.getopt(argv,"hi:o:s:d:",["ifile=","ofile=","source=","destination="])
+ except getopt.GetoptError:
+ print 'test_generator.py -i <inputfile> -o <outputfile> -s <source> -d <destination>'
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt == '-h':
+ print 'test_generator.py -i <inputfile> -o <outputfile> -s <source> -d <destination>'
+ sys.exit()
+ elif opt in ("-i", "--ifile"):
+ inputfile = arg
+ elif opt in ("-o", "--ofile"):
+ outputfile = arg
+ elif opt in ("-s", "--source"):
+ source = arg
+ elif opt in ("-d", "--destination"):
+ destination = arg
+ #set logging
+ logging.basicConfig(stream=sys.stderr, level=logging.INFO)
+ #capitalize ouput filename
+ dirname = os.path.dirname(outputfile)
+ basename = os.path.basename(outputfile)
+ basename = os.path.splitext(basename)[0]
+ basename = basename[0].upper() + basename[1:]
+
+ #print arguments
+ logging.debug('Input file is', inputfile)
+ logging.debug('Output file is', dirname + "/" + basename)
+ logging.debug('Source node is', source)
+ logging.debug('Destination node is', destination)
+
+ #begin file generation
+ with smart_open(dirname + "/" + basename + ".java") as f:
+ c = CodeGeneratorBackend()
+ c.begin(tab=" ")
+ c.writeln("package tests;")
+ c.writeln("import java.util.Calendar;")
+ c.writeln("import java.util.Date;")
+ c.writeln("import java.util.HashMap;")
+
+ c.writeln("import com.microsoft.z3.Context;")
+ c.writeln("import com.microsoft.z3.FuncDecl;")
+ c.writeln("import com.microsoft.z3.Model;")
+ c.writeln("import com.microsoft.z3.Status;")
+ c.writeln("import com.microsoft.z3.Z3Exception;")
+ c.writeln("import mcnet.components.IsolationResult;")
+
+
+ inputfile = os.path.basename(inputfile)
+ c.writeln("import tests.scenarios." + os.path.splitext(inputfile)[0] + ";")
+ c.writeln("public class " + basename + "{")
+
+ c.indent()
+ c.writeln("Context ctx;")
+
+ c.write("public void resetZ3() throws Z3Exception{\n\
+ HashMap<String, String> cfg = new HashMap<String, String>();\n\
+ cfg.put(\"model\", \"true\");\n\
+ ctx = new Context(cfg);\n\
+ \r\t}\n")
+
+ c.write("public void printVector (Object[] array){\n\
+ int i=0;\n\
+ System.out.println( \"*** Printing vector ***\");\n\
+ for (Object a : array){\n\
+ i+=1;\n\
+ System.out.println( \"#\"+i);\n\
+ System.out.println(a);\n\
+ System.out.println( \"*** \"+ i+ \" elements printed! ***\");\n\
+ }\n\
+ \r\t}\n")
+
+ c.write("public void printModel (Model model) throws Z3Exception{\n\
+ for (FuncDecl d : model.getFuncDecls()){\n\
+ System.out.println(d.getName() +\" = \"+ d.toString());\n\
+ System.out.println(\"\");\n\
+ }\n\
+ \r\t}\n")
+
+ c.writeln("public int run() throws Z3Exception{")
+ c.indent()
+
+ c.writeln(basename + " p = new " + basename + "();")
+
+ #adding time estimation
+ #c.writeln("int k = 0;")
+ #c.writeln("long t = 0;")
+
+ #c.writeln("for(;k<1;k++){")
+ #c.indent()
+
+ c.writeln("p.resetZ3();")
+
+ c.write(os.path.splitext(inputfile)[0] + " model = new " + os.path.splitext(inputfile)[0] + "(p.ctx);\n")
+
+ #c.writeln("Calendar cal = Calendar.getInstance();")
+ #c.writeln("Date start_time = cal.getTime();")
+
+ c.write("IsolationResult ret =model.check.checkIsolationProperty(model.")
+ c.append(source + ", model." + destination + ");\n")
+ #c.writeln("Calendar cal2 = Calendar.getInstance();")
+ #c.writeln("t = t+(cal2.getTime().getTime() - start_time.getTime());")
+
+ c.writeln("if (ret.result == Status.UNSATISFIABLE){\n\
+ System.out.println(\"UNSAT\");\n\
+ return -1;\n\
+ }else if (ret.result == Status.SATISFIABLE){\n\
+ System.out.println(\"SAT\");\n\
+ return 0;\n\
+ }else{\n\
+ System.out.println(\"UNKNOWN\");\n\
+ return -2;\n\
+ \r\t\t}")
+
+ #c.dedent()
+ #c.writeln("}")
+
+ #c.writeln("")
+ #c.writeln("System.out.printf(\"Mean execution time " + source + " -> " + destination + ": %.16f\", ((float) t/(float)1000)/k);")
+
+ c.dedent()
+ c.writeln("}")
+
+ c.dedent()
+ c.writeln("}")
+
+ print >>f, c.end()
+ logging.debug("File " + os.path.abspath(dirname + "/" + basename + ".java") + " has been successfully generated!!")
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/verigraph/service/src/tests/j-verigraph-generator/utility.py b/verigraph/service/src/tests/j-verigraph-generator/utility.py
new file mode 100644
index 0000000..47d0180
--- /dev/null
+++ b/verigraph/service/src/tests/j-verigraph-generator/utility.py
@@ -0,0 +1,257 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import json
+import contextlib
+import sys
+import os
+import subprocess
+from pprint import pprint
+
+#manages output easily (can either write to file or to stdout)
+@contextlib.contextmanager
+def smart_open(filename=None):
+ if filename and filename != '-':
+ fh = open(filename, 'w')
+ else:
+ fh = sys.stdout
+ try:
+ yield fh
+ finally:
+ if fh is not sys.stdout:
+ fh.close()
+
+def check_input_is_int(text):
+ while True:
+ data = raw_input(text)
+ try:
+ int_value = int(data)
+ except ValueError:
+ print "Please enter a valid number!"
+ continue
+ return int_value
+
+#parses a json file into a unicode dictionary
+def parse_json_file(filename):
+ with open(filename) as json_file:
+ return json.load(json_file)
+
+#returns an ascii dictionary from a unicode one
+def convert_unicode_to_ascii(input):
+ if isinstance(input, dict):
+ return {convert_unicode_to_ascii(key): convert_unicode_to_ascii(value) for key, value in input.iteritems()}
+ elif isinstance(input, list):
+ return [convert_unicode_to_ascii(element) for element in input]
+ elif isinstance(input, unicode):
+ return input.encode('utf-8')
+ else:
+ return input
+
+#parses a chains file
+def parse_chains(chains_file):
+ chains_json = convert_unicode_to_ascii(parse_json_file(chains_file))
+
+ chains = {}
+
+ for chn in chains_json["chains"]:
+ try:
+ chains[chn["id"]] = {}
+ #initiatlize the config dictionary for each node
+ for node in chn["nodes"]:
+ chains[chn["id"]][node["name"]] = {}
+ except:
+ raise KeyError("Chains file is not valid!")
+
+ for chn in chains_json["chains"]:
+ try:
+ #set chn values ---> chn(name, (field, value))
+ for node in chn["nodes"]:
+ for key, value in node.items():
+ #name key is redundant in map
+ if key != "name":
+ chains[chn["id"]][node["name"]][key] = value
+ except:
+ raise KeyError("Chains file is not valid!")
+ return chains
+
+def check_chains_integrity(filename):
+ print "Checking input file..."
+ try:
+ chains = convert_unicode_to_ascii(parse_json_file(filename))
+ print "File correctly parsed"
+ if isinstance(chains["chains"], list) == False:
+ print "Child of chains is not a list!"
+ return False
+ for chain in chains["chains"]:
+ print "Chain found, checking its fields..."
+ print "Checking chain id field... "
+ chain["id"]
+ print "OK!"
+ print "Checking chain flowspace field... "
+ chain["flowspace"]
+ print "OK!"
+ if isinstance(chain["nodes"], list) == False:
+ print "Chain #" + chain["id"] + " does not have a list of nodes!"
+ return False
+ for node in chain["nodes"]:
+ print "Node found, checking its fields..."
+ print "Checking node name... "
+ node["name"]
+ print "OK!"
+ print "Checking node functional_type field... "
+ node["functional_type"]
+ print "OK!"
+ print "Checking node address field... "
+ node["address"]
+ print "OK!"
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ print "One or more required fields are missing!"
+ return False
+ print filename + " validated successfully!"
+ return True
+
+def check_config_integrity(filename):
+ print "Checking input file..."
+ try:
+ config = convert_unicode_to_ascii(parse_json_file(filename))
+ pprint(config)
+ print "File correctly parsed"
+ if isinstance(config["nodes"], list) == False:
+ print "Child of nodes is not a list!"
+ return False
+ for node in config["nodes"]:
+ print "Node found, checking its fields..."
+ print "Checking id field... "
+ node["id"]
+ print "OK!"
+ print "Checking description field... "
+ node["description"]
+ print "OK!"
+ print "Checking configuration field... "
+ node["configuration"]
+ print "OK!"
+ if isinstance(node["configuration"], list) == False:
+ print "Checking if node configuration is a list..."
+ print "Node with id " + node["id"] + " does not have a configuration list!"
+ return False
+ for c in node["configuration"]:
+ print "Checking if node configuration element is a string or a dictionary..."
+ if (isinstance(c, str) == False and isinstance(c, dict) == False):
+ print "At least one element of node with id " + node["id"] + " has an invalid configuration (it is neither a string or a map)"
+ return False
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ print "One or more required fields are missing!"
+ return False
+ print filename + " validated successfully!"
+ return True
+
+def check_routing_integrity(filename):
+ print "Checking input file..."
+ try:
+ routing = convert_unicode_to_ascii(parse_json_file(filename))
+ print "File correctly parsed"
+ if isinstance(routing["routing_table"], list) == False:
+ print "Child of routing_table is not a list!"
+ return False
+ for node in routing["routing_table"]:
+ if isinstance(node, dict) == False:
+ print "Child of routing_table is not a map!"
+ return False
+ for n, rt in node.items():
+ if isinstance(rt, list) == False:
+ print "Routing table of element " + n + " is not a list!"
+ return False
+ for entry in rt:
+ if isinstance(entry, dict) == False:
+ print "Invalid entry for node " + n + " (not a map)!"
+ return False
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ print "One or more required fields are missing!"
+ return False
+ return True
+
+#prints every node for each input chain
+def print_chains(chains):
+ for chain in chains["chains"]:
+ print "CHAIN #" + str(chain["id"])
+ for node in chain["nodes"]:
+ print "Name: " + str(node["name"])
+ print "Functional type: " + str(node["functional_type"])
+ print "Address: " + str(node["address"])
+ print "-----------------------------------"
+ print ""
+
+#prints every node's configuration
+def print_configuration(configuration):
+ print "NODES CONFIGURATION"
+ for node in configuration["nodes"]:
+ print "Name: " + str(node["id"])
+ print "Description: " + str(node["description"])
+ print "Configuration: "
+ pprint(node["configuration"])
+ print "-----------------------------------"
+ print ""
+
+#print every node's routing table
+def print_routing_table(routing):
+ print "ROUTING"
+ for table in routing["routing_table"]:
+ for node,rt in table.items():
+ print "Name: " + str(node)
+ pprint(rt)
+ print "-----------------------------------"
+ print ""
+
+#returns a list of tuple [(k1, v1), (k2, v2)] from a list of maps like [{k1 : v1},{k2 : v2}]
+def formatted_list_from_list_of_maps(maps):
+ l = []
+ for map in maps:
+ if isinstance(map, dict):
+ for k, v in map.items():
+ #l.append("(ctx." + str(k) + ", ctx." + str(v) + ")")
+ l.append(str(k))
+ l.append(str(v))
+ else:
+ #l.append("ctx." + map)
+ l.append(map)
+ return l
+
+def list_directories(dir):
+ #output = subprocess.call(["ls", "-d", "*/"])
+ output = subprocess.call(["find", dir, "-type", "d"])
+
+ #TREE VERSION
+ #find = subprocess.Popen(["find", ".", "-type", "d"], stdout=subprocess.PIPE)
+ #output = subprocess.check_output(["sed", "-e", "s/[^-][^\/]*\// |/g", "-e", "s/|\([^ ]\)/|-\1/"], stdin=find.stdout)
+ #find.wait()
+
+# ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
+# output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
+# ps.wait()
+ return output
+
+def list_files(dir):
+ output = subprocess.call(["find", dir, "-type", "f"])
+ return output
+
+def search_node_in_chains(n):
+ found = []
+ for chain in chains["chains"]:
+ for node in chain["nodes"]:
+ if node["name"] == n:
+ found.append(node)
+ return found \ No newline at end of file
diff --git a/verigraph/src/main/java/it/polito/escape/verify/client/Neo4jManagerClient.java b/verigraph/src/main/java/it/polito/escape/verify/client/Neo4jManagerClient.java
new file mode 100644
index 0000000..044c136
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/client/Neo4jManagerClient.java
@@ -0,0 +1,339 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.client;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import it.polito.escape.verify.deserializer.PathsMessageBodyReader;
+import it.polito.escape.verify.model.Entry;
+import it.polito.nffg.neo4j.jaxb.ActionEnumType;
+import it.polito.nffg.neo4j.jaxb.ActionType;
+import it.polito.nffg.neo4j.jaxb.ActionsType;
+import it.polito.nffg.neo4j.jaxb.CiType;
+import it.polito.nffg.neo4j.jaxb.CiType.Attributes;
+import it.polito.nffg.neo4j.jaxb.CiType.Attributes.Attribute;
+import it.polito.nffg.neo4j.jaxb.CpType;
+import it.polito.nffg.neo4j.jaxb.CpointsType;
+import it.polito.nffg.neo4j.jaxb.CtrlInterfacesType;
+import it.polito.nffg.neo4j.jaxb.EpCpType;
+import it.polito.nffg.neo4j.jaxb.EpType;
+import it.polito.nffg.neo4j.jaxb.EpType.Flowspace;
+import it.polito.nffg.neo4j.jaxb.EpointsType;
+import it.polito.nffg.neo4j.jaxb.EpsCpsType;
+import it.polito.nffg.neo4j.jaxb.FlowrulesType;
+import it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp;
+import it.polito.nffg.neo4j.jaxb.MonParamsType;
+import it.polito.nffg.neo4j.jaxb.MonParamsType.Parameter;
+import it.polito.nffg.neo4j.jaxb.NeType;
+import it.polito.nffg.neo4j.jaxb.NelementsType;
+import it.polito.nffg.neo4j.jaxb.NfType;
+import it.polito.nffg.neo4j.jaxb.Nffg;
+import it.polito.nffg.neo4j.jaxb.NfunctionsType;
+import it.polito.nffg.neo4j.jaxb.ObjectFactory;
+import it.polito.nffg.neo4j.jaxb.Paths;
+import it.polito.nffg.neo4j.jaxb.PortDirEnumType;
+import it.polito.nffg.neo4j.jaxb.PortType;
+import it.polito.nffg.neo4j.jaxb.SpecType;
+import it.polito.nffg.neo4j.jaxb.SpecType.Cpu;
+import it.polito.nffg.neo4j.jaxb.SpecType.Deployment;
+import it.polito.nffg.neo4j.jaxb.SpecType.Image;
+import it.polito.nffg.neo4j.jaxb.SpecType.Memory;
+import it.polito.nffg.neo4j.jaxb.SpecType.Storage;
+
+public class Neo4jManagerClient {
+
+ private JAXBContext jc;
+
+ private String address;
+
+ private Nffg nffg;
+
+ private List<String> endpoints = new LinkedList<String>();
+
+ private List<String> firewalls = new LinkedList<String>();
+
+ private Map<String, List<Entry>> routingTable = new HashMap<String, List<Entry>>();
+
+ private String source;
+
+ private String destination;
+
+ private String xmlString;
+
+ private WebTarget baseTarget;
+
+ public Neo4jManagerClient() {
+
+ }
+
+ public Neo4jManagerClient( String address, String source, String destination, List<String> endpoints,
+ List<String> firewalls, Map<String, List<Entry>> routingTable) {
+ this.address = address;
+ this.source = source;
+ this.destination = destination;
+ this.endpoints = endpoints;
+ this.firewalls = firewalls;
+ this.routingTable = routingTable;
+
+ Client client = ClientBuilder.newBuilder().register(PathsMessageBodyReader.class).build();
+
+ this.baseTarget = client.target(this.address);
+ }
+
+ public Paths getPaths() throws Exception {
+ try {
+ this.generateCustomXml();
+ }
+ catch (JAXBException e) {
+ throw (e);
+ }
+
+ WebTarget graphsTarget = baseTarget.path("graphs");
+ WebTarget pathSourceDestination = graphsTarget.path("{graphId}/paths");
+ WebTarget deleteNffg = graphsTarget.path("{graphId}");
+
+ Response deleteNffgResponse = deleteNffg.resolveTemplate("graphId", "1").request().delete();
+ if (deleteNffgResponse.getStatus() != javax.ws.rs.core.Response.Status.NO_CONTENT.getStatusCode()
+ && deleteNffgResponse.getStatus() != javax.ws.rs.core.Response.Status.NOT_FOUND.getStatusCode()) {
+ throw new Exception("graph deletion failed");
+ }
+
+ Response createNffgResponse = graphsTarget .request("application/xml")
+ .post(Entity.entity(this.xmlString, "application/xml"));
+ if (createNffgResponse.getStatus() != javax.ws.rs.core.Response.Status.CREATED.getStatusCode()) {
+ throw new Exception("graph creation failed");
+ }
+
+ System.out.println("Getting paths from node \"" + this.source + "\" to node \"" + this.destination + "\"...");
+ Response getPath = pathSourceDestination.resolveTemplate("graphId", "1")
+ .queryParam("src", this.source)
+ .queryParam("dst", this.destination)
+ .queryParam("dir", "outgoing")
+ .request(MediaType.APPLICATION_XML)
+ .get();
+
+ System.out.println("Paths from node \"" + this.source + "\" to node \"" + this.destination + "\":");
+
+ Paths paths = null;
+ try {
+ paths = getPath.readEntity(Paths.class);
+ }
+ catch (ProcessingException e) {
+ throw (e);
+ }
+ catch (IllegalStateException e) {
+ throw (e);
+ }
+
+ return paths;
+ }
+
+ private void generateCustomXml() throws JAXBException {
+
+ jc = JAXBContext.newInstance("it.polito.nffg.neo4j.jaxb");
+
+ nffg = new Nffg();
+ nffg.setId("nffg_1");
+
+ generateEndpoints();
+ generateFirewalls();
+ generateConnections();
+
+ MonParamsType monitoring_parameters = new MonParamsType();
+ nffg.setMonitoringParameters(monitoring_parameters);
+
+ JAXBElement<Nffg> root = (new ObjectFactory()).createNffg(nffg);
+
+ Marshaller m;
+ try {
+ m = jc.createMarshaller();
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+ StringWriter stringWriter = new StringWriter();
+ try {
+ XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(stringWriter);
+ m.marshal(root, xmlStreamWriter);
+ xmlString = stringWriter.getBuffer().toString();
+ }
+ catch (XMLStreamException e) {
+ e.printStackTrace();
+ }
+ catch (FactoryConfigurationError e) {
+
+ e.printStackTrace();
+ }
+ // m.marshal( root, new File("nffg.xml") );
+ System.out.println(xmlString);
+
+ }
+ catch (JAXBException e) {
+ throw (e);
+ }
+ }
+
+ private void generateConnections() {
+ NelementsType network_elements = new NelementsType();
+ NeType network_element = new NeType();
+ network_element.setId("ne_1");
+ network_element.setType("BiSBiS");
+ EpsCpsType ep_cps = new EpsCpsType();
+
+ for (String node : routingTable.keySet()) {
+ EpCpType ep_cp = new EpCpType();
+ ep_cp.setIdRef(node);
+ FlowrulesType flowrules = new FlowrulesType();
+ it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace flowspace =
+ new it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace();
+ flowrules.setFlowspace(flowspace);
+ ActionsType actions = new ActionsType();
+ for (Entry e : routingTable.get(node)) {
+ ActionType action = new ActionType();
+ action.setType(ActionEnumType.fromValue(e.getDirection()));
+ action.setPort(e.getDestination());
+ actions.getAction().add(action);
+ }
+ flowrules.setActions(actions);
+
+ ep_cp.getFlowrules().add(flowrules);
+ ep_cps.getEpCp().add(ep_cp);
+ }
+ network_element.setEpsCps(ep_cps);
+
+ MonParamsType monitoring_parameters = new MonParamsType();
+ Parameter parameter = new Parameter();
+ parameter.getValue().add("Bandwith ep_1 cp_1 100mbit");
+ monitoring_parameters.getParameter().add(parameter);
+ Parameter parameter2 = new Parameter();
+ parameter2.getValue().add("Delay ep_1 cp_1 50ms");
+ monitoring_parameters.getParameter().add(parameter2);
+
+ network_element.setMonitoringParameters(monitoring_parameters);
+
+ network_elements.getNetworkElement().add(network_element);
+
+ nffg.setNetworkElements(network_elements);
+
+ }
+
+ private void generateFirewalls() {
+ NfunctionsType network_functions = new NfunctionsType();
+
+ for (String firewall : firewalls) {
+ NfType nf = new NfType();
+ nf.setId(firewall);
+ nf.setFunctionalType("firewall");
+
+ SpecType specification = new SpecType();
+ Deployment deployment = new Deployment();
+ deployment.setType("PolitoFirewall");
+ Image image = new Image();
+ image.setUri("http://www.polito.it");
+ Cpu cpu = new Cpu();
+ cpu.setNumCores((short) (7));
+ Memory memory = new Memory();
+ memory.setSize("10MiB");
+ Storage storage = new Storage();
+ storage.setSize("100MiB");
+ specification.setDeployment(deployment);
+ specification.setImage(image);
+ specification.setCpu(cpu);
+ specification.setMemory(memory);
+ specification.setStorage(storage);
+
+ CpointsType connection_points = new CpointsType();
+ CpType connection_point = new CpType();
+ connection_point.setId(firewall + "_in");
+ PortType port = new PortType();
+ port.setId(79);
+ port.setDirection(PortDirEnumType.IN);
+ port.setType("GbE");
+ connection_point.setPort(port);
+ connection_points.getConnectionPoint().add(connection_point);
+
+ CpType connection_point2 = new CpType();
+ connection_point2.setId(firewall + "_out");
+ PortType port2 = new PortType();
+ port2.setId(77);
+ port2.setDirection(PortDirEnumType.OUT);
+ port2.setType("10GbE");
+ connection_point2.setPort(port2);
+
+ connection_points.getConnectionPoint().add(connection_point2);
+
+ CtrlInterfacesType control_interfaces = new CtrlInterfacesType();
+ CiType control_interface = new CiType();
+ control_interface.setId(firewall + "_ci");
+
+ Attributes attributes = new Attributes();
+ Attribute attribute = new Attribute();
+ attribute.setValue("tcp://127.0.0.1:5555");
+ attributes.getAttribute().add(attribute);
+ Attribute attribute2 = new Attribute();
+ attribute2.setValue("Netconf");
+ attributes.getAttribute().add(attribute2);
+ control_interface.setAttributes(attributes);
+
+ control_interfaces.getControlInterface().add(control_interface);
+
+ MonParamsType monitoring_parameters = new MonParamsType();
+ Parameter parameter = new Parameter();
+ parameter.getValue().add("Measure script");
+ monitoring_parameters.getParameter().add(parameter);
+
+ nf.setSpecification(specification);
+ nf.setConnectionPoints(connection_points);
+ nf.setControlInterfaces(control_interfaces);
+ nf.setMonitoringParameters(monitoring_parameters);
+
+ network_functions.getNetworkFunction().add(nf);
+
+ }
+ nffg.setNetworkFunctions(network_functions);
+
+ }
+
+ private void generateEndpoints() {
+ EpointsType eps = new EpointsType();
+
+ for (String e : endpoints) {
+ EpType endpoint = new EpType();
+ endpoint.setId(e);
+ Flowspace flowspace = new Flowspace();
+ flowspace.setIngPhysPort("10");
+ Tcp tcp = new Tcp();
+ tcp.setSrc(80);
+ flowspace.setTcp(tcp);
+ endpoint.setFlowspace(flowspace);
+ eps.getEndpoint().add(endpoint);
+ }
+ nffg.setEndpoints(eps);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClient.java b/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClient.java
new file mode 100644
index 0000000..1997553
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClient.java
@@ -0,0 +1,444 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.client;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.ResponseProcessingException;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import it.polito.escape.verify.model.ErrorMessage;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.model.Verification;
+
+public class VerifyClient {
+
+ private WebTarget baseTarget;
+
+ private WebTarget graphsTarget;
+
+ private WebTarget graphTarget;
+
+ private WebTarget nodesTarget;
+
+ private WebTarget nodeTarget;
+
+ private WebTarget neighboursTarget;
+
+ private WebTarget neighbourTarget;
+
+ private WebTarget reachabilityTarget;
+
+ private WebTarget isolationTarget;
+
+ private WebTarget traversalTarget;
+
+ public VerifyClient(String address) {
+ Client client = ClientBuilder.newClient();
+
+ this.baseTarget = client.target(address);
+ this.graphsTarget = baseTarget.path("graphs");
+ this.graphTarget = graphsTarget.path("/{graphId}");
+ this.nodesTarget = graphTarget.path("/nodes");
+ this.nodeTarget = nodesTarget.path("//{nodeId}");
+ this.neighboursTarget = nodeTarget.path("/neighbours");
+ this.neighbourTarget = neighboursTarget.path("/{neighbourId}");
+ this.reachabilityTarget = graphTarget.path("/policy");
+ this.isolationTarget = graphTarget.path("/policy");
+ this.traversalTarget = graphTarget.path("/policy");
+ }
+
+ public void checkResponse(Response response) throws VerifyClientException {
+ int status = response.getStatus();
+
+ // 400
+ if (status == Response.Status.BAD_REQUEST.getStatusCode()) {
+ try {
+ // String responseString = response.readEntity(String.class);
+ // System.out.println(responseString);
+ ErrorMessage errorMessage = response.readEntity(ErrorMessage.class);
+ String message = errorMessage.getErrorMessage();
+ throw new VerifyClientException("Bad request: " + message);
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'ErrorMessage': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+ // 403
+ if (status == Response.Status.FORBIDDEN.getStatusCode()) {
+ try {
+ ErrorMessage errorMessage = response.readEntity(ErrorMessage.class);
+ String message = errorMessage.getErrorMessage();
+ throw new VerifyClientException("Forbidden: " + message);
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'ErrorMessage': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+ // 404
+ if (status == Response.Status.NOT_FOUND.getStatusCode()) {
+ try {
+ ErrorMessage errorMessage = response.readEntity(ErrorMessage.class);
+ String message = errorMessage.getErrorMessage();
+ throw new VerifyClientException("Not found: " + message);
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'ErrorMessage': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the 'Response' entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+ // 500
+ if (status == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
+ try {
+ ErrorMessage errorMessage = response.readEntity(ErrorMessage.class);
+ String message = errorMessage.getErrorMessage();
+ throw new VerifyClientException("Internal server error: " + message);
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'ErrorMessage': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+ if (status != Response.Status.ACCEPTED.getStatusCode() && status != Response.Status.CREATED.getStatusCode()
+ && status != Response.Status.NO_CONTENT.getStatusCode() && status != Response.Status.OK.getStatusCode())
+ throw new VerifyClientException("Unknown error");
+ }
+
+ public Response createGraph(Graph graph) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = graphsTarget.request().post(Entity.json(graph));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response createGraph(String graph) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = graphsTarget.request().post(Entity.entity(graph, "application/json"));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response retrieveGraph(long graphId) throws VerifyClientException, ProcessingException {
+ Response response = graphTarget.resolveTemplate("graphId", graphId).request().get();
+ checkResponse(response);
+ return response;
+ }
+
+ public Response updateGraph(long graphId, Graph graph) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = graphTarget.resolveTemplate("graphId", graphId).request().put(Entity.json(graph));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response deleteGraph(long graphId) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = graphTarget.resolveTemplate("graphId", graphId).request().delete();
+ checkResponse(response);
+ return response;
+ }
+
+ public Response createNode(long graphId, Node node) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = nodesTarget.resolveTemplate("graphId", graphId).request().post(Entity.json(node));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response retrieveNode(long graphId, long nodeId) throws VerifyClientException, ProcessingException {
+ Response response = nodeTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .request()
+ .get();
+ checkResponse(response);
+ return response;
+ }
+
+ public Response updateNode(long graphId, long nodeId, Node node) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = nodeTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .request()
+ .put(Entity.json(node));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response deleteNode(long graphId, long nodeId) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = nodeTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .request()
+ .delete();
+ checkResponse(response);
+ return response;
+ }
+
+ public Response createNeighbour(long graphId, long nodeId, Neighbour neighbour) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = neighboursTarget.resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .request()
+ .post(Entity.json(neighbour));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response retrieveNeighbour(long graphId, long nodeId, long neighbourId) throws VerifyClientException, ProcessingException {
+ Response response = neighbourTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .resolveTemplate("neighbourId", neighbourId)
+ .request()
+ .get();
+ checkResponse(response);
+ return response;
+ }
+
+ public Response updateNeighbour(long graphId, long nodeId, long neighbourId,
+ Neighbour neighbour) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = neighbourTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .resolveTemplate("neighbourId", neighbourId)
+ .request()
+ .put(Entity.json(neighbour));
+ checkResponse(response);
+ return response;
+ }
+
+ public Response deleteNeighbour(long graphId, long nodeId, long neighbourId) throws VerifyClientException, ResponseProcessingException, ProcessingException {
+ Response response = neighbourTarget .resolveTemplate("graphId", graphId)
+ .resolveTemplate("nodeId", nodeId)
+ .resolveTemplate("neighbourId", neighbourId)
+ .request()
+ .delete();
+ checkResponse(response);
+ return response;
+ }
+
+ public Verification getReachability(long graphId, String source, String destination) throws VerifyClientException, ProcessingException{
+ Response response = reachabilityTarget.resolveTemplate("graphId", graphId)
+ .queryParam("source", source)
+ .queryParam("destination", destination)
+ .queryParam("type", "reachability")
+ .request()
+ .get();
+ checkResponse(response);
+ try{
+ Verification verification = response.readEntity(Verification.class);
+ return verification;
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'Verification': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the 'Verification' entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+
+ public Verification getIsolation(long graphId, String source, String destination, String middlebox) throws VerifyClientException, ProcessingException{
+ Response response = isolationTarget.resolveTemplate("graphId", graphId)
+ .queryParam("source", source)
+ .queryParam("destination", destination)
+ .queryParam("middlebox", middlebox)
+ .queryParam("type", "isolation")
+ .request()
+ .get();
+ checkResponse(response);
+ try{
+ Verification verification = response.readEntity(Verification.class);
+ return verification;
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'Verification': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the 'Verification' entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+
+ public Verification getTraversal(long graphId, String source, String destination, String middlebox) throws VerifyClientException, ProcessingException{
+ Response response = traversalTarget.resolveTemplate("graphId", graphId)
+ .queryParam("source", source)
+ .queryParam("destination", destination)
+ .queryParam("middlebox", middlebox)
+ .queryParam("type", "traversal")
+ .request()
+ .get();
+ checkResponse(response);
+ try{
+ Verification verification = response.readEntity(Verification.class);
+ return verification;
+ }
+ catch (ProcessingException e) {
+ throw new VerifyClientException("the content of the message cannot be mapped to an entity of the 'Verification': "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new VerifyClientException("the 'Verification' entity is not backed by an input stream or the original entity input stream has already been consumed without buffering the entity data prior consuming: "
+ + e.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static String deserializeString(File file) throws IOException {
+ int len;
+ char[] chr = new char[4096];
+ final StringBuffer buffer = new StringBuffer();
+ final FileReader reader = new FileReader(file);
+ try {
+ while ((len = reader.read(chr)) > 0) {
+ buffer.append(chr, 0, len);
+ }
+ }
+ finally {
+ reader.close();
+ }
+ return buffer.toString();
+ }
+
+ public List<File> getFiles() {
+ List<File> filesList = new ArrayList<File>();
+
+ String folderString = System.getProperty("folder");
+ File folder;
+ if (folderString == null)
+ folder = new File(System.getProperty("user.dir") + "/examples");
+ else
+ folder = new File(folderString);
+
+ System.out.println("Folder set to " + folder.getAbsolutePath());
+
+ File[] files = folder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".json");
+ }
+ });
+
+ for (File f : files) {
+ filesList.add(f);
+ }
+
+ return filesList;
+ }
+
+ public Graph addGraphFromFile(File file) throws JsonParseException, JsonMappingException, IOException, Exception {
+ System.out.println("Parsing graph of file '" + file.getAbsolutePath() + "'...");
+ Graph graph = new ObjectMapper().readValue(file, Graph.class);
+ Response createGraphResponse = createGraph(graph);
+ if (createGraphResponse.getStatus() != Status.CREATED.getStatusCode()) {
+ throw new Exception("Creation of graph contained in file '" + file.getAbsolutePath() + "' returned status "
+ + createGraphResponse.getStatus());
+ }
+ String responseString = createGraphResponse.readEntity(String.class);
+ System.out.println("Response:");
+ System.out.println(responseString);
+ Graph response = new ObjectMapper().readValue(responseString, Graph.class);
+ printGraph(response);
+ return response;
+ }
+
+ public void printGraph(Graph graph) {
+ System.out.println("Graph " + graph.getId());
+ for (Node n : graph.getNodes().values()) {
+ System.out.println("\tNode " + n.getId());
+ System.out.println("\tName " + n.getName());
+ System.out.println("\tFunctional type: " + n.getFunctional_type());
+ for (Neighbour neighbour : n.getNeighbours().values()) {
+ System.out.println("\t\tNeighbour " + neighbour.getId());
+ System.out.println("\t\tName: " + neighbour.getName());
+ }
+ }
+ }
+
+ public Map<String, Graph> addGraphsFromFiles(List<File> files) throws JsonParseException, JsonMappingException, IOException,
+ Exception {
+ Map<String, Graph> graphs = new HashMap<String, Graph>();
+
+ for (File f : files) {
+ Graph graph = addGraphFromFile(f);
+ graphs.put(f.getName(), graph);
+ }
+
+ for (Map.Entry<String, Graph> graph : graphs.entrySet()) {
+ System.out.println(graph.getKey() + " -> graph " + graph.getValue().getId());
+ }
+ System.out.println("Graphs added");
+
+ return graphs;
+ }
+
+ public static void main(String[] args) throws IOException, Exception {
+ System.out.println("Adding graphs");
+
+ VerifyClient verifyClient = new VerifyClient("http://localhost:8080/verify/api");
+
+ List<File> files = verifyClient.getFiles();
+ Map<String, Graph> graphs = verifyClient.addGraphsFromFiles(files);
+
+ for (Graph g : graphs.values()) {
+ Response response = verifyClient.retrieveGraph(g.getId());
+ String responseString = response.readEntity(String.class);
+
+ System.out.println("Response");
+ System.out.println(responseString);
+ Graph graph = new ObjectMapper().readValue(responseString, Graph.class);
+ System.out.println("Read graph " + graph.getId());
+ System.out.println(response.getStatus());
+ }
+
+ Graph graph = graphs.get("budapest_sat.json");
+ System.out.println("graphId set to " + graph.getId());
+ System.out.println("Getting reachability from 'user1' to 'websever' in 'budapest' graph (expecting SAT)...");
+ Verification verification = verifyClient.getReachability(graph.getId(), "user1", "webserver");
+ System.out.println(verification.getResult());
+ graph = graphs.get("budapest_unsat.json");
+ System.out.println("graphId set to " + graph.getId());
+ System.out.println("Getting reachability from 'user1' to 'websever' in 'budapest' graph (expecting UNSAT)...");
+ verification = verifyClient.getReachability(graph.getId(), "user1", "webserver");
+ System.out.println(verification.getResult());
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClientException.java b/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClientException.java
new file mode 100644
index 0000000..d91d31e
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/client/VerifyClientException.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.client;
+
+
+public class VerifyClientException extends Exception{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4794956747093682854L;
+
+ public VerifyClientException(String message){
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/database/DatabaseClass.java b/verigraph/src/main/java/it/polito/escape/verify/database/DatabaseClass.java
new file mode 100644
index 0000000..7837e51
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/database/DatabaseClass.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.database;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.service.GraphService;
+
+public class DatabaseClass {
+
+ private static final DatabaseClass instance = new DatabaseClass();
+
+ private static ConcurrentHashMap<Long, Graph> graphs;
+
+ private static String persistenceFile;
+
+ private static boolean enablePersistence;
+
+ protected DatabaseClass() {
+ initialize();
+ if (enablePersistence)
+ loadDatabase();
+ }
+
+ private void initialize() {
+ graphs = new ConcurrentHashMap<>();
+ enablePersistence = false;
+ persistenceFile = System.getProperty("catalina.base") + "/webapps/verify/json/" + "database.json";
+ }
+
+ private void loadDatabase() {
+ ObjectMapper mapper = new ObjectMapper();
+
+ List<Graph> parsedGraphs = null;
+ try {
+ File databaseFile = new File(persistenceFile);
+ parsedGraphs = mapper.readValue(databaseFile,
+ TypeFactory.defaultInstance().constructCollectionType( List.class,
+ Graph.class));
+ }
+ catch (JsonParseException e) {
+ System.out.println("Database not loaded due to a JsonParseException: " + e.getMessage());
+ return;
+ }
+ catch (JsonMappingException e) {
+ System.out.println("Database not loaded due to a JsonMappingException: " + e.getMessage());
+ return;
+ }
+ catch (IOException e) {
+ //retry changing path
+ persistenceFile = "src/main/webapp/json/" + "database.json";
+
+ try {
+ File databaseFile = new File(persistenceFile);
+ parsedGraphs = mapper.readValue(databaseFile,
+ TypeFactory.defaultInstance().constructCollectionType( List.class,
+ Graph.class));
+ } catch (JsonParseException e1) {
+ System.out.println("Database not loaded due to a JsonParseException: " + e.getMessage());
+ return;
+ } catch (JsonMappingException e1) {
+ System.out.println("Database not loaded due to a JsonMappingException: " + e.getMessage());
+ return;
+ } catch (IOException e1) {
+ System.out.println("Database not loaded due to an IOException: " + e.getMessage());
+ return;
+ }
+ }
+
+ System.out.println("Loading database...");
+
+ for (Graph graph : parsedGraphs) {
+
+ try {
+ GraphService.validateGraph(graph);
+ }
+ catch (Exception e) {
+ System.out.println("Invalid database file: at least one graph is invalid!");
+ return;
+ }
+
+ graph.setId(getNumberOfGraphs() + 1);
+
+ for (Map.Entry<Long, Node> nodeEntry : graph.getNodes().entrySet()) {
+ nodeEntry.getValue().setId(nodeEntry.getKey());
+
+ for (Map.Entry<Long, Neighbour> neighbourEntry : nodeEntry.getValue().getNeighbours().entrySet()) {
+ neighbourEntry.getValue().setId(neighbourEntry.getKey());
+ }
+ }
+
+ graphs.put(graph.getId(), graph);
+ }
+
+ System.out.println("Database loaded!");
+ System.out.println(graphs.size() + " graphs added");
+ }
+
+ public static DatabaseClass getInstance() {
+ return instance;
+ }
+
+ public ConcurrentHashMap<Long, Graph> getGraphs() {
+ return graphs;
+ }
+
+ public synchronized int getNumberOfGraphs() {
+ return graphs.size();
+ }
+
+ public synchronized int getGraphNumberOfNodes(long graphId) {
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ return 0;
+ Map<Long, Node> nodes = graph.getNodes();
+ if (nodes == null)
+ return 0;
+ return nodes.size();
+ }
+
+ public static void persistDatabase() {
+ if (!enablePersistence)
+ return;
+ ObjectMapper mapper = new ObjectMapper();
+
+ try {
+ mapper.writeValue(new File(persistenceFile), graphs);
+ }
+ catch (JsonGenerationException e) {
+ throw new InternalServerErrorException("Unable to persist database due to a JsonGenerationException: "
+ + e.getMessage());
+ }
+ catch (JsonMappingException e) {
+ throw new InternalServerErrorException("Unable to persist database due to a JsonMappingException: "
+ + e.getMessage());
+ }
+ catch (IOException e) {
+ //retry changing path
+ persistenceFile = "src/main/webapp/json/" + "database.json";
+ try {
+ mapper.writeValue(new File(persistenceFile), graphs);
+ } catch (JsonGenerationException e1) {
+ throw new InternalServerErrorException("Unable to persist database due to a JsonGenerationException: "
+ + e.getMessage());
+ } catch (JsonMappingException e1) {
+ throw new InternalServerErrorException("Unable to persist database due to a JsonGenerationException: "
+ + e.getMessage());
+ } catch (IOException e1) {
+ throw new InternalServerErrorException("Unable to persist database due to an IOException: "
+ + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/deserializer/ConfigurationCustomDeserializer.java b/verigraph/src/main/java/it/polito/escape/verify/deserializer/ConfigurationCustomDeserializer.java
new file mode 100644
index 0000000..5cdd084
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/deserializer/ConfigurationCustomDeserializer.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.deserializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Configuration;
+
+public class ConfigurationCustomDeserializer extends JsonDeserializer<Configuration> {
+
+ @Override
+ public Configuration deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
+ JsonProcessingException {
+ try {
+ JsonNode root = jp.getCodec().readTree(jp);
+
+ return new Configuration("", "", root);
+ }
+ catch (JsonProcessingException e) {
+ throw new InternalServerErrorException("Error parsing configuration: " + e.getMessage());
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("I/O error parsing configuration: " + e.getMessage());
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/deserializer/GraphCustomDeserializer.java b/verigraph/src/main/java/it/polito/escape/verify/deserializer/GraphCustomDeserializer.java
new file mode 100644
index 0000000..f71c996
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/deserializer/GraphCustomDeserializer.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.deserializer;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+
+
+/**
+ * The Class GraphCustomDeserializer is a custom deserializer for a Graph object
+ */
+public class GraphCustomDeserializer extends JsonDeserializer<Graph>{
+
+ /* (non-Javadoc)
+ * @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
+ */
+ @Override
+ public Graph deserialize(JsonParser jp, DeserializationContext context){
+ JsonNode root = null;
+ try {
+ root = jp.getCodec().readTree(jp);
+ }
+ catch (JsonProcessingException e) {
+ throw new InternalServerErrorException("Error parsing a graph: " + e.getMessage());
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("I/O error parsing a graph: " + e.getMessage());
+ }
+
+ JsonNode nodesJson = root.get("nodes");
+
+ if(nodesJson == null)
+ throw new BadRequestException("Invalid graph");
+
+ List<Node> nodeList = null;
+ try {
+ nodeList = new ObjectMapper().readValue(nodesJson.toString(), TypeFactory.defaultInstance().constructCollectionType(List.class, Node.class));
+ }
+ catch (JsonParseException e) {
+ throw new BadRequestException("Invalid content for a graph: " + e.getMessage());
+ }
+ catch (JsonMappingException e) {
+ throw new BadRequestException("Invalid input json structure for a graph: " + e.getMessage());
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("I/O error parsing a graph: " + e.getMessage());
+ }
+
+ Graph graph = new Graph();
+ if(root.get("id") != null){
+ long graphId = root.get("id").asLong();
+ graph.setId(graphId);
+ }
+ Map<Long, Node> nodes = graph.getNodes();
+
+ long numberOfNodes = 0;
+ for (Node node : nodeList){
+ nodes.put(++numberOfNodes, node);
+ }
+ return graph;
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/deserializer/NodeCustomDeserializer.java b/verigraph/src/main/java/it/polito/escape/verify/deserializer/NodeCustomDeserializer.java
new file mode 100644
index 0000000..fb451db
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/deserializer/NodeCustomDeserializer.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.deserializer;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+
+public class NodeCustomDeserializer extends JsonDeserializer<Node> {
+
+ @Override
+ public Node deserialize(JsonParser jp, DeserializationContext context) {
+
+ try {
+ JsonNode root = jp.getCodec().readTree(jp);
+ JsonNode neighboursJson = root.get("neighbours");
+ JsonNode configurationJson = root.get("configuration");
+
+ String nodeName = root.get("name").asText();
+ String functionalType = root.get("functional_type").asText();
+
+ Node node = new Node();
+ if(root.get("id") != null){
+ long nodeId = root.get("id").asLong();
+ node.setId(nodeId);
+ }
+ node.setName(nodeName);
+ node.setFunctional_type(functionalType);
+
+ if (configurationJson == null)
+ node.setConfiguration(new Configuration(node.getName(), "", new ObjectMapper().createArrayNode()));
+ else {
+ Configuration conf = node.getConfiguration();
+ conf.setId(node.getName());
+ conf.setDescription("");
+ conf.setConfiguration(configurationJson);
+ }
+
+ try {
+ List<Neighbour> neighbourList = new ObjectMapper().readValue( neighboursJson.toString(),
+ TypeFactory .defaultInstance()
+ .constructCollectionType( List.class,
+ Neighbour.class));
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+
+ long numberOfNeighbours = 0;
+ for (Neighbour neighbour : neighbourList) {
+ neighbours.put(++numberOfNeighbours, neighbour);
+ }
+
+ return node;
+ }
+ catch (JsonParseException e) {
+ throw new BadRequestException("Invalid content for a node: " + e.getMessage());
+ }
+ catch (JsonMappingException e) {
+ throw new BadRequestException("Invalid input json structure for a node: " + e.getMessage());
+ }
+ }
+ catch (JsonProcessingException e) {
+ throw new InternalServerErrorException("Error parsing a node: " + e.getMessage());
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("I/O error parsing a node: " + e.getMessage());
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/deserializer/PathsMessageBodyReader.java b/verigraph/src/main/java/it/polito/escape/verify/deserializer/PathsMessageBodyReader.java
new file mode 100644
index 0000000..3b54503
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/deserializer/PathsMessageBodyReader.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.deserializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import it.polito.nffg.neo4j.jaxb.Paths;
+
+@Provider
+@Consumes(MediaType.APPLICATION_XML)
+public class PathsMessageBodyReader implements MessageBodyReader<Paths>{
+
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return type == Paths.class;
+ }
+
+ @Override
+ public Paths readFrom(Class<Paths> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+ throws IOException, WebApplicationException {
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(Paths.class);
+ Paths paths = (Paths) jaxbContext.createUnmarshaller()
+ .unmarshal(entityStream);
+ return paths;
+ } catch (JAXBException jaxbException) {
+ throw new ProcessingException("Error deserializing a Paths object.",
+ jaxbException);
+ }
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestException.java b/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestException.java
new file mode 100644
index 0000000..abbdbf0
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+public class BadRequestException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -548472179073745084L;
+
+ public BadRequestException(String message) {
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestExceptionMapper.java b/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestExceptionMapper.java
new file mode 100644
index 0000000..8f1ba9c
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/BadRequestExceptionMapper.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import it.polito.escape.verify.model.ErrorMessage;
+
+@Provider
+public class BadRequestExceptionMapper implements ExceptionMapper<BadRequestException> {
+
+ @Override
+ public Response toResponse(BadRequestException exception) {
+ ErrorMessage errorMessage = new ErrorMessage( exception.getMessage(),
+ 400,
+ "http://localhost:8080/verify/api-docs/");
+ return Response.status(Status.BAD_REQUEST).entity(errorMessage).build();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundException.java b/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundException.java
new file mode 100644
index 0000000..5cd1806
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+public class DataNotFoundException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6012364193903183208L;
+
+ public DataNotFoundException(String message) {
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundExceptionMapper.java b/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundExceptionMapper.java
new file mode 100644
index 0000000..62e3556
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/DataNotFoundExceptionMapper.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import it.polito.escape.verify.model.ErrorMessage;
+
+@Provider
+public class DataNotFoundExceptionMapper implements ExceptionMapper<DataNotFoundException> {
+
+ @Override
+ public Response toResponse(DataNotFoundException exception) {
+ ErrorMessage errorMessage = new ErrorMessage( exception.getMessage(),
+ 404,
+ "http://localhost:8080/verify/api-docs/");
+ return Response.status(Status.NOT_FOUND).entity(errorMessage).build();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenException.java b/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenException.java
new file mode 100644
index 0000000..dc79e97
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+public class ForbiddenException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4658914972167044321L;
+
+ public ForbiddenException(String message) {
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenExceptionMapper.java b/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenExceptionMapper.java
new file mode 100644
index 0000000..d060b8b
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/ForbiddenExceptionMapper.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import it.polito.escape.verify.model.ErrorMessage;
+
+@Provider
+public class ForbiddenExceptionMapper implements ExceptionMapper<ForbiddenException> {
+
+ @Override
+ public Response toResponse(ForbiddenException exception) {
+ ErrorMessage errorMessage = new ErrorMessage( exception.getMessage(),
+ 403,
+ "http://localhost:8080/verify/api-docs/");
+ return Response.status(Status.FORBIDDEN).entity(errorMessage).build();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/GenericExceptionMapper.java b/verigraph/src/main/java/it/polito/escape/verify/exception/GenericExceptionMapper.java
new file mode 100644
index 0000000..96f7caa
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/GenericExceptionMapper.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import it.polito.escape.verify.model.ErrorMessage;
+
+// @Provider
+public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
+
+ @Override
+ public Response toResponse(Throwable exception) {
+ ErrorMessage errorMessage = new ErrorMessage("Generic exception: " + exception.getMessage(),
+ 500,
+ "http://localhost:8080/verify/api-docs/");
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorException.java b/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorException.java
new file mode 100644
index 0000000..877edb5
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+public class InternalServerErrorException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 156815197709461502L;
+
+ public InternalServerErrorException(String message) {
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorExceptionMapper.java b/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorExceptionMapper.java
new file mode 100644
index 0000000..02b6765
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/exception/InternalServerErrorExceptionMapper.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import it.polito.escape.verify.model.ErrorMessage;
+
+@Provider
+public class InternalServerErrorExceptionMapper implements ExceptionMapper<InternalServerErrorException> {
+
+ @Override
+ public Response toResponse(InternalServerErrorException exception) {
+ ErrorMessage errorMessage = new ErrorMessage( exception.getMessage(),
+ 500,
+ "http://localhost:8080/verify/api-docs/");
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Configuration.java b/verigraph/src/main/java/it/polito/escape/verify/model/Configuration.java
new file mode 100644
index 0000000..3498a10
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Configuration.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import it.polito.escape.verify.deserializer.ConfigurationCustomDeserializer;
+import it.polito.escape.verify.serializer.CustomConfigurationSerializer;
+
+@XmlRootElement
+@ApiModel("Configuration")
+@JsonSerialize(using = CustomConfigurationSerializer.class)
+@JsonDeserialize(using = ConfigurationCustomDeserializer.class)
+public class Configuration {
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private String id;
+
+ @ApiModelProperty(required = false)
+ @XmlTransient
+ private String description = "";
+
+ @ApiModelProperty(required = true)
+ private JsonNode configuration;
+
+ public Configuration() {
+
+ }
+
+ public Configuration(String id, String description, JsonNode configuration) {
+ this.id = id;
+ this.description = description;
+ this.configuration = configuration;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public JsonNode getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(JsonNode configuration) {
+ this.configuration = configuration;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Entry.java b/verigraph/src/main/java/it/polito/escape/verify/model/Entry.java
new file mode 100644
index 0000000..f2fdf14
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Entry.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+public class Entry {
+ private String direction;
+ private String destination;
+
+ public Entry(String direction, String destination) {
+ this.direction = direction;
+ this.destination = destination;
+ }
+
+ public String getDirection() {
+ return direction;
+ }
+
+ public void setDirection(String direction) {
+ this.direction = direction;
+ }
+
+ public String getDestination() {
+ return destination;
+ }
+
+ public void setDestination(String destination) {
+ this.destination = destination;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/ErrorMessage.java b/verigraph/src/main/java/it/polito/escape/verify/model/ErrorMessage.java
new file mode 100644
index 0000000..e0e79d3
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/ErrorMessage.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "Error")
+@XmlRootElement
+public class ErrorMessage {
+
+ @ApiModelProperty(example = "Error message")
+ private String errorMessage;
+ @ApiModelProperty(allowableValues = "400,403,404,500", value = "HTTP error code", example = "[400,403,404,500]")
+ private int errorCode;
+ @ApiModelProperty(example = "http://localhost:8080/verify/api-docs/")
+ private String documentation;
+
+ public ErrorMessage() {
+
+ }
+
+ public ErrorMessage(String errorMessage, int errorCode, String documentation) {
+ this.errorMessage = errorMessage;
+ this.errorCode = errorCode;
+ this.documentation = documentation;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public String getDocumentation() {
+ return documentation;
+ }
+
+ public void setDocumentation(String documentation) {
+ this.documentation = documentation;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Graph.java b/verigraph/src/main/java/it/polito/escape/verify/model/Graph.java
new file mode 100644
index 0000000..44a2273
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Graph.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import it.polito.escape.verify.deserializer.GraphCustomDeserializer;
+import it.polito.escape.verify.serializer.CustomMapSerializer;
+
+@ApiModel(value = "Graph")
+@XmlRootElement
+@JsonDeserialize(using = GraphCustomDeserializer.class)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class Graph {
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private long id;
+
+ @ApiModelProperty(name = "nodes", notes = "Nodes", dataType = "List[it.polito.escape.verify.model.Node]")
+ private Map<Long, Node> nodes = new HashMap<Long, Node>();
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private Set<Link> links = new HashSet<Link>();
+
+ public Graph() {
+
+ }
+
+ public Graph(long id) {
+ this.id = id;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ @JsonSerialize(using = CustomMapSerializer.class)
+ public Map<Long, Node> getNodes() {
+ return nodes;
+ }
+
+ public void setNodes(Map<Long, Node> nodes) {
+ this.nodes = nodes;
+ }
+
+ @XmlTransient
+ public Set<Link> getLinks() {
+ return links;
+ }
+
+ public void setLinks(Set<Link> links) {
+ this.links = links;
+ }
+
+ public void addLink(String url, String rel) {
+ Link link = new Link();
+ link.setLink(url);
+ link.setRel(rel);
+ links.add(link);
+ }
+
+ public Node searchNodeByName(String name) {
+ for (Node node : this.nodes.values()) {
+ if (node.getName().equals(name))
+ return node;
+ }
+ return null;
+ }
+
+ public int nodesWithName(String name) {
+ int occurrences = 0;
+ for (Node node : this.nodes.values()) {
+ if (node.getName().equals(name))
+ occurrences++;
+
+ }
+ return occurrences;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Link.java b/verigraph/src/main/java/it/polito/escape/verify/model/Link.java
new file mode 100644
index 0000000..dc2b4c5
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Link.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "Link")
+public class Link {
+ @ApiModelProperty(required = false, hidden = true)
+ private String link;
+ @ApiModelProperty(required = false, hidden = true)
+ private String rel;
+
+ public String getLink() {
+ return link;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public String getRel() {
+ return rel;
+ }
+
+ public void setRel(String rel) {
+ this.rel = rel;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((link == null) ? 0 : link.hashCode());
+ result = prime * result + ((rel == null) ? 0 : rel.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Link other = (Link) obj;
+ if (link == null) {
+ if (other.link != null)
+ return false;
+ }
+ else if (!link.equals(other.link))
+ return false;
+ if (rel == null) {
+ if (other.rel != null)
+ return false;
+ }
+ else if (!rel.equals(other.rel))
+ return false;
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Neighbour.java b/verigraph/src/main/java/it/polito/escape/verify/model/Neighbour.java
new file mode 100644
index 0000000..4b1206c
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Neighbour.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import javax.xml.bind.annotation.XmlTransient;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "Neighbour")
+public class Neighbour {
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private long id;
+
+ @ApiModelProperty( required = true,
+ example = "nat",
+ value = "The neighbour name must refer to an existing node of the same graph")
+ private String name;
+
+ public Neighbour() {
+
+ }
+
+ public Neighbour(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ else
+ return false;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Node.java b/verigraph/src/main/java/it/polito/escape/verify/model/Node.java
new file mode 100644
index 0000000..9f667ce
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Node.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import it.polito.escape.verify.deserializer.NodeCustomDeserializer;
+import it.polito.escape.verify.serializer.CustomMapSerializer;
+
+@ApiModel(value = "Node")
+@XmlRootElement
+@JsonDeserialize(using = NodeCustomDeserializer.class)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class Node {
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private long id;
+
+ @ApiModelProperty(required = true, example = "ep", value = "The name of the node can be any string")
+ private String name;
+
+ @ApiModelProperty( required = true,
+ example = "endpoint",
+ value = "The functional types that are currently supported are: endpoint, firewall, nat, antispam, webclient, webserver, mailclient, mailserver")
+ private String functional_type;
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private Configuration configuration = new Configuration();
+
+ @ApiModelProperty( name = "neighbours",
+ notes = "Neighbours",
+ dataType = "List[it.polito.escape.verify.model.Neighbour]")
+ private Map<Long, Neighbour> neighbours = new HashMap<Long, Neighbour>();
+
+ @ApiModelProperty(required = false, hidden = true)
+ @XmlTransient
+ private Set<Link> links = new HashSet<>();
+
+ public Node() {
+
+ }
+
+ public Node(long id, String name, String functional_type, Configuration configuration) {
+ this.id = id;
+ this.name = name;
+ this.functional_type = functional_type;
+ this.configuration = configuration;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getFunctional_type() {
+ return functional_type;
+ }
+
+ public void setFunctional_type(String functional_type) {
+ this.functional_type = functional_type;
+ }
+
+ // @XmlTransient
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @JsonSerialize(using = CustomMapSerializer.class)
+ public Map<Long, Neighbour> getNeighbours() {
+ return neighbours;
+ }
+
+ public void setNeighbours(Map<Long, Neighbour> neighbours) {
+ this.neighbours = neighbours;
+ }
+
+ public long getId() {
+ return this.id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public Set<Link> getLinks() {
+ return links;
+ }
+
+ public void setLinks(Set<Link> links) {
+ this.links = links;
+ }
+
+ public void addLink(String url, String rel) {
+ Link link = new Link();
+ link.setLink(url);
+ link.setRel(rel);
+ links.add(link);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ else
+ return false;
+ }
+
+ public Neighbour searchNeighbourByName(String name) {
+ for (Neighbour neighbour : this.neighbours.values()) {
+ if (neighbour.getName().equals(name))
+ return neighbour;
+ }
+ return null;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Test.java b/verigraph/src/main/java/it/polito/escape/verify/model/Test.java
new file mode 100644
index 0000000..1127abc
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Test.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Test {
+ private List<Node> nodes = new ArrayList<Node>();
+ private String result;
+
+ public Test() {
+
+ }
+
+ public Test(List<Node> paths, int result) {
+ switch (result) {
+ case 0:
+ this.result = "SAT";
+ break;
+ case -1:
+ this.result = "UNSAT";
+ break;
+ case -2:
+ this.result = "UNKNOWN";
+ break;
+ default:
+ this.result = "UNKNWON";
+ break;
+ }
+ this.nodes = paths;
+ }
+
+ public Test(List<Node> paths, String result) {
+ this.nodes = paths;
+ this.result = result;
+ }
+
+ public List<Node> getPath() {
+ return nodes;
+ }
+
+ public void setPath(List<Node> paths) {
+ this.nodes = paths;
+ }
+
+ public String getResult() {
+ return result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/Verification.java b/verigraph/src/main/java/it/polito/escape/verify/model/Verification.java
new file mode 100644
index 0000000..60b4ddb
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/Verification.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "Policy verification")
+public class Verification {
+
+ @ApiModelProperty(example = "SAT | UNSAT | UNKNOWN")
+ private String result;
+ private String comment;
+ private List<Test> tests = new ArrayList<Test>();
+
+ public Verification() {
+
+ }
+
+ public Verification(String result) {
+ this.result = result;
+ }
+
+ public Verification(String result, List<Test> tests, String comment){
+ this.result = result;
+ this.tests = tests;
+ this.comment = comment;
+ }
+
+ public Verification(String result, String comment){
+ this.result = result;
+ this.comment = comment;
+ }
+
+ public String getResult() {
+ return result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ public List<Test> getTests() {
+ return tests;
+ }
+
+ public void setTests(List<Test> tests) {
+ this.tests = tests;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/model/jaxb.properties b/verigraph/src/main/java/it/polito/escape/verify/model/jaxb.properties
new file mode 100644
index 0000000..5837a4c
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/model/jaxb.properties
@@ -0,0 +1 @@
+javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory \ No newline at end of file
diff --git a/verigraph/src/main/java/it/polito/escape/verify/resources/GraphResource.java b/verigraph/src/main/java/it/polito/escape/verify/resources/GraphResource.java
new file mode 100644
index 0000000..e610f1d
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/resources/GraphResource.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.resources;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.BeanParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import it.polito.escape.verify.model.ErrorMessage;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Verification;
+import it.polito.escape.verify.resources.beans.VerificationBean;
+import it.polito.escape.verify.service.GraphService;
+import it.polito.escape.verify.service.VerificationService;
+
+@Path("/graphs")
+@Api(value = "/graphs", description = "Manage graphs")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class GraphResource {
+ GraphService graphService = new GraphService();
+ VerificationService verificationService = new VerificationService();
+
+ @GET
+ @ApiOperation( httpMethod = "GET",
+ value = "Returns all graphs",
+ notes = "Returns an array of graphs",
+ response = Graph.class,
+ responseContainer = "List")
+ @ApiResponses(value = { @ApiResponse( code = 200,
+ message = "All the graphs have been returned in the message body",
+ response = Graph.class,
+ responseContainer = "List"),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class)})
+ public List<Graph> getGraphs() {
+ return graphService.getAllGraphs();
+ }
+
+ @POST
+ @ApiOperation( httpMethod = "POST",
+ value = "Creates a graph",
+ notes = "Creates a signle graph",
+ response = Response.class)
+ @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid graph supplied", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 201, message = "Graph successfully created", response = Graph.class) })
+ public Response addGraph( @ApiParam(value = "New graph object", required = true) Graph graph,
+ @Context UriInfo uriInfo) {
+ Graph newGraph = graphService.addGraph(graph);
+ String newId = String.valueOf(newGraph.getId());
+ URI uri = uriInfo.getAbsolutePathBuilder().path(newId).build();
+ return Response.created(uri).entity(newGraph).build();
+ }
+
+ @GET
+ @Path("/{graphId}")
+ @ApiOperation( httpMethod = "GET",
+ value = "Returns a graph",
+ notes = "Returns a signle graph",
+ response = Graph.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse( code = 200,
+ message = "The requested graph has been returned in the message body",
+ response = Graph.class) })
+ public Graph getGraph( @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @Context UriInfo uriInfo) {
+ Graph graph = graphService.getGraph(graphId);
+ graph.addLink(getUriForSelf(uriInfo, graph), "self");
+ graph.addLink(getUriForNodes(uriInfo, graph), "nodes");
+ return graph;
+ }
+
+ @PUT
+ @Path("/{graphId}")
+ @ApiOperation(httpMethod = "PUT", value = "Edits a graph", notes = "Edits a single graph", response = Graph.class)
+ @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid graph object", response = ErrorMessage.class),
+ @ApiResponse(code = 403, message = "Invalid graph id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "Graph edited successfully", response = Graph.class) })
+ public Graph updateGraph( @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long id,
+ @ApiParam(value = "Updated graph object", required = true) Graph graph) {
+ graph.setId(id);
+ return graphService.updateGraph(graph);
+ }
+
+ @DELETE
+ @Path("/{graphId}")
+ @ApiOperation(httpMethod = "DELETE", value = "Deletes a graph", notes = "Deletes a signle graph")
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph id", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 204, message = "Graph successfully deleted") })
+ public void deleteGraph(@ApiParam(value = "Graph id", required = true) @PathParam("graphId") long id) {
+ graphService.removeGraph(id);
+ }
+
+ @GET
+ @Path("/{graphId}/policy")
+ @ApiOperation( httpMethod = "GET",
+ value = "Verifies a given policy in a graph",
+ notes = "In order to verify a given policy (e.g. 'reachability') all nodes of the desired graph must have a valid configuration.")
+ @ApiResponses(value = { @ApiResponse( code = 403,
+ message = "Invalid graph id or invalid configuration for source and/or destination node",
+ response = ErrorMessage.class),
+ @ApiResponse( code = 404,
+ message = "Graph not found or source node not found or destination node not found or configuration for source and/or destination node not available",
+ response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),})
+ public Verification verifyGraph(@ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam( value = "'source' and 'destination' must refer to names of existing nodes in the same graph, 'type' refers to the required verification between the two (e.g. 'reachability')",
+ required = true) @BeanParam VerificationBean verificationBean) {
+
+ return verificationService.verify(graphId, verificationBean);
+ }
+
+ private String getUriForSelf(UriInfo uriInfo, Graph graph) {
+ String uri = uriInfo.getBaseUriBuilder()
+ .path(GraphResource.class)
+ .path(Long.toString(graph.getId()))
+ .build()
+ .toString();
+ return uri;
+ }
+
+ private String getUriForNodes(UriInfo uriInfo, Graph graph) {
+ String uri = uriInfo.getBaseUriBuilder()
+ .path(GraphResource.class)
+ .path(GraphResource.class, "getNodeResource")
+ // .path(NodeResource.class)
+ .resolveTemplate("graphId", graph.getId())
+ .build()
+ .toString();
+ return uri;
+ }
+
+ @Path("/{graphId}/nodes")
+ public NodeResource getNodeResource() {
+ return new NodeResource();
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/resources/NeighbourResource.java b/verigraph/src/main/java/it/polito/escape/verify/resources/NeighbourResource.java
new file mode 100644
index 0000000..63376da
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/resources/NeighbourResource.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.resources;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import it.polito.escape.verify.model.ErrorMessage;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.service.NeighbourService;
+
+//@Path("/")
+@Api( hidden= true, value = "", description = "Manage neighbours" )
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class NeighbourResource {
+ private NeighbourService neighboursService = new NeighbourService();
+
+ @GET
+ @ApiOperation(
+ httpMethod = "GET",
+ value = "Returns all neighbours of a given node belonging to a given graph",
+ notes = "Returns an array of neighbours of a given node belonging to a given graph",
+ response = Neighbour.class,
+ responseContainer = "List")
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node id", response=ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response=ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "All the neighbours have been returned in the message body", response=Neighbour.class, responseContainer="List")})
+ public List<Neighbour> getAllNeighbours(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId){
+ return neighboursService.getAllNeighbours(graphId, nodeId);
+ }
+
+ @POST
+ @ApiOperation(
+ httpMethod = "POST",
+ value = "Adds a neighbour to a given node belonging to a given graph",
+ notes = "Adds single neighbour to a given node belonging to a given graph",
+ response = Neighbour.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node id", response=ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response=ErrorMessage.class),
+ @ApiResponse(code = 400, message = "Invalid neighbour object", response=ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 201, message = "Neighbour successfully created", response=Neighbour.class)})
+ public Response addNeighbour(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "New neighbour object. Neighbour name must refer to the name of an existing node of the same graph", required = true) Neighbour neighbour,
+ @Context UriInfo uriInfo){
+ Neighbour newNeighbour = neighboursService.addNeighbour(graphId, nodeId, neighbour);
+ String newId = String.valueOf(newNeighbour.getId());
+ URI uri = uriInfo.getAbsolutePathBuilder().path(newId).build();
+ return Response.created(uri)
+ .entity(newNeighbour)
+ .build();
+ }
+
+ @PUT
+ @Path("{neighbourId}")
+ @ApiOperation(
+ httpMethod = "PUT",
+ value = "Edits a neighbour of a given node belonging to a given graph",
+ notes = "Edits a single neighbour of a given node belonging to a given graph",
+ response = Neighbour.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node and/or neighbour id", response=ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node and /or neighbour not found", response=ErrorMessage.class),
+ @ApiResponse(code = 400, message = "Invalid neighbour object", response=ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "Neighbour edited successfully", response=Neighbour.class)})
+ public Neighbour updateNeighbour(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "Neighbour id", required = true) @PathParam("neighbourId") long neighbourId,
+ @ApiParam(value = "Updated neighbour object. Neighbour name must refer to the name of an existing node of the same graph", required = true) Neighbour neighbour){
+ neighbour.setId(neighbourId);
+ return neighboursService.updateNeighbour(graphId, nodeId, neighbour);
+ }
+
+ @DELETE
+ @Path("{neighbourId}")
+ @ApiOperation(
+ httpMethod = "DELETE",
+ value = "Removes a neighbour from a given node belonging to a given graph",
+ notes = "Deletes a single neighbour of a given node belonging to a given graph",
+ response = Neighbour.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node and/or neighbour id", response=ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response=ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 204, message = "Node successfully deleted")})
+ public void deleteNeighbour(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "Neighbour id", required = true) @PathParam("neighbourId") long neighbourId){
+ neighboursService.removeNeighbour(graphId, nodeId, neighbourId);
+ }
+
+ @GET
+ @Path("{neighbourId}")
+ @ApiOperation(
+ httpMethod = "GET",
+ value = "Returns a neighbour of a given node belonging to a given graph",
+ notes = "Returns a single neighbour of a given node belonging to a given graph",
+ response = Neighbour.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node and/or neighbour id", response=ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node and /or neighbour not found", response=ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "The requested neighbour has been returned in the message body", response=Neighbour.class)})
+ public Neighbour getNeighbour(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "Neighbour id", required = true) @PathParam("neighbourId") long neighbourId){
+ return neighboursService.getNeighbour(graphId, nodeId, neighbourId);
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/resources/NodeResource.java b/verigraph/src/main/java/it/polito/escape/verify/resources/NodeResource.java
new file mode 100644
index 0000000..58d4064
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/resources/NodeResource.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.resources;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.ErrorMessage;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.service.GraphService;
+import it.polito.escape.verify.service.NodeService;
+
+@Api( hidden= true, value = "", description = "Manage nodes" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class NodeResource {
+
+ NodeService nodeService = new NodeService();
+
+
+ @GET
+ @ApiOperation(
+ httpMethod = "GET",
+ value = "Returns all nodes of a given graph",
+ notes = "Returns an array of nodes belonging to a given graph",
+ response = Node.class,
+ responseContainer = "List")
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "All the nodes have been returned in the message body", response = Node.class, responseContainer = "List") })
+ public List<Node> getNodes(@ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId){
+ return nodeService.getAllNodes(graphId);
+ }
+
+ @POST
+ @ApiOperation(
+ httpMethod = "POST",
+ value = "Creates a node in a given graph",
+ notes = "Creates a single node for a given graph",
+ response = Response.class)
+ @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid node supplied", response = ErrorMessage.class),
+ @ApiResponse(code = 403, message = "Invalid graph id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 201, message = "Node successfully created", response = Node.class)})
+ public Response addNode(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "New node object", required = true) Node node,
+ @Context UriInfo uriInfo) {
+ Node newNode = nodeService.addNode(graphId, node);
+ String newId = String.valueOf(newNode.getId());
+ URI uri = uriInfo.getAbsolutePathBuilder().path(newId).build();
+ return Response.created(uri)
+ .entity(newNode)
+ .build();
+ }
+
+ @GET
+ @Path("{nodeId}")
+ @ApiOperation(
+ httpMethod = "GET",
+ value = "Returns a node of a given graph",
+ notes = "Returns a single node of a given graph",
+ response = Node.class)
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "The requested node has been returned in the message body", response = Node.class)})
+ public Node getNode(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @Context UriInfo uriInfo){
+ Node node = nodeService.getNode(graphId, nodeId);
+ node.addLink(getUriForSelf(uriInfo, graphId, node), "self");
+ node.addLink(getUriForNeighbours(uriInfo, graphId, node), "neighbours");
+ return node;
+ }
+
+ @PUT
+ @Path("{nodeId}/configuration")
+ @ApiOperation(
+ httpMethod = "PUT",
+ value = "Adds/edits a configuration to a node of a given graph",
+ notes = "Configures a node. Once all the nodes of a graph have been configured a given policy can be verified for the graph (e.g. 'reachability' between two nodes).")
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "Configuration updated for the requested node")})
+ public void addNodeConfiguration(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "Node configuration", required = true) Configuration nodeConfiguration,
+ @Context UriInfo uriInfo){
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ Graph graph = new GraphService().getGraph(graphId);
+ if (graph == null){
+ throw new BadRequestException("Graph with id " + graphId + " not found");
+ }
+ Node node = nodeService.getNode(graphId, nodeId);
+ if (node == null){
+ throw new BadRequestException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ Node nodeCopy = new Node();
+ nodeCopy.setId(node.getId());
+ nodeCopy.setName(node.getName());
+ nodeCopy.setFunctional_type(node.getFunctional_type());
+ Map<Long,Neighbour> nodes = new HashMap<Long,Neighbour>();
+ nodes.putAll(node.getNeighbours());
+ nodeCopy.setNeighbours(nodes);
+ nodeConfiguration.setId(nodeCopy.getName());
+ nodeCopy.setConfiguration(nodeConfiguration);
+
+ Graph graphCopy = new Graph();
+ graphCopy.setId(graph.getId());
+ graphCopy.setNodes(new HashMap<Long, Node>(graph.getNodes()));
+ graphCopy.getNodes().remove(node.getId());
+
+ NodeService.validateNode(graphCopy, nodeCopy);
+ graph.getNodes().put(nodeId, nodeCopy);
+ }
+
+
+ @PUT
+ @Path("{nodeId}")
+ @ApiOperation(
+ httpMethod = "PUT",
+ value = "Edits a node of a given graph",
+ notes = "Edits a single node of a given graph",
+ response = Node.class)
+ @ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid node object", response = ErrorMessage.class),
+ @ApiResponse(code = 403, message = "Invalid graph and/or node id", response = ErrorMessage.class),
+ @ApiResponse(code = 404, message = "Graph and/or node not found", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 200, message = "Node edited successfully", response = Node.class)})
+ public Node updateNode(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId,
+ @ApiParam(value = "Updated node object", required = true) Node node){
+ node.setId(nodeId);
+ return nodeService.updateNode(graphId, node);
+ }
+
+ @DELETE
+ @Path("{nodeId}")
+ @ApiOperation(
+ httpMethod = "DELETE",
+ value = "Deletes a node of a given graph",
+ notes = "Deletes a single node of a given graph")
+ @ApiResponses(value = { @ApiResponse(code = 403, message = "Invalid graph and/or node id", response = ErrorMessage.class),
+ @ApiResponse(code = 500, message = "Internal server error", response = ErrorMessage.class),
+ @ApiResponse(code = 204, message = "Node successfully deleted")})
+ public void deleteNode(
+ @ApiParam(value = "Graph id", required = true) @PathParam("graphId") long graphId,
+ @ApiParam(value = "Node id", required = true) @PathParam("nodeId") long nodeId){
+ nodeService.removeNode(graphId, nodeId);
+ }
+
+ private String getUriForSelf(UriInfo uriInfo, long graphId, Node node) {
+ String uri = uriInfo.getBaseUriBuilder()
+ //.path(NodeResource.class)
+ .path(GraphResource.class)
+ .path(GraphResource.class, "getNodeResource")
+ .resolveTemplate("graphId", graphId)
+ .path(Long.toString(node.getId()))
+ .build()
+ .toString();
+ return uri;
+ }
+
+ private String getUriForNeighbours(UriInfo uriInfo, long graphId, Node node) {
+ String uri = uriInfo.getBaseUriBuilder()
+ .path(GraphResource.class)
+ .path(GraphResource.class, "getNodeResource")
+ .resolveTemplate("graphId", graphId)
+ .path(Long.toString(node.getId()))
+ .path("neighbours")
+ .build()
+ .toString();
+// .path(NodeResource.class)
+// .path(NodeResource.class, "getNeighbourResource")
+// .path(NeighbourResource.class)
+// .resolveTemplate("nodeId", node.getId())
+// .build()
+// .toString();
+ return uri;
+ }
+
+ @Path("{nodeId}/neighbours")
+ public NeighbourResource getNeighbourResource(){
+ return new NeighbourResource();
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/resources/beans/VerificationBean.java b/verigraph/src/main/java/it/polito/escape/verify/resources/beans/VerificationBean.java
new file mode 100644
index 0000000..d6f9ca6
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/resources/beans/VerificationBean.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.resources.beans;
+
+import javax.ws.rs.QueryParam;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("Verification")
+public class VerificationBean {
+
+ @ApiModelProperty(example = "webclient", value = "Source node. Must refer to an existing node of the same graph")
+ private @QueryParam("source") String source;
+
+ @ApiModelProperty( example = "webserver",
+ value = "Destination node. Must refer to an existing node of the same graph")
+ private @QueryParam("destination") String destination;
+
+ @ApiModelProperty( example = "reachability",
+ value = "Verification policy ('reachability', 'isolation', 'traversal')")
+ private @QueryParam("type") String type;
+
+ @ApiModelProperty( example = "firewall",
+ value = "Absent if verification type is 'reachability', equal to the name of a middlebox to be avoided if verification type is 'isolation', equal to the name of a middlebox to be traversed if verification type is 'traversal'")
+ private @QueryParam("middlebox") String middlebox;
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public String getDestination() {
+ return destination;
+ }
+
+ public void setDestination(String destination) {
+ this.destination = destination;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getMiddlebox() {
+ return middlebox;
+ }
+
+ public void setMiddlebox(String middlebox) {
+ this.middlebox = middlebox;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomConfigurationSerializer.java b/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomConfigurationSerializer.java
new file mode 100644
index 0000000..e28273f
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomConfigurationSerializer.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.serializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Configuration;
+
+public class CustomConfigurationSerializer extends JsonSerializer<Configuration> {
+
+ @Override
+ public void serialize(Configuration conf, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonProcessingException {
+ try {
+ jgen.writeObject(conf.getConfiguration());
+ } catch (IOException e) {
+ throw new InternalServerErrorException("I/O error serializing a configuration object: " + e.getMessage());
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomMapSerializer.java b/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomMapSerializer.java
new file mode 100644
index 0000000..e811365
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/serializer/CustomMapSerializer.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.serializer;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import it.polito.escape.verify.exception.InternalServerErrorException;
+
+public class CustomMapSerializer extends JsonSerializer<Map<?, ?>> {
+ @Override
+ public void serialize(final Map<?, ?> value, final JsonGenerator jgen, final SerializerProvider provider) {
+ try {
+ jgen.writeObject(value.values());
+ } catch (IOException e) {
+ throw new InternalServerErrorException("I/O error serializing a map: " + e.getMessage());
+ }
+ }
+} \ No newline at end of file
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/GraphService.java b/verigraph/src/main/java/it/polito/escape/verify/service/GraphService.java
new file mode 100644
index 0000000..b34eb08
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/GraphService.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import it.polito.escape.verify.database.DatabaseClass;
+import it.polito.escape.verify.exception.DataNotFoundException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+
+public class GraphService {
+
+ private Map<Long, Graph> graphs = DatabaseClass.getInstance().getGraphs();
+
+ public GraphService() {
+
+ }
+
+ public List<Graph> getAllGraphs() {
+ return new ArrayList<Graph>(graphs.values());
+ }
+
+ public Graph getGraph(long id) {
+ if (id <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + id);
+ }
+ Graph graph = graphs.get(id);
+ if (graph == null) {
+ throw new DataNotFoundException("Graph with id " + id + " not found");
+ }
+ return graph;
+ }
+
+ public Graph updateGraph(Graph graph) {
+ if (graph.getId() <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graph.getId());
+ }
+ Graph localGraph = graphs.get(graph.getId());
+ if (localGraph == null) {
+ throw new DataNotFoundException("Graph with id " + graph.getId() + " not found");
+ }
+
+ validateGraph(graph);
+
+// int numberOfNodes = 0;
+// for (Node node : graph.getNodes().values()) {
+//
+// node.setId(++numberOfNodes);
+//
+// int numberOfNodeNeighbours = 0;
+// for (Neighbour neighbour : node.getNeighbours().values()) {
+// neighbour.setId(++numberOfNodeNeighbours);
+// }
+// }
+
+ for (Map.Entry<Long, Node> nodeEntry : graph.getNodes().entrySet()){
+ nodeEntry.getValue().setId(nodeEntry.getKey());
+
+ for (Map.Entry<Long, Neighbour> neighbourEntry : nodeEntry.getValue().getNeighbours().entrySet()){
+ neighbourEntry.getValue().setId(neighbourEntry.getKey());
+ }
+ }
+
+ synchronized(this){
+ graphs.put(graph.getId(), graph);
+ DatabaseClass.persistDatabase();
+ return graph;
+ }
+ }
+
+ public Graph removeGraph(long id) {
+ if (id <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + id);
+ }
+ synchronized(this){
+ return graphs.remove(id);
+ }
+ }
+
+ public Graph addGraph(Graph graph) {
+ validateGraph(graph);
+
+ synchronized (this) {
+ graph.setId(DatabaseClass.getInstance().getNumberOfGraphs() + 1);
+ }
+// int numberOfNodes = 0;
+// for (Node node : graph.getNodes().values()) {
+//
+// node.setId(++numberOfNodes);
+//
+// int numberOfNodeNeighbours = 0;
+// for (Neighbour neighbour : node.getNeighbours().values()) {
+// neighbour.setId(++numberOfNodeNeighbours);
+// }
+// }
+
+ for (Map.Entry<Long, Node> nodeEntry : graph.getNodes().entrySet()){
+ nodeEntry.getValue().setId(nodeEntry.getKey());
+
+ for (Map.Entry<Long, Neighbour> neighbourEntry : nodeEntry.getValue().getNeighbours().entrySet()){
+ neighbourEntry.getValue().setId(neighbourEntry.getKey());
+ }
+ }
+
+ synchronized(this){
+ graphs.put(graph.getId(), graph);
+ DatabaseClass.persistDatabase();
+ return graph;
+ }
+ }
+
+ public static void validateGraph(Graph graph) {
+ for (Node node : graph.getNodes().values()) {
+ NodeService.validateNode(graph, node);
+ }
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/JsonValidationService.java b/verigraph/src/main/java/it/polito/escape/verify/service/JsonValidationService.java
new file mode 100644
index 0000000..1ac6c1f
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/JsonValidationService.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.text.WordUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+
+public class JsonValidationService {
+
+ private Graph graph = new Graph();
+
+ private Node node = new Node();
+
+ public JsonValidationService() {
+
+ }
+
+ public JsonValidationService(Graph graph, Node node) {
+ this.graph = graph;
+ this.node = node;
+ }
+
+ public boolean validateFieldAgainstNodeNames(String value) {
+ for (Node node : this.graph.getNodes().values()) {
+ if (node.getName().equals(value))
+ return true;
+ }
+ return false;
+ }
+
+ public void validateFieldsAgainstNodeNames(JsonNode node) {
+ if (node.isTextual()) {
+ boolean isValid = validateFieldAgainstNodeNames(node.asText());
+ if (!isValid) {
+ System.out.println(node.asText() + " is not a valid string!");
+ throw new BadRequestException("String '" + node.asText()
+ + "' is not valid for the configuration of node '" + this.node.getName()
+ + "'");
+ }
+ }
+ if (node.isArray()) {
+ for (JsonNode object : node) {
+ validateFieldsAgainstNodeNames(object);
+ }
+ }
+ if (node.isObject()) {
+ Iterator<Entry<String, JsonNode>> iter = node.fields();
+
+ while (iter.hasNext()) {
+ Entry<String, JsonNode> item = iter.next();
+ validateFieldsAgainstNodeNames(item.getValue());
+ }
+ }
+
+ }
+
+ public boolean validateNodeConfiguration() {
+ String className = WordUtils.capitalize(node.getFunctional_type()) + "Validator";
+
+ Class<?> validator;
+ try {
+ validator = Class.forName("it.polito.escape.verify.validation." + className);
+ }
+ catch (ClassNotFoundException e) {
+ System.out.println(className + " not found, configuration properties of node '" + node.getName()
+ + "' will be validated against node names");
+ return false;
+ }
+
+ Class<?> graphClass;
+ Class<?> nodeClass;
+ Class<?> configurationClass;
+ try {
+ graphClass = Class.forName("it.polito.escape.verify.model.Graph");
+ nodeClass = Class.forName("it.polito.escape.verify.model.Node");
+ configurationClass = Class.forName("it.polito.escape.verify.model.Configuration");
+ }
+ catch (ClassNotFoundException e) {
+ throw new RuntimeException("Model classes not found");
+ }
+
+ Class<?>[] paramTypes = new Class[3];
+ paramTypes[0] = graphClass;
+ paramTypes[1] = nodeClass;
+ paramTypes[2] = configurationClass;
+
+ String methodName = "validate";
+
+ Object instance;
+ try {
+ instance = validator.newInstance();
+ }
+ catch (InstantiationException e) {
+ throw new RuntimeException("'" + className + "' cannot be instantiated");
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException("Illegal access to '" + className + "' instantiation");
+ }
+
+ Method myMethod;
+ try {
+ myMethod = validator.getDeclaredMethod(methodName, paramTypes);
+ }
+ catch (NoSuchMethodException e) {
+ throw new RuntimeException("'" + methodName + "' method has to be implemented in " + className + " class");
+ }
+ try {
+ myMethod.invoke(instance, graph, node, node.getConfiguration());
+ }
+ catch (IllegalAccessException e) {
+ throw new RuntimeException("Illegal access to '" + methodName + "' method in " + className + " instance");
+ }
+ catch (InvocationTargetException e) {
+ throw new BadRequestException("Validation failed for node '" + node.getName() + "': "
+ + e.getTargetException().getMessage());
+ }
+ return true;
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/NeighbourService.java b/verigraph/src/main/java/it/polito/escape/verify/service/NeighbourService.java
new file mode 100644
index 0000000..ecf4e69
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/NeighbourService.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import it.polito.escape.verify.database.DatabaseClass;
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.DataNotFoundException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+
+public class NeighbourService {
+
+ private Map<Long, Graph> graphs = DatabaseClass.getInstance().getGraphs();
+
+ public List<Neighbour> getAllNeighbours(long graphId, long nodeId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null)
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+ return new ArrayList<Neighbour>(neighbours.values());
+ }
+
+ public Neighbour getNeighbour(long graphId, long nodeId, long neighbourId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ if (neighbourId <= 0) {
+ throw new ForbiddenException("Illegal neighbour id: " + neighbourId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null) {
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+ Neighbour neighbour = neighbours.get(neighbourId);
+ if (neighbour == null) {
+ throw new DataNotFoundException("Neighbour with id " + neighbourId + " not found for node with id " + nodeId
+ + " in graph with id " + graphId);
+ }
+ return neighbour;
+ }
+
+ public Neighbour addNeighbour(long graphId, long nodeId, Neighbour neighbour) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null) {
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+
+ validateNeighbour(graph, node, neighbour);
+
+ synchronized (this) {
+ neighbour.setId(neighbours.size() + 1);
+ neighbours.put(neighbour.getId(), neighbour);
+ DatabaseClass.persistDatabase();
+ return neighbour;
+ }
+ }
+
+ public Neighbour updateNeighbour(long graphId, long nodeId, Neighbour neighbour) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ if (neighbour.getId() <= 0) {
+ throw new ForbiddenException("Illegal neighbour id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null) {
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+ Neighbour currentNeighbour = neighbours.get(neighbour.getId());
+ if (currentNeighbour == null) {
+ throw new DataNotFoundException("Neighbour with id " + neighbour.getId() + " not found for node with id "
+ + nodeId + " in graph with id " + graphId);
+ }
+
+ validateNeighbour(graph, node, neighbour);
+
+ synchronized (this) {
+ neighbours.put(neighbour.getId(), neighbour);
+ DatabaseClass.persistDatabase();
+ return neighbour;
+ }
+ }
+
+ public Neighbour removeNeighbour(long graphId, long nodeId, long neighbourId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ if (neighbourId <= 0) {
+ throw new ForbiddenException("Illegal neighbour id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null) {
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ Map<Long, Neighbour> neighbours = node.getNeighbours();
+
+ synchronized(this){
+ return neighbours.remove(neighbourId);
+ }
+ }
+
+ public static void validateNeighbour(Graph graph, Node node, Neighbour neighbour) {
+ if (graph == null)
+ throw new BadRequestException("Neighbour validation failed: cannot validate null graph");
+ if (node == null)
+ throw new BadRequestException("Neighbour validation failed: cannot validate null node");
+ if (neighbour == null)
+ throw new BadRequestException("Neighbour validation failed: cannot validate null neighbour");
+
+ if (neighbour.getName() == null)
+ throw new BadRequestException("Neighbour validation failed: neighbour 'name' field cannot be null");
+ if (neighbour.getName().equals(""))
+ throw new BadRequestException("Neighbour validation failed: neighbour 'name' field cannot be an empty string");
+
+ Node nodeFound = graph.searchNodeByName(neighbour.getName());
+ if ((nodeFound == null) || (nodeFound.getName().equals(node.getName())))
+ throw new BadRequestException("Neighbour validation failed: '" + neighbour.getName()
+ + "' is not a valid name for a neighbour of node '" + node.getName() + "'");
+
+ Neighbour neighbourFound = node.searchNeighbourByName(neighbour.getName());
+ if ((neighbourFound != null) && (neighbourFound.equals(neighbour) == false))
+ throw new BadRequestException("Neighbour validation failed: node '" + node.getName()
+ + "' already has a neighbour named '" + neighbour.getName() + "'");
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/NodeService.java b/verigraph/src/main/java/it/polito/escape/verify/service/NodeService.java
new file mode 100644
index 0000000..e6ad672
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/NodeService.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+
+import javax.ws.rs.InternalServerErrorException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.main.JsonSchema;
+
+import it.polito.escape.verify.database.DatabaseClass;
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.DataNotFoundException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+
+public class NodeService {
+
+ private Map<Long, Graph> graphs = DatabaseClass.getInstance().getGraphs();
+
+ public NodeService() {
+
+ }
+
+ public List<Node> getAllNodes(long graphId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ return new ArrayList<Node>(nodes.values());
+ }
+
+ public Node getNode(long graphId, long nodeId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node node = nodes.get(nodeId);
+ if (node == null) {
+ throw new DataNotFoundException("Node with id " + nodeId + " not found in graph with id " + graphId);
+ }
+ return node;
+ }
+
+ public Node updateNode(long graphId, Node node) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (node.getId() <= 0) {
+ throw new ForbiddenException("Illegal node id: " + node.getId());
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+ Node localNode = nodes.get(node.getId());
+ if (localNode == null) {
+ throw new DataNotFoundException("Node with id " + node.getId() + " not found in graph with id " + graphId);
+ }
+
+ Graph graphCopy = new Graph();
+ graphCopy.setId(graph.getId());
+ graphCopy.setNodes(new HashMap<Long, Node>(graph.getNodes()));
+ graphCopy.getNodes().remove(node.getId());
+
+ // int numberOfNeighbours = 0;
+ // for(Neighbour neighbour : node.getNeighbours().values()){
+ // neighbour.setId(++numberOfNeighbours);
+ // }
+
+ for (Map.Entry<Long, Neighbour> neighbourEntry : node.getNeighbours().entrySet()) {
+ neighbourEntry.getValue().setId(neighbourEntry.getKey());
+ }
+
+ validateNode(graphCopy, node);
+
+ synchronized (this) {
+ nodes.put(node.getId(), node);
+ DatabaseClass.persistDatabase();
+ return node;
+ }
+ }
+
+ public Node removeNode(long graphId, long nodeId) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ if (nodeId <= 0) {
+ throw new ForbiddenException("Illegal node id: " + nodeId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+
+ synchronized (this) {
+ return nodes.remove(nodeId);
+ }
+ }
+
+ public Node addNode(long graphId, Node node) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+
+ validateNode(graph, node);
+
+ synchronized (this) {
+ node.setId(DatabaseClass.getInstance().getGraphNumberOfNodes(graphId) + 1);
+ }
+
+ // int numberOfNeighbours = 0;
+
+ for (Map.Entry<Long, Neighbour> neighbourEntry : node.getNeighbours().entrySet()) {
+ neighbourEntry.getValue().setId(neighbourEntry.getKey());
+ }
+
+ // for (Neighbour neighbour : node.getNeighbours().values()) {
+ // neighbour.setId(++numberOfNeighbours);
+ // }
+
+ synchronized (this) {
+ nodes.put(node.getId(), node);
+ DatabaseClass.persistDatabase();
+ return node;
+ }
+ }
+
+ public Node searchByName(long graphId, String nodeName) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ Graph graph = graphs.get(graphId);
+ if (graph == null)
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ Map<Long, Node> nodes = graph.getNodes();
+
+ for (Node node : nodes.values()) {
+ if (node.getName().equals(nodeName))
+ return node;
+ }
+ return null;
+ }
+
+ public static void validateNode(Graph graph, Node node) {
+ if (graph == null)
+ throw new BadRequestException("Node validation failed: cannot validate null graph");
+ if (node == null)
+ throw new BadRequestException("Node validation failed: cannot validate null node");
+
+ if (node.getName() == null)
+ throw new BadRequestException("Node validation failed: node 'name' field cannot be null");
+ if (node.getFunctional_type() == null)
+ throw new BadRequestException("Node validation failed: node 'functional_type' field cannot be null");
+
+ if (node.getName().equals(""))
+ throw new BadRequestException("Node validation failed: node 'name' field cannot be an empty string");
+ if (node.getFunctional_type().equals(""))
+ throw new BadRequestException("Node validation failed: node 'functional_type' field cannot be an empty string");
+
+ Node nodeFound = graph.searchNodeByName(node.getName());
+ if ((nodeFound != null) && (nodeFound.equals(node) == false))
+ throw new BadRequestException("Node validation failed: graph already has a node named '" + node.getName()
+ + "'");
+ Configuration configuration = node.getConfiguration();
+ if (configuration != null) {
+ JsonNode configurationJsonNode = configuration.getConfiguration();
+ // validate configuration against schema file
+ validateNodeConfigurationAgainstSchemaFile(node, configurationJsonNode);
+ JsonValidationService jsonValidator = new JsonValidationService(graph, node);
+ boolean hasCustomValidator = jsonValidator.validateNodeConfiguration();
+ if (!hasCustomValidator) {
+ jsonValidator.validateFieldsAgainstNodeNames(configurationJsonNode);
+ }
+ }
+
+ // validate neighbours
+ Map<Long, Neighbour> nodeNeighboursMap = node.getNeighbours();
+ if (nodeNeighboursMap == null)
+ throw new BadRequestException("Node validation failed: node 'neighbours' cannot be null");
+ for (Neighbour neighbour : nodeNeighboursMap.values()) {
+ NeighbourService.validateNeighbour(graph, node, neighbour);
+ }
+ }
+
+ public static void validateNodeConfigurationAgainstSchemaFile(Node node, JsonNode configurationJson) {
+ String schemaFileName = node.getFunctional_type() + ".json";
+
+ File schemaFile = new File(System.getProperty("catalina.base") + "/webapps/verify/json/" + schemaFileName);
+
+ if (!schemaFile.exists()) {
+ //if no REST client, try gRPC application
+ schemaFile = new File("src/main/webapp/json/" + schemaFileName);
+
+ if (!schemaFile.exists()) {
+ throw new ForbiddenException("Functional type '" + node.getFunctional_type()
+ + "' is not supported! Please edit 'functional_type' field of node '"
+ + node.getName() + "'");
+ }
+ }
+
+ JsonSchema schemaNode = null;
+ try {
+ schemaNode = ValidationUtils.getSchemaNode(schemaFile);
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to load '" + schemaFileName + "' schema file");
+ }
+ catch (ProcessingException e) {
+ throw new InternalServerErrorException("Unable to resolve '" + schemaFileName
+ + "' schema file as a schema node");
+ }
+
+ try {
+ ValidationUtils.validateJson(schemaNode, configurationJson);
+ }
+ catch (ProcessingException e) {
+ throw new BadRequestException("Something went wrong trying to validate node '" + node.getName()
+ + "' with the following configuration: '" + configurationJson.toString()
+ + "' against the json schema '" + schemaFile.getName() + "': "
+ + e.getMessage());
+
+ }
+
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/ValidationUtils.java b/verigraph/src/main/java/it/polito/escape/verify/service/ValidationUtils.java
new file mode 100644
index 0000000..77ef4f7
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/ValidationUtils.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.fge.jackson.JsonLoader;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.core.report.ProcessingMessage;
+import com.github.fge.jsonschema.core.report.ProcessingReport;
+import com.github.fge.jsonschema.main.JsonSchema;
+import com.github.fge.jsonschema.main.JsonSchemaFactory;
+
+public class ValidationUtils {
+
+ public static final String JSON_V4_SCHEMA_IDENTIFIER = "http://json-schema.org/draft-04/schema#";
+ public static final String JSON_SCHEMA_IDENTIFIER_ELEMENT = "$schema";
+
+ public static JsonNode getJsonNode(String jsonText) throws IOException {
+ return JsonLoader.fromString(jsonText);
+ } // getJsonNode(text) ends
+
+ public static JsonNode getJsonNode(File jsonFile) throws IOException {
+ return JsonLoader.fromFile(jsonFile);
+ } // getJsonNode(File) ends
+
+ public static JsonNode getJsonNode(URL url) throws IOException {
+ return JsonLoader.fromURL(url);
+ } // getJsonNode(URL) ends
+
+ public static JsonNode getJsonNodeFromResource(String resource) throws IOException {
+ return JsonLoader.fromResource(resource);
+ } // getJsonNode(Resource) ends
+
+ public static JsonSchema getSchemaNode(String schemaText) throws IOException, ProcessingException {
+ final JsonNode schemaNode = getJsonNode(schemaText);
+ return _getSchemaNode(schemaNode);
+ } // getSchemaNode(text) ends
+
+ public static JsonSchema getSchemaNode(File schemaFile) throws IOException, ProcessingException {
+ final JsonNode schemaNode = getJsonNode(schemaFile);
+ return _getSchemaNode(schemaNode);
+ } // getSchemaNode(File) ends
+
+ public static JsonSchema getSchemaNode(URL schemaFile) throws IOException, ProcessingException {
+ final JsonNode schemaNode = getJsonNode(schemaFile);
+ return _getSchemaNode(schemaNode);
+ } // getSchemaNode(URL) ends
+
+ public static JsonSchema getSchemaNodeFromResource(String resource) throws IOException, ProcessingException {
+ final JsonNode schemaNode = getJsonNodeFromResource(resource);
+ return _getSchemaNode(schemaNode);
+ } // getSchemaNode() ends
+
+ public static void validateJson(JsonSchema jsonSchemaNode, JsonNode jsonNode) throws ProcessingException {
+ ProcessingReport report = jsonSchemaNode.validate(jsonNode);
+ if (!report.isSuccess()) {
+ for (ProcessingMessage processingMessage : report) {
+ throw new ProcessingException(processingMessage);
+ }
+ }
+ } // validateJson(Node) ends
+
+ public static boolean isJsonValid(JsonSchema jsonSchemaNode, JsonNode jsonNode) throws ProcessingException {
+ ProcessingReport report = jsonSchemaNode.validate(jsonNode);
+ return report.isSuccess();
+ } // validateJson(Node) ends
+
+ public static boolean isJsonValid(String schemaText, String jsonText) throws ProcessingException, IOException {
+ final JsonSchema schemaNode = getSchemaNode(schemaText);
+ final JsonNode jsonNode = getJsonNode(jsonText);
+ return isJsonValid(schemaNode, jsonNode);
+ } // validateJson(Node) ends
+
+ public static boolean isJsonValid(File schemaFile, File jsonFile) throws ProcessingException, IOException {
+ final JsonSchema schemaNode = getSchemaNode(schemaFile);
+ final JsonNode jsonNode = getJsonNode(jsonFile);
+ return isJsonValid(schemaNode, jsonNode);
+ } // validateJson(Node) ends
+
+ public static boolean isJsonValid(URL schemaURL, URL jsonURL) throws ProcessingException, IOException {
+ final JsonSchema schemaNode = getSchemaNode(schemaURL);
+ final JsonNode jsonNode = getJsonNode(jsonURL);
+ return isJsonValid(schemaNode, jsonNode);
+ } // validateJson(Node) ends
+
+ public static void validateJson(String schemaText, String jsonText) throws IOException, ProcessingException {
+ final JsonSchema schemaNode = getSchemaNode(schemaText);
+ final JsonNode jsonNode = getJsonNode(jsonText);
+ validateJson(schemaNode, jsonNode);
+ } // validateJson(text) ends
+
+ public static void validateJson(File schemaFile, File jsonFile) throws IOException, ProcessingException {
+ final JsonSchema schemaNode = getSchemaNode(schemaFile);
+ final JsonNode jsonNode = getJsonNode(jsonFile);
+ validateJson(schemaNode, jsonNode);
+ } // validateJson(File) ends
+
+ public static void validateJson(URL schemaDocument, URL jsonDocument) throws IOException, ProcessingException {
+ final JsonSchema schemaNode = getSchemaNode(schemaDocument);
+ final JsonNode jsonNode = getJsonNode(jsonDocument);
+ validateJson(schemaNode, jsonNode);
+ } // validateJson(URL) ends
+
+ public static void validateJsonResource(String schemaResource, String jsonResource) throws IOException,
+ ProcessingException {
+ final JsonSchema schemaNode = getSchemaNode(schemaResource);
+ final JsonNode jsonNode = getJsonNodeFromResource(jsonResource);
+ validateJson(schemaNode, jsonNode);
+ } // validateJsonResource() ends
+
+ private static JsonSchema _getSchemaNode(JsonNode jsonNode) throws ProcessingException {
+ final JsonNode schemaIdentifier = jsonNode.get(JSON_SCHEMA_IDENTIFIER_ELEMENT);
+ if (null == schemaIdentifier) {
+ ((ObjectNode) jsonNode).put(JSON_SCHEMA_IDENTIFIER_ELEMENT, JSON_V4_SCHEMA_IDENTIFIER);
+ }
+
+ final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
+ return factory.getJsonSchema(jsonNode);
+ } // _getSchemaNode() ends
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/service/VerificationService.java b/verigraph/src/main/java/it/polito/escape/verify/service/VerificationService.java
new file mode 100644
index 0000000..1d31ae9
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/service/VerificationService.java
@@ -0,0 +1,1185 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.service;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+import javax.ws.rs.ProcessingException;
+import javax.xml.bind.JAXBException;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.client.Neo4jManagerClient;
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.DataNotFoundException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.exception.InternalServerErrorException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Entry;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.model.Test;
+import it.polito.escape.verify.model.Verification;
+import it.polito.escape.verify.resources.beans.VerificationBean;
+import it.polito.nffg.neo4j.jaxb.Paths;
+import qj.util.ReflectUtil;
+import qj.util.lang.DynamicClassLoader;
+
+public class VerificationService {
+
+ private static final String generatorFolder = System.getProperty("catalina.base")
+ + "/webapps/verify/WEB-INF/classes/tests/j-verigraph-generator";
+
+ private static final String generatorFolderForGrpc = "service/src/tests/j-verigraph-generator";
+
+ private String testClassGenerator = generatorFolder + "/test_class_generator.py";
+
+ private String testGenerator = generatorFolder + "/test_generator.py";
+
+ public VerificationService() {
+
+ }
+
+ private Paths getPaths(Graph graph, Node sourceNode, Node destinationNode) {
+
+ String source = sourceNode.getName() + "_" + sourceNode.getId();
+ String destination = destinationNode.getName() + "_" + destinationNode.getId();
+
+ List<String> endpoints = new ArrayList<>();
+ List<String> firewalls = new ArrayList<>();
+ Map<String, List<Entry>> routingTable = new HashMap<>();
+
+ for (Node node : graph.getNodes().values()) {
+ // if firewall
+ if (node.getFunctional_type().equals("NF")) {
+ // add 2 connection points to RT
+ routingTable.put(node.getName() + "_" + node.getId() + "_in", new ArrayList<Entry>());
+ routingTable.put(node.getName() + "_" + node.getId() + "_out", new ArrayList<Entry>());
+ // add node to firewalls
+ firewalls.add(node.getName() + "_" + node.getId());
+ // scan neighbours
+ for (Neighbour neighbour : node.getNeighbours().values()) {
+ // check if neighbour is a firewall
+ Node hop = graph.searchNodeByName(neighbour.getName());
+ // if neighbour is a firewall connect to its input port
+ if (hop.getFunctional_type().equals("NF"))
+ routingTable.get(node.getName() + "_" + node.getId() + "_out")
+ .add(new Entry("output", neighbour.getName() + "_" + hop.getId() + "_in"));
+ else
+ // connect
+ // normally to
+ // node
+ routingTable.get(node.getName() + "_" + node.getId()
+ + "_out")
+ .add(new Entry( "output",
+ neighbour.getName() + "_"
+ + hop.getId()));
+ }
+ }
+ // if endpoint
+ else {
+ // add endpoint to RT
+ routingTable.put(node.getName() + "_" + node.getId(), new ArrayList<Entry>());
+ // add to endpoints
+ endpoints.add(node.getName() + "_" + node.getId());
+ // scan neighbours
+ for (Neighbour neighbour : node.getNeighbours().values()) {
+ // check if neighbour is a firewall
+ Node hop = graph.searchNodeByName(neighbour.getName());
+ // if neighbour is a firewall connect to its input port
+ if (hop.getFunctional_type().equals("NF"))
+ routingTable.get(node.getName() + "_" + node.getId())
+ .add(new Entry("output", neighbour.getName() + "_" + hop.getId() + "_in"));
+ else {
+ // connect
+ // normally to
+ // node
+ routingTable.get(node.getName() + "_" + node.getId())
+ .add(new Entry("output", neighbour.getName() + "_" + hop.getId()));
+ }
+ }
+ }
+
+ // end node scan
+ }
+ // debug print
+ System.out.println("Endpoints:");
+ for (String endpoint : endpoints) {
+ System.out.println(endpoint);
+ }
+ System.out.println("Firewalls:");
+ for (String firewall : firewalls) {
+ System.out.println(firewall);
+ }
+ System.out.println("Source: " + source);
+ System.out.println("Destination: " + destination);
+ for (String key : routingTable.keySet()) {
+ System.out.println("RT for node " + key);
+ for (Entry entry : routingTable.get(key)) {
+ System.out.println("\t" + entry.getDirection() + "->" + entry.getDestination());
+ }
+ }
+ // end debug print
+
+ Neo4jManagerClient client = new Neo4jManagerClient( "http://localhost:8080/neo4jmanager/rest/",
+ source,
+ destination,
+ endpoints,
+ firewalls,
+ routingTable);
+
+ Paths paths = null;
+ try {
+ paths = client.getPaths();
+ }
+ catch (JAXBException e) {
+ throw new InternalServerErrorException("Error generating input for neo4jmanager: " + e.getMessage());
+ }
+ catch (ProcessingException e) {
+ throw new InternalServerErrorException("Response of neo4jmanager doesn't contain any path: "
+ + e.getMessage());
+ }
+ catch (IllegalStateException e) {
+ throw new InternalServerErrorException("Error getting a response from neo4jmanager, no input stream for paths or input stream already consumed: "
+ + e.getMessage());
+ }
+ catch (Exception e) {
+ throw new InternalServerErrorException("Unable to continue due to a neo4jmanager error: " + e.getMessage());
+ }
+
+ return paths;
+
+ }
+
+ private List<String> sanitizePath(String path) {
+ List<String> newPath = new ArrayList<String>();
+ // find all nodes, i.e. all names between parentheses
+ Matcher m = Pattern.compile("\\(([^)]+)\\)").matcher(path);
+ while (m.find()) {
+ String node = m.group(1);
+
+ int spaceIndex = node.lastIndexOf("_");
+ if (spaceIndex != -1) {
+ node = node.substring(0, spaceIndex);
+ newPath.add(node);
+ }
+ }
+ return newPath;
+
+ }
+
+ private List<List<String>> sanitizePaths(Paths paths) {
+ List<List<String>> sanitizedPaths = new ArrayList<List<String>>();
+ for (String path : paths.getPath()) {
+ System.out.println("Original path: " + path);
+ List<String> newPath = sanitizePath(path);
+ sanitizedPaths.add(newPath);
+ }
+ return sanitizedPaths;
+ }
+
+ static private Map<String, Long> toMap(List<String> lst) {
+ return lst.stream().collect(Collectors.groupingBy(s -> s, Collectors.counting()));
+ }
+
+ private void eliminateLoopsInPaths(List<List<String>> sanitizedPaths) {
+ List<List<String>> pathsToBeRemoved = new ArrayList<List<String>>();
+
+ for (List<String> path : sanitizedPaths) {
+ Map<String, Long> occurrencesMap = toMap(path);
+ for (long occurrences : occurrencesMap.values()) {
+ if (occurrences > 1) {
+ pathsToBeRemoved.add(path);
+ break;
+ }
+ }
+ }
+ for (List<String> path : pathsToBeRemoved) {
+ sanitizedPaths.remove(path);
+ }
+ }
+
+ private void printListsOfStrings(String message, List<List<String>> lists) {
+ System.out.println(message);
+ for (List<String> element : lists) {
+ System.out.println(element);
+ }
+ }
+
+ private static File createTempDir(String prefix) throws IOException {
+ String tmpDirStr = System.getProperty("java.io.tmpdir");
+ if (tmpDirStr == null) {
+ throw new IOException("System property 'java.io.tmpdir' does not specify a tmp dir");
+ }
+
+ File tmpDir = new File(tmpDirStr);
+ if (!tmpDir.exists()) {
+ boolean created = tmpDir.mkdirs();
+ if (!created) {
+ throw new IOException("Unable to create tmp dir " + tmpDir);
+ }
+ }
+
+ File resultDir = null;
+ int suffix = (int) System.currentTimeMillis();
+ int failureCount = 0;
+ do {
+ resultDir = new File(tmpDir, prefix + suffix % 10000);
+ suffix++;
+ failureCount++;
+ } while (resultDir.exists() && failureCount < 50);
+
+ if (resultDir.exists()) {
+ throw new IOException(failureCount
+ + " attempts to generate a non-existent directory name failed, giving up");
+ }
+ boolean created = resultDir.mkdir();
+ if (!created) {
+ throw new IOException("Failed to create tmp directory");
+ }
+
+ return resultDir;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void generateChainsFile(Graph graph, List<List<String>> sanitizedPaths, String chainsFile) {
+ JSONObject root = new JSONObject();
+ JSONArray chains = new JSONArray();
+
+ int chainCounter = 0;
+
+ for (List<String> path : sanitizedPaths) {
+ Iterator<String> pathsIterator = path.iterator();
+ JSONObject chain = new JSONObject();
+ chain.put("id", ++chainCounter);
+ chain.put("flowspace", "tcp=80");
+ JSONArray nodes = new JSONArray();
+ while (pathsIterator.hasNext()) {
+ String nodeName = (String) pathsIterator.next();
+ Node currentNode = graph.searchNodeByName(nodeName);
+ if (currentNode == null) {
+ throw new InternalServerErrorException("Unable to generate 'chains.json' for neo4jmanager: node "
+ + nodeName + " not found");
+ }
+ JSONObject node = new JSONObject();
+ node.put("name", currentNode.getName());
+ // if(currentNode.getFunctional_type().equals("firewall"))
+ // node.put("address", "ip_nat");
+ // else
+ node.put("address", "ip_" + currentNode.getName());
+ node.put("functional_type", currentNode.getFunctional_type());
+ nodes.add(node);
+ chain.put("nodes", nodes);
+ }
+ chains.add(chain);
+ }
+ root.put("chains", chains);
+
+ try (FileWriter file = new FileWriter(chainsFile)) {
+ file.write(root.toJSONString());
+ System.out.println("Successfully created 'chains.json' with the following content:");
+ System.out.println(root);
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Error saving 'chains.json' for neo4jmanager");
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void generateConfigFile(Graph graph, String configFile) {
+ JSONObject root = new JSONObject();
+ JSONArray nodes = new JSONArray();
+
+ for (Node n : graph.getNodes().values()) {
+ JSONObject node = new JSONObject();
+ // JSONArray configuration = new JSONArray();
+ Configuration nodeConfig = n.getConfiguration();
+ JsonNode configuration = nodeConfig.getConfiguration();
+
+ node.put("configuration", configuration);
+ node.put("id", nodeConfig.getId());
+ node.put("description", nodeConfig.getDescription());
+
+ nodes.add(node);
+
+ }
+ root.put("nodes", nodes);
+
+ try (FileWriter file = new FileWriter(configFile)) {
+ file.write(root.toJSONString());
+ System.out.println("Successfully created 'config.json' with the following content:");
+ System.out.println(root);
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Error saving 'config.json' for neo4jmanager");
+ }
+
+ }
+
+ private void printCommand(String[] cmd) {
+ for (String c : cmd) {
+ System.out.printf(c + " ");
+ }
+ System.out.println("");
+ }
+
+ private String platfromIndependentPath(String path) {
+ path = path.replaceAll("/", Matcher.quoteReplacement(Character.toString(File.separatorChar)));
+ return path;
+ }
+
+ private void generateTestScenarios(String chainsFile, String configFile, String scenarioFile) {
+
+ String[] cmd = { "python", platfromIndependentPath(testClassGenerator), "-c",
+ platfromIndependentPath(chainsFile), "-f", platfromIndependentPath(configFile), "-o",
+ platfromIndependentPath(scenarioFile) };
+ printCommand(cmd);
+
+ ProcessBuilder pb = new ProcessBuilder(cmd);
+ pb.redirectErrorStream(true);
+ Process process;
+ try {
+ process = pb.start();
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null)
+ System.out.println("test_class_generator.py: " + line);
+ process.waitFor();
+ if (process.exitValue() != 0) {
+ throw new InternalServerErrorException("Unable to generate test scenario file for the verification request: test_class_generator returned "
+ + process.exitValue());
+ }
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Error generating tests for Z3: unable to execute generator");
+ }
+ catch (InterruptedException e) {
+ throw new InternalServerErrorException("Error generating tests for Z3: generator got interrupted during execution");
+ }
+
+ }
+
+ private void generateTests( int scenariosCounter, String scenariosBasename, String source, String destination,
+ String testsBasename) {
+
+ List<String> scenarios = new ArrayList<String>();
+ List<String> tests = new ArrayList<String>();
+ for (int i = 0; i < scenariosCounter; i++) {
+ scenarios.add(scenariosBasename + "_" + (i + 1) + ".java");
+ tests.add(testsBasename + "_" + (i + 1) + ".java");
+ }
+
+ for (int i = 0; i < scenariosCounter; i++) {
+ String[] cmd = { "python", platfromIndependentPath(testGenerator), "-i",
+ platfromIndependentPath(scenarios.get(i)), "-o", platfromIndependentPath(tests.get(i)),
+ "-s", source, "-d", destination };
+ printCommand(cmd);
+
+ ProcessBuilder pb = new ProcessBuilder(cmd);
+ pb.redirectErrorStream(true);
+ Process process;
+ try {
+ process = pb.start();
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null)
+ System.out.println("test_generator.py: " + line);
+ process.waitFor();
+ if (process.exitValue() != 0) {
+ throw new InternalServerErrorException("Unable to generate test file for the verification request: test_generator returned "
+ + process.exitValue());
+ }
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Error generating tests for Z3: unable to execute generator");
+ }
+ catch (InterruptedException e) {
+ throw new InternalServerErrorException("Error generating tests for Z3: generator got interrupted during execution");
+ }
+
+ }
+
+ }
+
+ private void prepareForCompilationAndExecution( int scenariosCounter, String scenarioBasename, String testBasename,
+ List<File> sourceFiles, List<File> classFiles) {
+ for (int i = 0; i < scenariosCounter; i++) {
+ String scenario = scenarioBasename + "_" + (i + 1) + ".java";
+ sourceFiles.add(new File(scenario));
+ System.out.println("Scenario file " + scenario + " added to compilation");
+
+ String testSource = testBasename + "_" + (i + 1) + ".java";
+ String testClass = testBasename + "_" + (i + 1);
+
+ sourceFiles.add(new File(testSource));
+ System.out.println("Test file " + testSource + " added to copilation");
+ classFiles.add(new File(testClass));
+ System.out.println("Test file " + testClass + " added to execution");
+ }
+ }
+
+ private void compileFiles(List<File> files, String folder) {
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ if (compiler == null) {
+ throw new InternalServerErrorException("Error getting the Java compiler: JDK >= 1.8 required");
+ }
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+
+ try {
+ // fileManager.setLocation(StandardLocation.CLASS_OUTPUT,
+ // Arrays.asList(new File(projectFolder)));
+
+ // String z3 = "/usr/lib/com.microsoft.z3.jar";
+ // List<String> optionList = new ArrayList<String>();
+ // optionList.add("-classpath");
+ // optionList.add(System.getProperty("java.class.path") + ":" + z3);
+ List<String> optionList = new ArrayList<String>();
+ optionList.add("-d");
+ optionList.add(folder);
+ DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
+
+ boolean success = compiler
+ .getTask( null,
+ fileManager,
+ diagnostics,
+ optionList,
+ null,
+ fileManager.getJavaFileObjectsFromFiles(files))
+ .call();
+ if (!success) {
+ Locale myLocale = Locale.getDefault();
+ StringBuilder msg = new StringBuilder();
+ msg.append("Error compiling Z3 test files: ");
+ for (Diagnostic<? extends JavaFileObject> err : diagnostics.getDiagnostics()) {
+ msg.append('\n');
+ msg.append(err.getKind());
+ msg.append(": ");
+ if (err.getSource() != null) {
+ msg.append(err.getSource().getName());
+ }
+ msg.append(':');
+ msg.append(err.getLineNumber());
+ msg.append(": ");
+ msg.append(err.getMessage(myLocale));
+ }
+ throw new InternalServerErrorException(msg.toString());
+ }
+ fileManager.close();
+
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to set the location of the Z3 test files to be compiled");
+ }
+
+ }
+
+ private int runIt(File filename, String folder) {
+ int endIndex = filename.getName().lastIndexOf(".");
+ String filenameNoExtension;
+ if (endIndex == -1) {
+ filenameNoExtension = filename.getName();
+ }
+ else {
+ filenameNoExtension = filename.getName().substring(0, endIndex);
+ if (!filenameNoExtension.matches("\\w+")) {
+ filenameNoExtension = filename.getName();
+ }
+ }
+
+ System.out.println("Filename is: " + filenameNoExtension);
+ try {
+ Class<?> userClass = new DynamicClassLoader(folder).load("tests." + filenameNoExtension);
+ Object context = ReflectUtil.newInstance(userClass);
+ Object result = ReflectUtil.invoke("run", context);
+ return (int) result;
+ }
+ catch (Exception e) {
+ StringWriter errors = new StringWriter();
+ e.printStackTrace(new PrintWriter(errors));
+ throw new InternalServerErrorException("Error executing Z3 tests: " + e.getMessage()
+ + ". There are errors in the Z3 model.");
+ }
+ }
+
+ private List<Test> runFiles(String folder, List<List<String>> paths, Graph graph, List<File> files) {
+ List<Test> tests = new ArrayList<Test>();
+ for (int i = 0; i < files.size(); i++) {
+ System.out.println("Running test file \"" + files.get(i).getAbsolutePath() + "\"");
+ int result = runIt(files.get(i), folder);
+ System.out.println("Execution returned: " + result);
+
+ List<Node> path = new ArrayList<Node>();
+ for (String nodeString : paths.get(i)) {
+ Node node = graph.searchNodeByName(nodeString);
+ path.add(node);
+ }
+ Test t = new Test(path, result);
+ tests.add(t);
+ }
+
+ return tests;
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean deleteDir(File dir) {
+ if (dir.isDirectory()) {
+ String[] children = dir.list();
+ for (int i = 0; i < children.length; i++) {
+ boolean success = deleteDir(new File(dir, children[i]));
+ if (!success) {
+ return false;
+ }
+ }
+ }
+
+ return dir.delete();
+
+ }
+
+ @SuppressWarnings("unused")
+ private void deleteFilesWithPrefix(String directory, String prefix, String extension) {
+ final File scenarioFolder = new File(directory);
+ final File[] scenarioFiles = scenarioFolder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(final File dir, final String name) {
+ return name.matches(prefix + ".*\\." + extension);
+ }
+ });
+ for (final File file : scenarioFiles) {
+ if (!file.delete()) {
+ System.err.println("Can't remove " + file.getAbsolutePath());
+ }
+ else {
+ System.out.println("Removed file " + file.getAbsolutePath());
+ }
+ }
+ }
+
+ public Verification verify(long graphId, VerificationBean verificationBean) {
+ if (graphId <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + graphId);
+ }
+ GraphService graphService = new GraphService();
+ Graph graph = graphService.getGraph(graphId);
+ if (graph == null) {
+ throw new DataNotFoundException("Graph with id " + graphId + " not found");
+ }
+ String source = verificationBean.getSource();
+ String destination = verificationBean.getDestination();
+ String type = verificationBean.getType();
+ if (source == null || source.equals("")) {
+ throw new BadRequestException("Please specify the 'source' parameter in your request");
+ }
+ if (destination == null || destination.equals("")) {
+ throw new BadRequestException("Please specify the 'destination' parameter in your request");
+ }
+ if (type == null || type.equals("")) {
+ throw new BadRequestException("Please specify the 'type' parameter in your request");
+ }
+
+ Node sourceNode = graph.searchNodeByName(verificationBean.getSource());
+ Node destinationNode = graph.searchNodeByName(verificationBean.getDestination());
+
+ if (sourceNode == null) {
+ throw new BadRequestException("The 'source' parameter '" + source + "' is not valid, please insert the name of an existing node");
+ }
+ if (destinationNode == null) {
+ throw new BadRequestException("The 'destination' parameter '" + destination + "' is not valid, please insert the name of an existing node");
+ }
+ if ((!type.equals("reachability")) && (!type.equals("isolation")) && (!type.equals("traversal"))) {
+ throw new BadRequestException("The 'type' parameter '" + type
+ + "' is not valid: valid types are: 'reachability', 'isolation' and 'traversal'");
+ }
+
+ Verification v = null;
+ String middlebox;
+ Node middleboxNode;
+ switch (type) {
+ case "reachability":
+ v = reachabilityVerification(graph, sourceNode, destinationNode);
+ break;
+ case "isolation":
+ middlebox = verificationBean.getMiddlebox();
+ if (middlebox == null || middlebox.equals("")) {
+ throw new BadRequestException("Please specify the 'middlebox' parameter in your request");
+ }
+
+ middleboxNode = graph.searchNodeByName(middlebox);
+ if (middleboxNode == null) {
+ throw new BadRequestException("The 'middlebox' parameter '" + middlebox + "' is not valid, please insert the name of an existing node");
+ }
+ if (middleboxNode.getFunctional_type().equals("endpoint")) {
+ throw new BadRequestException("'" + middlebox
+ + "' is of type 'endpoint', please choose a valid middlebox");
+ }
+ v = isolationVerification(graph, sourceNode, destinationNode, middleboxNode);
+ break;
+ case "traversal":
+ middlebox = verificationBean.getMiddlebox();
+ if (middlebox == null || middlebox.equals("")) {
+ throw new BadRequestException("Please specify the 'middlebox' parameter in your request");
+ }
+
+ middleboxNode = graph.searchNodeByName(middlebox);
+ if (middleboxNode == null) {
+ throw new BadRequestException("The 'middlebox' parameter '" + middlebox + "' is not valid, please insert the name of an existing node");
+ }
+ if (middleboxNode.getFunctional_type().equals("endpoint")) {
+ throw new BadRequestException("'" + middlebox
+ + "' is of type 'endpoint', please choose a valid middlebox");
+ }
+ v = traversalVerification(graph, sourceNode, destinationNode, middleboxNode);
+ break;
+ default:
+ break;
+ }
+
+ return v;
+ }
+
+ private Verification isolationVerification(Graph graph, Node sourceNode, Node destinationNode, Node middleboxNode) {
+
+ Paths paths = getPaths(graph, sourceNode, destinationNode);
+ if (paths.getPath().size() == 0) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ List<List<String>> sanitizedPaths = sanitizePaths(paths);
+
+ printListsOfStrings("Before loops removal", sanitizedPaths);
+
+ eliminateLoopsInPaths(sanitizedPaths);
+
+ printListsOfStrings("After loops removal", sanitizedPaths);
+
+ if (sanitizedPaths.isEmpty()) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ List<Test> tests = extractTestsFromPaths(graph, sanitizedPaths, "UNKNWON");
+
+ extractPathsWithMiddlebox(sanitizedPaths, middleboxNode.getName());
+
+ if (sanitizedPaths.isEmpty()) {
+ return new Verification("UNSAT",
+ tests,
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "' which traverse middlebox '"
+ + middleboxNode.getName() + "'. See below all the available paths.");
+ }
+
+ printListsOfStrings("Paths with middlebox '" + middleboxNode.getName() + "'", sanitizedPaths);
+
+ File tempDir = null;
+
+ try {
+ tempDir = createTempDir("isolation");
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to perform verification: " + e.getMessage());
+ }
+
+ String chainsFile = tempDir.getAbsolutePath() + "/chains.json";
+ generateChainsFile(graph, sanitizedPaths, chainsFile);
+
+ String configFile = tempDir.getAbsolutePath() + "/config.json";
+ generateConfigFile(graph, configFile);
+
+ String isolationScenariosBasename = tempDir.getAbsolutePath() + "/IsolationScenario";
+ try{
+ generateTestScenarios(chainsFile, configFile, isolationScenariosBasename);
+ }catch(Exception ex){
+ testClassGenerator = generatorFolderForGrpc + "/test_class_generator.py";
+ generateTestScenarios(chainsFile, configFile, isolationScenariosBasename);
+ }
+
+ String isolationTestsBasename = tempDir.getAbsolutePath() + "/IsolationTest";
+ try{
+ generateTests( sanitizedPaths.size(),
+ isolationScenariosBasename,
+ sourceNode.getName(),
+ middleboxNode.getName(),
+ isolationTestsBasename);
+ }catch(InternalServerErrorException ex){
+ testGenerator = generatorFolderForGrpc + "/test_generator.py";
+ generateTests( sanitizedPaths.size(),
+ isolationScenariosBasename,
+ sourceNode.getName(),
+ middleboxNode.getName(),
+ isolationTestsBasename);
+ }
+
+ List<File> sourceFiles = new ArrayList<File>();
+ List<File> classFiles = new ArrayList<File>();
+ prepareForCompilationAndExecution( sanitizedPaths.size(),
+ isolationScenariosBasename,
+ isolationTestsBasename,
+ sourceFiles,
+ classFiles);
+
+ compileFiles(sourceFiles, tempDir.getAbsolutePath());
+
+ tests = runFiles(tempDir.getAbsolutePath(), sanitizedPaths, graph, classFiles);
+
+ return evaluateIsolationResults(tests,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ middleboxNode.getName());
+
+ }
+
+ private List<Test> extractTestsFromPaths(Graph graph, List<List<String>> paths, String result) {
+ List<Test> tests = new ArrayList<Test>();
+ for (List<String> path : paths) {
+ List<Node> nodes = new ArrayList<Node>();
+ for (String nodeName : path) {
+ nodes.add(graph.searchNodeByName(nodeName));
+ }
+ tests.add(new Test(nodes, result));
+ }
+ return tests;
+ }
+
+ private Verification evaluateIsolationResults( List<Test> tests, String source, String destination,
+ String middlebox) {
+ Verification v = new Verification();
+ boolean isSat = false;
+ int unsatCounter = 0;
+ for (Test t : tests) {
+ v.getTests().add(t);
+
+ if (t.getResult().equals("SAT")) {
+ isSat = true;
+ }
+ else if (t.getResult().equals("UNKNOWN")) {
+ v.setResult("UNKNWON");
+ v.setComment("Isolation property with source '" + source + "', destination '" + destination
+ + "' and middlebox '" + middlebox + "' is UNKNOWN because although '" + source
+ + "' cannot reach '" + middlebox + "' in any path from '" + source + "' to '"
+ + destination + "' which traverses middlebox '" + middlebox
+ + "' at least one reachability test between '" + source + "' and '" + middlebox
+ + "' returned UNKNOWN (see below all the paths that have been checked)");
+ }
+ else if (t.getResult().equals("UNSAT")) {
+ unsatCounter++;
+ }
+ }
+ if (isSat) {
+ v.setResult("UNSAT");
+ v.setComment("Isolation property with source '" + source + "', destination '" + destination
+ + "' and middlebox '" + middlebox + "' is UNSATISFIED because reachability between '"
+ + source + "' and '" + middlebox + "' is SATISFIED in at least one path between '" + source
+ + "' and '" + destination + "' which traverses middlebox '" + middlebox
+ + "' (see below all the paths that have been checked)");
+ }
+ else if (unsatCounter == tests.size()) {
+ v.setResult("SAT");
+ v.setComment("Isolation property with source '" + source + "', destination '" + destination
+ + "' and middlebox '" + middlebox + "' is SATISFIED because reachability between '" + source
+ + "' and '" + middlebox + "' is UNSATISFIED in all paths between '" + source + "' and '"
+ + destination + "' which traverse middlebox '" + middlebox
+ + "' (see below all the paths that have been checked)");
+ }
+ return v;
+
+ }
+
+ private void extractPathsWithMiddlebox(List<List<String>> sanitizedPaths, String middleboxName) {
+ List<List<String>> pathsToBeRemoved = new ArrayList<List<String>>();
+ for (List<String> path : sanitizedPaths) {
+ boolean middleboxFound = false;
+ for (String node : path) {
+ if (node.equals(middleboxName)) {
+ middleboxFound = true;
+ break;
+ }
+ }
+ if (!middleboxFound) {
+ pathsToBeRemoved.add(path);
+ }
+ }
+
+ for (List<String> path : pathsToBeRemoved) {
+ sanitizedPaths.remove(path);
+ }
+
+ }
+
+ private void extractPathsWithoutMiddlebox(List<List<String>> sanitizedPaths, String middleboxName) {
+ List<List<String>> pathsToBeRemoved = new ArrayList<List<String>>();
+ for (List<String> path : sanitizedPaths) {
+ boolean middleboxFound = false;
+ for (String node : path) {
+ if (node.equals(middleboxName)) {
+ middleboxFound = true;
+ break;
+ }
+ }
+ if (middleboxFound) {
+ pathsToBeRemoved.add(path);
+ }
+ }
+
+ for (List<String> path : pathsToBeRemoved) {
+ sanitizedPaths.remove(path);
+ }
+
+ }
+
+ private Verification traversalVerification(Graph graph, Node sourceNode, Node destinationNode, Node middleboxNode) {
+
+ Paths paths = getPaths(graph, sourceNode, destinationNode);
+ if (paths.getPath().size() == 0) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ List<List<String>> pathsBetweenSourceAndDestination = sanitizePaths(paths);
+
+ printListsOfStrings("Before loops removal", pathsBetweenSourceAndDestination);
+
+ eliminateLoopsInPaths(pathsBetweenSourceAndDestination);
+
+ printListsOfStrings("After loops removal", pathsBetweenSourceAndDestination);
+
+ if (pathsBetweenSourceAndDestination.isEmpty()) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ List<Test> tests = extractTestsFromPaths(graph, pathsBetweenSourceAndDestination, "UNKNOWN");
+
+ List<List<String>> pathsWithMiddlebox = new ArrayList<List<String>>();
+ for (List<String> path : pathsBetweenSourceAndDestination) {
+ pathsWithMiddlebox.add(path);
+ }
+
+ extractPathsWithMiddlebox(pathsWithMiddlebox, middleboxNode.getName());
+
+ if (pathsWithMiddlebox.isEmpty()) {
+ return new Verification("UNSAT",
+ tests,
+ "There are no paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "' which traverse middlebox '"
+ + middleboxNode.getName() + "'. See below all the available paths");
+ }
+
+ printListsOfStrings("Paths with middlebox '" + middleboxNode.getName() + "'", pathsWithMiddlebox);
+
+ File tempDir = null;
+
+ try {
+ tempDir = createTempDir("traversal");
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to perform verification: " + e.getMessage());
+ }
+
+ String chainsFile = tempDir.getAbsolutePath() + "/chains.json";
+ generateChainsFile(graph, pathsWithMiddlebox, chainsFile);
+
+ String configFile = tempDir.getAbsolutePath() + "/config.json";
+ generateConfigFile(graph, configFile);
+
+ String traversalScenariosBasename = tempDir.getAbsolutePath() + "/TraversalScenario";
+ try{
+ generateTestScenarios(chainsFile, configFile, traversalScenariosBasename);
+ }catch(Exception ex){
+ testClassGenerator = generatorFolderForGrpc + "/test_class_generator.py";
+ generateTestScenarios(chainsFile, configFile, traversalScenariosBasename);
+ }
+
+ String traversalTestsBasename = tempDir.getAbsolutePath() + "/TraversalTest";
+ try{
+ generateTests( pathsWithMiddlebox.size(),
+ traversalScenariosBasename,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ traversalTestsBasename);
+ }catch(InternalServerErrorException ex){
+ testGenerator = generatorFolderForGrpc + "/test_generator.py";
+ generateTests( pathsWithMiddlebox.size(),
+ traversalScenariosBasename,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ traversalTestsBasename);
+ }
+ List<File> sourceFiles = new ArrayList<File>();
+ List<File> classFiles = new ArrayList<File>();
+ prepareForCompilationAndExecution( pathsWithMiddlebox.size(),
+ traversalScenariosBasename,
+ traversalTestsBasename,
+ sourceFiles,
+ classFiles);
+
+ compileFiles(sourceFiles, tempDir.getAbsolutePath());
+
+ tests = runFiles(tempDir.getAbsolutePath(), pathsWithMiddlebox, graph, classFiles);
+
+ for (Test t : tests) {
+ if (t.getResult().equals("UNSAT")) {
+ return new Verification("UNSAT",
+ tests,
+ "There is at least a path between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "' traversing middlebox '"
+ + middleboxNode.getName() + "' where '" + sourceNode.getName()
+ + "' cannot reach '" + destinationNode.getName()
+ + "'. See below the paths that have been checked");
+ }
+ if (t.getResult().equals("UNKNOWN")) {
+ return new Verification("UNKNOWN",
+ tests,
+ "There is at least a path between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "' traversing middlebox '"
+ + middleboxNode.getName() + "' where it is not guaranteed that '"
+ + sourceNode.getName() + "' can effectively reach '"
+ + destinationNode.getName()
+ + "'. See below the paths that have been checked");
+ }
+ }
+
+ extractPathsWithoutMiddlebox(pathsBetweenSourceAndDestination, middleboxNode.getName());
+ printListsOfStrings("Paths without middlebox '" + middleboxNode.getName() + "'", pathsBetweenSourceAndDestination);
+
+ if (pathsBetweenSourceAndDestination.isEmpty()) {
+ return new Verification("SAT",
+ tests,
+ "All the paths between node '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "' traverse middlebox '"
+ + middleboxNode.getName() + "'");
+ }
+
+ tempDir = null;
+
+ try {
+ tempDir = createTempDir("traversal");
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to perform verification: " + e.getMessage());
+ }
+
+ chainsFile = tempDir.getAbsolutePath() + "/chains.json";
+ generateChainsFile(graph, pathsBetweenSourceAndDestination, chainsFile);
+
+ configFile = tempDir.getAbsolutePath() + "/config.json";
+ generateConfigFile(graph, configFile);
+
+ traversalScenariosBasename = tempDir.getAbsolutePath() + "/TraversalScenario";
+ generateTestScenarios(chainsFile, configFile, traversalScenariosBasename);
+
+ traversalTestsBasename = tempDir.getAbsolutePath() + "/TraversalTest";
+ generateTests( pathsBetweenSourceAndDestination.size(),
+ traversalScenariosBasename,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ traversalTestsBasename);
+
+ sourceFiles = new ArrayList<File>();
+ classFiles = new ArrayList<File>();
+ prepareForCompilationAndExecution( pathsBetweenSourceAndDestination.size(),
+ traversalScenariosBasename,
+ traversalTestsBasename,
+ sourceFiles,
+ classFiles);
+
+ compileFiles(sourceFiles, tempDir.getAbsolutePath());
+
+ tests = runFiles(tempDir.getAbsolutePath(), pathsBetweenSourceAndDestination, graph, classFiles);
+
+ return evaluateTraversalResults(tests,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ middleboxNode.getName());
+
+ }
+
+ private Verification evaluateTraversalResults( List<Test> tests, String source, String destination,
+ String middlebox) {
+ Verification v = new Verification();
+ boolean isSat = false;
+ int unsatCounter = 0;
+ for (Test t : tests) {
+ v.getTests().add(t);
+
+ if (t.getResult().equals("SAT")) {
+ isSat = true;
+ }
+ else if (t.getResult().equals("UNKNOWN")) {
+ v.setResult("UNKNWON");
+ v.setComment("There is at least one path from '" + source + "' to '" + destination
+ + "' that doesn't traverse middlebox '" + middlebox
+ + "' (see below all the paths that have been checked)");
+ }
+ else if (t.getResult().equals("UNSAT")) {
+ unsatCounter++;
+ }
+ }
+ if (isSat) {
+ v.setResult("UNSAT");
+ v.setComment("There is at least one path from '" + source + "' to '" + destination
+ + "' that doesn't traverse middlebox '" + middlebox
+ + "' (see below all the paths that have been checked)");
+ }
+ else if (unsatCounter == tests.size()) {
+ v.setResult("SAT");
+ v.setComment("The only available paths from '" + source + "' to '" + destination
+ + "' are those that traverse middlebox '" + middlebox
+ + "' (see below the alternative paths that have been checked and are unusable)");
+ }
+ return v;
+ }
+
+ private Verification reachabilityVerification(Graph graph, Node sourceNode, Node destinationNode) {
+ Paths paths = getPaths(graph, sourceNode, destinationNode);
+
+ if (paths.getPath().size() == 0) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ List<List<String>> sanitizedPaths = sanitizePaths(paths);
+
+ printListsOfStrings("Before loops removal", sanitizedPaths);
+
+ eliminateLoopsInPaths(sanitizedPaths);
+
+ printListsOfStrings("After loops removal", sanitizedPaths);
+
+ if (sanitizedPaths.isEmpty()) {
+ return new Verification("UNSAT",
+ "There are no available paths between '" + sourceNode.getName() + "' and '"
+ + destinationNode.getName() + "'");
+ }
+
+ File tempDir = null;
+
+ try {
+ tempDir = createTempDir("reachability");
+ }
+ catch (IOException e) {
+ throw new InternalServerErrorException("Unable to perform verification: " + e.getMessage());
+ }
+
+ String chainsFile = tempDir.getAbsolutePath() + "/chains.json";
+ generateChainsFile(graph, sanitizedPaths, chainsFile);
+
+ String configFile = tempDir.getAbsolutePath() + "/config.json";
+ generateConfigFile(graph, configFile);
+
+ String reachabilityScenariosBasename = tempDir.getAbsolutePath() + "/ReachabilityScenario";
+ try{
+ generateTestScenarios(chainsFile, configFile, reachabilityScenariosBasename);
+ }catch(InternalServerErrorException ex){
+ testClassGenerator = generatorFolderForGrpc + "/test_class_generator.py";
+ generateTestScenarios(chainsFile, configFile, reachabilityScenariosBasename);
+ }
+
+
+ String reachabilityTestsBasename = tempDir.getAbsolutePath() + "/ReachabilityTest";
+ try{
+ generateTests( sanitizedPaths.size(),
+ reachabilityScenariosBasename,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ reachabilityTestsBasename);
+ }catch(InternalServerErrorException ex){
+ testGenerator = generatorFolderForGrpc + "/test_generator.py";
+ generateTests( sanitizedPaths.size(),
+ reachabilityScenariosBasename,
+ sourceNode.getName(),
+ destinationNode.getName(),
+ reachabilityTestsBasename);
+ }
+ List<File> sourceFiles = new ArrayList<File>();
+ List<File> classFiles = new ArrayList<File>();
+ prepareForCompilationAndExecution( sanitizedPaths.size(),
+ reachabilityScenariosBasename,
+ reachabilityTestsBasename,
+ sourceFiles,
+ classFiles);
+
+ compileFiles(sourceFiles, tempDir.getAbsolutePath());
+
+ List<Test> tests = runFiles(tempDir.getAbsolutePath(), sanitizedPaths, graph, classFiles);
+
+ return evaluateReachabilityResult(tests, sourceNode.getName(), destinationNode.getName());
+ }
+
+ private Verification evaluateReachabilityResult(List<Test> tests, String source, String destination) {
+ Verification v = new Verification();
+ boolean sat = false;
+ int unsat = 0;
+ for (Test t : tests) {
+ v.getTests().add(t);
+
+ if (t.getResult().equals("SAT")) {
+ sat = true;
+ }
+ else if (t.getResult().equals("UNKNOWN")) {
+ v.setResult("UNKNWON");
+ v.setComment("Reachability from '" + source + "' to '" + destination
+ + "' is unknown. See all the checked paths below");
+ }
+ else if (t.getResult().equals("UNSAT")) {
+ unsat++;
+ }
+ }
+ if (sat) {
+ v.setResult("SAT");
+ v.setComment("There is at least one path '" + source + "' can use to reach '" + destination
+ + "'. See all the available paths below");
+ }
+ else if (unsat == tests.size()) {
+ v.setResult("UNSAT");
+ v.setComment("There isn't any path '" + source + "' can use to reach '" + destination
+ + "'. See all the checked paths below");
+ }
+ return v;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/test/MultiThreadedTestCase.java b/verigraph/src/main/java/it/polito/escape/verify/test/MultiThreadedTestCase.java
new file mode 100644
index 0000000..7989b37
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/test/MultiThreadedTestCase.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.ws.rs.core.Response;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import it.polito.escape.verify.client.VerifyClient;
+import it.polito.escape.verify.client.VerifyClientException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+
+public class MultiThreadedTestCase {
+
+ private void testUpdateGraphStatus(final int threadCount) throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ final VerifyClient verifyClient = new VerifyClient("http://localhost:8080/verify/api");
+
+ Response retrieveGraphResponse = verifyClient.retrieveGraph(1);
+ String responseString = retrieveGraphResponse.readEntity(String.class);
+ System.out.println(responseString);
+
+ Graph graph = new ObjectMapper().readValue(responseString, Graph.class);
+
+ UpdateGraph task = new UpdateGraph(verifyClient, 1, graph);
+
+ List<MultiThreadedTestCase.UpdateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<Response>> futures = executorService.invokeAll(tasks);
+ List<Integer> resultList = new ArrayList<Integer>(futures.size());
+
+ // Check for exceptions
+ for (Future<Response> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ resultList.add(future.get().getStatus());
+ }
+ // Validate the dimensions
+ Assert.assertEquals(threadCount, futures.size());
+ List<Integer> expectedList = new ArrayList<Integer>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(200);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private void testUpdateGraph(final int threadCount) throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ final VerifyClient verifyClient = new VerifyClient("http://localhost:8080/verify/api");
+
+ Response retrieveGraphResponse = verifyClient.retrieveGraph(2L);
+ String responseString = retrieveGraphResponse.readEntity(String.class);
+ System.out.println(responseString);
+
+ Graph graph = new ObjectMapper().readValue(responseString, Graph.class);
+
+ Node nodeToEdit = graph.getNodes().get(1L);
+ nodeToEdit.setFunctional_type("endpoint");
+ nodeToEdit.setConfiguration(new Configuration(nodeToEdit.getName(), "", new ObjectMapper().createArrayNode()));
+
+ String graphAsString = new ObjectMapper().writeValueAsString(graph);
+ System.out.println(graphAsString);
+
+ UpdateGraph task = new UpdateGraph(verifyClient, 2, graph);
+
+ List<MultiThreadedTestCase.UpdateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<Response>> futures = executorService.invokeAll(tasks);
+ List<String> resultList = new ArrayList<String>(futures.size());
+
+ // Check for exceptions
+ for (Future<Response> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ resultList.add(future.get().readEntity(String.class));
+ }
+ // Validate dimensions
+ Assert.assertEquals(threadCount, futures.size());
+
+ List<String> expectedList = new ArrayList<String>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(graphAsString);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private void testCreateGraphStatus(final int threadCount, Graph graph) throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException {
+ final VerifyClient verifyClient = new VerifyClient("http://localhost:8080/verify/api");
+
+ CreateGraph task = new CreateGraph(verifyClient, graph);
+
+ List<MultiThreadedTestCase.CreateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<Response>> futures = executorService.invokeAll(tasks);
+ List<Integer> resultList = new ArrayList<Integer>(futures.size());
+
+ // Check for exceptions
+ for (Future<Response> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ resultList.add(future.get().getStatus());
+ }
+ // Validate the IDs
+ Assert.assertEquals(threadCount, futures.size());
+
+ List<Integer> expectedList = new ArrayList<Integer>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(201);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private int randInt(int min, int max){
+ Random rand = new Random();
+ int randomNum = rand.nextInt((max - min) + 1) + min;
+ return randomNum;
+ }
+
+ @Test
+ public void updateGraphStatusCheck() throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ testUpdateGraphStatus(64);
+ }
+
+ @Test
+ public void updateGraphResponseCheck() throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ testUpdateGraph(16);
+ }
+
+ @Test
+ public void createGraphStatusCheck() throws JsonParseException, JsonMappingException, InterruptedException, ExecutionException, IOException {
+ Graph graph = new Graph();
+ testCreateGraphStatus(8, graph);
+ }
+
+ class UpdateGraph implements Callable<Response> {
+
+ private VerifyClient verifyClient;
+
+ private int graphId;
+
+ private Graph graph;
+
+ public UpdateGraph(VerifyClient verifyClient, int graphId, Graph graph) {
+ this.graphId = graphId;
+ this.graph = graph;
+ this.verifyClient = verifyClient;
+ }
+
+ @Override
+ public Response call() throws Exception {
+ Thread.sleep(randInt(0,2000));
+ Response updateGraphResponse = this.verifyClient.updateGraph(this.graphId, this.graph);
+ return updateGraphResponse;
+ }
+ }
+
+ class CreateGraph implements Callable<Response> {
+
+ private VerifyClient verifyClient;
+
+ private Graph graph;
+
+ public CreateGraph(VerifyClient verifyClient, Graph graph) {
+ this.graph = graph;
+ this.verifyClient = verifyClient;
+ }
+
+ @Override
+ public Response call() throws Exception {
+ Thread.sleep(randInt(0,2000));
+ return this.verifyClient.createGraph(this.graph);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/verigraph/src/main/java/it/polito/escape/verify/test/Scalability.java b/verigraph/src/main/java/it/polito/escape/verify/test/Scalability.java
new file mode 100644
index 0000000..3039ca0
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/test/Scalability.java
@@ -0,0 +1,409 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.test;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import it.polito.escape.verify.client.VerifyClient;
+import it.polito.escape.verify.client.VerifyClientException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.model.Verification;
+
+public class Scalability {
+
+ private VerifyClient client = new VerifyClient("http://localhost:8080/verify/api");
+
+ public static void main(String[] args) throws VerifyClientException {
+ Scalability s = new Scalability();
+
+ reachabilityTest(s, 10);
+
+ isolationTest(s,1500);
+ traversalTest(s,600);
+ }
+
+ private static void reachabilityTest(Scalability s, int n) throws VerifyClientException {
+ System.out.printf("Reachability test with N=" + n + ": ");
+ printTimestamp();
+ Graph graph = generateNatScenario(n);
+ Graph createdGraph = s.client.createGraph(graph).readEntity(Graph.class);
+ Verification result = s.client.getReachability(createdGraph.getId(), "client", "server");
+ System.out.println("Test returned " + result.getResult());
+ System.out.printf("Finished reachability test with N=" + n + ": ");
+ printTimestamp();
+ System.out.println();
+ }
+
+ private static void isolationTest(Scalability s, int n) throws VerifyClientException {
+ System.out.printf("Isolation test with N=" + n + ": ");
+ printTimestamp();
+ Graph graph = generateNatScenario(n);
+ Graph createdGraph = s.client.createGraph(graph).readEntity(Graph.class);
+ Verification result = s.client.getIsolation(createdGraph.getId(), "client", "server", "firewall");
+ System.out.println("Test returned " + result.getResult());
+ System.out.printf("Finished isolation test with N=" + n + ": ");
+ printTimestamp();
+ System.out.println();
+ }
+
+ private static void traversalTest(Scalability s, int n) throws VerifyClientException {
+ System.out.printf("Traversal test with N=" + n + ": ");
+ printTimestamp();
+ Graph graph = generateNatScenario(n);
+ Graph createdGraph = s.client.createGraph(graph).readEntity(Graph.class);
+ Verification result = s.client.getTraversal(createdGraph.getId(), "client", "server", "firewall");
+ System.out.println("Test returned " + result.getResult());
+// System.out.println("Result explanation: " + result.getComment());
+ System.out.printf("Finished traversal test with N=" + n + ": ");
+ printTimestamp();
+ System.out.println();
+ }
+
+ private static void printTimestamp() {
+ java.util.Date date= new java.util.Date();
+ System.out.println(new Timestamp(date.getTime()));
+ }
+
+ private static Graph generateNatScenario(int n) {
+ List<Node> nodes = new ArrayList<Node>();
+
+ Node client = new Node();
+ client.setName("client");
+ client.setFunctional_type("endhost");
+ ArrayNode clientConfigArray = new ObjectMapper().createArrayNode();
+ JsonNode clientConfig = new ObjectMapper().createObjectNode();
+ ((ObjectNode)clientConfig).put("url", "www.facebook.com");
+ ((ObjectNode)clientConfig).put("body", "word");
+ ((ObjectNode)clientConfig).put("destination","server");
+ ((ObjectNode)clientConfig).put("protocol", "HTTP_REQUEST");
+ clientConfigArray.add(clientConfig);
+ client.setConfiguration(new Configuration(client.getName(),"", clientConfigArray));
+
+ Map<Long, Neighbour> clientNeighbours = new HashMap<Long, Neighbour>();
+ clientNeighbours.put(1L, new Neighbour(1L, "nat1"));
+ client.setNeighbours(clientNeighbours );
+ //add client to list
+ nodes.add(client);
+
+ for(int i=0; i< n;i++){
+ Node nat = new Node();
+ nat.setId(i+1);
+ nat.setName("nat" + (i+1));
+ nat.setFunctional_type("nat");
+ ArrayNode configArray = new ObjectMapper().createArrayNode();
+
+ Map<Long, Neighbour> natNeighbours = new HashMap<Long, Neighbour>();
+
+ //set left neighbour for each node except the first
+ if(nat.getId() != 1){
+ natNeighbours.put(1L, new Neighbour(1L, "nat" + i));
+ configArray.add("client");
+ for (int j=1; j <= i; j++){
+ configArray.add("nat" + j);
+ }
+ }
+ //first nat: set only client as neighbour and natted node
+ else{
+ natNeighbours.put(1L, new Neighbour(1L, "client"));
+ configArray.add("client");
+ }
+ //set right neighbour for each node except the last
+ if(nat.getId() != n){
+ natNeighbours.put(2L, new Neighbour(1L, "nat" + (i+2)));
+ }
+ //last nat: set server as neighbour
+ else{
+ natNeighbours.put(2L, new Neighbour(1L, "server"));
+ }
+
+ nat.setNeighbours(natNeighbours);
+ nat.setConfiguration(new Configuration(nat.getName(),"", configArray));
+
+ //add nat to list
+ nodes.add(nat);
+ }
+
+ Node server = new Node();
+ server.setName("server");
+ server.setFunctional_type("webserver");
+ ArrayNode serverConfigArray = new ObjectMapper().createArrayNode();
+ server.setConfiguration(new Configuration(server.getName(),"", serverConfigArray));
+
+ Map<Long, Neighbour> serverNeighbours = new HashMap<Long, Neighbour>();
+ serverNeighbours.put(1L, new Neighbour(1L, "nat" + (n)));
+ server.setNeighbours(serverNeighbours );
+
+ //add server to list
+ nodes.add(server);
+
+ //create graph
+ Graph g = new Graph();
+ Map<Long, Node> graphNodes = new HashMap<Long, Node>();
+ long index = 1L;
+ for (Node node : nodes){
+ graphNodes.put(index, node);
+ index++;
+ }
+ g.setNodes(graphNodes);
+
+ return g;
+ }
+
+ private static Graph generateFirewallScenario(int n) {
+ List<Node> nodes = new ArrayList<Node>();
+
+ Node client = new Node();
+ client.setName("client");
+ client.setFunctional_type("endhost");
+ ArrayNode clientConfigArray = new ObjectMapper().createArrayNode();
+ JsonNode clientConfig = new ObjectMapper().createObjectNode();
+ ((ObjectNode)clientConfig).put("url", "www.facebook.com");
+ ((ObjectNode)clientConfig).put("body", "word");
+ ((ObjectNode)clientConfig).put("destination","server");
+ ((ObjectNode)clientConfig).put("protocol", "HTTP_REQUEST");
+ clientConfigArray.add(clientConfig);
+ client.setConfiguration(new Configuration(client.getName(),"", clientConfigArray));
+
+ Map<Long, Neighbour> clientNeighbours = new HashMap<Long, Neighbour>();
+ clientNeighbours.put(1L, new Neighbour(1L, "firewall1"));
+ client.setNeighbours(clientNeighbours );
+ //add client to list
+ nodes.add(client);
+
+ for(int i=0; i< n;i++){
+ Node firewall = new Node();
+ firewall.setId(i+1);
+ firewall.setName("firewall" + (i+1));
+ firewall.setFunctional_type("firewall");
+ ArrayNode configArray = new ObjectMapper().createArrayNode();
+
+ Map<Long, Neighbour> natNeighbours = new HashMap<Long, Neighbour>();
+
+ //set left neighbour for each node except the first
+ if(firewall.getId() != 1){
+ natNeighbours.put(1L, new Neighbour(1L, "firewall" + i));
+ }
+ //first firewall: set only client as neighbour and natted node
+ else{
+ natNeighbours.put(1L, new Neighbour(1L, "client"));
+ }
+ //set right neighbour for each node except the last
+ if(firewall.getId() != n){
+ natNeighbours.put(2L, new Neighbour(1L, "firewall" + (i+2)));
+ }
+ //last firewall: set server as neighbour
+ else{
+ natNeighbours.put(2L, new Neighbour(1L, "server"));
+ }
+
+ firewall.setNeighbours(natNeighbours);
+ firewall.setConfiguration(new Configuration(firewall.getName(),"", configArray));
+
+ //add nat to list
+ nodes.add(firewall);
+ }
+
+ Node server = new Node();
+ server.setName("server");
+ server.setFunctional_type("webserver");
+ ArrayNode serverConfigArray = new ObjectMapper().createArrayNode();
+ server.setConfiguration(new Configuration(server.getName(),"", serverConfigArray));
+
+ Map<Long, Neighbour> serverNeighbours = new HashMap<Long, Neighbour>();
+ serverNeighbours.put(1L, new Neighbour(1L, "firewall" + (n)));
+ server.setNeighbours(serverNeighbours );
+
+ //add server to list
+ nodes.add(server);
+
+ //create graph
+ Graph g = new Graph();
+ Map<Long, Node> graphNodes = new HashMap<Long, Node>();
+ long index = 1L;
+ for (Node node : nodes){
+ graphNodes.put(index, node);
+ index++;
+ }
+ g.setNodes(graphNodes);
+
+ return g;
+ }
+
+ private static Graph generateScenario(int n) {
+ List<Node> nodes = new ArrayList<Node>();
+
+ Node firewall = new Node();
+ firewall.setName("firewall");
+ firewall.setFunctional_type("firewall");
+ ArrayNode firewallConfigArray = new ObjectMapper().createArrayNode();
+ Map<Long, Neighbour> firewallNeighbours = new HashMap<Long, Neighbour>();
+
+ for (int i=0; i < n; i++){
+ if(i!=0){
+ JsonNode firewallEntry = new ObjectMapper().createObjectNode();
+ ((ObjectNode) firewallEntry).put("server", "client" + (i+1));
+ firewallConfigArray.add(firewallEntry);
+ }
+ firewallNeighbours.put(new Long(i+1), new Neighbour(new Long(i+1), "client" + (i+1)));
+ }
+
+ firewallNeighbours.put(new Long(n+1), new Neighbour(new Long(n+1), "server"));
+
+ firewall.setConfiguration(new Configuration(firewall.getName(),"", firewallConfigArray));
+
+
+ firewall.setNeighbours(firewallNeighbours );
+ //add client to list
+ nodes.add(firewall);
+
+ for(int i=0; i< n;i++){
+ Node client = new Node();
+ client.setId(i+1);
+ client.setName("client" + (i+1));
+ client.setFunctional_type("endhost");
+ ArrayNode clientConfigArray = new ObjectMapper().createArrayNode();
+ JsonNode clientConfig = new ObjectMapper().createObjectNode();
+ ((ObjectNode)clientConfig).put("url", "www.facebook.com");
+ ((ObjectNode)clientConfig).put("body", "word");
+ ((ObjectNode)clientConfig).put("destination","server");
+ ((ObjectNode)clientConfig).put("protocol", "HTTP_REQUEST");
+ clientConfigArray.add(clientConfig);
+
+ Map<Long, Neighbour> clientNeighbours = new HashMap<Long, Neighbour>();
+
+ clientNeighbours.put(1L, new Neighbour(1L, "firewall"));
+
+ client.setNeighbours(clientNeighbours);
+ client.setConfiguration(new Configuration(client.getName(),"", clientConfigArray));
+
+ //add client to list
+ nodes.add(client);
+ }
+
+ Node server = new Node();
+ server.setName("server");
+ server.setFunctional_type("webserver");
+ ArrayNode serverConfigArray = new ObjectMapper().createArrayNode();
+ server.setConfiguration(new Configuration(server.getName(),"", serverConfigArray));
+
+ Map<Long, Neighbour> serverNeighbours = new HashMap<Long, Neighbour>();
+ serverNeighbours.put(1L, new Neighbour(1L, "firewall"));
+ server.setNeighbours(serverNeighbours );
+
+ //add server to list
+ nodes.add(server);
+
+ //create graph
+ Graph g = new Graph();
+ Map<Long, Node> graphNodes = new HashMap<Long, Node>();
+ long index = 1L;
+ for (Node node : nodes){
+ graphNodes.put(index, node);
+ index++;
+ }
+ g.setNodes(graphNodes);
+
+ return g;
+ }
+
+ private static Graph generateDpiScenario(int n) {
+ List<Node> nodes = new ArrayList<Node>();
+
+ Node client = new Node();
+ client.setName("client");
+ client.setFunctional_type("endhost");
+ ArrayNode clientConfigArray = new ObjectMapper().createArrayNode();
+ JsonNode clientConfig = new ObjectMapper().createObjectNode();
+ ((ObjectNode)clientConfig).put("url", "www.facebook.com");
+ ((ObjectNode)clientConfig).put("body", "word");
+ ((ObjectNode)clientConfig).put("destination","server");
+ ((ObjectNode)clientConfig).put("protocol", "HTTP_REQUEST");
+ clientConfigArray.add(clientConfig);
+ client.setConfiguration(new Configuration(client.getName(),"", clientConfigArray));
+
+ Map<Long, Neighbour> clientNeighbours = new HashMap<Long, Neighbour>();
+ clientNeighbours.put(1L, new Neighbour(1L, "dpi1"));
+ client.setNeighbours(clientNeighbours );
+ //add client to list
+ nodes.add(client);
+
+ for(int i=0; i< n;i++){
+ Node dpi = new Node();
+ dpi.setId(i+1);
+ dpi.setName("dpi" + (i+1));
+ dpi.setFunctional_type("dpi");
+ ArrayNode configArray = new ObjectMapper().createArrayNode();
+ configArray.add("drug");
+
+ Map<Long, Neighbour> natNeighbours = new HashMap<Long, Neighbour>();
+
+ //set left neighbour for each node except the first
+ if(dpi.getId() != 1){
+ natNeighbours.put(1L, new Neighbour(1L, "dpi" + i));
+ }
+ //first firewall: set only client as neighbour and natted node
+ else{
+ natNeighbours.put(1L, new Neighbour(1L, "client"));
+ }
+ //set right neighbour for each node except the last
+ if(dpi.getId() != n){
+ natNeighbours.put(2L, new Neighbour(1L, "dpi" + (i+2)));
+ }
+ //last firewall: set server as neighbour
+ else{
+ natNeighbours.put(2L, new Neighbour(1L, "server"));
+ }
+
+ dpi.setNeighbours(natNeighbours);
+ dpi.setConfiguration(new Configuration(dpi.getName(),"", configArray));
+
+ //add nat to list
+ nodes.add(dpi);
+ }
+
+ Node server = new Node();
+ server.setName("server");
+ server.setFunctional_type("webserver");
+ ArrayNode serverConfigArray = new ObjectMapper().createArrayNode();
+ server.setConfiguration(new Configuration(server.getName(),"", serverConfigArray));
+
+ Map<Long, Neighbour> serverNeighbours = new HashMap<Long, Neighbour>();
+ serverNeighbours.put(1L, new Neighbour(1L, "dpi" + (n)));
+ server.setNeighbours(serverNeighbours );
+
+ //add server to list
+ nodes.add(server);
+
+ //create graph
+ Graph g = new Graph();
+ Map<Long, Node> graphNodes = new HashMap<Long, Node>();
+ long index = 1L;
+ for (Node node : nodes){
+ graphNodes.put(index, node);
+ index++;
+ }
+ g.setNodes(graphNodes);
+
+ return g;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/test/TestCase.java b/verigraph/src/main/java/it/polito/escape/verify/test/TestCase.java
new file mode 100644
index 0000000..a4c85ab
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/test/TestCase.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import it.polito.escape.verify.model.Graph;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "id", "name", "description", "policy_url_parameters", "result", "graph" })
+public class TestCase {
+
+ @JsonProperty("id")
+ private Integer id;
+
+ @JsonProperty("name")
+ private String name;
+
+ @JsonProperty("description")
+ private String description;
+
+ @JsonProperty("policy_url_parameters")
+ private String policyUrlParameters;
+
+ @JsonProperty("result")
+ private String result;
+
+ @JsonProperty("graph")
+ private Graph graph;
+
+ @JsonIgnore
+ private Map<String, Object> additionalProperties = new HashMap<String, Object>();
+
+ /**
+ * @return The id
+ */
+ @JsonProperty("id")
+ public Integer getId() {
+ return id;
+ }
+
+ /**
+ * @param id
+ * The id
+ */
+ @JsonProperty("id")
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ /**
+ * @return The name
+ */
+ @JsonProperty("name")
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name
+ * The name
+ */
+ @JsonProperty("name")
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return The description
+ */
+ @JsonProperty("description")
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @param description
+ * The description
+ */
+ @JsonProperty("description")
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * @return The policyUrlParameters
+ */
+ @JsonProperty("policy_url_parameters")
+ public String getPolicyUrlParameters() {
+ return policyUrlParameters;
+ }
+
+ /**
+ * @param policyUrlParameters
+ * The policy_url_parameters
+ */
+ @JsonProperty("policy_url_parameters")
+ public void setPolicyUrlParameters(String policyUrlParameters) {
+ this.policyUrlParameters = policyUrlParameters;
+ }
+
+ /**
+ * @return The result
+ */
+ @JsonProperty("result")
+ public String getResult() {
+ return result;
+ }
+
+ /**
+ * @param result
+ * The result
+ */
+ @JsonProperty("result")
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ /**
+ * @return The graph
+ */
+ @JsonProperty("graph")
+ public Graph getGraph() {
+ return graph;
+ }
+
+ /**
+ * @param graph
+ * The graph
+ */
+ @JsonProperty("graph")
+ public void setGraph(Graph graph) {
+ this.graph = graph;
+ }
+
+ @JsonAnyGetter
+ public Map<String, Object> getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/test/TestExecutionException.java b/verigraph/src/main/java/it/polito/escape/verify/test/TestExecutionException.java
new file mode 100644
index 0000000..8babe7b
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/test/TestExecutionException.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.test;
+
+
+public class TestExecutionException extends Exception{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4749065055436886197L;
+
+ public TestExecutionException(String message){
+ super(message);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/test/Tester.java b/verigraph/src/main/java/it/polito/escape/verify/test/Tester.java
new file mode 100644
index 0000000..4b85e1e
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/test/Tester.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ResponseProcessingException;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.main.JsonSchema;
+
+import it.polito.escape.verify.client.VerifyClient;
+import it.polito.escape.verify.client.VerifyClientException;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Verification;
+import it.polito.escape.verify.service.ValidationUtils;
+
+public class Tester {
+
+ private File schema;
+
+ private List<File> testFiles = new ArrayList<File>();
+
+ private List<TestCase> testCases = new ArrayList<TestCase>();
+
+ private String target;
+
+ private VerifyClient verifyClient;
+
+ public Tester(String target, File schema, File folder) throws JsonParseException, JsonMappingException, IOException,
+ Exception {
+ init(target, schema, folder);
+ }
+
+ private void init(String target, File schema, File folder) throws JsonParseException, JsonMappingException,
+ IOException, Exception {
+ this.target = target;
+ this.verifyClient = new VerifyClient(this.target);
+ this.schema = schema;
+ this.testFiles = getTests(folder);
+ this.testCases = getTestCases(this.testFiles);
+ }
+
+ public List<File> getTests(File folder) {
+ List<File> filesList = new ArrayList<File>();
+
+ System.out.println("Test folder set to '" + folder.getAbsolutePath() + "'");
+
+ File[] files = folder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".json");
+ }
+ });
+
+ for (File f : files) {
+ filesList.add(f);
+ System.out.println("File '" + f.getName() + "' added to test files");
+ }
+
+ return filesList;
+ }
+
+ public List<TestCase> getTestCases(List<File> files) throws JsonParseException, JsonMappingException, IOException,
+ Exception {
+ List<TestCase> testCases = new ArrayList<TestCase>();
+
+ for (File file : files) {
+ validateTestFile(file);
+ try {
+ TestCase tc = new ObjectMapper().readValue(file, TestCase.class);
+ testCases.add(tc);
+ }
+ catch (Exception e) {
+ throw e;
+ }
+ }
+
+ return testCases;
+ }
+
+ private void runTestCases() throws VerifyClientException, TestExecutionException {
+ int counter = 0;
+ for (TestCase tc : this.testCases) {
+ String result = runTestCase(tc);
+ if (!result.equals(tc.getResult()))
+ throw new TestExecutionException("Error running test given in file '" + this.testFiles.get(counter).getName()
+ + "'. Test returned '" + result + "' instead of '" + tc.getResult() + "'.");
+ else
+ System.out.println("Test given in file '" + this.testFiles.get(counter).getName() + "' returned '"
+ + result + "' as expected");
+ counter++;
+ }
+ System.out.println("All tests PASSED");
+ }
+
+ private String runTestCase(TestCase tc) throws VerifyClientException, TestExecutionException{
+ Client client = ClientBuilder.newClient();
+
+ Graph graph = tc.getGraph();
+ Response response = null;
+ try{
+ response = this.verifyClient.createGraph(graph);
+ }
+ catch(ResponseProcessingException e){
+ throw new TestExecutionException("Response processing has failed: " + e.getResponse().readEntity(String.class));
+ }
+ catch(javax.ws.rs.ProcessingException e){
+ throw new TestExecutionException("HTTP request failed");
+ }
+ Graph createdGraph = response.readEntity(Graph.class);
+ String urlParams = tc.getPolicyUrlParameters();
+ WebTarget target = client.target(this.target + "/graphs/" + createdGraph.getId() + "/policy" + urlParams);
+
+ response = target.request().get();
+ Verification verification = response.readEntity(Verification.class);
+ return verification.getResult();
+ }
+
+ public void validateTestFile(File testFile) throws Exception {
+ JsonSchema schemaNode = null;
+ try {
+ schemaNode = ValidationUtils.getSchemaNode(schema);
+ }
+ catch (IOException e) {
+ throw new Exception("Unable to load '" + schema.getAbsolutePath() + "' schema file");
+ }
+ catch (ProcessingException e) {
+ throw new Exception("Unable to resolve '" + schema.getAbsolutePath() + "' schema file as a schema node");
+ }
+
+ JsonNode jsonNode;
+ try {
+ jsonNode = ValidationUtils.getJsonNode(testFile);
+ }
+ catch (IOException e) {
+ throw new Exception("Unable to load '" + testFile.getAbsolutePath() + "' as a json node");
+ }
+
+ try {
+ ValidationUtils.validateJson(schemaNode, jsonNode);
+ }
+ catch (ProcessingException e) {
+ throw new Exception("There were errors in the validation of file '" + testFile.getAbsolutePath()
+ + "' against the json schema '" + schema.getAbsolutePath() + "': " + e.getMessage());
+
+ }
+ }
+
+ public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException,
+ VerifyClientException, Exception {
+ String folderName = System.getProperty("user.dir") + "/tester/testcases";
+ File folder = new File(folderName);
+ if (!folder.exists()) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String s;
+ do{
+ System.out.println("Please enter the testcases folder path: ");
+ s = in.readLine();
+ if (isValidpath(s)){
+ folder = new File(s);
+ break;
+ }
+ }while (s != null && s.length() != 0);
+ if(s == null)
+ System.exit(0);
+ }
+ String schemaName = System.getProperty("user.dir") + "/tester/testcase_schema.json";
+ File schema = new File(schemaName);
+ if (!schema.exists()) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String s;
+ do{
+ System.out.println("Please enter the full path of 'testcase_schema.json': ");
+ s = in.readLine();
+ if (isValidpath(s)){
+ folder = new File(s);
+ break;
+ }
+ }while (s != null && s.length() != 0);
+ if(s == null)
+ System.exit(0);
+ }
+
+ Tester tester = new Tester("http://localhost:8080/verify/api", schema, folder);
+
+ tester.runTestCases();
+
+ }
+
+ private static boolean isValidpath(String s) {
+ if (s==null)
+ return false;
+ File file = new File(s);
+ return file.exists();
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/DpiValidator.java b/verigraph/src/main/java/it/polito/escape/verify/validation/DpiValidator.java
new file mode 100644
index 0000000..2666755
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/DpiValidator.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.validation.exception.ValidationException;
+
+public class DpiValidator implements ValidationInterface {
+
+ public DpiValidator(){
+
+ }
+
+ private void validateKey(String key) throws ValidationException {
+ if (!key.matches("\\w+"))
+ throw new ValidationException("'" + key + "' is not a valid configuration string for a 'dpi'");
+ }
+
+ @Override
+ public void validate(Graph graph, Node node, Configuration configuration) throws ValidationException {
+
+ JsonNode conf = configuration.getConfiguration();
+
+ if (!conf.isArray()) {
+ throw new ValidationException("Configuration of a 'dpi' must be an array");
+ }
+ for (JsonNode key : conf) {
+ if (!key.isTextual())
+ throw new ValidationException("Configuration of a 'dpi' must be an array of strings");
+ validateKey(key.asText());
+ }
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/EndhostValidator.java b/verigraph/src/main/java/it/polito/escape/verify/validation/EndhostValidator.java
new file mode 100644
index 0000000..3d9eb75
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/EndhostValidator.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation;
+
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.validation.exception.ValidationException;
+
+
+public class EndhostValidator implements ValidationInterface {
+
+ @Override
+ public void validate(Graph graph, Node node, Configuration configuration) throws ValidationException {
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/ValidationInterface.java b/verigraph/src/main/java/it/polito/escape/verify/validation/ValidationInterface.java
new file mode 100644
index 0000000..25608dd
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/ValidationInterface.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation;
+
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.validation.exception.ValidationException;
+
+public interface ValidationInterface {
+
+ void validate(Graph graph, Node node, Configuration configuration) throws ValidationException;
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/VpnaccessValidator.java b/verigraph/src/main/java/it/polito/escape/verify/validation/VpnaccessValidator.java
new file mode 100644
index 0000000..6abd603
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/VpnaccessValidator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.validation.exception.ValidationException;
+
+public class VpnaccessValidator implements ValidationInterface {
+
+ @Override
+ public void validate(Graph graph, Node node, Configuration configuration) throws ValidationException {
+ JsonNode configurationNode = configuration.getConfiguration();
+
+ if (!configurationNode.isArray())
+ throw new ValidationException("configuration must be an array");
+
+ for (JsonNode object : configurationNode) {
+ JsonNode vpnexit = object.get("vpnexit");
+ if (!vpnexit.isTextual())
+ throw new ValidationException("value corresponding to the key 'vpnexit' must be a string");
+ validateObject(graph, node, vpnexit.asText());
+ }
+
+ }
+
+ private void validateObject(Graph g, Node node, String field) throws ValidationException {
+ boolean isValid = false;
+ for (Node n : g.getNodes().values()) {
+ if ((n.getFunctional_type().equals("vpnexit")) && (n.getName().equals(field)))
+ isValid = true;
+ }
+
+ if (!isValid)
+ throw new ValidationException("'" + field + "' is not a valid value for the configuration of a type '"
+ + node.getFunctional_type()
+ + "'. Please use the name of an existing node of type 'vpnexit'.");
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/VpnexitValidator.java b/verigraph/src/main/java/it/polito/escape/verify/validation/VpnexitValidator.java
new file mode 100644
index 0000000..782e124
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/VpnexitValidator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.validation.exception.ValidationException;
+
+public class VpnexitValidator implements ValidationInterface {
+
+ @Override
+ public void validate(Graph graph, Node node, Configuration configuration) throws ValidationException {
+ JsonNode configurationNode = configuration.getConfiguration();
+
+ if (!configurationNode.isArray())
+ throw new ValidationException("configuration must be an array");
+
+ for (JsonNode object : configurationNode) {
+ JsonNode vpnexit = object.get("vpnaccess");
+ if (!vpnexit.isTextual())
+ throw new ValidationException("value corresponding to the key 'vpnaccess' must be a string");
+ validateObject(graph, node, vpnexit.asText());
+ }
+
+ }
+
+ private void validateObject(Graph g, Node node, String field) throws ValidationException {
+ boolean isValid = false;
+ for (Node n : g.getNodes().values()) {
+ if ((n.getFunctional_type().equals("vpnaccess")) && (n.getName().equals(field)))
+ isValid = true;
+ }
+
+ if (!isValid)
+ throw new ValidationException("'" + field + "' is not a valid value for the configuration of a type '"
+ + node.getFunctional_type()
+ + "'. Please use the name of an existing node of type 'vpnaccess'.");
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/escape/verify/validation/exception/ValidationException.java b/verigraph/src/main/java/it/polito/escape/verify/validation/exception/ValidationException.java
new file mode 100644
index 0000000..8b94748
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/escape/verify/validation/exception/ValidationException.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.escape.verify.validation.exception;
+
+
+public class ValidationException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8251271078519549101L;
+
+ private String message;
+
+ public ValidationException(String message){
+// super(message);
+ this.message = message;
+ }
+
+ @Override
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/Client.java b/verigraph/src/main/java/it/polito/grpc/Client.java
new file mode 100644
index 0000000..adc16da
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/Client.java
@@ -0,0 +1,550 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.google.protobuf.Message;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.StatusRuntimeException;
+import io.grpc.verigraph.ConfigurationGrpc;
+import io.grpc.verigraph.GetRequest;
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NeighbourGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.NewNeighbour;
+import io.grpc.verigraph.NewNode;
+import io.grpc.verigraph.NodeGrpc;
+import io.grpc.verigraph.NodeGrpc.FunctionalType;
+import io.grpc.verigraph.Policy;
+import io.grpc.verigraph.Policy.PolicyType;
+import io.grpc.verigraph.RequestID;
+import io.grpc.verigraph.Status;
+import io.grpc.verigraph.TestGrpc;
+import io.grpc.verigraph.VerificationGrpc;
+import io.grpc.verigraph.VerigraphGrpc;
+
+public class Client {
+
+ private final ManagedChannel channel;
+ private final VerigraphGrpc.VerigraphBlockingStub blockingStub;
+
+ public Client(String host, int port) {
+ this(ManagedChannelBuilder.forAddress(host, port).usePlaintext(true));
+ }
+
+ /** Construct client for accessing RouteGuide server using the existing channel. */
+ public Client(ManagedChannelBuilder<?> channelBuilder) {
+ channel = channelBuilder.build();
+ blockingStub = VerigraphGrpc.newBlockingStub(channel);
+ }
+
+ /** Get array of graphs */
+ public List<GraphGrpc> getGraphs() {
+ List<GraphGrpc> graphsRecveived = new ArrayList<GraphGrpc>();
+ GetRequest request = GetRequest.newBuilder().build();
+ Iterator<GraphGrpc> graphs;
+ try {
+ graphs = blockingStub.getGraphs(request);
+ while (graphs.hasNext()) {
+ GraphGrpc graph = graphs.next();
+ System.out.println("Graph id : "+graph.getId());
+ if(graph.getErrorMessage().equals("")){
+ System.out.println("Node id : "+graph.getId());
+ graphsRecveived.add(graph);
+ }else{
+ System.out.println("Error : " + graph.getErrorMessage());
+ return graphsRecveived;
+ }
+ }
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ }
+ return graphsRecveived;
+ }
+
+ /** Create new Graph */
+ public NewGraph createGraph(GraphGrpc gr) {
+ NewGraph response;
+ try {
+ response = blockingStub.createGraph(gr);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewGraph.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Delete a Graph */
+ public boolean deleteGraph(long idGraph) {
+
+ RequestID id = RequestID.newBuilder().setIdGraph(idGraph).build();
+ Status response;
+ try {
+ response = blockingStub.deleteGraph(id);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ return true;
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ }
+ return false;
+ }
+
+ /** Edits a single graph */
+ public NewGraph updateGraph(long idGraph, GraphGrpc newGraph) {
+
+ GraphGrpc gr = GraphGrpc.newBuilder(newGraph).setId(idGraph).build();
+ NewGraph response;
+ try {
+ response = blockingStub.updateGraph(gr);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewGraph.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Get a single graph*/
+ public GraphGrpc getGraph(long idGraph) {
+
+ RequestID request = RequestID.newBuilder().setIdGraph(idGraph).build() ;
+ try {
+ GraphGrpc graph = blockingStub.getGraph(request);
+ if(!graph.getErrorMessage().equals("")){
+ System.out.println("Error in operation: " + graph.getErrorMessage());
+ }
+ return graph;
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ return null;
+ }
+ }
+
+ /** Verify a given policy*/
+ public VerificationGrpc verify(Policy policy) {
+
+ VerificationGrpc response;
+ try {
+ response = blockingStub.verifyPolicy(policy);
+ if(!response.getErrorMessage().equals("")){
+ System.out.println("Error in operation: " + response.getErrorMessage());
+ }
+ System.out.println("Result : "+response.getResult());
+ System.out.println("Comment : "+response.getComment());
+ //uncomment if you want to print the paths
+ /*for(TestGrpc test:response.getTestList()){
+ System.out.println("Test : "+test.getResult()+". Traversed nodes:");
+ for(NodeGrpc node:test.getNodeList()){
+ //prints only the name
+ System.out.println("Node "+node.getName());
+ }
+ }*/
+ return response;
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return null;
+ }
+ }
+
+ /*Node part*/
+
+ /** Get array of nodes */
+ public List<NodeGrpc> getNodes(long idGraph) {
+ List<NodeGrpc> nodesReceived = new ArrayList<NodeGrpc>();
+ RequestID request = RequestID.newBuilder().setIdGraph(idGraph).build() ;
+ Iterator<NodeGrpc> nodes;
+ try {
+ nodes = blockingStub.getNodes(request);
+ while (nodes.hasNext()) {
+ NodeGrpc node = nodes.next();
+ if(node.getErrorMessage().equals("")){
+ System.out.println("Node id : "+node.getId());
+ nodesReceived.add(node);
+ }else{
+ System.out.println("Error : " + node.getErrorMessage());
+ return nodesReceived;
+ }
+ }
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ }
+ return nodesReceived;
+ }
+
+ /** Create new Node */
+ public NewNode createNode(NodeGrpc node, long idGraph) {
+
+ NewNode response;
+ try {
+ NodeGrpc n = NodeGrpc.newBuilder(node).setIdGraph(idGraph).build();
+ response = blockingStub.createNode(n);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewNode.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Delete a Node */
+ public boolean deleteNode(long idGraph, long idNode) {
+
+ RequestID id = RequestID.newBuilder().setIdGraph(idGraph).setIdNode(idNode).build();
+ Status response;
+ try {
+ response = blockingStub.deleteNode(id);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ return true;
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ }
+ return false;
+ }
+
+ /** Edits a single Node */
+ public NewNode updateNode(long idGraph, long idNode, NodeGrpc node) {
+
+ NodeGrpc nu = NodeGrpc.newBuilder(node).setIdGraph(idGraph).setId(idNode).build();
+ NewNode response;
+ try {
+ response = blockingStub.updateNode(nu);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewNode.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Get a single Node*/
+ public NodeGrpc getNode(long idGraph, long idNode) {
+
+ RequestID request = RequestID.newBuilder().setIdGraph(idGraph).setIdNode(idNode).build() ;
+ try {
+ NodeGrpc node = blockingStub.getNode(request);
+ if(!node.getErrorMessage().equals("")){
+ System.out.println("Error in operation: " + node.getErrorMessage());
+ }
+ return node;
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ return null;
+ }
+ }
+
+ /** Configure a single Node*/
+ public boolean configureNode(long idGraph, long idNode, ConfigurationGrpc configuration) {
+
+ try {
+ ConfigurationGrpc request = ConfigurationGrpc.newBuilder(configuration)
+ .setIdGraph(idGraph).setIdNode(idNode).build() ;
+
+ Status response = blockingStub.configureNode(request);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ return true;
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ }
+ return false;
+ }
+
+ /*Neighbour part*/
+
+ /** Get array of neighbours */
+ public List<NeighbourGrpc> getNeighbours(long idGraph, long idNode) {
+
+ List<NeighbourGrpc> neighboursReceived = new ArrayList<NeighbourGrpc>();
+ RequestID request = RequestID.newBuilder().setIdGraph(idGraph).setIdNode(idNode).build() ;
+ Iterator<NeighbourGrpc> neighbours;
+ try {
+ neighbours = blockingStub.getNeighbours(request);
+ while (neighbours.hasNext()) {
+ NeighbourGrpc neighbour = neighbours.next();
+ if(neighbour.getErrorMessage().equals("")){
+ System.out.println("Neighbour id : "+neighbour.getId());
+ neighboursReceived.add(neighbour);
+ }else{
+ System.out.println("Error : " + neighbour.getErrorMessage());
+ return neighboursReceived;
+ }
+ }
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ }
+ return neighboursReceived;
+ }
+
+ /** Create new Neighbour */
+ public NewNeighbour createNeighbour(NeighbourGrpc neighbour, long idGraph, long idNode) {
+
+ NewNeighbour response;
+ try {
+ NeighbourGrpc n = NeighbourGrpc.newBuilder(neighbour).setIdGraph(idGraph)
+ .setIdNode(idNode).build();
+ response = blockingStub.createNeighbour(n);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewNeighbour.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Delete a Neighbour */
+ public boolean deleteNeighbour(long idGraph, long idNode, long idNeighbour) {
+
+ RequestID id = RequestID.newBuilder().setIdGraph(idGraph).setIdNode(idNode).setIdNeighbour(idNeighbour).build();
+ Status response;
+ try {
+ response = blockingStub.deleteNeighbour(id);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ return true;
+ }else{
+ System.out.println("Unsuccesful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ }
+ return false;
+ }
+
+ /** Edits a single Neighbour */
+ public NewNeighbour updateNeighbour(long idGraph, long idNode, long idNeighbour, NeighbourGrpc neighbour) {
+
+ NeighbourGrpc nu = NeighbourGrpc.newBuilder(neighbour).setIdGraph(idGraph).setIdNode(idNode)
+ .setId(idNeighbour).build();
+ NewNeighbour response;
+ try {
+ response = blockingStub.updateNeighbour(nu);
+ if(response.getSuccess()){
+ System.out.println("Successful operation ");
+ }else{
+ System.out.println("Unsuccessful operation: " + response.getErrorMessage());
+ }
+ } catch (StatusRuntimeException e) {
+ System.err.println("RPC failed: " + e.getStatus());
+ return NewNeighbour.newBuilder().setSuccess(false).build();
+ }
+ return response;
+ }
+
+ /** Get a single Neighbour*/
+ public NeighbourGrpc getNeighbour(long idGraph, long idNode, long idNeighbour) {
+
+ RequestID request = RequestID.newBuilder().setIdGraph(idGraph).setIdNode(idNode).setIdNeighbour(idNeighbour).build() ;
+ try {
+ NeighbourGrpc neighbour = blockingStub.getNeighbour(request);
+ if(!neighbour.getErrorMessage().equals("")){
+ System.out.println("Error in operation: " + neighbour.getErrorMessage());
+ }
+ return neighbour;
+ } catch (StatusRuntimeException ex) {
+ System.err.println("RPC failed: " + ex.getStatus());
+ return null;
+ }
+ }
+
+ public void shutdown() throws InterruptedException {
+ channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /** Test on the Server. */
+ public static void main(String[] args) throws Exception {
+
+ List<Long> listGraph = new ArrayList<Long>(); //list of ID
+
+ Client client = new Client("localhost" , 50051);
+ try {
+ NodeGrpc node1 = createNodeGrpc("Node1", "endhost", null, null);
+ List<NeighbourGrpc> neighbours = new ArrayList<NeighbourGrpc>();
+ NeighbourGrpc nb = createNeighbourGrpc("Node1");
+ neighbours.add(nb);
+ NodeGrpc node2 = createNodeGrpc("Node2", "endpoint", neighbours, null);
+ List<NodeGrpc> nodes = new ArrayList<NodeGrpc>();
+ nodes.add(node1);
+ nodes.add(node2);
+
+ GraphGrpc graph = createGraphGrpc(nodes);
+
+ NewGraph createdGraph = client.createGraph(graph);
+ if(createdGraph.getSuccess() == true){
+ listGraph.add(createdGraph.getGraph().getId());
+ System.out.println("Created graph with id :"+ createdGraph.getGraph().getId());
+ }
+
+ client.getGraphs();
+ } catch(Exception ex){
+ System.out.println("Error: " + ex.getMessage());
+ ex.printStackTrace();
+ }finally {
+ client.shutdown();
+ }
+ }
+
+ public static NeighbourGrpc createNeighbourGrpc(String name){
+ return NeighbourGrpc.newBuilder().setName(name).build();
+ }
+
+ public static NodeGrpc createNodeGrpc(String name, String functionalType, List<NeighbourGrpc> neighbours, ConfigurationGrpc conf) throws Exception{
+ NodeGrpc.Builder nb = NodeGrpc.newBuilder();
+
+ if(name != null)
+ nb.setName(name);
+ else
+ throw new Exception("Node must have a name");
+
+ if(functionalType != null)
+ nb.setFunctionalType(FunctionalType.valueOf(functionalType));
+ else
+ throw new Exception("Node must have a functional type");
+
+ if( neighbours!= null){
+ for(NeighbourGrpc value:neighbours)
+ nb.addNeighbour(value);
+ }
+ if(conf == null){
+ try{
+ conf = createConfigurationGrpc(null, null, null, null);
+ }catch(Exception e){
+ throw new Exception(e.getMessage());
+ }
+ }
+ nb.setConfiguration(conf);
+ return nb.build();
+ }
+
+ public static GraphGrpc createGraphGrpc(List<NodeGrpc> nodes){
+ GraphGrpc.Builder gb = GraphGrpc.newBuilder();
+ if(nodes != null){
+ for(NodeGrpc value:nodes)
+ gb.addNode(value);
+ }
+ return gb.build();
+ }
+
+ public static Policy createPolicy(String src, String dst, String type, String middlebox, long idGraph) throws IllegalArgumentException{
+ if(!validMiddlebox(type, middlebox))
+ throw new IllegalArgumentException("Not valid middlebox valid with this type");
+ Policy.Builder policy = Policy.newBuilder();
+ policy.setIdGraph(idGraph);
+ if(src != null)
+ policy.setSource(src);
+ else{
+ throw new IllegalArgumentException("Please insert source field");
+ }
+ if(dst != null)
+ policy.setDestination(dst);
+ else{
+ throw new IllegalArgumentException("Please insert destination field");
+ }
+ if(type != null)
+ policy.setType(PolicyType.valueOf(type));
+ if(middlebox != null)
+ policy.setMiddlebox(middlebox);
+ return policy.build();
+ }
+
+ public static ConfigurationGrpc createConfigurationGrpc(Map<String,String> parameters, List<String> lists, String id, String description) throws Exception{
+ ConfigurationGrpc.Builder cb = ConfigurationGrpc.newBuilder();
+ StringBuilder sb = new StringBuilder("[");
+ if(parameters != null && lists == null){
+ int i = 0;
+ sb.append("{");
+ for (String key: parameters.keySet()) {
+ sb.append("\"");
+ sb.append(key);
+ sb.append("\":\"");
+ sb.append(parameters.get(key));
+ sb.append("\"");
+ if((i+1)<parameters.keySet().size()){
+ sb.append(", ");
+ }
+ i++;
+ }
+ sb.append("}");
+ }
+ else if(parameters == null && lists != null){
+ int i = 0;
+ for (String value: lists) {
+ sb.append("\"");
+ sb.append(value);
+ sb.append("\"");
+ if((i+1)<lists.size()){
+ sb.append(", ");
+ }
+ i++;
+ }
+ }
+ else if(parameters != null && lists != null){
+ throw new Exception("Error, configuration must contains or a sequence name:value or sequence"
+ + "of string, but not both");
+ }
+ sb.append("]");
+ cb.setConfiguration(sb.toString());
+ if(id != null)
+ cb.setId(id);
+ if(description != null)
+ cb.setDescription(description);
+ return cb.build();
+ }
+
+ private static boolean validMiddlebox(String type, String middlebox) {
+ if(type == null)
+ return false;
+ if(type.equals("reachability") && (middlebox == null || middlebox.equals("")))
+ return true;
+ if(type.equals("isolation") && !(middlebox == null || middlebox.equals("")))
+ return true;
+ if(type.equals("traversal") && !(middlebox == null || middlebox.equals("")))
+ return true;
+ return false;
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/GrpcUtils.java b/verigraph/src/main/java/it/polito/grpc/GrpcUtils.java
new file mode 100644
index 0000000..0ed002c
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/GrpcUtils.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Splitter;
+
+import io.grpc.verigraph.ConfigurationGrpc;
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NeighbourGrpc;
+import io.grpc.verigraph.NodeGrpc;
+import io.grpc.verigraph.TestGrpc;
+import io.grpc.verigraph.VerificationGrpc;
+import io.grpc.verigraph.NodeGrpc.FunctionalType;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.model.Test;
+import it.polito.escape.verify.model.Verification;
+
+public class GrpcUtils {
+ private static final Logger logger = Logger.getLogger(GrpcUtils.class.getName());
+
+ public static NeighbourGrpc obtainNeighbour(Neighbour ne){
+ return NeighbourGrpc.newBuilder()
+ .setId(ne.getId())
+ .setName(ne.getName())
+ .build();
+ }
+
+ public static Neighbour deriveNeighbour(NeighbourGrpc request) {
+ //id is not present
+ Neighbour ne = new Neighbour();
+ ne.setName(request.getName());
+ return ne;
+ }
+
+ public static ConfigurationGrpc obtainConfiguration(Configuration conf){
+ return ConfigurationGrpc.newBuilder()
+ .setId(conf.getId())
+ .setDescription(conf.getDescription())
+ .setConfiguration(conf.getConfiguration().toString())
+ .build();
+ }
+
+ public static Configuration deriveConfiguration(ConfigurationGrpc request) {
+ Configuration conf = new Configuration();
+ conf.setId(request.getId());
+ conf.setDescription(request.getDescription());
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode rootNode = null;
+ try {
+ if ("".equals(request.getConfiguration()))
+ rootNode=mapper.readTree("[]");
+ else
+ rootNode = mapper.readTree(request.getConfiguration());
+ } catch (IOException e) {
+ logger.log(Level.WARNING, e.getMessage());
+ }
+ conf.setConfiguration(rootNode);
+ return conf;
+ }
+
+ public static NodeGrpc obtainNode(Node node) {
+ NodeGrpc.Builder nr = NodeGrpc.newBuilder();
+ nr.setId(node.getId());
+ nr.setName(node.getName());
+ nr.setFunctionalType(FunctionalType.valueOf(node.getFunctional_type()));
+ for(Neighbour neighbour:node.getNeighbours().values()){
+ NeighbourGrpc ng = obtainNeighbour(neighbour);
+ nr.addNeighbour(ng);
+ }
+ nr.setConfiguration(obtainConfiguration(node.getConfiguration()));
+ return nr.build();
+ }
+
+ public static Node deriveNode(NodeGrpc request) {
+ //id is not present
+ Node node = new Node();
+ node.setName(request.getName());
+ node.setFunctional_type(request.getFunctionalType().toString());
+ Configuration conf = deriveConfiguration(request.getConfiguration());
+ node.setConfiguration(conf);
+
+ Map<Long,Neighbour> neighours = node.getNeighbours();
+ long i = 1;
+ for(NeighbourGrpc neighbour:request.getNeighbourList()){
+ Neighbour ng = deriveNeighbour(neighbour);
+ neighours.put(i++, ng);
+ }
+
+ return node;
+ }
+
+ public static GraphGrpc obtainGraph(Graph graph){
+ GraphGrpc.Builder gr = GraphGrpc.newBuilder();
+ gr.setId(graph.getId());
+ for(Node node:graph.getNodes().values()){
+ NodeGrpc ng = obtainNode(node);
+ gr.addNode(ng);
+ }
+ return gr.build();
+ }
+
+ public static Graph deriveGraph(GraphGrpc request) {
+ //id is not present
+ Graph graph = new Graph();
+
+ long i=1;
+ Map<Long, Node> nodes = graph.getNodes();
+ for(NodeGrpc node:request.getNodeList()){
+ Node ng = deriveNode(node);
+ nodes.put(i++, ng);
+ }
+
+ return graph;
+ }
+
+ public static VerificationGrpc obtainVerification(Verification verify){
+ VerificationGrpc.Builder ver = VerificationGrpc.newBuilder();
+ ver.setComment(verify.getComment());
+ ver.setResult(verify.getResult());
+ for(Test test:verify.getTests()){
+ TestGrpc.Builder tst = TestGrpc.newBuilder().setResult(test.getResult());
+ for(Node node:test.getPath()){
+ NodeGrpc ng = obtainNode(node);
+ tst.addNode(ng);
+ }
+ ver.addTest(tst);
+ }
+ return ver.build();
+ }
+
+ /**Intended for string that begins with "?"
+ * */
+ public static Map<String,String> getParamGivenString(String str){
+ String string = str.substring(1);
+ final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator("=").
+ split(string);
+ return map;
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/README.rst b/verigraph/src/main/java/it/polito/grpc/README.rst
new file mode 100644
index 0000000..d089908
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/README.rst
@@ -0,0 +1,442 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+gRPC Project
+============
+
+This project contains the interfaces for a web service based on gRPC.
+
+How to install:
+---------------
+
+For gRPC interface, add to your ``pom.xml`` (in the project this part is
+already present):
+
+::
+
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-netty</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-protobuf</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+
+For protobuf-based codegen integrated with the Maven build system, you
+can use protobuf-maven-plugin :
+
+::
+
+ <build>
+ <extensions>
+ <extension>
+ <groupId>kr.motd.maven</groupId>
+ <artifactId>os-maven-plugin</artifactId>
+ <version>1.4.1.Final</version>
+ </extension>
+ </extensions>
+ <plugins>
+ <plugin>
+ <groupId>org.xolstice.maven.plugins</groupId>
+ <artifactId>protobuf-maven-plugin</artifactId>
+ <version>0.5.0</version>
+ <configuration>
+ <protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact>
+ <pluginId>grpc-java</pluginId>
+ <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>compile-custom</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+| In order to run the gRPC server and the junit test, you need to download the Manven Ant Task library
+ from `here <https://mvnrepository.com/artifact/org.apache.maven/maven-ant-tasks/2.1.3>`__
+ and copy into ``[verigraph]/lib/``
+
+| Due to the fact that the project is intended for Eclipse, you need to
+ install an additional Eclipse plugin because
+ `m2e <https://www.eclipse.org/m2e/>`__ does not evaluate the extension
+ specified in a ``pom.xml``. `Download
+ ``os-maven-plugin-1.5.0.Final.jar`` <http://repo1.maven.org/maven2/kr/motd/maven/os-maven-plugin/1.5.0.Final/os-maven-plugin-1.5.0.Final.jar>`__
+ and put it into the ``<ECLIPSE_HOME>/plugins`` directory.
+| (As you might have noticed, ``os-maven-plugin`` is a Maven extension,
+ a Maven plugin, and an Eclipse plugin.)
+
+If you are using IntelliJ IDEA, you should not have any problem.
+
+If you are using other IDEs such as NetBeans, you need to set the system
+properties ``os-maven-plugin`` sets manually when your IDE is launched.
+You usually use JVM's ``-D`` flags like the following:
+
+ | -Dos.detected.name=linux
+ | -Dos.detected.arch=x86\_64
+ | -Dos.detected.classifier=linux-x86\_64
+
+Included files:
+---------------
+
+Here you can find a brief description about useful files for the gRPC
+interface:
+
+**src/main/java:**
+
+- *it.polito.grpc:*
+
+This package includes 2 classes that represent the client and server.
+
+ **Client.java:**
+
+ | Client of gRPC application. It implements all possible methods
+ necessary for communicate with server.
+ | It prints out the received response.
+ | Moreover it provides some static methods that are used for
+ creating the instances of requests.
+
+ **Service.java:**
+
+ | Server of gRPC application. It implements all possible methods
+ necessary for communicate with client.
+ | It saves the received request on log.
+ | This server could be accessed by multiple clients, because
+ synchronizes concurrent accesses.
+ | Each method that is possible to call is has the equivalent
+ operation in REST-interface.
+
+ **GrpcUtils.java:**
+
+ | This class provides some static methods that are used by
+ ``Service.java`` in order to translate a request into a class that
+ is accepted by Verigraph.
+ | Other methods are used to translate the class of Verigraph in the
+ proper gRPC response.
+ | These functionalities are exploited by test classes.
+ | Furthermore this set of methods is public, so in your application
+ you could call them, even if this should not be useful because
+ ``Client.java`` provides other high-level functions.
+
+- *it.polito.grpc.test:*
+
+ This package includes classes for testing the gRPC application.
+
+ **GrpcServerTest.java:**
+
+ | For each possible method we test if works correctly.
+ | We create a fake client (so this test doesn't use the method that
+ are present in client class) and test if it receives the expected
+ response.
+ | In a nutshell, it tests the methods of Client in case of a fake
+ server.
+ | Please notice that the test prints some errors but this is
+ intentional, because the program tests also error case.
+ | Indeed, not all methods are tested, because we have another class
+ (ReachabilityTest.java) that is specialized for testing the
+ verification method.
+
+ **GrpcTest.java:**
+
+ | This set of tests is intended to control the most common use
+ cases, in particular all methods that are callable in Client and
+ Service class, apart from verifyPolicy for the same reason as
+ before.
+ | It tries also to raise an exception and verify if the behavior is
+ as expected.
+
+ **MultiThreadTest.java:**
+
+ | This test creates multiple clients that connect to the server and
+ verify is the result is correct. These methods test the
+ synchronization on
+ | server-side.
+
+ **ReachabilityTest.java:**
+
+ | This file tests the verification method, it exploits the test case
+ already present in the project and consequently has the certainty
+ of testing not so simple case. In particular it reads the file in
+ "src/main/webapp/json" and use this as starting point.
+ | Some exceptions are thrown in order to verify if they are handled
+ in a correct way.
+
+**src/main/proto:**
+
+ **verigraph.proto:**
+
+ | File containing the description of the service. This includes the
+ definition of all classes used in the application.
+ | Moreover contains the definition of the methods that is possible
+ to call.
+ | Each possible method called by REST API is mapped on a proper gRPC
+ method.
+ | In case of error a message containing the reason is returned to
+ the client.
+ | More details are available in the section about Proto Buffer.
+
+**taget/generated-sources/protobuf/java:**
+
+- *io.grpc.verigraph:*
+
+ This package includes all classes generated from verigraph.proto by
+ means of protoc. For each object you can find 2 classes :
+
+ **{NameObject}Grpc.java**
+
+ **{NameObject}GrpcOrBuilder.java**
+
+ The first is the real implementation, the second is the
+ interface.
+
+**taget/generated-sources/protobuf/grpc-java:**
+
+- *io.grpc.verigraph:*
+
+ This package includes a single class generated from verigraph.proto
+ by means of protoc.
+
+ **VerigraphGrpc.java:**
+
+ This is useful in order to create the stubs that are necessary to
+ communicate both for client and server.
+
+**lib:**
+
+This folder includes a jar used for compiling the project with Ant.
+
+ \*\*maven-ant-tasks-2.1.3.\ jar:**
+
+ This file is used by build.xml in order to include the maven
+ dependencies.
+
+**pom.xml:**
+
+| Modified in order to add all necessary dependencies. It contains also
+ the build tag used for create the generated-sources folders.
+| This part is added according to documentation of gRPC for java as
+ explained above in How To Install section.
+| For further clarification go to `this
+ link <https://github.com/grpc/grpc-java/blob/master/README.md>`__.
+
+**build.xml:**
+
+This ant file permit to run and compile the program in a simple way, it
+exploits the maven-ant-tasks-2.1.3.jar already present in project.
+
+It contains 3 fundamental tasks for gRPC interface:
+
+- **build:** compile the program
+
+- **run:** run both client and server
+
+- **run-client :** run only client
+
+- **run-server :** run only server
+
+- **run-test :** launch all tests that are present in the package,
+ prints out the partial results and global result.
+
+Note that the execution of these tests may take up to 1-2 minutes when
+successful, according to your computer architecture.
+
+More Information About Proto Buffer:
+------------------------------------
+
+Further clarification about verigraph.proto:
+
+- A ``simple RPC`` where the client sends a request to the server using
+ the stub and waits for a response to come back, just like a normal
+ function call.
+
+ .. code:: xml
+
+ // Obtains a graph
+ rpc GetGraph (RequestID) returns (GraphGrpc) {}
+
+In this case we send a request that contains the id of the graph and the
+response is a Graph.
+
+- A ``server-side streaming RPC`` where the client sends a request to
+ the server and gets a stream to read a sequence of messages back. The
+ client reads from the returned stream until there are no more
+ messages. As you can see in our example, you specify a server-side
+ streaming method by placing the stream keyword before the response
+ type.
+
+ .. code:: xml
+
+
+ // Obtains a list of Nodes
+ rpc GetNodes (RequestID) returns (stream NodeGrpc) {}
+
+In this case we send a request that contains the id of the graph and the
+response is a list of Nodes that are inside graph.
+
+Further possibilities are available but in this project are not
+expolied. If you are curious see
+`here <http://www.grpc.io/docs/tutorials/basic/java.html#defining-the-service>`__.
+
+Our ``.proto`` file also contains protocol buffer message type
+definitions for all the request and response types used in our service
+methods - for example, hereÂ’s the ``RequestID`` message type:
+
+.. code:: xml
+
+ message RequestID {
+ int64 idGraph = 1;
+ int64 idNode = 2;
+ int64 idNeighbour = 3;
+ }
+
+The " = 1", " = 2" markers on each element identify the unique "tag"
+that field uses in the binary encoding. Tag numbers 1-15 require one
+less byte to encode than higher numbers, so as an optimization you can
+decide to use those tags for the commonly used or repeated elements,
+leaving tags 16 and higher for less-commonly used optional elements.
+Each element in a repeated field requires re-encoding the tag number, so
+repeated fields are particularly good candidates for this optimization.
+
+Protocol buffers are the flexible, efficient, automated solution to
+solve exactly the problem of serialization. With protocol buffers, you
+write a .proto description of the data structure you wish to store. From
+that, the protocol buffer compiler creates a class that implements
+automatic encoding and parsing of the protocol buffer data with an
+efficient binary format. The generated class provides getters and
+setters for the fields that make up a protocol buffer and takes care of
+the details of reading and writing the protocol buffer as a unit.
+Importantly, the protocol buffer format supports the idea of extending
+the format over time in such a way that the code can still read data
+encoded with the old format.
+
+::
+
+ syntax = "proto3";
+
+ package verigraph;
+
+ option java_multiple_files = true;
+ option java_package = "io.grpc.verigraph";
+ option java_outer_classname = "VerigraphProto";
+ ```
+
+This .proto file works for protobuf 3, that is slightly different from
+the version 2, so be careful if you have code already installed.
+
+The .proto file starts with a package declaration, which helps to
+prevent naming conflicts between different projects. In Java, the
+package name is used as the ``Java package`` unless you have explicitly
+specified a java\_package, as we have here. Even if you do provide a
+``java_package``, you should still define a normal ``package`` as well
+to avoid name collisions in the Protocol Buffers name space as well as
+in non-Java languages.
+
+| After the package declaration, you can see two options that are
+ Java-specific: ``java_package`` and ``java_outer_classname``.
+ ``java_package`` specifies in what Java package name your generated
+ classes should live. If you don't specify this explicitly, it simply
+ matches the package name given by the package declaration, but these
+ names usually aren't appropriate Java package names (since they
+ usually don't start with a domain name). The ``java_outer_classname``
+ option defines the class name which should contain all of the classes
+ in this file. If you don't give a ``java_outer_classname explicitly``,
+ it will be generated by converting the file name to camel case. For
+ example, "my\_proto.proto" would, by default, use "MyProto" as the
+ outer class name.
+| In this case this file is not generated, because
+ ``java_multiple_files`` option is true, so for each message we
+ generate a different class.
+
+For further clarifications see
+`here <https://developers.google.com/protocol-buffers/docs/javatutorial>`__
+
+Notes
+-----
+
+For gRPC interface you need that neo4jmanager service is already
+deployed, so if this is not the case, please follow the instructions at
+this
+`link <https://github.com/netgroup-polito/verigraph/blob/a3c008a971a8b16552a20bf2484ebf8717735dd6/README.md>`__.
+
+In this version there are some modified files compared to the original
+`Verigraph project <https://github.com/netgroup-polito/verigraph>`__
+
+**it.polito.escape.verify.service.NodeService:**
+
+At line 213 we modified the path, because this service is intended to
+run not only in container, as Tomcat, so we added other possibility that
+files is placed in src/main/webapp/json/ folder.
+
+**it.polito.escape.verify.service.VerificationService:**
+
+In the original case it searches for python files in "webapps" folder,
+that is present if the service is deployed in a container, but absent
+otherwise. So we added another string that will be used in the case the
+service doesn't run in Tomcat.
+
+**it.polito.escape.verify.databese.DatabaseClass:**
+
+Like before we added the possibility that files are not in "webapps"
+folder, so is modified in order to run in any environment. Modification
+in method loadDataBase() and persistDatabase().
+
+| Pay attention that Python is needed for the project. If it is not
+ already present on your computer, please `download
+ it <https://www.python.org/download/releases/2.7.3/>`__.
+| It works fine with Python 2.7.3, or in general Python 2.
+
+| If you have downloaded a Python version for 64-bit architecture please
+ copy the files in "service/z3\_64" and paste in "service/build" and
+ substitute them,
+| because this project works with Python for 32-bit architecture.
+
+Python and Z3 must support the same architetcure.
+
+Moreover you need the following dependencies installed on your python
+distribution:
+
+- "requests" python package ->
+http://docs.python-requests.org/en/master/
+
+- "jsonschema" python package -> https://pypi.python.org/pypi/jsonschema
+
+| HINT - to install a package you can raise the following command (Bash
+ on Linux or DOS shell on Windows): python -m pip install jsonschema
+ python -m pip install requests
+| Pay attention that it is possible that you have to modify the PATH
+ environment variable because is necessary to address the python
+ folder, used for verification phase.
+
+Remember to read the
+`README.rtf <https://gitlab.com/serena.spinoso/DP2.2017.SpecialProject2.gRPC/tree/master>`__
+and to follow the instructions in order to deploy the Verigraph service.
+
+| In the latest version of Maven there is the possibility that the
+ downloaded files are incompatible with Java Version of the project
+ (1.8).
+| In this case you have to modify the file ``hk2-parent-2.4.0-b31.pom``
+ under your local Maven repository (e.g.
+ 'C:\\Users\\Standard.m2\\repository')
+| and in the path ``\org\glassfish\hk2\hk2-parent\2.4.0-b31`` find the
+ file and modify at line 1098 (in section ``profile``) the ``jdk``
+ version to ``[1.8,)`` .
+
+| Admittedly, the version that is supported by the downloaded files from
+ Maven Dependencies is incompatible with jdk of the project.
+| So modify the file ``gson-2.3.pom`` in Maven repository, under
+ ``com\google\code\gson\gson\2.3`` directory, in particular line 91,
+ from ``[1.8,`` to ``[1.8,)``.
+
+This project was also tested on Linux Ubuntu 15.10.
diff --git a/verigraph/src/main/java/it/polito/grpc/Service.java b/verigraph/src/main/java/it/polito/grpc/Service.java
new file mode 100644
index 0000000..8a77d05
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/Service.java
@@ -0,0 +1,462 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
+import io.grpc.verigraph.ConfigurationGrpc;
+import io.grpc.verigraph.GetRequest;
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NeighbourGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.NewNeighbour;
+import io.grpc.verigraph.NewNode;
+import io.grpc.verigraph.NodeGrpc;
+import io.grpc.verigraph.Policy;
+import io.grpc.verigraph.RequestID;
+import io.grpc.verigraph.Status;
+import io.grpc.verigraph.VerificationGrpc;
+import io.grpc.verigraph.VerigraphGrpc;
+import it.polito.escape.verify.exception.BadRequestException;
+import it.polito.escape.verify.exception.DataNotFoundException;
+import it.polito.escape.verify.exception.ForbiddenException;
+import it.polito.escape.verify.model.Configuration;
+import it.polito.escape.verify.model.Graph;
+import it.polito.escape.verify.model.Neighbour;
+import it.polito.escape.verify.model.Node;
+import it.polito.escape.verify.model.Verification;
+import it.polito.escape.verify.resources.beans.VerificationBean;
+import it.polito.escape.verify.service.GraphService;
+import it.polito.escape.verify.service.NeighbourService;
+import it.polito.escape.verify.service.NodeService;
+import it.polito.escape.verify.service.VerificationService;
+
+public class Service {
+ /** Port on which the server should run. */
+ private static final Logger logger = Logger.getLogger(Service.class.getName());
+ private static final int port = 50051;
+ private static final String internalError = "Internal Server Error";
+ private Server server;
+ private GraphService graphService = new GraphService();
+ private VerificationService verificationService = new VerificationService();
+ private NodeService nodeService = new NodeService();
+ private NeighbourService neighboursService = new NeighbourService();
+
+ public Service(int port) {
+ this(ServerBuilder.forPort(port), port);
+ }
+
+ /** Create a RouteGuide server using serverBuilder as a base and features as data. */
+ public Service(ServerBuilder<?> serverBuilder, int port) {
+ server = serverBuilder.addService(new VerigraphImpl())
+ .build();
+ }
+
+ public void start() throws IOException {
+ server.start();
+ logger.info("Server started, listening on "+ port);
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ logger.info("*** Shutting down gRPC server since JVM is shutting down");
+ Service.this.stop();
+ logger.info("*** Server shut down");
+ }
+ });
+ }
+
+ public void stop() {
+ if (server != null) {
+ server.shutdown();
+ }
+ }
+
+ private void blockUntilShutdown() throws InterruptedException {
+ if (server != null) {
+ server.awaitTermination();
+ }
+ }
+
+ /** Main function to launch server from cmd. */
+ public static void main(String[] args) throws IOException, InterruptedException {
+ try{
+ Service server = new Service(port);
+ server.start();
+ server.blockUntilShutdown();
+ }
+ catch(Exception ex){
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ }
+
+ /**Here start method of my impementation*/
+ private class VerigraphImpl extends VerigraphGrpc.VerigraphImplBase{
+
+ /** Here start methods of GraphResource*/
+ @Override
+ public void getGraphs(GetRequest request, StreamObserver<GraphGrpc> responseObserver) {
+ try{
+ for(Graph item : graphService.getAllGraphs()) {
+ GraphGrpc gr = GrpcUtils.obtainGraph(item);
+ responseObserver.onNext(gr);
+ }
+ }catch(Exception ex){
+ GraphGrpc nr = GraphGrpc.newBuilder().setErrorMessage(internalError).build();
+ responseObserver.onNext(nr);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void createGraph(GraphGrpc request, StreamObserver<NewGraph> responseObserver) {
+ NewGraph.Builder response = NewGraph.newBuilder();
+ try{
+ Graph graph = GrpcUtils.deriveGraph(request);
+ Graph newGraph = graphService.addGraph(graph);
+ response.setSuccess(true).setGraph(GrpcUtils.obtainGraph(newGraph));
+ }catch(BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void deleteGraph(RequestID request, StreamObserver<Status> responseObserver) {
+
+ Status.Builder response = Status.newBuilder();
+ try{
+ graphService.removeGraph(request.getIdGraph());
+ response.setSuccess(true);
+ }catch(ForbiddenException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ } catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void getGraph(RequestID request, StreamObserver<GraphGrpc> responseObserver) {
+ try{
+ Graph graph = graphService.getGraph(request.getIdGraph());
+ GraphGrpc gr = GrpcUtils.obtainGraph(graph);
+ responseObserver.onNext(gr);
+ }catch(ForbiddenException | DataNotFoundException ex){
+ GraphGrpc grError = GraphGrpc.newBuilder().setErrorMessage(ex.getMessage()).build();
+ responseObserver.onNext(grError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ GraphGrpc grError = GraphGrpc.newBuilder().setErrorMessage(internalError).build();
+ responseObserver.onNext(grError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void updateGraph(GraphGrpc request, StreamObserver<NewGraph> responseObserver) {
+ NewGraph.Builder response = NewGraph.newBuilder();
+ try{
+ Graph graph = GrpcUtils.deriveGraph(request);
+ graph.setId(request.getId());
+ Graph newGraph = graphService.updateGraph(graph);
+ response.setSuccess(true).setGraph(GrpcUtils.obtainGraph(newGraph));
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void verifyPolicy(Policy request, StreamObserver<VerificationGrpc> responseObserver) {
+
+ VerificationGrpc.Builder verification;
+ try{
+ //Convert request
+ VerificationBean verify = new VerificationBean();
+ verify.setDestination(request.getDestination());
+ verify.setSource(request.getSource());
+ verify.setType(request.getType().toString());
+ verify.setMiddlebox(request.getMiddlebox());
+
+ //Convert Response
+ Verification ver = verificationService.verify(request.getIdGraph(), verify);
+ verification = VerificationGrpc.newBuilder(GrpcUtils.obtainVerification(ver))
+ .setSuccessOfOperation(true);
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ verification = VerificationGrpc.newBuilder().setSuccessOfOperation(false)
+ .setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ } catch(Exception ex){
+ verification = VerificationGrpc.newBuilder().setSuccessOfOperation(false)
+ .setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(verification.build());
+ responseObserver.onCompleted();
+ }
+
+ /** Here start methods of NodeResource*/
+
+ @Override
+ public void getNodes(RequestID request, StreamObserver<NodeGrpc> responseObserver) {
+ try{
+ for (Node item : nodeService.getAllNodes(request.getIdGraph())) {
+ NodeGrpc nr = GrpcUtils.obtainNode(item);
+ responseObserver.onNext(nr);
+ }
+ }catch(ForbiddenException | DataNotFoundException ex){
+ NodeGrpc nr = NodeGrpc.newBuilder().setErrorMessage(ex.getMessage()).build();
+ responseObserver.onNext(nr);
+ logger.log(Level.WARNING, ex.getMessage());
+ } catch(Exception ex){
+ NodeGrpc nr = NodeGrpc.newBuilder().setErrorMessage(internalError).build();
+ responseObserver.onNext(nr);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void createNode(NodeGrpc request, StreamObserver<NewNode> responseObserver) {
+ NewNode.Builder response = NewNode.newBuilder();
+ try{
+ Node node = GrpcUtils.deriveNode(request);
+ Node newNode = nodeService.addNode(request.getIdGraph(), node);
+ response.setSuccess(true).setNode(GrpcUtils.obtainNode(newNode));
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void deleteNode(RequestID request, StreamObserver<Status> responseObserver) {
+ Status.Builder response = Status.newBuilder();
+ try{
+ nodeService.removeNode(request.getIdGraph(), request.getIdNode());
+ response.setSuccess(true);
+ }catch(ForbiddenException | DataNotFoundException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void getNode(RequestID request, StreamObserver<NodeGrpc> responseObserver) {
+ NodeGrpc nr;
+ try{
+ Node node = nodeService.getNode(request.getIdGraph(), request.getIdNode());
+ nr= GrpcUtils.obtainNode(node);
+ }catch(ForbiddenException | DataNotFoundException ex){
+ nr = NodeGrpc.newBuilder().setErrorMessage(ex.getMessage()).build();
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ nr = NodeGrpc.newBuilder().setErrorMessage(internalError).build();
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(nr);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void updateNode(NodeGrpc request, StreamObserver<NewNode> responseObserver) {
+ NewNode.Builder response = NewNode.newBuilder();
+ try{
+ Node node = GrpcUtils.deriveNode(request);
+ node.setId(request.getId());
+ Node newNode = nodeService.updateNode(request.getIdGraph(), node);
+ response.setSuccess(true).setNode(GrpcUtils.obtainNode(newNode));
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void configureNode(ConfigurationGrpc request, StreamObserver<Status> responseObserver) {
+ Status.Builder response = Status.newBuilder();
+ try{
+ if (request.getIdGraph() <= 0) {
+ throw new ForbiddenException("Illegal graph id: " + request.getIdGraph());
+ }
+ if (request.getIdNode() <= 0) {
+ throw new ForbiddenException("Illegal node id: " + request.getIdNode());
+ }
+ Graph graph = new GraphService().getGraph(request.getIdGraph());
+ if (graph == null){
+ throw new BadRequestException("Graph with id " + request.getIdGraph() + " not found");
+ }
+ Node node = nodeService.getNode(request.getIdGraph(), request.getIdNode());
+ if (node == null){
+ throw new BadRequestException("Node with id " + request.getIdNode() + " not found in graph with id " + request.getIdGraph());
+ }
+ Configuration nodeConfiguration = GrpcUtils.deriveConfiguration(request);
+ Node nodeCopy = new Node();
+ nodeCopy.setId(node.getId());
+ nodeCopy.setName(node.getName());
+ nodeCopy.setFunctional_type(node.getFunctional_type());
+ Map<Long,Neighbour> nodes = new HashMap<Long,Neighbour>();
+ nodes.putAll(node.getNeighbours());
+ nodeCopy.setNeighbours(nodes);
+ nodeConfiguration.setId(nodeCopy.getName());
+ nodeCopy.setConfiguration(nodeConfiguration);
+
+ Graph graphCopy = new Graph();
+ graphCopy.setId(graph.getId());
+ graphCopy.setNodes(new HashMap<Long, Node>(graph.getNodes()));
+ graphCopy.getNodes().remove(node.getId());
+
+ NodeService.validateNode(graphCopy, nodeCopy);
+
+ graph.getNodes().put(request.getIdNode(), nodeCopy);
+ response.setSuccess(true);
+ }catch(ForbiddenException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(internalError);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ /** Here start methods of NeighbourResource*/
+ @Override
+ public void getNeighbours(RequestID request, StreamObserver<NeighbourGrpc> responseObserver) {
+ try{
+ for(Neighbour item : neighboursService.getAllNeighbours(request.getIdGraph(), request.getIdNode())) {
+ NeighbourGrpc nr = GrpcUtils.obtainNeighbour(item);
+ responseObserver.onNext(nr);
+ }
+ }catch(ForbiddenException | DataNotFoundException ex){
+ NeighbourGrpc nr = NeighbourGrpc.newBuilder().setErrorMessage(ex.getMessage()).build();
+ responseObserver.onNext(nr);
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ NeighbourGrpc nr = NeighbourGrpc.newBuilder().setErrorMessage(internalError).build();
+ responseObserver.onNext(nr);
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void createNeighbour(NeighbourGrpc request, StreamObserver<NewNeighbour> responseObserver) {
+ NewNeighbour.Builder response = NewNeighbour.newBuilder();
+ try{
+ Neighbour neighbour = GrpcUtils.deriveNeighbour(request);
+ Neighbour newNeighbour = neighboursService.addNeighbour(request.getIdGraph(), request.getIdNode(), neighbour);
+ response.setSuccess(true).setNeighbour(GrpcUtils.obtainNeighbour(newNeighbour));
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void deleteNeighbour(RequestID request, StreamObserver<Status> responseObserver) {
+ Status.Builder response = Status.newBuilder();
+ try{
+ neighboursService.removeNeighbour(request.getIdGraph(), request.getIdNode(), request.getIdNeighbour());
+ response.setSuccess(true);
+ }catch(ForbiddenException | DataNotFoundException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void getNeighbour(RequestID request, StreamObserver<NeighbourGrpc> responseObserver) {
+ NeighbourGrpc nr;
+ try{
+ Neighbour neighbour = neighboursService.getNeighbour(request.getIdGraph(),
+ request.getIdNode(), request.getIdNeighbour());
+ nr = GrpcUtils.obtainNeighbour(neighbour);
+
+ }catch(ForbiddenException | DataNotFoundException ex){
+ nr = NeighbourGrpc.newBuilder().setErrorMessage(ex.getMessage()).build();
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ nr = NeighbourGrpc.newBuilder().setErrorMessage(internalError).build();
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(nr);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void updateNeighbour(NeighbourGrpc request, StreamObserver<NewNeighbour> responseObserver) {
+ NewNeighbour.Builder response = NewNeighbour.newBuilder();
+ try{
+ Neighbour neighbour = GrpcUtils.deriveNeighbour(request);
+ neighbour.setId(request.getId());
+ Neighbour newNeighbour = neighboursService.updateNeighbour(request.getIdGraph(), request.getIdNode(), neighbour);
+ response.setSuccess(true).setNeighbour(GrpcUtils.obtainNeighbour(newNeighbour));
+ }catch(ForbiddenException | DataNotFoundException | BadRequestException ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }catch(Exception ex){
+ response.setSuccess(false).setErrorMessage(ex.getMessage());
+ logger.log(Level.WARNING, ex.getMessage());
+ }
+ responseObserver.onNext(response.build());
+ responseObserver.onCompleted();
+ }
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/test/GrpcServerTest.java b/verigraph/src/main/java/it/polito/grpc/test/GrpcServerTest.java
new file mode 100644
index 0000000..7344447
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/test/GrpcServerTest.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc.test;
+
+import static org.junit.Assert.assertEquals;
+
+import io.grpc.ManagedChannel;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import io.grpc.verigraph.ConfigurationGrpc;
+import io.grpc.verigraph.GetRequest;
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NeighbourGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.NewNeighbour;
+import io.grpc.verigraph.NewNode;
+import io.grpc.verigraph.NodeGrpc;
+import io.grpc.verigraph.NodeGrpc.FunctionalType;
+import io.grpc.verigraph.RequestID;
+import io.grpc.verigraph.Status;
+import io.grpc.verigraph.VerigraphGrpc;
+import it.polito.grpc.Client;
+import it.polito.grpc.Service;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link Service}.
+ * For testing basic gRPC unit test only.
+ * Not intended to provide a high code coverage or to test every major usecase.
+ */
+@RunWith(JUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class GrpcServerTest {
+ private Service server;
+ private ManagedChannel inProcessChannel;
+
+ @Before
+ public void setUp() throws Exception {
+ String uniqueServerName = "in-process server for " + getClass();
+ // use directExecutor for both InProcessServerBuilder and InProcessChannelBuilder can reduce the
+ // usage timeouts and latches in test. But we still add timeout and latches where they would be
+ // needed if no directExecutor were used, just for demo purpose.
+ server = new Service(InProcessServerBuilder.forName(uniqueServerName).directExecutor(),0);
+ server.start();
+ inProcessChannel = InProcessChannelBuilder.forName(uniqueServerName).directExecutor().build();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ inProcessChannel.shutdownNow();
+ server.stop();
+ }
+
+ @Test
+ public void test1Graph() throws Exception {
+ RequestID request = RequestID.newBuilder().setIdGraph(1).build() ;//id not present
+ GraphGrpc ufoundedGraph = GraphGrpc.newBuilder()
+ .setErrorMessage("Graph with id 1 not found").build();
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ // graph not found in the server
+ GraphGrpc graph = stub.getGraph(request);
+
+ assertEquals(ufoundedGraph, graph);
+
+ // getGraph in the server, but first add it
+ GraphGrpc addedGraph = GraphGrpc.newBuilder().build();
+ NewGraph response = stub.createGraph(addedGraph);
+ addedGraph = response.getGraph();
+ request = RequestID.newBuilder().setIdGraph(1).build() ;
+ graph = stub.getGraph(request);
+
+ assertEquals(addedGraph.getId(), graph.getId());
+
+ //updateGraph
+ GraphGrpc updatedGraph = GraphGrpc.newBuilder().setId(response.getGraph().getId()).build();
+ response = stub.updateGraph(updatedGraph);
+
+ assertEquals(response.getSuccess(),true);
+ }
+
+ @Test
+ public void test2Graphs() throws Exception {
+ // setup
+ GetRequest request = GetRequest.newBuilder().build();
+ GraphGrpc g1 = GraphGrpc.newBuilder().build();
+ GraphGrpc g2 = GraphGrpc.newBuilder().build();
+ GraphGrpc g3 = GraphGrpc.newBuilder().build();
+ GraphGrpc g4 = GraphGrpc.newBuilder().build();
+
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ stub.createGraph(g1);
+ stub.createGraph(g2);
+ stub.createGraph(g3);
+ stub.createGraph(g4);
+ g1 = GraphGrpc.newBuilder(g1).setId(1).build();
+ g2 = GraphGrpc.newBuilder(g2).setId(2).build();
+ g3 = GraphGrpc.newBuilder(g3).setId(3).build();
+ g4 = GraphGrpc.newBuilder(g4).setId(4).build();
+ // run
+ Iterator<GraphGrpc> graphs = stub.getGraphs(request);
+
+ assertEquals(graphs.next(), g1);
+ assertEquals(graphs.next(), g2);
+ assertEquals(graphs.next(), g3);
+ assertEquals(graphs.next(), g4);
+
+ //deleteGraph
+ RequestID req = RequestID.newBuilder().setIdGraph(g1.getId()).build();
+ stub.deleteGraph(req);
+ // run
+ graphs = stub.getGraphs(request);
+
+ assertEquals(graphs.next(), g2);
+ assertEquals(graphs.next(), g3);
+ assertEquals(graphs.next(), g4);
+ }
+
+ @Test
+ public void test3Node() throws Exception {
+ RequestID request = RequestID.newBuilder().setIdGraph(2).setIdNode(1).build() ;//id not present
+ NodeGrpc ufoundedGraph = NodeGrpc.newBuilder()
+ .setErrorMessage("Node with id 1 not found in graph with id 2").build();
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ // graph not found in the server
+ NodeGrpc node = stub.getNode(request);
+
+ assertEquals(ufoundedGraph, node);
+
+ // graph found in the server, but first add it
+ NodeGrpc addedNode = NodeGrpc.newBuilder().setName("client").setIdGraph(2)
+ .setFunctionalType(FunctionalType.endhost).build();
+ NewNode response = stub.createNode(addedNode);
+ addedNode = response.getNode();
+ request = RequestID.newBuilder().setIdGraph(2).setIdNode(1).build() ;
+ node = stub.getNode(request);
+
+ assertEquals(addedNode.getId(), node.getId());
+ assertEquals(addedNode.getName(),"client");
+
+ //updateNode
+ NodeGrpc updatedNode = NodeGrpc.newBuilder().setName("Nodo2").setIdGraph(2).setId(1)
+ .setFunctionalType(FunctionalType.endhost).build();
+ response = stub.updateNode(updatedNode);
+
+ assertEquals(response.getSuccess(),true);
+ assertEquals(response.getNode().getName(),"Nodo2");
+
+ //configureNode
+ Map<String,String> params = new HashMap<String,String>();
+ params.put("url", "www.facebook.com");
+ params.put("body", "word");
+ params.put("destination","server");
+ params.put("protocol", "HTTP_REQUEST");
+ ConfigurationGrpc configuration = Client.createConfigurationGrpc(params, null, null, null);
+ ConfigurationGrpc config = ConfigurationGrpc.newBuilder(configuration).setIdGraph(2)
+ .setIdNode(1).build();
+
+ Status status = stub.configureNode(config);
+
+ assertEquals(status.getSuccess(),true);
+ }
+
+ @Test
+ public void test4Nodes() throws Exception {
+ // setup
+ RequestID request = RequestID.newBuilder().setIdGraph(2).build();
+ NodeGrpc n1 = NodeGrpc.newBuilder(Client.createNodeGrpc("Node5", "endhost", null, null))
+ .setIdGraph(2).build();
+ NodeGrpc n2 = NodeGrpc.newBuilder(Client.createNodeGrpc("Node3", "endhost", null, null))
+ .setIdGraph(2).build();
+ NodeGrpc n3 = NodeGrpc.newBuilder(Client.createNodeGrpc("Node4", "endhost", null, null))
+ .setIdGraph(2).build();
+ NodeGrpc n4 = NodeGrpc.newBuilder(Client.createNodeGrpc("client", "endhost", null, null))
+ .setIdGraph(2).build();
+
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ stub.createNode(n1);
+ stub.createNode(n2);
+ stub.createNode(n3);
+ stub.createNode(n4);
+ n1 = NodeGrpc.newBuilder(n1).setId(2).setIdGraph(0).build();
+ n2 = NodeGrpc.newBuilder(n2).setId(3).setIdGraph(0).build();
+ n3 = NodeGrpc.newBuilder(n3).setId(4).setIdGraph(0).build();
+ n4 = NodeGrpc.newBuilder(n4).setId(5).setIdGraph(0).build();
+ // run
+ Iterator<NodeGrpc> nodes = stub.getNodes(request);
+
+ nodes.next();
+ assertEquals(nodes.next(), n1);
+ assertEquals(nodes.next(), n2);
+ assertEquals(nodes.next(), n3);
+ assertEquals(nodes.next(), n4);
+
+ //deleteNode
+ RequestID req = RequestID.newBuilder().setIdGraph(2).setIdNode(1).build();
+ stub.deleteNode(req);
+ // run
+ nodes = stub.getNodes(request);
+
+ assertEquals(nodes.next(), n1);
+ assertEquals(nodes.next(), n2);
+ assertEquals(nodes.next(), n3);
+ assertEquals(nodes.next(), n4);
+ }
+
+ @Test
+ public void test5Neighbours() throws Exception {
+ RequestID request = RequestID.newBuilder().setIdGraph(2).setIdNode(2).setIdNeighbour(1).build() ;//id not present
+ NeighbourGrpc ufoundedNeighbour = NeighbourGrpc.newBuilder()
+ .setErrorMessage("Neighbour with id 1 not found for node with id 2 in graph with id 2").build();;
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ // Neighbour not found in the server
+ NeighbourGrpc neighbour = stub.getNeighbour(request);
+
+ assertEquals(ufoundedNeighbour, neighbour);
+
+ // getNeighbour, but first add it
+ NeighbourGrpc addedNeighbour = NeighbourGrpc.newBuilder().setIdGraph(2).setIdNode(2)
+ .setName("client").build();
+ NewNeighbour response = stub.createNeighbour(addedNeighbour);
+ addedNeighbour = response.getNeighbour();
+ request = RequestID.newBuilder().setIdGraph(2).setIdNode(2)
+ .setIdNeighbour(addedNeighbour.getId()).build();
+ neighbour = stub.getNeighbour(request);
+
+ assertEquals(addedNeighbour.getId(), neighbour.getId());
+
+ //updateNeighbour
+ NeighbourGrpc updatedNeighbour = Client.createNeighbourGrpc("Node4");
+ NeighbourGrpc nu = NeighbourGrpc.newBuilder(updatedNeighbour)
+ .setId(response.getNeighbour().getId()).setIdGraph(2).setIdNode(2).build();
+ response = stub.updateNeighbour(nu);
+
+ assertEquals(response.getSuccess(),true);
+ assertEquals(response.getNeighbour().getName(),"Node4");
+ }
+
+ @Test
+ public void test6Neighbours() throws Exception {
+ // setup
+ RequestID request = RequestID.newBuilder().setIdGraph(2).setIdNode(2).build();
+ NeighbourGrpc n1 = NeighbourGrpc.newBuilder().setIdGraph(2).setIdNode(2)
+ .setName("Node3").build();
+ NeighbourGrpc n2 = NeighbourGrpc.newBuilder().setIdGraph(2).setIdNode(2)
+ .setName("client").build();
+
+ VerigraphGrpc.VerigraphBlockingStub stub = VerigraphGrpc.newBlockingStub(inProcessChannel);
+
+ stub.createNeighbour(n1);
+ stub.createNeighbour(n2);
+ n1 = NeighbourGrpc.newBuilder(n1).setId(2).setIdGraph(0).setIdNode(0).build();
+ n2 = NeighbourGrpc.newBuilder(n2).setId(3).setIdGraph(0).setIdNode(0).build();
+ // run
+ Iterator<NeighbourGrpc> neighbours = stub.getNeighbours(request);
+
+ neighbours.next();
+ assertEquals(neighbours.next(), n1);
+ assertEquals(neighbours.next(), n2);
+
+ //deleteNeighbour
+ RequestID req = RequestID.newBuilder().setIdGraph(2).setIdNode(2).setIdNeighbour(1).build();
+ stub.deleteNeighbour(req);
+ // run
+ neighbours = stub.getNeighbours(request);
+
+ assertEquals(neighbours.next(), n1);
+ assertEquals(neighbours.next(), n2);
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/test/GrpcTest.java b/verigraph/src/main/java/it/polito/grpc/test/GrpcTest.java
new file mode 100644
index 0000000..41f9cad
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/test/GrpcTest.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.junit.runners.MethodSorters;
+
+import io.grpc.verigraph.ConfigurationGrpc;
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NeighbourGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.NewNeighbour;
+import io.grpc.verigraph.NewNode;
+import io.grpc.verigraph.NodeGrpc;
+import it.polito.grpc.Client;
+import it.polito.grpc.Service;
+
+@RunWith(JUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class GrpcTest {
+ private Service server;
+ private Client client;
+
+ @Before
+ public void setUpBeforeClass() throws Exception {
+ client = new Client("localhost" , 50051);
+ server = new Service(50051);
+ server.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ server.stop();
+ client.shutdown();
+ }
+
+ // method for comparing two non-null strings
+ private void compareString(String rs, String ts, String meaning) {
+ assertNotNull("NULL "+meaning, ts);
+ assertEquals("Wrong "+meaning, rs, ts);
+ }
+
+ @Test
+ public final void test1Load() throws Exception{
+ String funcType1 = "vpnaccess";
+ String funcType2 = "vpnexit";
+
+ // load an existing graph with 2 nodes
+ Map<String,String> map = new HashMap<String,String>();
+ map.put("vpnexit", "Node2");
+ ConfigurationGrpc conf = Client.createConfigurationGrpc(map, null, null, null);
+ NodeGrpc node1 = Client.createNodeGrpc("Node1", funcType1, null, conf);
+ List<NeighbourGrpc> neighbours = new ArrayList<NeighbourGrpc>();
+ NeighbourGrpc nb = Client.createNeighbourGrpc("Node1");
+ neighbours.add(nb);
+ map.clear();
+ map.put("vpnaccess", "Node1");
+ conf = Client.createConfigurationGrpc(map, null, null, null);
+ NodeGrpc node2 = Client.createNodeGrpc("Node2", funcType2, neighbours, conf);
+ List<NodeGrpc> nodes = new ArrayList<NodeGrpc>();
+ nodes.add(node1);
+ nodes.add(node2);
+ GraphGrpc graph = Client.createGraphGrpc(nodes);
+ //createGraph
+ graph = client.createGraph(graph).getGraph();
+
+ //getGraph
+ GraphGrpc retreivedGraph = client.getGraph(graph.getId());
+
+ assertNotNull("NULL Graph ",retreivedGraph);
+ assertEquals(graph.getId(), retreivedGraph.getId());
+
+ // check the name of first node and the id
+ compareString(retreivedGraph.getNodeList().get(0).getName(), graph.getNodeList().get(0).getName(), "node name");
+ assertEquals(retreivedGraph.getNodeList().get(0).getId(), graph.getNodeList().get(0).getId());
+
+ // check the name of second node and the id
+ compareString(retreivedGraph.getNodeList().get(1).getName(), graph.getNodeList().get(1).getName(), "node name");
+ assertEquals(retreivedGraph.getNodeList().get(1).getId(), graph.getNodeList().get(1).getId());
+
+ //updateGraph
+ GraphGrpc updatedGraph = GraphGrpc.newBuilder().build();
+ NewGraph response = client.updateGraph(graph.getId(),updatedGraph);
+
+ assertEquals(response.getSuccess(),true);
+ }
+
+ @Test
+ public final void test2LoadWithError() throws Exception{
+ // try to load a graph with node without functionalType
+ NodeGrpc node = null;
+ try{
+ node = Client.createNodeGrpc("Node1", null, null, null);
+ fail( "createNodeGrpc didn't throw when I expected it to" );
+ }
+ catch(Exception ex){
+ }
+ List<NodeGrpc> nodes = new ArrayList<NodeGrpc>();
+ if(node != null)
+ nodes.add(node);
+
+ GraphGrpc graph = Client.createGraphGrpc(nodes);
+ graph = client.createGraph(graph).getGraph();
+
+ assertEquals(graph.getId(), 2);
+
+ //getGraphs
+ Iterator<GraphGrpc> graphs = client.getGraphs().iterator();
+
+ assertEquals(graphs.next().getId(), 1);
+ assertEquals(graphs.next(), graph);
+
+ //deleteGraph
+ boolean resp= client.deleteGraph(graph.getId());
+ assertEquals(resp, true);
+
+ List<GraphGrpc> listGraphs = client.getGraphs();
+
+ assertEquals(listGraphs.size(), 1);
+ assertEquals(listGraphs.get(0).getId(), 1);
+ }
+
+ @Test
+ public void test3Node() throws Exception {
+ NodeGrpc ufoundedGraph = NodeGrpc.newBuilder()
+ .setErrorMessage("Node with id 1 not found in graph with id 1").build();
+
+ // graph not found in the server
+ NodeGrpc node = client.getNode(1, 1);//id not present
+
+ assertEquals(ufoundedGraph, node);
+
+ // graph found in the server, but first add it
+ NodeGrpc addedNode = Client.createNodeGrpc("Node4", "firewall", null, null);
+ NewNode response = client.createNode(addedNode, 1);
+ addedNode = response.getNode();
+ node = client.getNode(1, 1);
+
+ assertEquals(addedNode.getId(), node.getId());
+
+ //updateNode
+ NodeGrpc updatedNode = Client.createNodeGrpc("Node9", "endhost", null, null);
+ response = client.updateNode(1, addedNode.getId(), updatedNode);
+
+ assertEquals(response.getSuccess(),true);
+
+ //configureNode
+ //this configuration is valid only on endhost!
+ Map<String,String> params = new HashMap<String,String>();
+ params.put("url", "www.facebook.com");
+ params.put("body", "word");
+ params.put("destination","server");
+ params.put("protocol", "HTTP_REQUEST");
+ ConfigurationGrpc configuration = Client.createConfigurationGrpc(params, null, null, null);
+
+ boolean status = client.configureNode(1, 1, configuration);
+
+ assertEquals(status,true);
+ }
+
+ @Test
+ public void test4Nodes() throws Exception {
+ // setup
+ GraphGrpc graph = Client.createGraphGrpc(null);
+ //createGraph
+ graph = client.createGraph(graph).getGraph();
+
+ List<NeighbourGrpc> neighbours = new ArrayList<NeighbourGrpc>();
+ NeighbourGrpc nb = Client.createNeighbourGrpc("Node6");
+ neighbours.add(nb);
+ NodeGrpc n1 = Client.createNodeGrpc("Node6", "mailserver", null, null);
+ NodeGrpc n2 = Client.createNodeGrpc("Node9", "endhost", neighbours, null);
+ Map<String,String> map = new HashMap<String,String>();
+ map.put("mailserver", "Node6");
+ ConfigurationGrpc conf = Client.createConfigurationGrpc(map, null, null, null);
+ NodeGrpc n3 = Client.createNodeGrpc("Node10", "mailclient", null, conf);
+ NodeGrpc n4 = Client.createNodeGrpc("Node11", "nat", null, null);
+
+ NewNode nw1 = client.createNode(n1, graph.getId());
+ NewNode nw2 = client.createNode(n2, graph.getId());
+ NewNode nw3 = client.createNode(n3, graph.getId());
+ NewNode nw4 = client.createNode(n4, graph.getId());
+ assertEquals(nw1.getSuccess(),true);
+ assertEquals(nw2.getSuccess(),true);
+ assertEquals(nw3.getSuccess(),true);
+ assertEquals(nw4.getSuccess(),true);
+ n1 = NodeGrpc.newBuilder(n1).setId(nw1.getNode().getId()).build();
+ n2 = NodeGrpc.newBuilder(n2).setId(nw2.getNode().getId()).build();
+ n3 = NodeGrpc.newBuilder(n3).setId(nw3.getNode().getId()).build();
+ n4 = NodeGrpc.newBuilder(n4).setId(nw4.getNode().getId()).build();
+
+ // getNodes
+ Iterator<NodeGrpc> nodes = client.getNodes(graph.getId()).iterator();
+
+ assertEquals(nodes.next().getName(), n1.getName());
+ assertEquals(nodes.next().getName(), n2.getName());
+ assertEquals(nodes.next().getName(), n3.getName());
+ assertEquals(nodes.next().getName(), n4.getName());
+
+ //deleteNode
+ client.deleteNode(graph.getId(), 1);
+ // run
+ nodes = client.getNodes(graph.getId()).iterator();
+
+ assertEquals(nodes.next().getName(), n2.getName());
+ assertEquals(nodes.next().getName(), n3.getName());
+ assertEquals(nodes.next().getName(), n4.getName());
+ }
+
+ @Test
+ public void test5Neighbours() throws Exception {
+ NeighbourGrpc ufoundedNeighbour = NeighbourGrpc.newBuilder()
+ .setErrorMessage("Neighbour with id 1 not found for node with id 1 in graph with id 1").build();;
+
+ // Neighbour not found in the server
+ NeighbourGrpc neighbour = client.getNeighbour(1, 1, 1);//id not present
+
+ assertEquals(ufoundedNeighbour, neighbour);
+
+ GraphGrpc graph = Client.createGraphGrpc(null);
+ graph = client.createGraph(graph).getGraph();
+
+ List<NeighbourGrpc> neighbours = new ArrayList<NeighbourGrpc>();
+ NeighbourGrpc nb = Client.createNeighbourGrpc("Node1");
+ neighbours.add(nb);
+ NodeGrpc n1 = Client.createNodeGrpc("Node1", "antispam", null, null);
+ NodeGrpc n2 = Client.createNodeGrpc("Node2", "endhost", neighbours, null);
+ NodeGrpc n3 = Client.createNodeGrpc("Node3", "endhost", null, null);
+ NodeGrpc n4 = Client.createNodeGrpc("Node4", "endpoint", null, null);
+ NodeGrpc n5 = Client.createNodeGrpc("Node5", "webserver", null, null);
+ Map<String,String> map = new HashMap<String,String>();
+ map.put("webserver", "Node5");
+ ConfigurationGrpc conf = Client.createConfigurationGrpc(map, null, null, null);
+ NodeGrpc n6 = Client.createNodeGrpc("Node6", "webclient", null, conf);
+ NodeGrpc n7 = Client.createNodeGrpc("Node7", "cache", null, null);
+ NodeGrpc n8 = Client.createNodeGrpc("Node8", "firewall", null, null);
+ NodeGrpc n9 = Client.createNodeGrpc("Node9", "fieldmodifier", null, null);
+ NodeGrpc n10 = Client.createNodeGrpc("Node10", "dpi", null, null);
+ NewNode nw1 = client.createNode(n1, graph.getId());
+ NewNode nw2 = client.createNode(n2, graph.getId());
+ NewNode nw3 = client.createNode(n3, graph.getId());
+ NewNode nw4 = client.createNode(n4, graph.getId());
+ NewNode nw5 = client.createNode(n5, graph.getId());
+ NewNode nw6 = client.createNode(n6, graph.getId());
+ NewNode nw7 = client.createNode(n7, graph.getId());
+ NewNode nw8 = client.createNode(n8, graph.getId());
+ NewNode nw9 = client.createNode(n9, graph.getId());
+ NewNode nw10 = client.createNode(n10, graph.getId());
+ assertEquals(nw1.getSuccess(),true);
+ assertEquals(nw2.getSuccess(),true);
+ assertEquals(nw3.getSuccess(),true);
+ assertEquals(nw4.getSuccess(),true);
+ assertEquals(nw5.getSuccess(),true);
+ assertEquals(nw6.getSuccess(),true);
+ assertEquals(nw7.getSuccess(),true);
+ assertEquals(nw8.getSuccess(),true);
+ assertEquals(nw9.getSuccess(),true);
+ assertEquals(nw10.getSuccess(),true);
+
+ // getNeighbour, but first add it
+ NeighbourGrpc addedNeighbour = Client.createNeighbourGrpc("Node9");
+ NewNeighbour response = client.createNeighbour(addedNeighbour, graph.getId(), nw1.getNode().getId());
+ addedNeighbour = response.getNeighbour();
+ neighbour = client.getNeighbour(graph.getId(), nw1.getNode().getId(), addedNeighbour.getId());
+
+ assertEquals(addedNeighbour.getId(), neighbour.getId());
+
+ //updateNeighbour
+ NeighbourGrpc updatedNeighbour = Client.createNeighbourGrpc("Node10");
+
+ response = client.updateNeighbour(graph.getId(), 1, addedNeighbour.getId(),updatedNeighbour);
+
+ assertEquals(response.getSuccess(),true);
+ assertEquals(response.getNeighbour().getName(),"Node10");
+ }
+
+ @Test
+ public void test6Neighbours() throws Exception {
+ // setup
+ GraphGrpc graph = Client.createGraphGrpc(null);
+ //createGraph
+ graph = client.createGraph(graph).getGraph();
+
+ NodeGrpc n1 = Client.createNodeGrpc("Node1", "antispam", null, null);
+ NodeGrpc n2 = Client.createNodeGrpc("Node2", "endhost", null, null);
+ NodeGrpc n3 = Client.createNodeGrpc("Node3", "endhost", null, null);
+ NodeGrpc n4 = Client.createNodeGrpc("Node4", "endpoint", null, null);
+ NewNode nw1 = client.createNode(n1, graph.getId());
+ NewNode nw2 = client.createNode(n2, graph.getId());
+ NewNode nw3 = client.createNode(n3, graph.getId());
+ NewNode nw4 = client.createNode(n4, graph.getId());
+ assertEquals(nw1.getSuccess(),true);
+ assertEquals(nw2.getSuccess(),true);
+ assertEquals(nw3.getSuccess(),true);
+ assertEquals(nw4.getSuccess(),true);
+
+ //createNeighbour
+ NeighbourGrpc nn1 = Client.createNeighbourGrpc("Node2");
+ NewNeighbour addedNeighbour1 = client.createNeighbour(nn1, graph.getId(), nw1.getNode().getId());
+ assertEquals(addedNeighbour1.getSuccess(),true);
+ NeighbourGrpc nn2 = Client.createNeighbourGrpc("Node3");
+ NewNeighbour addedNeighbour2 = client.createNeighbour(nn2, graph.getId(), nw1.getNode().getId());
+ assertEquals(addedNeighbour2.getSuccess(),true);
+ NeighbourGrpc nn3 = Client.createNeighbourGrpc("Node4");
+ NewNeighbour addedNeighbour3 = client.createNeighbour(nn3, graph.getId(), nw1.getNode().getId());
+ assertEquals(addedNeighbour3.getSuccess(),true);
+
+ nn1 = NeighbourGrpc.newBuilder(nn1).setId(1).build();
+ nn2 = NeighbourGrpc.newBuilder(nn2).setId(2).build();
+ nn3 = NeighbourGrpc.newBuilder(nn3).setId(3).build();
+ // run
+ Iterator<NeighbourGrpc> neighbours = client.getNeighbours(graph.getId(), nw1.getNode().getId()).iterator();
+
+ assertEquals(neighbours.next(), nn1);
+ assertEquals(neighbours.next(), nn2);
+ assertEquals(neighbours.next(), nn3);
+
+ //deleteNeighbour
+ boolean succ = client.deleteNeighbour(graph.getId(), nw1.getNode().getId(), 1);
+ assertEquals(succ, true);
+ // run
+ neighbours = client.getNeighbours(graph.getId(), nw1.getNode().getId()).iterator();
+
+ assertEquals(neighbours.next(), nn2);
+ assertEquals(neighbours.next(), nn3);
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/test/MultiThreadTest.java b/verigraph/src/main/java/it/polito/grpc/test/MultiThreadTest.java
new file mode 100644
index 0000000..5b76bea
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/test/MultiThreadTest.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc.test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.junit.runners.MethodSorters;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.NodeGrpc;
+import it.polito.escape.verify.client.VerifyClientException;
+import it.polito.grpc.Client;
+import it.polito.grpc.Service;
+
+/**
+ * Unit tests for gRPC project.
+ * For testing concurrency on server side.
+ */
+@RunWith(JUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MultiThreadTest {
+ private Service server;
+ private Client client;
+
+ @Before
+ public void setUp() throws Exception {
+ client = new Client("localhost" , 50051);
+ server = new Service(50051);
+
+ server.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ server.stop();
+ client.shutdown();
+ }
+
+ private void testUpdateGraphStatus(final int threadCount) throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ GraphGrpc retrieveGraphResponse =client.getGraph(1);
+
+ UpdateGraph task = new UpdateGraph(client, 1, retrieveGraphResponse);
+
+ List<MultiThreadTest.UpdateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<NewGraph>> futures = executorService.invokeAll(tasks);
+ List<Boolean> resultList = new ArrayList<Boolean>(futures.size());
+
+ // Check for exceptions
+ for (Future<NewGraph> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ resultList.add(future.get().getSuccess());
+ }
+ // Validate the dimensions
+ Assert.assertEquals(threadCount, futures.size());
+
+ List<Boolean> expectedList = new ArrayList<Boolean>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(true);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private void testUpdateGraph(final int threadCount) throws Exception {
+ GraphGrpc retrieveGraph = client.getGraph(2L);
+ NodeGrpc nodeToEdit = Client.createNodeGrpc("client",
+ "endpoint",
+ null,
+ Client.createConfigurationGrpc(null, null, "client", ""));
+
+ GraphGrpc graphToUpdate = GraphGrpc.newBuilder(retrieveGraph).addNode(nodeToEdit).build();
+
+ String graphAsString = graphToUpdate.toString();
+
+ UpdateGraph task = new UpdateGraph(client, 2, graphToUpdate);
+
+ List<MultiThreadTest.UpdateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<NewGraph>> futures = executorService.invokeAll(tasks);
+ List<String> resultList = new ArrayList<String>(futures.size());
+
+ // Check for exceptions
+ for (Future<NewGraph> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ GraphGrpc graphReceived = future.get().getGraph();
+ NodeGrpc node = NodeGrpc.newBuilder(graphReceived.getNode(0)).setId(0).build();
+ GraphGrpc graph = GraphGrpc.newBuilder(graphReceived).setNode(0, node).build();
+ resultList.add(graph.toString());
+ }
+ // Validate dimensions
+ Assert.assertEquals(threadCount, futures.size());
+
+ List<String> expectedList = new ArrayList<String>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(graphAsString);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private void testCreateGraphStatus(final int threadCount) throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException {
+
+ GraphGrpc graph = GraphGrpc.newBuilder().build();
+
+ CreateGraph task = new CreateGraph(client, graph);
+
+ List<MultiThreadTest.CreateGraph> tasks = Collections.nCopies(threadCount, task);
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+ List<Future<Boolean>> futures = executorService.invokeAll(tasks);
+ List<Boolean> resultList = new ArrayList<Boolean>(futures.size());
+
+ // Check for exceptions
+ for (Future<Boolean> future : futures) {
+ // Throws an exception if an exception was thrown by the task.
+ resultList.add(future.get());
+ }
+ // Validate the IDs
+ Assert.assertEquals(threadCount, futures.size());
+
+ List<Boolean> expectedList = new ArrayList<Boolean>(threadCount);
+ for (int i = 1; i <= threadCount; i++) {
+ expectedList.add(true);
+ }
+ // Validate expected results
+ Assert.assertEquals(expectedList, resultList);
+ }
+
+ private int randInt(int min, int max){
+ Random rand = new Random();
+ int randomNum = rand.nextInt((max - min) + 1) + min;
+ return randomNum;
+ }
+
+ @Test
+ public void updateGraphStatusCheck() throws InterruptedException, ExecutionException, JsonParseException, JsonMappingException, IOException, VerifyClientException {
+ testUpdateGraphStatus(64);
+ }
+
+ @Test
+ public void updateGraphResponseCheck() throws Exception {
+ testUpdateGraph(16);
+ }
+
+ @Test
+ public void createGraphStatusCheck() throws JsonParseException, JsonMappingException, InterruptedException, ExecutionException, IOException {
+ testCreateGraphStatus(8);
+ }
+
+ class UpdateGraph implements Callable<NewGraph> {
+
+ private Client verifyClient;
+
+ private int graphId;
+
+ private GraphGrpc graph;
+
+ public UpdateGraph(Client verifyClient, int graphId, GraphGrpc graph) {
+ this.graphId = graphId;
+ this.graph = graph;
+ this.verifyClient = verifyClient;
+ }
+
+ @Override
+ public NewGraph call() throws Exception {
+ Thread.sleep(randInt(0,2000));
+ return this.verifyClient.updateGraph(this.graphId, this.graph);
+ }
+ }
+
+ class CreateGraph implements Callable<Boolean> {
+
+ private Client verifyClient;
+
+ private GraphGrpc graph;
+
+ public CreateGraph(Client verifyClient, GraphGrpc graph) {
+ this.graph = graph;
+ this.verifyClient = verifyClient;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ Thread.sleep(randInt(0,2000));
+ return this.verifyClient.createGraph(this.graph).getSuccess();
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/grpc/test/ReachabilityTest.java b/verigraph/src/main/java/it/polito/grpc/test/ReachabilityTest.java
new file mode 100644
index 0000000..a120aff
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/grpc/test/ReachabilityTest.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.grpc.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.junit.runners.MethodSorters;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedReader;
+import java.io.FilenameFilter;
+import java.io.InputStreamReader;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.main.JsonSchema;
+
+import io.grpc.verigraph.GraphGrpc;
+import io.grpc.verigraph.NewGraph;
+import io.grpc.verigraph.Policy;
+import io.grpc.verigraph.VerificationGrpc;
+import it.polito.escape.verify.client.VerifyClientException;
+import it.polito.escape.verify.service.ValidationUtils;
+import it.polito.escape.verify.test.TestCase;
+import it.polito.escape.verify.test.TestExecutionException;
+import it.polito.grpc.Client;
+import it.polito.grpc.GrpcUtils;
+import it.polito.grpc.Service;
+
+@RunWith(JUnit4.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ReachabilityTest {
+ private File schema;
+ private List<File> testFiles = new ArrayList<File>();
+ private List<TestCase> testCases = new ArrayList<TestCase>();
+ private Client client;
+ private Service server;
+
+ @Before
+ public void setUpBeforeClass() throws Exception {
+ client = new Client("localhost" , 50051);
+ server = new Service(50051);
+ server.start();
+
+ String folderName = System.getProperty("user.dir") + "/tester/testcases";
+ File folder = new File(folderName);
+ if (!folder.exists()) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String s;
+ do{
+ System.out.println("Please enter the testcases folder path: ");
+ s = in.readLine();
+ if (isValidpath(s)){
+ folder = new File(s);
+ break;
+ }
+ }while (s != null && s.length() != 0);
+ if(s == null)
+ System.exit(0);
+ }
+ String schemaName = System.getProperty("user.dir") + "/tester/testcase_schema.json";
+ File schema = new File(schemaName);
+ if (!schema.exists()) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String s;
+ do{
+ System.out.println("Please enter the full path of 'testcase_schema.json': ");
+ s = in.readLine();
+ if (isValidpath(s)){
+ folder = new File(s);
+ break;
+ }
+ }while (s != null && s.length() != 0);
+ if(s == null)
+ System.exit(0);
+ }
+
+ this.schema = schema;
+ this.testFiles = getTests(folder);
+ this.testCases = getTestCases(this.testFiles);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ server.stop();
+ client.shutdown();
+ }
+
+ @Test
+ public final void wrongReachability() {
+ System.out.println("DEBUG: starting testWrongReachability");
+
+ VerificationGrpc nullVer = VerificationGrpc.newBuilder()
+ .setErrorMessage("Graph with id 52 not found").build();
+ //verification on uncreated graph
+ Policy policyToVerify = Client.createPolicy("Node1", "Node4", "reachability", null, 52);
+ VerificationGrpc ver = client.verify(policyToVerify);
+ assertEquals(ver, nullVer);
+
+ //verification on uncreated nodes
+ nullVer = VerificationGrpc.newBuilder()
+ .setErrorMessage("The \'source\' parameter \'Node5\' is not valid, please insert the name of an existing node").build();
+ policyToVerify = Client.createPolicy("Node5", "Node4", "reachability", null, 1);
+ ver = client.verify(policyToVerify);
+ assertEquals(ver, nullVer);
+
+ //verification on uncreated nodes
+ nullVer = VerificationGrpc.newBuilder()
+ .setErrorMessage("The \'source\' parameter \'Node1\' is not valid, please insert the name of an existing node").build();
+
+ policyToVerify = Client.createPolicy("Node1", "Node10", "reachability", null, 1);
+ ver = client.verify(policyToVerify);
+ assertEquals(ver, nullVer);
+
+ }
+
+ public List<File> getTests(File folder) {
+ List<File> filesList = new ArrayList<File>();
+
+ System.out.println("Test folder set to '" + folder.getAbsolutePath() + "'");
+
+ File[] files = folder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".json");
+ }
+ });
+
+ for (File f : files) {
+ filesList.add(f);
+ System.out.println("File '" + f.getName() + "' added to test files");
+ }
+
+ return filesList;
+ }
+
+ public List<TestCase> getTestCases(List<File> files) throws JsonParseException, JsonMappingException, IOException,
+ Exception {
+ List<TestCase> testCases = new ArrayList<TestCase>();
+
+ for (File file : files) {
+ validateTestFile(file);
+ try {
+ TestCase tc = new ObjectMapper().readValue(file, TestCase.class);
+ testCases.add(tc);
+ }
+ catch (Exception e) {
+ throw e;
+ }
+ }
+
+ return testCases;
+ }
+
+ @Test
+ public void runTestCases() throws VerifyClientException, TestExecutionException {
+ int counter = 0;
+ for (TestCase tc : this.testCases) {
+ String result = runTestCase(tc);
+ if (!result.equals(tc.getResult()))
+ throw new TestExecutionException("Error running test given in file '" + this.testFiles.get(counter).getName()
+ + "'. Test returned '" + result + "' instead of '" + tc.getResult() + "'.");
+ else
+ System.out.println("Test given in file '" + this.testFiles.get(counter).getName() + "' returned '"
+ + result + "' as expected");
+ counter++;
+
+ }
+ System.out.println("All tests PASSED");
+ }
+
+ private String runTestCase(TestCase tc) throws VerifyClientException, TestExecutionException{
+ GraphGrpc graph = GrpcUtils.obtainGraph(tc.getGraph());
+
+ NewGraph newGraph = this.client.createGraph(graph);
+ if(newGraph.getSuccess() == false)
+ throw new VerifyClientException("gRPC request failed");
+ GraphGrpc createdGraph = newGraph.getGraph();
+
+ GraphGrpc addedgraph = client.getGraph(createdGraph.getId());
+ System.out.println(addedgraph);
+
+ final Map<String, String> map = GrpcUtils.getParamGivenString(tc.getPolicyUrlParameters());
+
+ Policy policy = Client.createPolicy(map.get("source"),
+ map.get("destination"),
+ map.get("type"),
+ map.get("middlebox"),
+ createdGraph.getId());
+ VerificationGrpc verification = this.client.verify(policy);
+ return verification.getResult();
+ }
+
+ public void validateTestFile(File testFile) throws Exception {
+ JsonSchema schemaNode = null;
+ try {
+ schemaNode = ValidationUtils.getSchemaNode(schema);
+ }
+ catch (IOException e) {
+ throw new Exception("Unable to load '" + schema.getAbsolutePath() + "' schema file");
+ }
+ catch (ProcessingException e) {
+ throw new Exception("Unable to resolve '" + schema.getAbsolutePath() + "' schema file as a schema node");
+ }
+
+ JsonNode jsonNode;
+ try {
+ jsonNode = ValidationUtils.getJsonNode(testFile);
+ }
+ catch (IOException e) {
+ throw new Exception("Unable to load '" + testFile.getAbsolutePath() + "' as a json node");
+ }
+
+ try {
+ ValidationUtils.validateJson(schemaNode, jsonNode);
+ }
+ catch (ProcessingException e) {
+ throw new Exception("There were errors in the validation of file '" + testFile.getAbsolutePath()
+ + "' against the json schema '" + schema.getAbsolutePath() + "': " + e.getMessage());
+
+ }
+ }
+
+ private static boolean isValidpath(String s) {
+ if (s==null)
+ return false;
+ File file = new File(s);
+ return file.exists();
+ }
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionEnumType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionEnumType.java
new file mode 100644
index 0000000..e7504b5
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionEnumType.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for actionEnumType.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="actionEnumType">
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * &lt;enumeration value="discard"/>
+ * &lt;enumeration value="output"/>
+ * &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ *
+ */
+@XmlType(name = "actionEnumType")
+@XmlEnum
+public enum ActionEnumType {
+
+ @XmlEnumValue("discard")
+ DISCARD("discard"),
+ @XmlEnumValue("output")
+ OUTPUT("output");
+ private final String value;
+
+ ActionEnumType(String v) {
+ value = v;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public static ActionEnumType fromValue(String v) {
+ for (ActionEnumType c: ActionEnumType.values()) {
+ if (c.value.equals(v)) {
+ return c;
+ }
+ }
+ throw new IllegalArgumentException(v);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionType.java
new file mode 100644
index 0000000..db86975
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionType.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for actionType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="actionType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" use="required" type="{http://www.example.org/nffg/}actionEnumType" />
+ * &lt;attribute name="port" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "actionType")
+public class ActionType {
+
+ @XmlAttribute(name = "type", required = true)
+ protected ActionEnumType type;
+ @XmlAttribute(name = "port")
+ protected String port;
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link ActionEnumType }
+ */
+ public ActionEnumType getType() {
+ return type;
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link ActionEnumType }
+ */
+ public void setType(ActionEnumType value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the port property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getPort() {
+ return port;
+ }
+
+ /**
+ * Sets the value of the port property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setPort(String value) {
+ this.port = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionsType.java
new file mode 100644
index 0000000..5b81ae7
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ActionsType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for actionsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="actionsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="action" type="{http://www.example.org/nffg/}actionType" maxOccurs="unbounded"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "actionsType", propOrder = {
+ "action"
+})
+public class ActionsType {
+
+ @XmlElement(required = true)
+ protected List<ActionType> action;
+
+ /**
+ * Gets the value of the action property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the action property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAction().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link ActionType }
+ */
+ public List<ActionType> getAction() {
+ if (action == null) {
+ action = new ArrayList<ActionType>();
+ }
+ return this.action;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CiType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CiType.java
new file mode 100644
index 0000000..9a82728
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CiType.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for ciType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="ciType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="attributes">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="attribute" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.example.org/nffg/}ciIdType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "ciType", propOrder = {
+ "attributes"
+})
+public class CiType {
+
+ @XmlElement(required = true)
+ protected CiType.Attributes attributes;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+
+ /**
+ * Gets the value of the attributes property.
+ * @return
+ * possible object is
+ * {@link CiType.Attributes }
+ */
+ public CiType.Attributes getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Sets the value of the attributes property.
+ * @param value
+ * allowed object is
+ * {@link CiType.Attributes }
+ */
+ public void setAttributes(CiType.Attributes value) {
+ this.attributes = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="attribute" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "attribute"
+ })
+ public static class Attributes {
+
+ protected List<CiType.Attributes.Attribute> attribute;
+
+ /**
+ * Gets the value of the attribute property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the attribute property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAttribute().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link CiType.Attributes.Attribute }
+ */
+ public List<CiType.Attributes.Attribute> getAttribute() {
+ if (attribute == null) {
+ attribute = new ArrayList<CiType.Attributes.Attribute>();
+ }
+ return this.attribute;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Attribute {
+
+ @XmlAttribute(name = "value", required = true)
+ protected String value;
+
+ /**
+ * Gets the value of the value property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpType.java
new file mode 100644
index 0000000..4a67b79
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpType.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for cpType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="cpType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="port" type="{http://www.example.org/nffg/}portType"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.example.org/nffg/}cpIdType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "cpType", propOrder = {
+ "port"
+})
+public class CpType {
+
+ @XmlElement(required = true)
+ protected PortType port;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+
+ /**
+ * Gets the value of the port property.
+ * @return
+ * possible object is
+ * {@link PortType }
+ */
+ public PortType getPort() {
+ return port;
+ }
+
+ /**
+ * Sets the value of the port property.
+ * @param value
+ * allowed object is
+ * {@link PortType }
+ */
+ public void setPort(PortType value) {
+ this.port = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpointsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpointsType.java
new file mode 100644
index 0000000..4c820ed
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CpointsType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for cpointsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="cpointsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="connection_point" type="{http://www.example.org/nffg/}cpType" maxOccurs="unbounded"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "cpointsType", propOrder = {
+ "connectionPoint"
+})
+public class CpointsType {
+
+ @XmlElement(name = "connection_point", required = true)
+ protected List<CpType> connectionPoint;
+
+ /**
+ * Gets the value of the connectionPoint property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the connectionPoint property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getConnectionPoint().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link CpType }
+ */
+ public List<CpType> getConnectionPoint() {
+ if (connectionPoint == null) {
+ connectionPoint = new ArrayList<CpType>();
+ }
+ return this.connectionPoint;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CtrlInterfacesType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CtrlInterfacesType.java
new file mode 100644
index 0000000..02ad675
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/CtrlInterfacesType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for ctrlInterfacesType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="ctrlInterfacesType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="control_interface" type="{http://www.example.org/nffg/}ciType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "ctrlInterfacesType", propOrder = {
+ "controlInterface"
+})
+public class CtrlInterfacesType {
+
+ @XmlElement(name = "control_interface")
+ protected List<CiType> controlInterface;
+
+ /**
+ * Gets the value of the controlInterface property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the controlInterface property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getControlInterface().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link CiType }
+ */
+ public List<CiType> getControlInterface() {
+ if (controlInterface == null) {
+ controlInterface = new ArrayList<CiType>();
+ }
+ return this.controlInterface;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpCpType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpCpType.java
new file mode 100644
index 0000000..a9448c1
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpCpType.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for ep-cpType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="ep-cpType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="flowrules" type="{http://www.example.org/nffg/}flowrulesType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id_ref" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "ep-cpType", propOrder = {
+ "flowrules"
+})
+public class EpCpType {
+
+ protected List<FlowrulesType> flowrules;
+ @XmlAttribute(name = "id_ref", required = true)
+ protected String idRef;
+
+ /**
+ * Gets the value of the flowrules property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the flowrules property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getFlowrules().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link FlowrulesType }
+ */
+ public List<FlowrulesType> getFlowrules() {
+ if (flowrules == null) {
+ flowrules = new ArrayList<FlowrulesType>();
+ }
+ return this.flowrules;
+ }
+
+ /**
+ * Gets the value of the idRef property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getIdRef() {
+ return idRef;
+ }
+
+ /**
+ * Sets the value of the idRef property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setIdRef(String value) {
+ this.idRef = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpType.java
new file mode 100644
index 0000000..2ae875d
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpType.java
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for epType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="epType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="flowspace">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;group ref="{http://www.example.org/nffg/}L2HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L3HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L4HeaderParameters"/>
+ * &lt;/sequence>
+ * &lt;attribute name="nodeId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="ingPhysPort" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.example.org/nffg/}epIdType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "epType", propOrder = {
+ "flowspace"
+})
+public class EpType {
+
+ @XmlElement(required = true)
+ protected EpType.Flowspace flowspace;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+
+ /**
+ * Gets the value of the flowspace property.
+ * @return
+ * possible object is
+ * {@link EpType.Flowspace }
+ */
+ public EpType.Flowspace getFlowspace() {
+ return flowspace;
+ }
+
+ /**
+ * Sets the value of the flowspace property.
+ * @param value
+ * allowed object is
+ * {@link EpType.Flowspace }
+ */
+ public void setFlowspace(EpType.Flowspace value) {
+ this.flowspace = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;group ref="{http://www.example.org/nffg/}L2HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L3HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L4HeaderParameters"/>
+ * &lt;/sequence>
+ * &lt;attribute name="nodeId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="ingPhysPort" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "mac",
+ "ip",
+ "tcp",
+ "udp"
+ })
+ public static class Flowspace {
+
+ protected it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Mac mac;
+ protected it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Ip ip;
+ protected it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp tcp;
+ protected it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Udp udp;
+ @XmlAttribute(name = "nodeId")
+ protected String nodeId;
+ @XmlAttribute(name = "ingPhysPort")
+ protected String ingPhysPort;
+
+ /**
+ * Gets the value of the mac property.
+ * @return
+ * possible object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Mac }
+ */
+ public it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Mac getMac() {
+ return mac;
+ }
+
+ /**
+ * Sets the value of the mac property.
+ * @param value
+ * allowed object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Mac }
+ */
+ public void setMac(it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Mac value) {
+ this.mac = value;
+ }
+
+ /**
+ * Gets the value of the ip property.
+ * @return
+ * possible object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Ip }
+ */
+ public it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Ip getIp() {
+ return ip;
+ }
+
+ /**
+ * Sets the value of the ip property.
+ * @param value
+ * allowed object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Ip }
+ */
+ public void setIp(it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Ip value) {
+ this.ip = value;
+ }
+
+ /**
+ * Gets the value of the tcp property.
+ * @return
+ * possible object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp }
+ */
+ public it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp getTcp() {
+ return tcp;
+ }
+
+ /**
+ * Sets the value of the tcp property.
+ * @param value
+ * allowed object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp }
+ */
+ public void setTcp(it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Tcp value) {
+ this.tcp = value;
+ }
+
+ /**
+ * Gets the value of the udp property.
+ * @return
+ * possible object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Udp }
+ */
+ public it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Udp getUdp() {
+ return udp;
+ }
+
+ /**
+ * Sets the value of the udp property.
+ * @param value
+ * allowed object is
+ * {@link it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Udp }
+ */
+ public void setUdp(it.polito.nffg.neo4j.jaxb.FlowrulesType.Flowspace.Udp value) {
+ this.udp = value;
+ }
+
+ /**
+ * Gets the value of the nodeId property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Sets the value of the nodeId property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setNodeId(String value) {
+ this.nodeId = value;
+ }
+
+ /**
+ * Gets the value of the ingPhysPort property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getIngPhysPort() {
+ return ingPhysPort;
+ }
+
+ /**
+ * Sets the value of the ingPhysPort property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setIngPhysPort(String value) {
+ this.ingPhysPort = value;
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpointsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpointsType.java
new file mode 100644
index 0000000..850d8b6
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpointsType.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for epointsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="epointsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="endpoint" type="{http://www.example.org/nffg/}epType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "epointsType", propOrder = {
+ "endpoint"
+})
+public class EpointsType {
+
+ protected List<EpType> endpoint;
+
+ /**
+ * Gets the value of the endpoint property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the endpoint property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getEndpoint().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link EpType }
+ */
+ public List<EpType> getEndpoint() {
+ if (endpoint == null) {
+ endpoint = new ArrayList<EpType>();
+ }
+ return this.endpoint;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpsCpsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpsCpsType.java
new file mode 100644
index 0000000..181085e
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/EpsCpsType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for eps-cpsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="eps-cpsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="ep-cp" type="{http://www.example.org/nffg/}ep-cpType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "eps-cpsType", propOrder = {
+ "epCp"
+})
+public class EpsCpsType {
+
+ @XmlElement(name = "ep-cp")
+ protected List<EpCpType> epCp;
+
+ /**
+ * Gets the value of the epCp property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the epCp property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getEpCp().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link EpCpType }
+ */
+ public List<EpCpType> getEpCp() {
+ if (epCp == null) {
+ epCp = new ArrayList<EpCpType>();
+ }
+ return this.epCp;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/FlowrulesType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/FlowrulesType.java
new file mode 100644
index 0000000..53c8f79
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/FlowrulesType.java
@@ -0,0 +1,619 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for flowrulesType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="flowrulesType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="flowspace">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;group ref="{http://www.example.org/nffg/}L2HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L3HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L4HeaderParameters"/>
+ * &lt;/sequence>
+ * &lt;attribute name="ingPort" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="actions" type="{http://www.example.org/nffg/}actionsType"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "flowrulesType", propOrder = {
+ "flowspace",
+ "actions"
+})
+public class FlowrulesType {
+
+ @XmlElement(required = true)
+ protected FlowrulesType.Flowspace flowspace;
+ @XmlElement(required = true)
+ protected ActionsType actions;
+
+ /**
+ * Gets the value of the flowspace property.
+ * @return
+ * possible object is
+ * {@link FlowrulesType.Flowspace }
+ */
+ public FlowrulesType.Flowspace getFlowspace() {
+ return flowspace;
+ }
+
+ /**
+ * Sets the value of the flowspace property.
+ * @param value
+ * allowed object is
+ * {@link FlowrulesType.Flowspace }
+ */
+ public void setFlowspace(FlowrulesType.Flowspace value) {
+ this.flowspace = value;
+ }
+
+ /**
+ * Gets the value of the actions property.
+ * @return
+ * possible object is
+ * {@link ActionsType }
+ */
+ public ActionsType getActions() {
+ return actions;
+ }
+
+ /**
+ * Sets the value of the actions property.
+ * @param value
+ * allowed object is
+ * {@link ActionsType }
+ */
+ public void setActions(ActionsType value) {
+ this.actions = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;group ref="{http://www.example.org/nffg/}L2HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L3HeaderParameters"/>
+ * &lt;group ref="{http://www.example.org/nffg/}L4HeaderParameters"/>
+ * &lt;/sequence>
+ * &lt;attribute name="ingPort" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "mac",
+ "ip",
+ "tcp",
+ "udp"
+ })
+ public static class Flowspace {
+
+ protected FlowrulesType.Flowspace.Mac mac;
+ protected FlowrulesType.Flowspace.Ip ip;
+ protected FlowrulesType.Flowspace.Tcp tcp;
+ protected FlowrulesType.Flowspace.Udp udp;
+ @XmlAttribute(name = "ingPort")
+ protected String ingPort;
+
+ /**
+ * Gets the value of the mac property.
+ * @return
+ * possible object is
+ * {@link FlowrulesType.Flowspace.Mac }
+ */
+ public FlowrulesType.Flowspace.Mac getMac() {
+ return mac;
+ }
+
+ /**
+ * Sets the value of the mac property.
+ * @param value
+ * allowed object is
+ * {@link FlowrulesType.Flowspace.Mac }
+ */
+ public void setMac(FlowrulesType.Flowspace.Mac value) {
+ this.mac = value;
+ }
+
+ /**
+ * Gets the value of the ip property.
+ * @return
+ * possible object is
+ * {@link FlowrulesType.Flowspace.Ip }
+ */
+ public FlowrulesType.Flowspace.Ip getIp() {
+ return ip;
+ }
+
+ /**
+ * Sets the value of the ip property.
+ * @param value
+ * allowed object is
+ * {@link FlowrulesType.Flowspace.Ip }
+ */
+ public void setIp(FlowrulesType.Flowspace.Ip value) {
+ this.ip = value;
+ }
+
+ /**
+ * Gets the value of the tcp property.
+ * @return
+ * possible object is
+ * {@link FlowrulesType.Flowspace.Tcp }
+ */
+ public FlowrulesType.Flowspace.Tcp getTcp() {
+ return tcp;
+ }
+
+ /**
+ * Sets the value of the tcp property.
+ * @param value
+ * allowed object is
+ * {@link FlowrulesType.Flowspace.Tcp }
+ */
+ public void setTcp(FlowrulesType.Flowspace.Tcp value) {
+ this.tcp = value;
+ }
+
+ /**
+ * Gets the value of the udp property.
+ * @return
+ * possible object is
+ * {@link FlowrulesType.Flowspace.Udp }
+ */
+ public FlowrulesType.Flowspace.Udp getUdp() {
+ return udp;
+ }
+
+ /**
+ * Sets the value of the udp property.
+ * @param value
+ * allowed object is
+ * {@link FlowrulesType.Flowspace.Udp }
+ */
+ public void setUdp(FlowrulesType.Flowspace.Udp value) {
+ this.udp = value;
+ }
+
+ /**
+ * Gets the value of the ingPort property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getIngPort() {
+ return ingPort;
+ }
+
+ /**
+ * Sets the value of the ingPort property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setIngPort(String value) {
+ this.ingPort = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="src" type="{http://www.example.org/net/}ipAddressType" />
+ * &lt;attribute name="dst" type="{http://www.example.org/net/}ipAddressType" />
+ * &lt;attribute name="ipProtocol" type="{http://www.w3.org/2001/XMLSchema}unsignedByte" />
+ * &lt;attribute name="tos" type="{http://www.w3.org/2001/XMLSchema}unsignedByte" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Ip {
+
+ @XmlAttribute(name = "src")
+ protected String src;
+ @XmlAttribute(name = "dst")
+ protected String dst;
+ @XmlAttribute(name = "ipProtocol")
+ @XmlSchemaType(name = "unsignedByte")
+ protected Short ipProtocol;
+ @XmlAttribute(name = "tos")
+ @XmlSchemaType(name = "unsignedByte")
+ protected Short tos;
+
+ /**
+ * Gets the value of the src property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSrc() {
+ return src;
+ }
+
+ /**
+ * Sets the value of the src property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSrc(String value) {
+ this.src = value;
+ }
+
+ /**
+ * Gets the value of the dst property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDst() {
+ return dst;
+ }
+
+ /**
+ * Sets the value of the dst property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDst(String value) {
+ this.dst = value;
+ }
+
+ /**
+ * Gets the value of the ipProtocol property.
+ * @return
+ * possible object is
+ * {@link Short }
+ */
+ public Short getIpProtocol() {
+ return ipProtocol;
+ }
+
+ /**
+ * Sets the value of the ipProtocol property.
+ * @param value
+ * allowed object is
+ * {@link Short }
+ */
+ public void setIpProtocol(Short value) {
+ this.ipProtocol = value;
+ }
+
+ /**
+ * Gets the value of the tos property.
+ * @return
+ * possible object is
+ * {@link Short }
+ */
+ public Short getTos() {
+ return tos;
+ }
+
+ /**
+ * Sets the value of the tos property.
+ * @param value
+ * allowed object is
+ * {@link Short }
+ */
+ public void setTos(Short value) {
+ this.tos = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="src" type="{http://www.example.org/net/}macAddressType" />
+ * &lt;attribute name="dst" type="{http://www.example.org/net/}macAddressType" />
+ * &lt;attribute name="ethertype" type="{http://www.example.org/net/}ethertypeType" />
+ * &lt;attribute name="vlanId" type="{http://www.example.org/net/}vlanIdType" />
+ * &lt;attribute name="vlanPcp" type="{http://www.example.org/net/}vlanPcpType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Mac {
+
+ @XmlAttribute(name = "src")
+ protected String src;
+ @XmlAttribute(name = "dst")
+ protected String dst;
+ @XmlAttribute(name = "ethertype")
+ protected Integer ethertype;
+ @XmlAttribute(name = "vlanId")
+ protected Integer vlanId;
+ @XmlAttribute(name = "vlanPcp")
+ protected Integer vlanPcp;
+
+ /**
+ * Gets the value of the src property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSrc() {
+ return src;
+ }
+
+ /**
+ * Sets the value of the src property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSrc(String value) {
+ this.src = value;
+ }
+
+ /**
+ * Gets the value of the dst property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDst() {
+ return dst;
+ }
+
+ /**
+ * Sets the value of the dst property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDst(String value) {
+ this.dst = value;
+ }
+
+ /**
+ * Gets the value of the ethertype property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getEthertype() {
+ return ethertype;
+ }
+
+ /**
+ * Sets the value of the ethertype property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setEthertype(Integer value) {
+ this.ethertype = value;
+ }
+
+ /**
+ * Gets the value of the vlanId property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getVlanId() {
+ return vlanId;
+ }
+
+ /**
+ * Sets the value of the vlanId property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setVlanId(Integer value) {
+ this.vlanId = value;
+ }
+
+ /**
+ * Gets the value of the vlanPcp property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getVlanPcp() {
+ return vlanPcp;
+ }
+
+ /**
+ * Sets the value of the vlanPcp property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setVlanPcp(Integer value) {
+ this.vlanPcp = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="src" type="{http://www.example.org/net/}portNumberType" />
+ * &lt;attribute name="dst" type="{http://www.example.org/net/}portNumberType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Tcp {
+
+ @XmlAttribute(name = "src")
+ protected Integer src;
+ @XmlAttribute(name = "dst")
+ protected Integer dst;
+
+ /**
+ * Gets the value of the src property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getSrc() {
+ return src;
+ }
+
+ /**
+ * Sets the value of the src property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setSrc(Integer value) {
+ this.src = value;
+ }
+
+ /**
+ * Gets the value of the dst property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getDst() {
+ return dst;
+ }
+
+ /**
+ * Sets the value of the dst property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setDst(Integer value) {
+ this.dst = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="src" type="{http://www.example.org/net/}portNumberType" />
+ * &lt;attribute name="dst" type="{http://www.example.org/net/}portNumberType" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Udp {
+
+ @XmlAttribute(name = "src")
+ protected Integer src;
+ @XmlAttribute(name = "dst")
+ protected Integer dst;
+
+ /**
+ * Gets the value of the src property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getSrc() {
+ return src;
+ }
+
+ /**
+ * Sets the value of the src property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setSrc(Integer value) {
+ this.src = value;
+ }
+
+ /**
+ * Gets the value of the dst property.
+ * @return
+ * possible object is
+ * {@link Integer }
+ */
+ public Integer getDst() {
+ return dst;
+ }
+
+ /**
+ * Sets the value of the dst property.
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ */
+ public void setDst(Integer value) {
+ this.dst = value;
+ }
+
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/HttpMessage.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/HttpMessage.java
new file mode 100644
index 0000000..5dc7c29
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/HttpMessage.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="statusCode" type="{http://www.w3.org/2001/XMLSchema}unsignedShort"/>
+ * &lt;element name="reasonPhrase" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "statusCode",
+ "reasonPhrase",
+ "message"
+})
+@XmlRootElement(name = "httpMessage", namespace = "http://www.example.org/response/")
+public class HttpMessage {
+
+ @XmlElement(namespace = "http://www.example.org/response/", defaultValue = "500")
+ @XmlSchemaType(name = "unsignedShort")
+ protected int statusCode;
+ @XmlElement(namespace = "http://www.example.org/response/", required = true, defaultValue = "Internal Server Error")
+ protected String reasonPhrase;
+ @XmlElement(namespace = "http://www.example.org/response/")
+ protected String message;
+
+ /**
+ * Gets the value of the statusCode property.
+ */
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ /**
+ * Sets the value of the statusCode property.
+ */
+ public void setStatusCode(int value) {
+ this.statusCode = value;
+ }
+
+ /**
+ * Gets the value of the reasonPhrase property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getReasonPhrase() {
+ return reasonPhrase;
+ }
+
+ /**
+ * Sets the value of the reasonPhrase property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setReasonPhrase(String value) {
+ this.reasonPhrase = value;
+ }
+
+ /**
+ * Gets the value of the message property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets the value of the message property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setMessage(String value) {
+ this.message = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/MonParamsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/MonParamsType.java
new file mode 100644
index 0000000..8651966
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/MonParamsType.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for monParamsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="monParamsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="parameter" maxOccurs="unbounded" minOccurs="0">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}NMTOKENS" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "monParamsType", propOrder = {
+ "parameter"
+})
+public class MonParamsType {
+
+ protected List<MonParamsType.Parameter> parameter;
+
+ /**
+ * Gets the value of the parameter property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the parameter property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getParameter().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link MonParamsType.Parameter }
+ */
+ public List<MonParamsType.Parameter> getParameter() {
+ if (parameter == null) {
+ parameter = new ArrayList<MonParamsType.Parameter>();
+ }
+ return this.parameter;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}NMTOKENS" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Parameter {
+
+ @XmlAttribute(name = "value", required = true)
+ @XmlSchemaType(name = "NMTOKENS")
+ protected List<String> value;
+
+ /**
+ * Gets the value of the value property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the value property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getValue().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ */
+ public List<String> getValue() {
+ if (value == null) {
+ value = new ArrayList<String>();
+ }
+ return this.value;
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NeType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NeType.java
new file mode 100644
index 0000000..9cdecdd
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NeType.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for neType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="neType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="eps-cps" type="{http://www.example.org/nffg/}eps-cpsType"/>
+ * &lt;element name="monitoring_parameters" type="{http://www.example.org/nffg/}monParamsType"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.example.org/nffg/}neIdType" />
+ * &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "neType", propOrder = {
+ "epsCps",
+ "monitoringParameters"
+})
+public class NeType {
+
+ @XmlElement(name = "eps-cps", required = true)
+ protected EpsCpsType epsCps;
+ @XmlElement(name = "monitoring_parameters", required = true)
+ protected MonParamsType monitoringParameters;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+ @XmlAttribute(name = "type", required = true)
+ protected String type;
+
+ /**
+ * Gets the value of the epsCps property.
+ * @return
+ * possible object is
+ * {@link EpsCpsType }
+ */
+ public EpsCpsType getEpsCps() {
+ return epsCps;
+ }
+
+ /**
+ * Sets the value of the epsCps property.
+ * @param value
+ * allowed object is
+ * {@link EpsCpsType }
+ */
+ public void setEpsCps(EpsCpsType value) {
+ this.epsCps = value;
+ }
+
+ /**
+ * Gets the value of the monitoringParameters property.
+ * @return
+ * possible object is
+ * {@link MonParamsType }
+ */
+ public MonParamsType getMonitoringParameters() {
+ return monitoringParameters;
+ }
+
+ /**
+ * Sets the value of the monitoringParameters property.
+ * @param value
+ * allowed object is
+ * {@link MonParamsType }
+ */
+ public void setMonitoringParameters(MonParamsType value) {
+ this.monitoringParameters = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NelementsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NelementsType.java
new file mode 100644
index 0000000..0ccef60
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NelementsType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for nelementsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="nelementsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="network_element" type="{http://www.example.org/nffg/}neType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "nelementsType", propOrder = {
+ "networkElement"
+})
+public class NelementsType {
+
+ @XmlElement(name = "network_element")
+ protected List<NeType> networkElement;
+
+ /**
+ * Gets the value of the networkElement property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the networkElement property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getNetworkElement().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link NeType }
+ */
+ public List<NeType> getNetworkElement() {
+ if (networkElement == null) {
+ networkElement = new ArrayList<NeType>();
+ }
+ return this.networkElement;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfType.java
new file mode 100644
index 0000000..f2b50ea
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfType.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for nfType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="nfType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="specification" type="{http://www.example.org/nffg/}specType"/>
+ * &lt;element name="connection_points" type="{http://www.example.org/nffg/}cpointsType"/>
+ * &lt;element name="control_interfaces" type="{http://www.example.org/nffg/}ctrlInterfacesType"/>
+ * &lt;element name="monitoring_parameters" type="{http://www.example.org/nffg/}monParamsType"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.example.org/nffg/}nfIdType" />
+ * &lt;attribute name="functionalType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "nfType", propOrder = {
+ "specification",
+ "connectionPoints",
+ "controlInterfaces",
+ "monitoringParameters"
+})
+public class NfType {
+
+ @XmlElement(required = true)
+ protected SpecType specification;
+ @XmlElement(name = "connection_points", required = true)
+ protected CpointsType connectionPoints;
+ @XmlElement(name = "control_interfaces", required = true)
+ protected CtrlInterfacesType controlInterfaces;
+ @XmlElement(name = "monitoring_parameters", required = true)
+ protected MonParamsType monitoringParameters;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+ @XmlAttribute(name = "functionalType", required = true)
+ protected String functionalType;
+
+ /**
+ * Gets the value of the specification property.
+ * @return
+ * possible object is
+ * {@link SpecType }
+ */
+ public SpecType getSpecification() {
+ return specification;
+ }
+
+ /**
+ * Sets the value of the specification property.
+ * @param value
+ * allowed object is
+ * {@link SpecType }
+ */
+ public void setSpecification(SpecType value) {
+ this.specification = value;
+ }
+
+ /**
+ * Gets the value of the connectionPoints property.
+ * @return
+ * possible object is
+ * {@link CpointsType }
+ */
+ public CpointsType getConnectionPoints() {
+ return connectionPoints;
+ }
+
+ /**
+ * Sets the value of the connectionPoints property.
+ * @param value
+ * allowed object is
+ * {@link CpointsType }
+ */
+ public void setConnectionPoints(CpointsType value) {
+ this.connectionPoints = value;
+ }
+
+ /**
+ * Gets the value of the controlInterfaces property.
+ * @return
+ * possible object is
+ * {@link CtrlInterfacesType }
+ */
+ public CtrlInterfacesType getControlInterfaces() {
+ return controlInterfaces;
+ }
+
+ /**
+ * Sets the value of the controlInterfaces property.
+ * @param value
+ * allowed object is
+ * {@link CtrlInterfacesType }
+ */
+ public void setControlInterfaces(CtrlInterfacesType value) {
+ this.controlInterfaces = value;
+ }
+
+ /**
+ * Gets the value of the monitoringParameters property.
+ * @return
+ * possible object is
+ * {@link MonParamsType }
+ */
+ public MonParamsType getMonitoringParameters() {
+ return monitoringParameters;
+ }
+
+ /**
+ * Sets the value of the monitoringParameters property.
+ * @param value
+ * allowed object is
+ * {@link MonParamsType }
+ */
+ public void setMonitoringParameters(MonParamsType value) {
+ this.monitoringParameters = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the functionalType property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getFunctionalType() {
+ return functionalType;
+ }
+
+ /**
+ * Sets the value of the functionalType property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setFunctionalType(String value) {
+ this.functionalType = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Nffg.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Nffg.java
new file mode 100644
index 0000000..54e6daf
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Nffg.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="endpoints" type="{http://www.example.org/nffg/}epointsType"/>
+ * &lt;element name="network_functions" type="{http://www.example.org/nffg/}nfunctionsType"/>
+ * &lt;element name="network_elements" type="{http://www.example.org/nffg/}nelementsType"/>
+ * &lt;element name="monitoring_parameters" type="{http://www.example.org/nffg/}monParamsType"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" type="{http://www.example.org/nffg/}nffgIdType" />
+ * &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "endpoints",
+ "networkFunctions",
+ "networkElements",
+ "monitoringParameters"
+})
+@XmlRootElement(name = "nffg")
+public class Nffg {
+
+ @XmlElement(required = true)
+ protected EpointsType endpoints;
+ @XmlElement(name = "network_functions", required = true)
+ protected NfunctionsType networkFunctions;
+ @XmlElement(name = "network_elements", required = true)
+ protected NelementsType networkElements;
+ @XmlElement(name = "monitoring_parameters", required = true)
+ protected MonParamsType monitoringParameters;
+ @XmlAttribute(name = "id")
+ protected String id;
+ @XmlAttribute(name = "version")
+ protected String version;
+
+ /**
+ * Gets the value of the endpoints property.
+ * @return
+ * possible object is
+ * {@link EpointsType }
+ */
+ public EpointsType getEndpoints() {
+ return endpoints;
+ }
+
+ /**
+ * Sets the value of the endpoints property.
+ * @param value
+ * allowed object is
+ * {@link EpointsType }
+ */
+ public void setEndpoints(EpointsType value) {
+ this.endpoints = value;
+ }
+
+ /**
+ * Gets the value of the networkFunctions property.
+ * @return
+ * possible object is
+ * {@link NfunctionsType }
+ */
+ public NfunctionsType getNetworkFunctions() {
+ return networkFunctions;
+ }
+
+ /**
+ * Sets the value of the networkFunctions property.
+ * @param value
+ * allowed object is
+ * {@link NfunctionsType }
+ */
+ public void setNetworkFunctions(NfunctionsType value) {
+ this.networkFunctions = value;
+ }
+
+ /**
+ * Gets the value of the networkElements property.
+ * @return
+ * possible object is
+ * {@link NelementsType }
+ */
+ public NelementsType getNetworkElements() {
+ return networkElements;
+ }
+
+ /**
+ * Sets the value of the networkElements property.
+ * @param value
+ * allowed object is
+ * {@link NelementsType }
+ */
+ public void setNetworkElements(NelementsType value) {
+ this.networkElements = value;
+ }
+
+ /**
+ * Gets the value of the monitoringParameters property.
+ * @return
+ * possible object is
+ * {@link MonParamsType }
+ */
+ public MonParamsType getMonitoringParameters() {
+ return monitoringParameters;
+ }
+
+ /**
+ * Sets the value of the monitoringParameters property.
+ * @param value
+ * allowed object is
+ * {@link MonParamsType }
+ */
+ public void setMonitoringParameters(MonParamsType value) {
+ this.monitoringParameters = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the version property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Sets the value of the version property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setVersion(String value) {
+ this.version = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NffgSet.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NffgSet.java
new file mode 100644
index 0000000..8fdc137
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NffgSet.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element ref="{http://www.example.org/nffg/}nffg" maxOccurs="unbounded"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "nffg"
+})
+@XmlRootElement(name = "nffg-set")
+public class NffgSet {
+
+ @XmlElement(required = true)
+ protected List<Nffg> nffg;
+
+ /**
+ * Gets the value of the nffg property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the nffg property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getNffg().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Nffg }
+ */
+ public List<Nffg> getNffg() {
+ if (nffg == null) {
+ nffg = new ArrayList<Nffg>();
+ }
+ return this.nffg;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfunctionsType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfunctionsType.java
new file mode 100644
index 0000000..7b26ac3
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/NfunctionsType.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for nfunctionsType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="nfunctionsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="network_function" type="{http://www.example.org/nffg/}nfType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "nfunctionsType", propOrder = {
+ "networkFunction"
+})
+public class NfunctionsType {
+
+ @XmlElement(name = "network_function")
+ protected List<NfType> networkFunction;
+
+ /**
+ * Gets the value of the networkFunction property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the networkFunction property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getNetworkFunction().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link NfType }
+ */
+ public List<NfType> getNetworkFunction() {
+ if (networkFunction == null) {
+ networkFunction = new ArrayList<NfType>();
+ }
+ return this.networkFunction;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ObjectFactory.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ObjectFactory.java
new file mode 100644
index 0000000..1c7c7f5
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/ObjectFactory.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the it.polito.nffg.neo4j.jaxb package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _Nffg_QNAME = new QName("http://www.example.org/nffg/", "nffg");
+ private final static QName _NffgSet_QNAME = new QName("http://www.example.org/nffg/", "nffg-set");
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: it.polito.nffg.neo4j.jaxb
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType }
+ */
+ public FlowrulesType createFlowrulesType() {
+ return new FlowrulesType();
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType.Flowspace }
+ */
+ public FlowrulesType.Flowspace createFlowrulesTypeFlowspace() {
+ return new FlowrulesType.Flowspace();
+ }
+
+ /**
+ * Create an instance of {@link CiType }
+ */
+ public CiType createCiType() {
+ return new CiType();
+ }
+
+ /**
+ * Create an instance of {@link CiType.Attributes }
+ */
+ public CiType.Attributes createCiTypeAttributes() {
+ return new CiType.Attributes();
+ }
+
+ /**
+ * Create an instance of {@link EpType }
+ */
+ public EpType createEpType() {
+ return new EpType();
+ }
+
+ /**
+ * Create an instance of {@link SpecType }
+ */
+ public SpecType createSpecType() {
+ return new SpecType();
+ }
+
+ /**
+ * Create an instance of {@link MonParamsType }
+ */
+ public MonParamsType createMonParamsType() {
+ return new MonParamsType();
+ }
+
+ /**
+ * Create an instance of {@link NffgSet }
+ */
+ public NffgSet createNffgSet() {
+ return new NffgSet();
+ }
+
+ /**
+ * Create an instance of {@link Nffg }
+ */
+ public Nffg createNffg() {
+ return new Nffg();
+ }
+
+ /**
+ * Create an instance of {@link EpointsType }
+ */
+ public EpointsType createEpointsType() {
+ return new EpointsType();
+ }
+
+ /**
+ * Create an instance of {@link NfunctionsType }
+ */
+ public NfunctionsType createNfunctionsType() {
+ return new NfunctionsType();
+ }
+
+ /**
+ * Create an instance of {@link NelementsType }
+ */
+ public NelementsType createNelementsType() {
+ return new NelementsType();
+ }
+
+ /**
+ * Create an instance of {@link CpointsType }
+ */
+ public CpointsType createCpointsType() {
+ return new CpointsType();
+ }
+
+ /**
+ * Create an instance of {@link NfType }
+ */
+ public NfType createNfType() {
+ return new NfType();
+ }
+
+ /**
+ * Create an instance of {@link EpCpType }
+ */
+ public EpCpType createEpCpType() {
+ return new EpCpType();
+ }
+
+ /**
+ * Create an instance of {@link EpsCpsType }
+ */
+ public EpsCpsType createEpsCpsType() {
+ return new EpsCpsType();
+ }
+
+ /**
+ * Create an instance of {@link ActionsType }
+ */
+ public ActionsType createActionsType() {
+ return new ActionsType();
+ }
+
+ /**
+ * Create an instance of {@link ActionType }
+ */
+ public ActionType createActionType() {
+ return new ActionType();
+ }
+
+ /**
+ * Create an instance of {@link PortType }
+ */
+ public PortType createPortType() {
+ return new PortType();
+ }
+
+ /**
+ * Create an instance of {@link CpType }
+ */
+ public CpType createCpType() {
+ return new CpType();
+ }
+
+ /**
+ * Create an instance of {@link CtrlInterfacesType }
+ */
+ public CtrlInterfacesType createCtrlInterfacesType() {
+ return new CtrlInterfacesType();
+ }
+
+ /**
+ * Create an instance of {@link NeType }
+ */
+ public NeType createNeType() {
+ return new NeType();
+ }
+
+ /**
+ * Create an instance of {@link Paths }
+ */
+ public Paths createPaths() {
+ return new Paths();
+ }
+
+ /**
+ * Create an instance of {@link HttpMessage }
+ */
+ public HttpMessage createHttpMessage() {
+ return new HttpMessage();
+ }
+
+ /**
+ * Create an instance of {@link Property }
+ */
+ public Property createProperty() {
+ return new Property();
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType.Flowspace.Mac }
+ */
+ public FlowrulesType.Flowspace.Mac createFlowrulesTypeFlowspaceMac() {
+ return new FlowrulesType.Flowspace.Mac();
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType.Flowspace.Ip }
+ */
+ public FlowrulesType.Flowspace.Ip createFlowrulesTypeFlowspaceIp() {
+ return new FlowrulesType.Flowspace.Ip();
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType.Flowspace.Tcp }
+ */
+ public FlowrulesType.Flowspace.Tcp createFlowrulesTypeFlowspaceTcp() {
+ return new FlowrulesType.Flowspace.Tcp();
+ }
+
+ /**
+ * Create an instance of {@link FlowrulesType.Flowspace.Udp }
+ */
+ public FlowrulesType.Flowspace.Udp createFlowrulesTypeFlowspaceUdp() {
+ return new FlowrulesType.Flowspace.Udp();
+ }
+
+ /**
+ * Create an instance of {@link CiType.Attributes.Attribute }
+ */
+ public CiType.Attributes.Attribute createCiTypeAttributesAttribute() {
+ return new CiType.Attributes.Attribute();
+ }
+
+ /**
+ * Create an instance of {@link EpType.Flowspace }
+ */
+ public EpType.Flowspace createEpTypeFlowspace() {
+ return new EpType.Flowspace();
+ }
+
+ /**
+ * Create an instance of {@link SpecType.Deployment }
+ */
+ public SpecType.Deployment createSpecTypeDeployment() {
+ return new SpecType.Deployment();
+ }
+
+ /**
+ * Create an instance of {@link SpecType.Image }
+ */
+ public SpecType.Image createSpecTypeImage() {
+ return new SpecType.Image();
+ }
+
+ /**
+ * Create an instance of {@link SpecType.Cpu }
+ */
+ public SpecType.Cpu createSpecTypeCpu() {
+ return new SpecType.Cpu();
+ }
+
+ /**
+ * Create an instance of {@link SpecType.Memory }
+ */
+ public SpecType.Memory createSpecTypeMemory() {
+ return new SpecType.Memory();
+ }
+
+ /**
+ * Create an instance of {@link SpecType.Storage }
+ */
+ public SpecType.Storage createSpecTypeStorage() {
+ return new SpecType.Storage();
+ }
+
+ /**
+ * Create an instance of {@link MonParamsType.Parameter }
+ */
+ public MonParamsType.Parameter createMonParamsTypeParameter() {
+ return new MonParamsType.Parameter();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link NffgType }{@code >}}
+ */
+ @XmlElementDecl(namespace = "http://www.example.org/nffg/", name = "nffg")
+ public JAXBElement<Nffg> createNffg(Nffg value) {
+ return new JAXBElement<Nffg>(_Nffg_QNAME, Nffg.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link NffgSetType }{@code >}}
+ */
+ @XmlElementDecl(namespace = "http://www.example.org/nffg/", name = "nffg-set")
+ public JAXBElement<NffgSet> createNffgSet(NffgSet value) {
+ return new JAXBElement<NffgSet>(_NffgSet_QNAME, NffgSet.class, null, value);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Paths.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Paths.java
new file mode 100644
index 0000000..f097b30
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Paths.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;choice>
+ * &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="path" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/>
+ * &lt;/choice>
+ * &lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="destination" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="direction" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "message",
+ "path"
+})
+@XmlRootElement(name = "paths", namespace = "http://www.example.org/response/")
+public class Paths {
+
+ @XmlElement(namespace = "http://www.example.org/response/")
+ protected String message;
+ @XmlElement(namespace = "http://www.example.org/response/")
+ protected List<String> path;
+ @XmlAttribute(name = "source")
+ protected String source;
+ @XmlAttribute(name = "destination")
+ protected String destination;
+ @XmlAttribute(name = "direction")
+ protected String direction;
+
+ /**
+ * Gets the value of the message property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets the value of the message property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setMessage(String value) {
+ this.message = value;
+ }
+
+ /**
+ * Gets the value of the path property.
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the path property.
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getPath().add(newItem);
+ * </pre>
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ */
+ public List<String> getPath() {
+ if (path == null) {
+ path = new ArrayList<String>();
+ }
+ return this.path;
+ }
+
+ /**
+ * Gets the value of the source property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Sets the value of the source property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSource(String value) {
+ this.source = value;
+ }
+
+ /**
+ * Gets the value of the destination property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDestination() {
+ return destination;
+ }
+
+ /**
+ * Sets the value of the destination property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDestination(String value) {
+ this.destination = value;
+ }
+
+ /**
+ * Gets the value of the direction property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the value of the direction property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDirection(String value) {
+ this.direction = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortDirEnumType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortDirEnumType.java
new file mode 100644
index 0000000..f98907d
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortDirEnumType.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for portDirEnumType.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p>
+ * <pre>
+ * &lt;simpleType name="portDirEnumType">
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * &lt;enumeration value="in"/>
+ * &lt;enumeration value="out"/>
+ * &lt;enumeration value="both"/>
+ * &lt;/restriction>
+ * &lt;/simpleType>
+ * </pre>
+ */
+@XmlType(name = "portDirEnumType")
+@XmlEnum
+public enum PortDirEnumType {
+
+ @XmlEnumValue("in")
+ IN("in"),
+ @XmlEnumValue("out")
+ OUT("out"),
+ @XmlEnumValue("both")
+ BOTH("both");
+ private final String value;
+
+ PortDirEnumType(String v) {
+ value = v;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public static PortDirEnumType fromValue(String v) {
+ for (PortDirEnumType c: PortDirEnumType.values()) {
+ if (c.value.equals(v)) {
+ return c;
+ }
+ }
+ throw new IllegalArgumentException(v);
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortType.java
new file mode 100644
index 0000000..4d44cf5
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/PortType.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for portType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="portType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}unsignedShort" />
+ * &lt;attribute name="direction" use="required" type="{http://www.example.org/nffg/}portDirEnumType" />
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "portType")
+public class PortType {
+
+ @XmlAttribute(name = "id", required = true)
+ @XmlSchemaType(name = "unsignedShort")
+ protected int id;
+ @XmlAttribute(name = "direction", required = true)
+ protected PortDirEnumType direction;
+ @XmlAttribute(name = "type")
+ protected String type;
+
+ /**
+ * Gets the value of the id property.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ */
+ public void setId(int value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the direction property.
+ * @return
+ * possible object is
+ * {@link PortDirEnumType }
+ */
+ public PortDirEnumType getDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the value of the direction property.
+ * @param value
+ * allowed object is
+ * {@link PortDirEnumType }
+ */
+ public void setDirection(PortDirEnumType value) {
+ this.direction = value;
+ }
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getType() {
+ if (type == null) {
+ return "N.A.";
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Property.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Property.java
new file mode 100644
index 0000000..973eaf8
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/Property.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * &lt;element name="response" type="{http://www.w3.org/2001/XMLSchema}boolean"/>
+ * &lt;/sequence>
+ * &lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="destination" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="direction" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "name",
+ "response"
+})
+@XmlRootElement(name = "property", namespace = "http://www.example.org/response/")
+public class Property {
+
+ @XmlElement(namespace = "http://www.example.org/response/", required = true)
+ protected String name;
+ @XmlElement(namespace = "http://www.example.org/response/")
+ protected boolean response;
+ @XmlAttribute(name = "source")
+ protected String source;
+ @XmlAttribute(name = "destination")
+ protected String destination;
+ @XmlAttribute(name = "direction")
+ protected String direction;
+
+ /**
+ * Gets the value of the name property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the response property.
+ */
+ public boolean isResponse() {
+ return response;
+ }
+
+ /**
+ * Sets the value of the response property.
+ */
+ public void setResponse(boolean value) {
+ this.response = value;
+ }
+
+ /**
+ * Gets the value of the source property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Sets the value of the source property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSource(String value) {
+ this.source = value;
+ }
+
+ /**
+ * Gets the value of the destination property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDestination() {
+ return destination;
+ }
+
+ /**
+ * Sets the value of the destination property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDestination(String value) {
+ this.destination = value;
+ }
+
+ /**
+ * Gets the value of the direction property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the value of the direction property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setDirection(String value) {
+ this.direction = value;
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/SpecType.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/SpecType.java
new file mode 100644
index 0000000..e4d434b
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/SpecType.java
@@ -0,0 +1,577 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+package it.polito.nffg.neo4j.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for specType complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType name="specType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="deployment">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="image">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="uri" type="{http://www.w3.org/2001/XMLSchema}anyURI" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="cpu">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="model" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="architecture" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="numCores" type="{http://www.w3.org/2001/XMLSchema}unsignedByte" default="1" />
+ * &lt;attribute name="clockSpeed" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="memory">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="size" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;element name="storage">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="size" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "specType", propOrder = {
+ "deployment",
+ "image",
+ "cpu",
+ "memory",
+ "storage"
+})
+public class SpecType {
+
+ @XmlElement(required = true)
+ protected SpecType.Deployment deployment;
+ @XmlElement(required = true)
+ protected SpecType.Image image;
+ @XmlElement(required = true)
+ protected SpecType.Cpu cpu;
+ @XmlElement(required = true)
+ protected SpecType.Memory memory;
+ @XmlElement(required = true)
+ protected SpecType.Storage storage;
+
+ /**
+ * Gets the value of the deployment property.
+ * @return
+ * possible object is
+ * {@link SpecType.Deployment }
+ */
+ public SpecType.Deployment getDeployment() {
+ return deployment;
+ }
+
+ /**
+ * Sets the value of the deployment property.
+ * @param value
+ * allowed object is
+ * {@link SpecType.Deployment }
+ */
+ public void setDeployment(SpecType.Deployment value) {
+ this.deployment = value;
+ }
+
+ /**
+ * Gets the value of the image property.
+ * @return
+ * possible object is
+ * {@link SpecType.Image }
+ */
+ public SpecType.Image getImage() {
+ return image;
+ }
+
+ /**
+ * Sets the value of the image property.
+ * @param value
+ * allowed object is
+ * {@link SpecType.Image }
+ */
+ public void setImage(SpecType.Image value) {
+ this.image = value;
+ }
+
+ /**
+ * Gets the value of the cpu property.
+ * @return
+ * possible object is
+ * {@link SpecType.Cpu }
+ */
+ public SpecType.Cpu getCpu() {
+ return cpu;
+ }
+
+ /**
+ * Sets the value of the cpu property.
+ * @param value
+ * allowed object is
+ * {@link SpecType.Cpu }
+ */
+ public void setCpu(SpecType.Cpu value) {
+ this.cpu = value;
+ }
+
+ /**
+ * Gets the value of the memory property.
+ * @return
+ * possible object is
+ * {@link SpecType.Memory }
+ */
+ public SpecType.Memory getMemory() {
+ return memory;
+ }
+
+ /**
+ * Sets the value of the memory property.
+ * @param value
+ * allowed object is
+ * {@link SpecType.Memory }
+ */
+ public void setMemory(SpecType.Memory value) {
+ this.memory = value;
+ }
+
+ /**
+ * Gets the value of the storage property.
+ * @return
+ * possible object is
+ * {@link SpecType.Storage }
+ */
+ public SpecType.Storage getStorage() {
+ return storage;
+ }
+
+ /**
+ * Sets the value of the storage property.
+ * @param value
+ * allowed object is
+ * {@link SpecType.Storage }
+ */
+ public void setStorage(SpecType.Storage value) {
+ this.storage = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="model" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="architecture" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="numCores" type="{http://www.w3.org/2001/XMLSchema}unsignedByte" default="1" />
+ * &lt;attribute name="clockSpeed" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Cpu {
+
+ @XmlAttribute(name = "model")
+ protected String model;
+ @XmlAttribute(name = "architecture")
+ protected String architecture;
+ @XmlAttribute(name = "numCores")
+ @XmlSchemaType(name = "unsignedByte")
+ protected Short numCores;
+ @XmlAttribute(name = "clockSpeed")
+ protected String clockSpeed;
+
+ /**
+ * Gets the value of the model property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getModel() {
+ if (model == null) {
+ return "N.A.";
+ } else {
+ return model;
+ }
+ }
+
+ /**
+ * Sets the value of the model property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setModel(String value) {
+ this.model = value;
+ }
+
+ /**
+ * Gets the value of the architecture property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getArchitecture() {
+ if (architecture == null) {
+ return "N.A.";
+ } else {
+ return architecture;
+ }
+ }
+
+ /**
+ * Sets the value of the architecture property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setArchitecture(String value) {
+ this.architecture = value;
+ }
+
+ /**
+ * Gets the value of the numCores property.
+ * @return
+ * possible object is
+ * {@link Short }
+ */
+ public short getNumCores() {
+ if (numCores == null) {
+ return ((short) 1);
+ } else {
+ return numCores;
+ }
+ }
+
+ /**
+ * Sets the value of the numCores property.
+ * @param value
+ * allowed object is
+ * {@link Short }
+ */
+ public void setNumCores(Short value) {
+ this.numCores = value;
+ }
+
+ /**
+ * Gets the value of the clockSpeed property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getClockSpeed() {
+ if (clockSpeed == null) {
+ return "N.A.";
+ } else {
+ return clockSpeed;
+ }
+ }
+
+ /**
+ * Sets the value of the clockSpeed property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setClockSpeed(String value) {
+ this.clockSpeed = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Deployment {
+
+ @XmlAttribute(name = "type")
+ protected String type;
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getType() {
+ if (type == null) {
+ return "N.A.";
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="uri" type="{http://www.w3.org/2001/XMLSchema}anyURI" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Image {
+
+ @XmlAttribute(name = "uri")
+ @XmlSchemaType(name = "anyURI")
+ protected String uri;
+
+ /**
+ * Gets the value of the uri property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getUri() {
+ if (uri == null) {
+ return "N.A.";
+ } else {
+ return uri;
+ }
+ }
+
+ /**
+ * Sets the value of the uri property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setUri(String value) {
+ this.uri = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="size" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Memory {
+
+ @XmlAttribute(name = "type")
+ protected String type;
+ @XmlAttribute(name = "size")
+ protected String size;
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getType() {
+ if (type == null) {
+ return "N.A.";
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the size property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSize() {
+ if (size == null) {
+ return "N.A.";
+ } else {
+ return size;
+ }
+ }
+
+ /**
+ * Sets the value of the size property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSize(String value) {
+ this.size = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <pre>
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;attribute name="size" type="{http://www.w3.org/2001/XMLSchema}string" default="N.A." />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Storage {
+
+ @XmlAttribute(name = "type")
+ protected String type;
+ @XmlAttribute(name = "size")
+ protected String size;
+
+ /**
+ * Gets the value of the type property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getType() {
+ if (type == null) {
+ return "N.A.";
+ } else {
+ return type;
+ }
+ }
+
+ /**
+ * Sets the value of the type property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the size property.
+ * @return
+ * possible object is
+ * {@link String }
+ */
+ public String getSize() {
+ if (size == null) {
+ return "N.A.";
+ } else {
+ return size;
+ }
+ }
+
+ /**
+ * Sets the value of the size property.
+ * @param value
+ * allowed object is
+ * {@link String }
+ */
+ public void setSize(String value) {
+ this.size = value;
+ }
+
+ }
+
+}
diff --git a/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/package-info.java b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/package-info.java
new file mode 100644
index 0000000..3d3c7b4
--- /dev/null
+++ b/verigraph/src/main/java/it/polito/nffg/neo4j/jaxb/package-info.java
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Politecnico di Torino and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Apache License, Version 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *******************************************************************************/
+
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/nffg/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package it.polito.nffg.neo4j.jaxb;
diff --git a/verigraph/src/main/proto/verigraph.proto b/verigraph/src/main/proto/verigraph.proto
new file mode 100644
index 0000000..5f77c78
--- /dev/null
+++ b/verigraph/src/main/proto/verigraph.proto
@@ -0,0 +1,154 @@
+syntax = "proto3";
+
+package verigraph;
+
+option java_multiple_files = true;
+option java_package = "io.grpc.verigraph";
+option java_outer_classname = "VerigraphProto";
+
+// The service definition.
+service Verigraph {
+ // Obtains a list of graphs
+ rpc GetGraphs (GetRequest) returns (stream GraphGrpc) {}
+ // Obtains a graph
+ rpc GetGraph (RequestID) returns (GraphGrpc) {}
+ // Obtains a list of Nodes
+ rpc GetNodes (RequestID) returns (stream NodeGrpc) {}
+ // Obtains a node
+ rpc GetNode (RequestID) returns (NodeGrpc) {}
+ // Obtains a list of Neighbours
+ rpc GetNeighbours (RequestID) returns (stream NeighbourGrpc) {}
+ // Obtains a Neighbour
+ rpc GetNeighbour (RequestID) returns (NeighbourGrpc) {}
+
+ // Creates a graph
+ rpc CreateGraph (GraphGrpc) returns (NewGraph) {}
+ // Delete a graph
+ rpc DeleteGraph (RequestID) returns (Status) {}
+ // Updates a graph
+ rpc UpdateGraph (GraphGrpc) returns (NewGraph) {}
+ // Verify a policy
+ rpc VerifyPolicy (Policy) returns (VerificationGrpc) {}
+
+ // Creates a Node
+ rpc CreateNode (NodeGrpc) returns (NewNode) {}
+ // Delete a Node
+ rpc DeleteNode (RequestID) returns (Status) {}
+ // Updates a Node
+ rpc UpdateNode (NodeGrpc) returns (NewNode) {}
+ // Configures a Node
+ rpc ConfigureNode (ConfigurationGrpc) returns (Status) {}
+
+ // Creates a neighbour
+ rpc CreateNeighbour (NeighbourGrpc) returns (NewNeighbour) {}
+ // Delete a neighbour
+ rpc DeleteNeighbour (RequestID) returns (Status) {}
+ // Updates a neighbour
+ rpc UpdateNeighbour (NeighbourGrpc) returns (NewNeighbour) {}
+}
+
+message GetRequest {
+}
+
+message RequestID {
+ int64 idGraph = 1;
+ int64 idNode = 2;
+ int64 idNeighbour = 3;
+}
+
+message Policy{
+ int64 idGraph = 1;
+ string source = 2;
+ string destination = 3;
+ enum PolicyType {
+ reachability = 0;
+ isolation = 1;
+ traversal = 2;
+ }
+ PolicyType type = 4;
+ string middlebox = 5;
+}
+
+message ConfigurationGrpc{
+ int64 idGraph = 1;
+ int64 idNode = 2;
+ string description = 3;
+ string configuration = 4;
+ string id = 5;
+}
+
+message NodeGrpc{
+ int64 idGraph = 1;
+ string name = 2;
+ int64 id = 3; //long
+ enum FunctionalType {
+ antispam = 0;
+ cache = 1;
+ dpi = 2;
+ endhost = 3;
+ endpoint = 4;
+ fieldmodifier = 5;
+ firewall = 6;
+ mailclient = 7;
+ mailserver = 8;
+ nat = 9;
+ vpnaccess = 10;
+ vpnexit = 11;
+ webclient = 12;
+ webserver = 13;
+ }
+ FunctionalType functional_type = 4;
+ repeated NeighbourGrpc neighbour = 5;
+ ConfigurationGrpc configuration = 6;
+ string errorMessage = 7;
+}
+
+message GraphGrpc{
+ int64 id = 1; //long
+ repeated NodeGrpc node = 2;
+ string errorMessage = 3;
+}
+
+message NeighbourGrpc{
+ int64 idGraph = 1;
+ int64 idNode = 2;
+ string name = 3;
+ int64 id = 4; //long
+ string errorMessage = 5;
+}
+
+message NewGraph{
+ bool success = 1;
+ GraphGrpc graph = 2;
+ string errorMessage = 3;
+}
+
+message NewNode{
+ bool success = 1;
+ NodeGrpc node = 2;
+ string errorMessage = 3;
+}
+
+message NewNeighbour{
+ bool success = 1;
+ NeighbourGrpc neighbour = 2;
+ string errorMessage = 3;
+}
+
+message TestGrpc {
+ repeated NodeGrpc node = 1;
+ string result = 2;
+}
+
+message VerificationGrpc{
+ bool successOfOperation = 1;
+ string result = 2;
+ string comment = 3;
+ repeated TestGrpc test = 4;
+ string errorMessage = 5;
+}
+
+message Status{
+ bool success = 1;
+ string errorMessage = 2;
+} \ No newline at end of file
diff --git a/verigraph/src/main/schema/net_types.xsd b/verigraph/src/main/schema/net_types.xsd
new file mode 100644
index 0000000..c99c7a6
--- /dev/null
+++ b/verigraph/src/main/schema/net_types.xsd
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:net="http://www.example.org/net/"
+ targetNamespace="http://www.example.org/net/"
+ elementFormDefault="qualified">
+
+ <annotation>
+ <documentation>
+ Copyright (C) 2006-2007 Code Synthesis Tools CC
+
+ Redistribution and use with or without modification are permitted
+ under the terms of the new BSD license. See the accompanying LICENSE
+ file.
+ </documentation>
+ </annotation>
+
+ <simpleType name="macAddressType">
+ <restriction base="string">
+ <pattern value="(([a-fA-F0-9]{2})-){5,7}[a-fA-F0-9]{2}"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="ipAddressType">
+ <restriction base="string">
+ <pattern value="((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])"/>
+ <pattern value="(([0-9a-fA-F]{1,4}:){6})(([0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))"/>
+ <pattern value="(([0-9a-fA-F]{1,4}:)*|([0-9a-fA-F]{1,4}))*(::)(([0-9a-fA-F]{1,4}:)*|([0-9a-fA-F]{1,4}))*"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="portNumberType">
+ <restriction base="unsignedShort">
+ <minInclusive value="1"/>
+ </restriction>
+ </simpleType>
+
+ <!-- <complexType name="ipEndpointStructType">
+ <sequence>
+ <element name="address" type="net:ipAddressType"/>
+ <element name="port" type="net:portNumberType"/>
+ </sequence>
+ </complexType> -->
+
+ <simpleType name="ethertypeType">
+ <restriction base="unsignedShort">
+ <minInclusive value="1536"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="vlanIdType">
+ <restriction base="unsignedShort">
+ <minInclusive value="1"/>
+ <maxInclusive value="4095"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="vlanPcpType">
+ <restriction base="unsignedShort">
+ <maxInclusive value="7"/>
+ </restriction>
+ </simpleType>
+</schema> \ No newline at end of file
diff --git a/verigraph/src/main/schema/nffg.xsd b/verigraph/src/main/schema/nffg.xsd
new file mode 100644
index 0000000..77e6f40
--- /dev/null
+++ b/verigraph/src/main/schema/nffg.xsd
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://www.example.org/nffg/"
+ xmlns:net="http://www.example.org/net/"
+ targetNamespace="http://www.example.org/nffg/"
+ elementFormDefault="qualified">
+
+ <import namespace="http://www.example.org/net/" schemaLocation="net_types.xsd"/>
+
+ <annotation>
+ <documentation xml:lang="it">
+ Il formato prevede si possa avere come radice "nffg-set" oppure "nffg".
+ Nel primo caso ci sono più nf-fg contenuti nello stesso documento XML.
+ </documentation>
+ </annotation>
+
+ <group name="L2HeaderParameters">
+ <sequence>
+ <element name="Mac" minOccurs="0">
+ <complexType>
+ <attribute name="src" type="net:macAddressType" use="optional"/>
+ <attribute name="dst" type="net:macAddressType" use="optional"/>
+ <attribute name="ethertype" type="net:ethertypeType" use="optional"/>
+ <attribute name="vlanId" type="net:vlanIdType" use="optional"/>
+ <attribute name="vlanPcp" type="net:vlanPcpType" use="optional"/>
+ </complexType>
+ </element>
+ </sequence>
+ </group>
+
+ <group name="L3HeaderParameters">
+ <sequence>
+ <element name="Ip" minOccurs="0">
+ <complexType>
+ <attribute name="src" type="net:ipAddressType" use="optional"/>
+ <attribute name="dst" type="net:ipAddressType" use="optional"/>
+ <attribute name="ipProtocol" type="unsignedByte" use="optional"/>
+ <attribute name="tos" type="unsignedByte" use="optional"/>
+ </complexType>
+ </element>
+ </sequence>
+ </group>
+
+ <!-- controllare nel programma che non ci siano combinazioni non ammesse -->
+ <group name="L4HeaderParameters">
+ <choice>
+ <element name="Tcp" minOccurs="0">
+ <complexType>
+ <attribute name="src" type="net:portNumberType" use="optional"/>
+ <attribute name="dst" type="net:portNumberType" use="optional"/>
+ </complexType>
+ </element>
+ <element name="Udp" minOccurs="0">
+ <complexType>
+ <attribute name="src" type="net:portNumberType" use="optional"/>
+ <attribute name="dst" type="net:portNumberType" use="optional"/>
+ </complexType>
+ </element>
+ </choice>
+ </group>
+
+ <!-- alla fine controlloare tutti gli xpath perchè dopo dei cambiamenti potrebbero non andare più bene -->
+ <element name="nffg-set" type="tns:nffg-setType">
+ <unique name="nffgIdUnique">
+ <selector xpath="tns:nf-fg"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <!-- forse la NF va spostata dentro graphs e resa referenziabile (condivisibile da più nffg) -->
+ <!-- così facendo però, si deve trovare un modo per avere le NF dentro nffg nel caso sia questo la radice -->
+ <unique name="nfIdUnique">
+ <selector xpath="tns:nf-fg/tns:network_functions/tns:network_function"/>
+ <field xpath="@id"/>
+ </unique>
+ </element>
+
+ <element name="nffg" type="tns:nffgType">
+ <unique name="epIdUnique">
+ <selector xpath="tns:endpoints/tns:endpoint"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <unique name="cpIdUnique">
+ <selector xpath="tns:network_functions/tns:network_function/tns:connection_points/tns:connection_point"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <unique name="portIdUnique">
+ <selector xpath="tns:network_functions/tns:network_function/tns:connection_points/tns:connection_point/tns:port"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <unique name="ciIdUnique">
+ <selector xpath="tns:network_functions/tns:network_function/tns:control_interfaces/tns:control_interface"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <unique name="neIdUnique">
+ <selector xpath="tns:network_elements/tns:network_element"/>
+ <field xpath="@id"/>
+ </unique>
+
+ <unique name="epcpIdRefUnique">
+ <selector xpath="tns:network_elements/tns:network_element/tns:eps-cps/tns:ep-cp"/>
+ <field xpath="@id_ref"/>
+ </unique>
+ </element>
+
+ <complexType name="monParamsType">
+ <sequence>
+ <element name="parameter" maxOccurs="unbounded">
+ <complexType>
+ <attribute name="value" type="NMTOKENS" use="required"/>
+ </complexType>
+ </element>
+ </sequence>
+ </complexType>
+
+ <complexType name="nffg-setType">
+ <sequence>
+ <element ref="tns:nffg" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="nffgType">
+ <sequence>
+ <element name="endpoints" type="tns:epointsType" nillable="true"/>
+ <element name="network_functions" type="tns:nfunctionsType" nillable="true"/>
+ <element name="network_elements" type="tns:nelementsType" nillable="true"/>
+ <element name="monitoring_parameters" type="tns:monParamsType" nillable="true"/>
+ </sequence>
+ <attribute name="id" type="tns:nffgIdType" use="optional"/>
+ <attribute name="version" type="string" use="optional"/>
+ </complexType>
+
+ <simpleType name="nffgIdType">
+ <restriction base="string">
+ <pattern value="nffg_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="epointsType">
+ <sequence>
+ <element name="endpoint" type="tns:epType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="epType">
+ <sequence>
+ <!-- valutare se renderlo nillable o tenere la cardinalità a * -->
+ <element name="flowspace">
+ <complexType>
+ <sequence>
+ <group ref="tns:L2HeaderParameters"/>
+ <group ref="tns:L3HeaderParameters"/>
+ <group ref="tns:L4HeaderParameters"/>
+ </sequence>
+ <attribute name="nodeId" type="string" use="optional"/>
+ <attribute name="ingPhysPort" type="string" use="optional"/>
+ </complexType>
+ </element>
+ </sequence>
+ <attribute name="id" type="tns:epIdType" use="required"/>
+ </complexType>
+
+ <simpleType name="epIdType">
+ <restriction base="string">
+ <pattern value="[a-z]*_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="nfunctionsType">
+ <sequence>
+ <element name="network_function" type="tns:nfType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="nfType">
+ <sequence>
+ <element name="specification" type="tns:specType"/>
+ <element name="connection_points" type="tns:cpointsType"/>
+ <element name="control_interfaces" type="tns:ctrlInterfacesType"/>
+ <element name="monitoring_parameters" type="tns:monParamsType" nillable="true"/>
+ </sequence>
+ <attribute name="id" type="tns:nfIdType" use="required"/>
+ <attribute name="functionalType" type="string" use="required"/>
+ </complexType>
+
+ <simpleType name="nfIdType">
+ <restriction base="string">
+ <pattern value="[a-z]*_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="specType">
+ <sequence>
+ <element name="deployment">
+ <complexType>
+ <attribute name="type" type="string" use="optional" default="N.A."/>
+ </complexType>
+ </element>
+ <element name="image">
+ <complexType>
+ <!-- controllare come viene mappata la info -->
+ <attribute name="uri" type="anyURI" use="optional" default="N.A."/>
+ </complexType>
+ </element>
+ <element name="cpu">
+ <complexType>
+ <attribute name="model" type="string" use="optional" default="N.A."/>
+ <attribute name="architecture" type="string" use="optional" default="N.A."/>
+ <attribute name="numCores" type="unsignedByte" use="optional" default="1"/>
+ <attribute name="clockSpeed" type="string" use="optional" default="N.A."/>
+ </complexType>
+ </element>
+ <element name="memory">
+ <complexType>
+ <attribute name="type" type="string" use="optional" default="N.A."/>
+ <attribute name="size" type="string" use="optional" default="N.A."/>
+ </complexType>
+ </element>
+ <element name="storage">
+ <complexType>
+ <attribute name="type" type="string" use="optional" default="N.A."/>
+ <attribute name="size" type="string" use="optional" default="N.A."/>
+ </complexType>
+ </element>
+ </sequence>
+ </complexType>
+
+ <complexType name="cpointsType">
+ <sequence>
+ <element name="connection_point" type="tns:cpType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="cpType">
+ <sequence>
+ <element name="port" type="tns:portType"/>
+ </sequence>
+ <attribute name="id" type="tns:cpIdType" use="required"/>
+ </complexType>
+
+ <complexType name="portType">
+ <attribute name="id" type="unsignedShort" use="required"/>
+ <attribute name="direction" type="tns:portDirEnumType" use="required"/>
+ <attribute name="type" type="string" use="optional" default="N.A."/>
+ </complexType>
+
+ <simpleType name="portDirEnumType">
+ <restriction base="string">
+ <enumeration value="in"/>
+ <enumeration value="out"/>
+ <enumeration value="both"/>
+ </restriction>
+ </simpleType>
+
+ <simpleType name="cpIdType">
+ <restriction base="string">
+ <pattern value="cp_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="ctrlInterfacesType">
+ <sequence>
+ <!-- valutare se renderlo nillable -->
+ <element name="control_interface" type="tns:ciType" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="ciType">
+ <sequence>
+ <element name="attributes">
+ <complexType>
+ <sequence>
+ <element name="attribute" minOccurs="0" maxOccurs="unbounded">
+ <complexType>
+ <attribute name="value" type="string" use="required"/>
+ </complexType>
+ </element>
+ </sequence>
+ </complexType>
+ </element>
+ </sequence>
+ <attribute name="id" type="tns:ciIdType" use="required"/>
+ </complexType>
+
+ <simpleType name="ciIdType">
+ <restriction base="string">
+ <pattern value="ci_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="nelementsType">
+ <sequence>
+ <element name="network_element" type="tns:neType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="neType">
+ <sequence>
+ <element name="eps-cps" type="tns:eps-cpsType"/>
+ <element name="monitoring_parameters" type="tns:monParamsType" nillable="true"/>
+ </sequence>
+ <attribute name="id" type="tns:neIdType" use="required"/>
+ <attribute name="type" type="string" use="required"/>
+ </complexType>
+
+ <simpleType name="neIdType">
+ <restriction base="string">
+ <pattern value="ne_\d+"/>
+ </restriction>
+ </simpleType>
+
+ <complexType name="eps-cpsType">
+ <sequence>
+ <element name="ep-cp" type="tns:ep-cpType" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="ep-cpType">
+ <sequence>
+ <element name="flowrules" type="tns:flowrulesType" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="id_ref" type="string" use="required"/>
+ </complexType>
+
+ <complexType name="flowrulesType">
+ <sequence>
+ <!-- da fare valutazioni analoghe al flowspace di sopra -->
+ <element name="flowspace">
+ <complexType>
+ <sequence>
+ <group ref="tns:L2HeaderParameters"/>
+ <group ref="tns:L3HeaderParameters"/>
+ <group ref="tns:L4HeaderParameters"/>
+ </sequence>
+ <attribute name="ingPort" type="string" use="optional"/>
+ </complexType>
+ </element>
+ <element name="actions" type="tns:actionsType"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="actionsType">
+ <sequence>
+ <element name="action" type="tns:actionType" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="actionType">
+ <attribute name="type" type="tns:actionEnumType" use="required"/>
+ <attribute name="port" type="string" use="optional"/>
+ </complexType>
+
+ <!-- controllare via SW che se l'aziione è output la porta deve esserci -->
+ <simpleType name="actionEnumType">
+ <restriction base="string">
+ <enumeration value="discard"/>
+ <enumeration value="output"/>
+ </restriction>
+ </simpleType>
+</schema> \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/antispam.json b/verigraph/src/main/webapp/json/antispam.json
new file mode 100644
index 0000000..dae3db9
--- /dev/null
+++ b/verigraph/src/main/webapp/json/antispam.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Antispam",
+ "description": "Polito Antispam",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/cache.json b/verigraph/src/main/webapp/json/cache.json
new file mode 100644
index 0000000..0511e7b
--- /dev/null
+++ b/verigraph/src/main/webapp/json/cache.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Cache",
+ "description": "Polito Cache",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/database.json b/verigraph/src/main/webapp/json/database.json
new file mode 100644
index 0000000..5b02a50
--- /dev/null
+++ b/verigraph/src/main/webapp/json/database.json
@@ -0,0 +1,5 @@
+[
+
+
+
+]
diff --git a/verigraph/src/main/webapp/json/dpi.json b/verigraph/src/main/webapp/json/dpi.json
new file mode 100644
index 0000000..6e4dd6f
--- /dev/null
+++ b/verigraph/src/main/webapp/json/dpi.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Dpi",
+ "description": "Polito IDS",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/endhost.json b/verigraph/src/main/webapp/json/endhost.json
new file mode 100644
index 0000000..37c8881
--- /dev/null
+++ b/verigraph/src/main/webapp/json/endhost.json
@@ -0,0 +1,42 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Endhost",
+ "description": "Polito Endhost",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "description": "HTTP body",
+ "type": "string"
+ },
+ "sequence": {
+ "description": "Sequence number",
+ "type": "integer"
+ },
+ "protocol": {
+ "description": "Protocol",
+ "type": "string",
+ "enum": ["HTTP_REQUEST", "HTTP_RESPONSE", "POP3_REQUEST", "POP3_RESPONSE"]
+ },
+ "email_from": {
+ "description": "E-mail sender",
+ "type": "string"
+ },
+ "url": {
+ "description": "URL",
+ "type": "string"
+ },
+ "options": {
+ "description": "Options",
+ "type": "string"
+ },
+ "destination": {
+ "description": "Destination node",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "maxItems": 1
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/endpoint.json b/verigraph/src/main/webapp/json/endpoint.json
new file mode 100644
index 0000000..1e6a521
--- /dev/null
+++ b/verigraph/src/main/webapp/json/endpoint.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Endpoint",
+ "description": "Polito Endpoint",
+ "type": "array",
+ "minItems": 0,
+ "maxItems":0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/fieldmodifier.json b/verigraph/src/main/webapp/json/fieldmodifier.json
new file mode 100644
index 0000000..8be9419
--- /dev/null
+++ b/verigraph/src/main/webapp/json/fieldmodifier.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Field Modifier",
+ "description": "Polito Field Modifier",
+ "type": "array",
+ "items": {
+ "type": "object"
+ },
+ "minItems": 0,
+ "maxItems":0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/firewall.json b/verigraph/src/main/webapp/json/firewall.json
new file mode 100644
index 0000000..01ec63f
--- /dev/null
+++ b/verigraph/src/main/webapp/json/firewall.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Firewall",
+ "description": "Polito Firewall",
+ "type": "array",
+ "items": {
+ "type": "object"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/mailclient.json b/verigraph/src/main/webapp/json/mailclient.json
new file mode 100644
index 0000000..cacfd5f
--- /dev/null
+++ b/verigraph/src/main/webapp/json/mailclient.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Mail Client",
+ "description": "Polito Mail Client",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "mailserver": {
+ "description": "Mail server name",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "mailserver"
+ ]
+ },
+ "minItems": 1,
+ "maxItems": 1,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/mailserver.json b/verigraph/src/main/webapp/json/mailserver.json
new file mode 100644
index 0000000..974b560
--- /dev/null
+++ b/verigraph/src/main/webapp/json/mailserver.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Mail Server",
+ "description": "Polito Mail Server",
+ "type": "array",
+ "items": {
+ "type": "object"
+ },
+ "minItems": 0,
+ "maxItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/nat.json b/verigraph/src/main/webapp/json/nat.json
new file mode 100644
index 0000000..f2b973a
--- /dev/null
+++ b/verigraph/src/main/webapp/json/nat.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Nat",
+ "description": "Polito Nat",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/vpnaccess.json b/verigraph/src/main/webapp/json/vpnaccess.json
new file mode 100644
index 0000000..907118d
--- /dev/null
+++ b/verigraph/src/main/webapp/json/vpnaccess.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Vpn Access",
+ "description": "Polito Vpn Access",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "vpnexit": {
+ "description": "Vpn Exit",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "vpnexit"
+ ]
+ },
+ "minItems": 1,
+ "maxItems": 1,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/vpnexit.json b/verigraph/src/main/webapp/json/vpnexit.json
new file mode 100644
index 0000000..c80a138
--- /dev/null
+++ b/verigraph/src/main/webapp/json/vpnexit.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Vpn Exit",
+ "description": "Polito Vpn Exit",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "vpnaccess": {
+ "description": "Vpn Access",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "vpnaccess"
+ ]
+ },
+ "minItems": 1,
+ "maxItems": 1,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/webclient.json b/verigraph/src/main/webapp/json/webclient.json
new file mode 100644
index 0000000..dfbc55e
--- /dev/null
+++ b/verigraph/src/main/webapp/json/webclient.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Web client",
+ "description": "Polito Web Client",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "webserver": {
+ "description": "Web server name",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "webserver"
+ ]
+ },
+ "minItems": 1,
+ "maxItems": 1,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/src/main/webapp/json/webserver.json b/verigraph/src/main/webapp/json/webserver.json
new file mode 100644
index 0000000..5d7a1c4
--- /dev/null
+++ b/verigraph/src/main/webapp/json/webserver.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Web Server",
+ "description": "Polito Web Server",
+ "type": "array",
+ "items": {
+ "type": "object"
+ },
+ "minItems": 0,
+ "maxItems": 0,
+ "uniqueItems": true
+} \ No newline at end of file
diff --git a/verigraph/target/m2e-wtp/web-resources/META-INF/MANIFEST.MF b/verigraph/target/m2e-wtp/web-resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6cec037
--- /dev/null
+++ b/verigraph/target/m2e-wtp/web-resources/META-INF/MANIFEST.MF
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Built-By: verigraph
+Build-Jdk: 1.8.0_121
+Created-By: Maven Integration for Eclipse
+
diff --git a/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.properties b/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.properties
new file mode 100644
index 0000000..0d84612
--- /dev/null
+++ b/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.properties
@@ -0,0 +1,7 @@
+#Generated by Maven Integration for Eclipse
+#Sat Feb 25 09:43:36 CET 2017
+version=0.0.1-SNAPSHOT
+groupId=it.polito.escape
+m2e.projectName=Verigraph4Parser
+m2e.projectLocation=/home/verigraph/workspace/Verigraph4Parser
+artifactId=verify
diff --git a/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.xml b/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.xml
new file mode 100644
index 0000000..cc211f1
--- /dev/null
+++ b/verigraph/target/m2e-wtp/web-resources/META-INF/maven/it.polito.escape/verify/pom.xml
@@ -0,0 +1,211 @@
+<!-- Copyright (c) 2017 Politecnico di Torino and others. All rights reserved.
+ This program and the accompanying materials are made available under the
+ terms of the Apache License, Version 2.0 which accompanies this distribution,
+ and is available at http://www.apache.org/licenses/LICENSE-2.0 -->
+
+<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/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>it.polito.escape</groupId>
+ <artifactId>verify</artifactId>
+ <packaging>war</packaging>
+ <version>0.0.1-SNAPSHOT</version>
+ <name>verify</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <grpc.version>1.0.3</grpc.version><!-- CURRENT_GRPC_VERSION -->
+ <jersey.version>2.22.1</jersey.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <build>
+ <finalName>verify</finalName>
+ <extensions>
+ <extension>
+ <groupId>kr.motd.maven</groupId>
+ <artifactId>os-maven-plugin</artifactId>
+ <version>1.4.1.Final</version>
+ </extension>
+ </extensions>
+ <plugins>
+ <plugin>
+ <groupId>org.xolstice.maven.plugins</groupId>
+ <artifactId>protobuf-maven-plugin</artifactId>
+ <version>0.5.0</version>
+ <configuration>
+ <protocArtifact>com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier}</protocArtifact>
+ <pluginId>grpc-java</pluginId>
+ <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>compile-custom</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <inherited>true</inherited>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <versionRange>[1.0.0,)</versionRange>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey</groupId>
+ <artifactId>jersey-bom</artifactId>
+ <version>${jersey.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet-core</artifactId>
+ <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
+ <!-- artifactId>jersey-container-servlet</artifactId -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.bundles</groupId>
+ <artifactId>jaxrs-ri</artifactId>
+ </dependency>
+
+ <!-- <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId>
+ </dependency> -->
+
+ <dependency>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <artifactId>jersey-media-json-jackson</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>io.swagger</groupId>
+ <artifactId>swagger-jersey2-jaxrs</artifactId>
+ <version>1.5.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.googlecode.json-simple</groupId>
+ <artifactId>json-simple</artifactId>
+ <version>1.1</version>
+ </dependency>
+
+ <!-- added to retrieve server path -->
+ <!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version> <scope>provided</scope> </dependency> -->
+
+ <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.5.6</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>com.github.fge</groupId>
+ <artifactId>json-schema-validator</artifactId>
+ <version>2.2.6</version>
+ </dependency>
+
+ <!-- http://mvnrepository.com/artifact/org.json/json -->
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20160212</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/junit/junit -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- here start dependencies for grpc -->
+ <dependency>
+ <groupId>org.apache.thrift</groupId>
+ <artifactId>libthrift</artifactId>
+ <version>0.9.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-netty</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-protobuf</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>${grpc.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>3.0.2</version>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/verigraph/tester/README.rst b/verigraph/tester/README.rst
new file mode 100644
index 0000000..35396a3
--- /dev/null
+++ b/verigraph/tester/README.rst
@@ -0,0 +1,38 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+In order to run the automatic testing script test.py, you need the
+following dependencies installed on your python distribution:
+
+- "requests" python package ->
+ http://docs.python-requests.org/en/master/
+- "jsonschema" python package ->
+ https://pypi.python.org/pypi/jsonschema
+
+IMPORTANT - If you have multiple versions of Python installed on your
+machine, check carefully that the version you are actually using when
+running the script, has the required packages installed. Requested
+version is Python 3+
+
+| HINT - to install a package you can raise the following command (Bash
+ on Linux or DOS shell on Windows):
+| python -m pip install jsonschema
+| python -m pip install requests
+
+Tested on PYTHON 3.4.3
+
+To add a new test, just put a new .json file inside the testcases
+folder. The corresponding JSON schema is in the testcase\_schema.json
+file and some examples are already available. Each json file should
+specify:
+
+- id, an integer for the testcase;
+- name, the name for the testcase;
+- description, an optional description;
+- policy\_url\_parameters, the parameters to be appended after the
+ verification URL (including the '?' character);
+- result, the expected verification result;
+- graph, the graph to be tested (the same object that you usually POST
+ to VeriGraph to create a new graph).
+ The test.py script will test each .json file contained into the
+ testcases folder and will provide a complete output.
diff --git a/verigraph/tester/test.py b/verigraph/tester/test.py
new file mode 100644
index 0000000..ad0b82a
--- /dev/null
+++ b/verigraph/tester/test.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+
+##############################################################################
+# Copyright (c) 2017 Politecnico di Torino and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from __future__ import print_function
+from jsonschema import validate
+from pprint import pprint
+import sys
+import requests
+from requests.exceptions import *
+from jsonschema.exceptions import *
+import json
+import getopt
+import os
+import subprocess
+
+# Constants (change them, if appropriate)
+VERIGRAPH_PORT = "8080"
+TEST_CASES_DIR = "testcases"
+BASE_URL = "http://localhost:"+VERIGRAPH_PORT+"/verify/api/graphs/"
+SCHEMA_FILE = "testcase_schema.json"
+
+# Variables
+success = 0
+run = 0
+
+# Utils
+def eprint(toPrint):
+ sys.stdout.flush()
+ print(toPrint, file=sys.stderr)
+ sys.stderr.flush()
+
+# Print PYTHON ver
+print("PYTHON " + sys.version)
+
+# Loading schema file
+try:
+ schema = json.load(open(SCHEMA_FILE))
+except ValueError:
+ eprint("Invalid json schema (check your "+SCHEMA_FILE+")!\nExiting.")
+ exit(-1)
+
+# Iterate over .json files contained in the TEST_CASES_DIR
+for i in os.listdir(TEST_CASES_DIR):
+ if i.endswith(".json"):
+ with open(TEST_CASES_DIR+os.path.sep+i) as data_file:
+ try:
+ # Load json file (raise exception if malformed)
+ data = json.load(data_file)
+
+ # Validate input json against schema (raise exception if invalid)
+ validate(data, schema)
+
+ run += 1
+ print("Test case ID: "+str(data["id"]))
+ print("\tFILE NAME: "+i)
+ print("\tTEST NAME: "+data["name"])
+ print("\tTEST DESCRIPTION: "+data["description"])
+
+ # POST the graph
+ r = requests.post(BASE_URL, json=data["graph"])
+ if r.status_code == 201:
+ graph_id = r.json()["id"]
+ print("\tCreated Graph has ID " + str(graph_id) + " on VeriGraph")
+
+ # GET the policy verification result
+ policy = requests.get(BASE_URL+str(graph_id)+"/policy"+data["policy_url_parameters"])
+
+ # Check the response
+ if policy.status_code == 200:
+ print("\tVerification result is " + policy.json()["result"])
+
+ # Check the result with the expected one
+ if policy.json()["result"] == data["result"]:
+ # SUCCESS
+ print("\t+++ Test passed +++")
+ success += 1
+ else:
+ # FAIL
+ eprint("\t[ERROR] Expected result was " + data["result"] + " but VeriGraph returned " + policy.json()["result"])
+ print("\t--- Test failed ---")
+ else:
+ print("\tVeriGraph returned an unexpected response -> " + str(policy.status_code), policy.reason)
+ print("\t--- Test failed ---")
+ print()
+ except ValueError:
+ print("Malformed json!\nSkipping "+i+" file")
+ print("\t--- Test failed ---")
+ except ValidationError:
+ print("Invalid json (see Schema file)!\nSkipping "+i+" file")
+ print("\t--- Test failed ---")
+ except ConnectionError:
+ print("Connection refused!")
+ print("\t--- Test failed ---")
+ except HTTPError:
+ print("HTTP error!")
+ print("\t--- Test failed ---")
+
+# Final output
+print("\nTest run = "+str(run))
+print("Test succeded = "+str(success))
+if run != 0:
+ if success != run:
+ print("\n --- Some tests failed. See the output. ---")
+ else:
+ print("\n +++ All tests passed +++")
+else:
+ print("\n\n +++ 0 tests executed +++") \ No newline at end of file
diff --git a/verigraph/tester/testcase_schema.json b/verigraph/tester/testcase_schema.json
new file mode 100644
index 0000000..b069705
--- /dev/null
+++ b/verigraph/tester/testcase_schema.json
@@ -0,0 +1,33 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Testcase",
+ "description": "A testcase for VeriGraph",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "The unique identifier for a testcase",
+ "type": "integer"
+ },
+ "name": {
+ "description": "Name of the testcase",
+ "type": "string"
+ },
+ "description": {
+ "description": "A description for the testcase, specifying what is going to be tested",
+ "type": "string"
+ },
+ "policy_url_parameters": {
+ "description": "The set of parameters to be passed in GET request to the verification service",
+ "type": "string"
+ },
+ "result": {
+ "description": "The set of parameters to be passed in GET request to the verification service",
+ "type": "string"
+ },
+ "graph": {
+ "description": "The graph to be tested",
+ "type": "object"
+ }
+ },
+ "required": ["id", "name", "policy_url_parameters", "result", "graph"]
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_budapest_sap1_webserver_sat.json b/verigraph/tester/testcases/test_budapest_sap1_webserver_sat.json
new file mode 100644
index 0000000..62b4eb5
--- /dev/null
+++ b/verigraph/tester/testcases/test_budapest_sap1_webserver_sat.json
@@ -0,0 +1,122 @@
+{
+ "id":6,
+ "name":"budapest_test_case_sat",
+ "description":"This test case verifies budapest scenario, chain sap1->webserver1",
+ "policy_url_parameters":"?type=reachability&source=sap1&destination=webserver1",
+ "result":"SAT",
+ "graph": {
+ "nodes":[
+ {
+ "neighbours":[
+ {
+ "name":"webserver1"
+ },
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "ip_sap1":"webserver1"
+ }
+ ],
+ "name":"fw",
+ "functional_type":"firewall"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap3"
+ },
+ {
+ "name":"fw"
+ }
+ ],
+ "name":"webserver1",
+ "functional_type":"webserver"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap1"
+ },
+ {
+ "name":"dpi"
+ },
+ {
+ "name":"fw"
+ }
+ ],
+ "configuration":[
+ "sap1",
+ "sap2"
+ ],
+ "name":"nat",
+ "functional_type":"nat"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap2"
+ }
+ ],
+ "configuration":[
+ "drug"
+ ],
+ "name":"dpi",
+ "functional_type":"dpi"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap2",
+ "functional_type":"endhost"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap1",
+ "functional_type":"endhost"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"webserver1"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap3",
+ "functional_type":"endhost"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_budapest_sap1_webserver_unsat.json b/verigraph/tester/testcases/test_budapest_sap1_webserver_unsat.json
new file mode 100644
index 0000000..211b310
--- /dev/null
+++ b/verigraph/tester/testcases/test_budapest_sap1_webserver_unsat.json
@@ -0,0 +1,122 @@
+{
+ "id":7,
+ "name":"budapest_test_case_unsat",
+ "description":"This test case verifies budapest scenario, chain sap1->webserver1 with fw blocking",
+ "policy_url_parameters":"?type=reachability&source=sap1&destination=webserver1",
+ "result":"UNSAT",
+ "graph":{
+ "nodes":[
+ {
+ "neighbours":[
+ {
+ "name":"webserver1"
+ },
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "webserver1":"nat"
+ }
+ ],
+ "name":"fw",
+ "functional_type":"firewall"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap3"
+ },
+ {
+ "name":"fw"
+ }
+ ],
+ "name":"webserver1",
+ "functional_type":"webserver"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap1"
+ },
+ {
+ "name":"dpi"
+ },
+ {
+ "name":"fw"
+ }
+ ],
+ "configuration":[
+ "sap1",
+ "sap2"
+ ],
+ "name":"nat",
+ "functional_type":"nat"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"sap2"
+ }
+ ],
+ "configuration":[
+ "drug"
+ ],
+ "name":"dpi",
+ "functional_type":"dpi"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap2",
+ "functional_type":"endhost"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap1",
+ "functional_type":"endhost"
+ },
+ {
+ "neighbours":[
+ {
+ "name":"webserver1"
+ }
+ ],
+ "configuration":[
+ {
+ "url":"www.facebook.com",
+ "body":"cats",
+ "destination":"webserver1",
+ "protocol":"HTTP_REQUEST"
+ }
+ ],
+ "name":"sap3",
+ "functional_type":"endhost"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficAllowed.json b/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficAllowed.json
new file mode 100644
index 0000000..8e19352
--- /dev/null
+++ b/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficAllowed.json
@@ -0,0 +1,59 @@
+{
+ "id": 2,
+ "name": "simple_test_case",
+ "description": "This test case contains a graph with client, firewall and server",
+ "policy_url_parameters": "?type=reachability&source=user1&destination=webserver",
+ "result": "SAT",
+ "graph": {
+ "nodes":[
+ {
+ "name":"user1",
+ "functional_type":"endhost",
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":
+ [
+ {
+ "body": "cartoon",
+ "protocol": "HTTP_REQUEST",
+ "destination": "webserver"
+ }
+ ]
+ },
+ {
+ "name":"nat",
+ "functional_type":"nat",
+ "neighbours":[
+ {
+ "name":"dpi"
+ }
+ ],
+ "configuration":[
+ "user1"
+ ]
+ },
+ {
+ "name":"dpi",
+ "functional_type":"dpi",
+ "neighbours":[
+ {
+ "name":"webserver"
+ }
+ ],
+ "configuration":[
+ "sex", "droga"
+ ]
+ },
+ {
+ "name":"webserver",
+ "functional_type":"webserver",
+ "neighbours":[
+
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficBlocked.json b/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficBlocked.json
new file mode 100644
index 0000000..285ecf2
--- /dev/null
+++ b/verigraph/tester/testcases/test_user_nat_dpi_webserver_trafficBlocked.json
@@ -0,0 +1,59 @@
+{
+ "id": 1,
+ "name": "simple_test_case",
+ "description": "This test case contains a graph with client, firewall and server",
+ "policy_url_parameters": "?type=reachability&source=user1&destination=webserver",
+ "result": "UNSAT",
+ "graph": {
+ "nodes":[
+ {
+ "name":"user1",
+ "functional_type":"endhost",
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":
+ [
+ {
+ "body": "sex",
+ "protocol": "HTTP_REQUEST",
+ "destination": "webserver"
+ }
+ ]
+ },
+ {
+ "name":"nat",
+ "functional_type":"nat",
+ "neighbours":[
+ {
+ "name":"dpi"
+ }
+ ],
+ "configuration":[
+ "user1"
+ ]
+ },
+ {
+ "name":"dpi",
+ "functional_type":"dpi",
+ "neighbours":[
+ {
+ "name":"webserver"
+ }
+ ],
+ "configuration":[
+ "sex", "droga"
+ ]
+ },
+ {
+ "name":"webserver",
+ "functional_type":"webserver",
+ "neighbours":[
+
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_user_nat_vpn_fieldmod_webserver_unsat.json b/verigraph/tester/testcases/test_user_nat_vpn_fieldmod_webserver_unsat.json
new file mode 100644
index 0000000..252e3b5
--- /dev/null
+++ b/verigraph/tester/testcases/test_user_nat_vpn_fieldmod_webserver_unsat.json
@@ -0,0 +1,94 @@
+{
+ "id": 4,
+ "name": "nat_vpn_with_fieldmodifier_test_case",
+ "description": "This test case contains a graph with client, nat, vpn (with field mod in between) and server",
+ "policy_url_parameters": "?type=reachability&source=user1&destination=webserver",
+ "result": "UNSAT",
+ "graph": {
+ "nodes":[
+ {
+ "name":"user1",
+ "functional_type":"endhost",
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":
+ [
+ {
+ "body": "cartoon",
+ "protocol": "HTTP_REQUEST",
+ "destination": "webserver"
+ }
+ ]
+ },
+ {
+ "name":"nat",
+ "functional_type":"nat",
+ "neighbours":[
+ {
+ "name":"user1"
+ },
+ {
+ "name":"vpnaccess"
+ }
+ ],
+ "configuration":[
+ "user1"
+ ]
+ },
+ {
+ "name":"vpnaccess",
+ "functional_type":"vpnaccess",
+ "neighbours":[
+ {
+ "name":"nat"
+ },
+ {
+ "name":"fieldmodifier"
+ }
+ ],
+ "configuration":[
+ {"vpnexit": "vpnexit"}
+ ]
+ },
+ {
+ "name":"fieldmodifier",
+ "functional_type":"fieldmodifier",
+ "neighbours":[
+ {
+ "name":"vpnaccess"
+ },
+ {
+ "name":"vpnexit"
+ }
+ ]
+ },
+ {
+ "name":"vpnexit",
+ "functional_type":"vpnexit",
+ "neighbours":[
+ {
+ "name":"fieldmodifier"
+ },
+ {
+ "name":"webserver"
+ }
+ ],
+ "configuration":[
+ {"vpnaccess": "vpnaccess"}
+ ]
+ },
+ {
+ "name":"webserver",
+ "functional_type":"webserver",
+ "neighbours":[
+ {
+ "name": "vpnexit"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_user_nat_vpn_webserver_sat.json b/verigraph/tester/testcases/test_user_nat_vpn_webserver_sat.json
new file mode 100644
index 0000000..2ae31bc
--- /dev/null
+++ b/verigraph/tester/testcases/test_user_nat_vpn_webserver_sat.json
@@ -0,0 +1,82 @@
+{
+ "id": 3,
+ "name": "nat_vpn_test_case",
+ "description": "This test case contains a graph with client, nat, vpn and server",
+ "policy_url_parameters": "?type=reachability&source=user1&destination=webserver",
+ "result": "SAT",
+ "graph": {
+ "nodes":[
+ {
+ "name":"user1",
+ "functional_type":"endhost",
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":
+ [
+ {
+ "body": "cartoon",
+ "protocol": "HTTP_REQUEST",
+ "destination": "webserver"
+ }
+ ]
+ },
+ {
+ "name":"nat",
+ "functional_type":"nat",
+ "neighbours":[
+ {
+ "name":"user1"
+ },
+ {
+ "name":"vpnaccess"
+ }
+ ],
+ "configuration":[
+ "user1"
+ ]
+ },
+ {
+ "name":"vpnaccess",
+ "functional_type":"vpnaccess",
+ "neighbours":[
+ {
+ "name":"nat"
+ },
+ {
+ "name":"vpnexit"
+ }
+ ],
+ "configuration":[
+ {"vpnexit": "vpnexit"}
+ ]
+ },
+ {
+ "name":"vpnexit",
+ "functional_type":"vpnexit",
+ "neighbours":[
+ {
+ "name":"vpnaccess"
+ },
+ {
+ "name":"webserver"
+ }
+ ],
+ "configuration":[
+ {"vpnaccess": "vpnaccess"}
+ ]
+ },
+ {
+ "name":"webserver",
+ "functional_type":"webserver",
+ "neighbours":[
+ {
+ "name": "vpnexit"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/verigraph/tester/testcases/test_webserver_vpn_nat_user_unsat.json b/verigraph/tester/testcases/test_webserver_vpn_nat_user_unsat.json
new file mode 100644
index 0000000..60d09b3
--- /dev/null
+++ b/verigraph/tester/testcases/test_webserver_vpn_nat_user_unsat.json
@@ -0,0 +1,82 @@
+{
+ "id": 5,
+ "name": "nat_vpn_test_case_serv_to_user",
+ "description": "This test case contains a graph with client, nat, vpn and server. webserver -> client",
+ "policy_url_parameters": "?type=reachability&source=webserver&destination=user1",
+ "result": "UNSAT",
+ "graph": {
+ "nodes":[
+ {
+ "name":"user1",
+ "functional_type":"endhost",
+ "neighbours":[
+ {
+ "name":"nat"
+ }
+ ],
+ "configuration":
+ [
+ {
+ "body": "cartoon",
+ "protocol": "HTTP_REQUEST",
+ "destination": "webserver"
+ }
+ ]
+ },
+ {
+ "name":"nat",
+ "functional_type":"nat",
+ "neighbours":[
+ {
+ "name":"user1"
+ },
+ {
+ "name":"vpnaccess"
+ }
+ ],
+ "configuration":[
+ "user1"
+ ]
+ },
+ {
+ "name":"vpnaccess",
+ "functional_type":"vpnaccess",
+ "neighbours":[
+ {
+ "name":"nat"
+ },
+ {
+ "name":"vpnexit"
+ }
+ ],
+ "configuration":[
+ {"vpnexit": "vpnexit"}
+ ]
+ },
+ {
+ "name":"vpnexit",
+ "functional_type":"vpnexit",
+ "neighbours":[
+ {
+ "name":"vpnaccess"
+ },
+ {
+ "name":"webserver"
+ }
+ ],
+ "configuration":[
+ {"vpnaccess": "vpnaccess"}
+ ]
+ },
+ {
+ "name":"webserver",
+ "functional_type":"webserver",
+ "neighbours":[
+ {
+ "name": "vpnexit"
+ }
+ ]
+ }
+ ]
+ }
+} \ No newline at end of file