summaryrefslogtreecommitdiffstats
path: root/tosca2heat/heat-translator
diff options
context:
space:
mode:
Diffstat (limited to 'tosca2heat/heat-translator')
-rw-r--r--tosca2heat/heat-translator/CONTRIBUTING.rst16
-rw-r--r--tosca2heat/heat-translator/HACKING.rst4
-rw-r--r--tosca2heat/heat-translator/LICENSE175
-rw-r--r--tosca2heat/heat-translator/MANIFEST.in6
-rw-r--r--tosca2heat/heat-translator/README.rst47
-rw-r--r--tosca2heat/heat-translator/babel.cfg1
-rw-r--r--tosca2heat/heat-translator/doc/source/conf.py75
-rw-r--r--tosca2heat/heat-translator/doc/source/contributing.rst1
-rw-r--r--tosca2heat/heat-translator/doc/source/index.rst29
-rw-r--r--tosca2heat/heat-translator/doc/source/installation.rst15
-rw-r--r--tosca2heat/heat-translator/doc/source/usage.rst81
-rw-r--r--tosca2heat/heat-translator/heat_translator.py20
-rw-r--r--tosca2heat/heat-translator/heat_translator_logging.conf43
-rw-r--r--tosca2heat/heat-translator/openstack-common.conf6
-rw-r--r--tosca2heat/heat-translator/requirements.txt10
-rw-r--r--tosca2heat/heat-translator/setup.cfg55
-rw-r--r--tosca2heat/heat-translator/setup.py29
-rw-r--r--tosca2heat/heat-translator/test-requirements.txt14
-rw-r--r--tosca2heat/heat-translator/tox.ini37
-rw-r--r--tosca2heat/heat-translator/translator/__init__.py19
-rw-r--r--tosca2heat/heat-translator/translator/common/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/common/exception.py48
-rw-r--r--tosca2heat/heat-translator/translator/common/utils.py319
-rw-r--r--tosca2heat/heat-translator/translator/conf/__init__.py36
-rw-r--r--tosca2heat/heat-translator/translator/conf/config.py67
-rw-r--r--tosca2heat/heat-translator/translator/conf/translator.conf4
-rw-r--r--tosca2heat/heat-translator/translator/custom/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/custom/hot/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_output.py25
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_parameter.py52
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py362
-rw-r--r--tosca2heat/heat-translator/translator/hot/syntax/hot_template.py83
-rw-r--r--tosca2heat/heat-translator/translator/hot/tests/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/tests/test_hot_parameter.py44
-rw-r--r--tosca2heat/heat-translator/translator/hot/tests/test_translate_inputs.py351
-rw-r--r--tosca2heat/heat-translator/translator/hot/tests/test_translate_outputs.py50
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_blockstorage.py84
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py286
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_objectstore.py71
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_policies.py80
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py71
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py48
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py280
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py30
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py30
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py118
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py114
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py57
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py36
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py30
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py30
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py30
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca_translator.py68
-rw-r--r--tosca2heat/heat-translator/translator/hot/translate_inputs.py167
-rw-r--r--tosca2heat/heat-translator/translator/hot/translate_node_templates.py483
-rw-r--r--tosca2heat/heat-translator/translator/hot/translate_outputs.py48
-rw-r--r--tosca2heat/heat-translator/translator/osc/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/osc/osc_plugin.py41
-rw-r--r--tosca2heat/heat-translator/translator/osc/utils.py45
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/tests/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py32
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/tests/test_translate.py448
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/tests/utils.py19
-rw-r--r--tosca2heat/heat-translator/translator/osc/v1/translate.py106
-rw-r--r--tosca2heat/heat-translator/translator/shell.py238
-rw-r--r--tosca2heat/heat-translator/translator/tests/__init__.py0
-rw-r--r--tosca2heat/heat-translator/translator/tests/base.py53
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/config.py25
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/create.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/start.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/create.sh14
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/start.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/config.sh7
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/create.sh12
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/start.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_collectd.py28
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_elasticsearch.py26
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_rsyslog.py25
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/create.sh20
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/start.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/config.sh7
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create.sh14
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create_database.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/start.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_database_configure.sh8
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_configure.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_install.sh9
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_start.sh2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/config.sh28
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/create.sh7
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/start.sh3
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/config.sh30
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/create.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/start.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_install.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_start.sh2
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_configure.sh4
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_install.sh5
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_elk.zipbin0 -> 17488 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_hello_world.zipbin0 -> 936 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_metadata_not_yaml.zipbin0 -> 936 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_not_zip.zip1
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_single_instance_wordpress.zipbin0 -> 5967 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_import_path.zipbin0 -> 5978 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_script_url.zipbin0 -> 6034 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/csar_wrong_metadata_file.zipbin0 -> 873 bytes
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/collectd.yaml13
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/elasticsearch.yaml12
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/kibana.yaml14
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/logstash.yaml25
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/paypalpizzastore_nodejs_app.yaml29
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/rsyslog.yaml13
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/custom_types/wordpress.yaml19
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml30
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml34
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml34
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml34
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml551
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml551
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml18
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml18
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml14
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml19
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml135
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml35
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml185
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml25
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml209
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml207
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml21
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml36
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml36
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml36
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml17
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml58
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml100
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml33
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml44
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml71
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml27
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml72
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml71
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml92
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml92
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml96
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml96
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml72
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml65
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml109
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml109
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_defs.yaml41
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_imports.yaml41
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_inline.yaml82
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_one_network.yaml43
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_three_networks.yaml64
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/tosca_server_on_existing_network.yaml39
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/network/tosca_two_servers_one_network.yaml79
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment.yaml61
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation1.yaml87
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation2.yaml99
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_custom_relationship_type.yaml64
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_relationship_template.yaml59
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_multiple_blockstorage_with_attachment.yaml93
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/storage/tosca_single_object_store.yaml17
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_host_assignment.yaml80
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_single_server_without_optional_version_prop.yaml24
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml40
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type.yaml47
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type_with_override.yaml45
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml29
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/test_tosca_nfv_sample.yaml43
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_elk.yaml219
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_helloworld.yaml23
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_helloworld_invalid.yaml23
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_nodejs_mongodb_two_instances.yaml96
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_policies.yaml28
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress.yaml120
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml125
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_url_import.yaml120
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_single_server.yaml32
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_single_server_with_defaults.yaml35
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_software_component.yaml40
-rw-r--r--tosca2heat/heat-translator/translator/tests/data/tosca_web_application.yaml56
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_conf.py57
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_shell.py191
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_template.py63
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py633
-rw-r--r--tosca2heat/heat-translator/translator/tests/test_utils.py236
193 files changed, 12445 insertions, 0 deletions
diff --git a/tosca2heat/heat-translator/CONTRIBUTING.rst b/tosca2heat/heat-translator/CONTRIBUTING.rst
new file mode 100644
index 0000000..e12c422
--- /dev/null
+++ b/tosca2heat/heat-translator/CONTRIBUTING.rst
@@ -0,0 +1,16 @@
+If you would like to contribute to the development of OpenStack,
+you must follow the steps in this page:
+
+ http://docs.openstack.org/infra/manual/developers.html
+
+Once those steps have been completed, changes to OpenStack
+should be submitted for review via the Gerrit tool, following
+the workflow documented at:
+
+ http://docs.openstack.org/infra/manual/developers.html#development-workflow
+
+Pull requests submitted through GitHub will be ignored.
+
+Bugs should be filed on Launchpad, not GitHub:
+
+ https://bugs.launchpad.net/heat-translator \ No newline at end of file
diff --git a/tosca2heat/heat-translator/HACKING.rst b/tosca2heat/heat-translator/HACKING.rst
new file mode 100644
index 0000000..9c60464
--- /dev/null
+++ b/tosca2heat/heat-translator/HACKING.rst
@@ -0,0 +1,4 @@
+heat-translator Style Commandments
+===============================================
+
+Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ \ No newline at end of file
diff --git a/tosca2heat/heat-translator/LICENSE b/tosca2heat/heat-translator/LICENSE
new file mode 100644
index 0000000..67db858
--- /dev/null
+++ b/tosca2heat/heat-translator/LICENSE
@@ -0,0 +1,175 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
diff --git a/tosca2heat/heat-translator/MANIFEST.in b/tosca2heat/heat-translator/MANIFEST.in
new file mode 100644
index 0000000..90f8a7a
--- /dev/null
+++ b/tosca2heat/heat-translator/MANIFEST.in
@@ -0,0 +1,6 @@
+include AUTHORS
+include ChangeLog
+exclude .gitignore
+exclude .gitreview
+
+global-exclude *.pyc \ No newline at end of file
diff --git a/tosca2heat/heat-translator/README.rst b/tosca2heat/heat-translator/README.rst
new file mode 100644
index 0000000..1bad459
--- /dev/null
+++ b/tosca2heat/heat-translator/README.rst
@@ -0,0 +1,47 @@
+===============
+Heat-Translator
+===============
+
+Overview
+--------
+
+Heat-Translator is an Openstack project and licensed under Apache 2. It is a
+command line tool which takes non-Heat templates as an input and produces a
+Heat Orchestration Template (HOT) which can be deployed by Heat. Currently the
+development and testing is done with an aim to translate OASIS Topology and
+Orchestration Specification for Cloud Applications (TOSCA) templates to
+HOT. However, the tool is designed to be easily extended to use with any
+format other than TOSCA.
+
+Architecture
+------------
+
+Heat-Translator project takes a non-Heat template (e.g. TOSCA flat YAML
+template or template embedded in TOSCA Cloud Service Archive (CSAR) format) as
+an input, calls an appropriate Parser (e.g. TOSCA Parser) per the type of input
+template to parse it and create an in-memory graph, maps it to Heat resources
+and then produces a Heat Orchestration Template (HOT) as an output.
+
+How To Use
+----------
+Please refer to `doc/source/usage.rst <https://github.com/openstack/heat-translator/blob/master/doc/source/usage.rst>`_
+
+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.
+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.
+
+Project Info
+------------
+
+* License: Apache License, Version 2.0
+* Documentation: http://docs.openstack.org/developer/heat-translator/
+* Launchpad: https://launchpad.net/heat-translator
+* Blueprints: https://blueprints.launchpad.net/heat-translator
+* Bugs: https://bugs.launchpad.net/heat-translator
+* Source: http://git.openstack.org/cgit/openstack/heat-translator/
+* IRC Channel: #openstack-heat-translator
diff --git a/tosca2heat/heat-translator/babel.cfg b/tosca2heat/heat-translator/babel.cfg
new file mode 100644
index 0000000..efceab8
--- /dev/null
+++ b/tosca2heat/heat-translator/babel.cfg
@@ -0,0 +1 @@
+[python: **.py]
diff --git a/tosca2heat/heat-translator/doc/source/conf.py b/tosca2heat/heat-translator/doc/source/conf.py
new file mode 100644
index 0000000..23aa050
--- /dev/null
+++ b/tosca2heat/heat-translator/doc/source/conf.py
@@ -0,0 +1,75 @@
+# -*- 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath('../..'))
+# -- General configuration ----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ #'sphinx.ext.intersphinx',
+ 'oslosphinx'
+]
+
+# autodoc generation is a bit aggressive and a nuisance when doing heavy
+# text edit cycles.
+# execute "export SPHINX_DEBUG=1" in your terminal to disable
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'heat-translator'
+copyright = u'2013, OpenStack Foundation'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+add_module_names = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+# html_theme_path = ["."]
+# html_theme = 'default'
+# html_static_path = ['static']
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = '%sdoc' % project
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass
+# [howto/manual]).
+latex_documents = [
+ ('index',
+ '%s.tex' % project,
+ u'%s Documentation' % project,
+ u'OpenStack Foundation', 'manual'),
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+#intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/tosca2heat/heat-translator/doc/source/contributing.rst b/tosca2heat/heat-translator/doc/source/contributing.rst
new file mode 100644
index 0000000..8cb3146
--- /dev/null
+++ b/tosca2heat/heat-translator/doc/source/contributing.rst
@@ -0,0 +1 @@
+.. include:: ../../CONTRIBUTING.rst \ No newline at end of file
diff --git a/tosca2heat/heat-translator/doc/source/index.rst b/tosca2heat/heat-translator/doc/source/index.rst
new file mode 100644
index 0000000..dd3f04f
--- /dev/null
+++ b/tosca2heat/heat-translator/doc/source/index.rst
@@ -0,0 +1,29 @@
+.. heat-translator documentation master file, created by
+ sphinx-quickstart on Tue Jul 9 22:26:36 2013.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to heat-translator's documentation!
+===========================================
+
+The heat-translator tool is aimed to translate non-heat templates to OpenStack
+Heat Orchestration Template (HOT). Initially the tool is aimed to translate
+OASIS Topology and Orchestration Specification for Cloud Applications (TOSCA)
+to HOT. However, the tool can be easily extended to support any non-heat
+template format to produce HOT.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ installation
+ usage
+ contributing
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/tosca2heat/heat-translator/doc/source/installation.rst b/tosca2heat/heat-translator/doc/source/installation.rst
new file mode 100644
index 0000000..71c5237
--- /dev/null
+++ b/tosca2heat/heat-translator/doc/source/installation.rst
@@ -0,0 +1,15 @@
+============
+Installation
+============
+
+Assuming that OpenStackClient (OSC) is available in your environment, you can easily install Heat-Translator to use with OSC by following three steps::
+
+ git clone https://github.com/openstack/heat-translator
+ cd heat-translator
+ sudo python setup.py install
+
+You can also clone the project and use it without any specific OpenStack environment set up as below::
+
+ git clone https://github.com/openstack/heat-translator
+
+Heat-Translator can be installed via PyPI package as well. Refer to https://pypi.python.org/pypi/heat-translator for available packages.
diff --git a/tosca2heat/heat-translator/doc/source/usage.rst b/tosca2heat/heat-translator/doc/source/usage.rst
new file mode 100644
index 0000000..ebad0e8
--- /dev/null
+++ b/tosca2heat/heat-translator/doc/source/usage.rst
@@ -0,0 +1,81 @@
+=====
+Usage
+=====
+
+Use Heat-Translator with OpenStackClient (OSC)
+----------------------------------------------
+Assuming that OpenStackClient (OSC) is available in your environment, you can easily install Heat-Translator to use with OSC by following three steps::
+
+ git clone https://github.com/openstack/heat-translator
+ cd heat-translator
+ sudo python setup.py install
+
+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.
+
+Translate and get output on command line. For example: ::
+
+ openstack translate template --template-file /home/openstack/heat-translator/translator/tests/data/tosca_helloworld.yaml --template-type tosca
+
+Translate and save output of translated file to a desired destination. For example: ::
+
+ openstack translate template --template-file /home/openstack/heat-translator/translator/tests/data/tosca_helloworld.yaml --template-type tosca --output-file /tmp/hot_hello_world.yaml
+
+Do not translate but only validate template file. For example: ::
+
+ openstack translate template --template-file /home/openstack/heat-translator/translator/tests/data/tosca_helloworld.yaml --template-type tosca --validate-only=true
+
+You can learn more about available options by running following help command::
+
+ openstack help translate template
+
+
+Use Heat-Translator on its own
+------------------------------
+Heat-Translator can be used without any specific OpenStack environment set up as below::
+
+ git clone https://github.com/openstack/heat-translator
+ 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
+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
+
+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: ::
+
+ python heat_translator.py --template-file=translator/tests/data/tosca_helloworld.yaml --template-type=tosca --output-file=/tmp/hot_helloworld.yaml
+
+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
+
+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::
+ heat-translator --template-file=translator/tests/data/tosca_helloworld.yaml --template-type=tosca
+
+Things To Consider
+------------------
+* When deploying the translated template with Heat, please ensure that you have image registered in the Glance. The Heat-Translator
+ project sets flavor and image from a pre-defined set of values (as listed in /home/openstack/heat-translator/translator/hot/tosca/tosca_compute.py)
+ with the best possible match to the constraints defined in the TOSCA template. If there is no possible match found, a null value is set currently.
+ Per the future plan, an image and flavor will be provided from an online repository.
+* The ``key_name`` property of Nova server is irrelevant to the TOSCA specification and can not be used in TOSCA template. In order to use it in
+ the translated templates, the user must provide it via parameters, and the heat-translator will set it to all resources of ``OS::Nova::Server`` type.
+* Since properties of TOSCA Compute OS and HOST capabilities are optional, the user should make sure that either they set these properties correctly
+ in the TOSCA template or provide them via CLI parameters in order to find best match of flavor and image.
+* The ``flavor`` and ``image`` properties of ``OS::Nova::Server`` resource is irrelevant to the TOSCA specification and can not be used in the TOSCA
+ template as such. Heat-Translator sets these properties in the translated template based on constraints defined per TOSCA Compute OS and HOST
+ 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.
+
diff --git a/tosca2heat/heat-translator/heat_translator.py b/tosca2heat/heat-translator/heat_translator.py
new file mode 100644
index 0000000..80a435b
--- /dev/null
+++ b/tosca2heat/heat-translator/heat_translator.py
@@ -0,0 +1,20 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+# Keep this file around for backwards compatibility, and make it call the
+# new translator's shell file instead, as it's now packaged
+
+from translator import shell as translator_shell
+
+if __name__ == '__main__':
+ translator_shell.main()
diff --git a/tosca2heat/heat-translator/heat_translator_logging.conf b/tosca2heat/heat-translator/heat_translator_logging.conf
new file mode 100644
index 0000000..e01a889
--- /dev/null
+++ b/tosca2heat/heat-translator/heat_translator_logging.conf
@@ -0,0 +1,43 @@
+
+[loggers]
+keys=root,heat-translator
+
+[handlers]
+keys=RotatingFileHandler,SysLogHandler,NullHandler
+
+[formatters]
+keys=form01
+
+[logger_root]
+level=DEBUG
+handlers=NullHandler
+
+[logger_heat-translator]
+level=INFO
+#one can be removed based on requirements
+handlers=SysLogHandler, RotatingFileHandler
+qualname=heat-translator
+propagate=1
+
+[handler_RotatingFileHandler]
+class=handlers.RotatingFileHandler
+level=INFO
+formatter=form01
+#rotation happens after 100MB
+args=('/tmp/heat-translator.log', 'a', 100000000, 5, 'utf8')
+
+[handler_SysLogHandler]
+class=handlers.SysLogHandler
+formatter=form01
+level=INFO
+args=('/dev/log', handlers.SysLogHandler.LOG_SYSLOG)
+
+[handler_NullHandler]
+class=NullHandler
+formatter=form01
+level=DEBUG
+args=()
+
+[formatter_form01]
+format = %(asctime)s - %(name)s - %(levelname)s - %(filename)s : %(message)s
+datefmt =
diff --git a/tosca2heat/heat-translator/openstack-common.conf b/tosca2heat/heat-translator/openstack-common.conf
new file mode 100644
index 0000000..d359e40
--- /dev/null
+++ b/tosca2heat/heat-translator/openstack-common.conf
@@ -0,0 +1,6 @@
+[DEFAULT]
+
+# The list of modules to copy from oslo-incubator.git
+
+# The base module to hold the copy of openstack.common
+base=translator \ No newline at end of file
diff --git a/tosca2heat/heat-translator/requirements.txt b/tosca2heat/heat-translator/requirements.txt
new file mode 100644
index 0000000..e54d0ab
--- /dev/null
+++ b/tosca2heat/heat-translator/requirements.txt
@@ -0,0 +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
+Babel>=1.3 # BSD
+cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
+PyYAML>=3.1.0 # MIT
+python-dateutil>=2.4.2 # BSD
+six>=1.9.0 # MIT
+tosca-parser>=0.4.0 # Apache-2.0
diff --git a/tosca2heat/heat-translator/setup.cfg b/tosca2heat/heat-translator/setup.cfg
new file mode 100644
index 0000000..029eeff
--- /dev/null
+++ b/tosca2heat/heat-translator/setup.cfg
@@ -0,0 +1,55 @@
+[metadata]
+name = heat-translator
+summary = Tool to translate non-heat templates to Heat Orchestration Template.
+description-file =
+ README.rst
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
+home-page = http://www.openstack.org/
+classifier =
+ Environment :: OpenStack
+ 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.4
+
+[files]
+packages =
+ translator
+
+[entry_points]
+openstack.cli.extension =
+ translator = translator.osc.osc_plugin
+
+openstack.translator.v1 =
+ translate_template = translator.osc.v1.translate:TranslateTemplate
+
+console_scripts =
+ heat-translator = translator.shell:main
+
+[build_sphinx]
+source-dir = doc/source
+build-dir = doc/build
+all_files = 1
+
+[upload_sphinx]
+upload-dir = doc/build/html
+
+[compile_catalog]
+directory = translator/locale
+domain = translator
+
+[update_catalog]
+domain = translator
+output_dir = translator/locale
+input_file = translator/locale/translator.pot
+
+[extract_messages]
+keywords = _ gettext ngettext l_ lazy_gettext
+mapping_file = babel.cfg
+output_file = translator/locale/translator.pot
diff --git a/tosca2heat/heat-translator/setup.py b/tosca2heat/heat-translator/setup.py
new file mode 100644
index 0000000..782bb21
--- /dev/null
+++ b/tosca2heat/heat-translator/setup.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
+import setuptools
+
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+ import multiprocessing # noqa
+except ImportError:
+ pass
+
+setuptools.setup(
+ setup_requires=['pbr>=1.8'],
+ pbr=True)
diff --git a/tosca2heat/heat-translator/test-requirements.txt b/tosca2heat/heat-translator/test-requirements.txt
new file mode 100644
index 0000000..2b9cae7
--- /dev/null
+++ b/tosca2heat/heat-translator/test-requirements.txt
@@ -0,0 +1,14 @@
+# 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.
+hacking<0.11,>=0.10.0
+coverage>=3.6 # Apache-2.0
+discover # BSD
+fixtures>=1.3.1 # Apache-2.0/BSD
+oslotest>=1.10.0 # Apache-2.0
+oslosphinx!=3.4.0,>=2.5.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
+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/tox.ini b/tosca2heat/heat-translator/tox.ini
new file mode 100644
index 0000000..868e95a
--- /dev/null
+++ b/tosca2heat/heat-translator/tox.ini
@@ -0,0 +1,37 @@
+[tox]
+minversion = 1.6
+envlist = py34,py27,pypy,pep8
+skipsdist = True
+
+[testenv]
+usedevelop = True
+install_command = pip install -U {opts} {packages}
+setenv =
+ VIRTUAL_ENV={envdir}
+deps = -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
+commands = python setup.py test --slowest --testr-args='{posargs}'
+
+[testenv:pep8]
+commands = flake8
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py test --coverage --coverage-package-name=translator --testr-args='{posargs}'
+
+[testenv:docs]
+commands = python setup.py build_sphinx
+
+[testenv:debug]
+commands = oslo_debug_helper -t translator/tests {posargs}
+
+[flake8]
+# H803 skipped on purpose per list discussion.
+# E123, E125 skipped as they are invalid PEP-8.
+
+show-source = True
+ignore = E123,E125,H803
+builtins = _
+exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
diff --git a/tosca2heat/heat-translator/translator/__init__.py b/tosca2heat/heat-translator/translator/__init__.py
new file mode 100644
index 0000000..3c2a807
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/__init__.py
@@ -0,0 +1,19 @@
+# -*- 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 pbr.version
+
+
+__version__ = pbr.version.VersionInfo(
+ 'heat-translator').version_string()
diff --git a/tosca2heat/heat-translator/translator/common/__init__.py b/tosca2heat/heat-translator/translator/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/common/__init__.py
diff --git a/tosca2heat/heat-translator/translator/common/exception.py b/tosca2heat/heat-translator/translator/common/exception.py
new file mode 100644
index 0000000..be86116
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/common/exception.py
@@ -0,0 +1,48 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+'''
+Exceptions for the TOSCA Translator package.
+'''
+
+from toscaparser.common.exception import TOSCAException
+from toscaparser.utils.gettextutils import _
+
+
+class ConfFileParseError(TOSCAException):
+ msg_fmt = _('%(message)s')
+
+
+class ConfOptionNotDefined(TOSCAException):
+ msg_fmt = _('Option %(key)s in section %(section)s '
+ 'is not defined in conf file')
+
+
+class ConfSectionNotDefined(TOSCAException):
+ msg_fmt = _('Section %(section)s is not defined in conf file')
+
+
+class ToscaModImportError(TOSCAException):
+ msg_fmt = _('Unable to import module %(mod_name)s. '
+ 'Check to see that it exists and has no '
+ 'language definition errors.')
+
+
+class ToscaClassImportError(TOSCAException):
+ msg_fmt = _('Unable to import class %(name)s in '
+ 'module %(mod_name)s. Check to see that it '
+ 'exists and has no language definition errors.')
+
+
+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/utils.py b/tosca2heat/heat-translator/translator/common/utils.py
new file mode 100644
index 0000000..459b5ee
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/common/utils.py
@@ -0,0 +1,319 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+import json
+import logging
+import math
+import numbers
+import os
+import re
+import requests
+from six.moves.urllib.parse import urlparse
+import yaml
+
+from toscaparser.utils.gettextutils import _
+import toscaparser.utils.yamlparser
+
+YAML_ORDER_PARSER = toscaparser.utils.yamlparser.simple_ordered_parse
+log = logging.getLogger('heat-translator')
+
+# Required environment variables to create openstackclient object.
+ENV_VARIABLES = ['OS_AUTH_URL', 'OS_PASSWORD', 'OS_USERNAME', 'OS_TENANT_NAME']
+
+
+class MemoryUnit(object):
+
+ UNIT_SIZE_DEFAULT = 'B'
+ UNIT_SIZE_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000,
+ 'MiB': 1048576, 'GB': 1000000000,
+ 'GiB': 1073741824, 'TB': 1000000000000,
+ 'TiB': 1099511627776}
+
+ @staticmethod
+ def convert_unit_size_to_num(size, unit=None):
+ """Convert given size to a number representing given unit.
+
+ If unit is None, convert to a number representing UNIT_SIZE_DEFAULT
+ :param size: unit size e.g. 1 TB
+ :param unit: unit to be converted to e.g GB
+ :return: converted number e.g. 1000 for 1 TB size and unit GB
+ """
+ if unit:
+ unit = MemoryUnit.validate_unit(unit)
+ else:
+ unit = MemoryUnit.UNIT_SIZE_DEFAULT
+ log.info(_('A memory unit is not provided for size; using the '
+ 'default unit %(default)s.') % {'default': 'B'})
+ regex = re.compile('(\d*)\s*(\w*)')
+ result = regex.match(str(size)).groups()
+ if result[1]:
+ unit_size = MemoryUnit.validate_unit(result[1])
+ converted = int(str_to_num(result[0])
+ * MemoryUnit.UNIT_SIZE_DICT[unit_size]
+ * math.pow(MemoryUnit.UNIT_SIZE_DICT
+ [unit], -1))
+ log.info(_('Given size %(size)s is converted to %(num)s '
+ '%(unit)s.') % {'size': size,
+ 'num': converted, 'unit': unit})
+ else:
+ converted = (str_to_num(result[0]))
+ return converted
+
+ @staticmethod
+ def validate_unit(unit):
+ if unit in MemoryUnit.UNIT_SIZE_DICT.keys():
+ return unit
+ else:
+ for key in MemoryUnit.UNIT_SIZE_DICT.keys():
+ if key.upper() == unit.upper():
+ return key
+
+ msg = _('Provided unit "{0}" is not valid. The valid units are'
+ ' {1}').format(unit, MemoryUnit.UNIT_SIZE_DICT.keys())
+ log.error(msg)
+ raise ValueError(msg)
+
+
+class CompareUtils(object):
+
+ MISMATCH_VALUE1_LABEL = "<Expected>"
+ MISMATCH_VALUE2_LABEL = "<Provided>"
+ ORDERLESS_LIST_KEYS = ['allowed_values', 'depends_on']
+
+ @staticmethod
+ def compare_dicts(dict1, dict2):
+ """Return False if not equal, True if both are equal."""
+
+ if dict1 is None and dict2 is None:
+ return True
+ if dict1 is None or dict2 is None:
+ return False
+
+ both_equal = True
+ for dict1_item, dict2_item in zip(dict1.items(), dict2.items()):
+ if dict1_item != dict2_item:
+ msg = (_("%(label1)s: %(item1)s \n is not equal to \n:"
+ "%(label2)s: %(item2)s")
+ % {'label1': CompareUtils.MISMATCH_VALUE2_LABEL,
+ 'item1': dict1_item,
+ 'label2': CompareUtils.MISMATCH_VALUE1_LABEL,
+ 'item2': dict2_item})
+ log.warning(msg)
+ both_equal = False
+ break
+ return both_equal
+
+ @staticmethod
+ def compare_hot_yamls(generated_yaml, expected_yaml):
+ hot_translated_dict = YAML_ORDER_PARSER(generated_yaml)
+ hot_expected_dict = YAML_ORDER_PARSER(expected_yaml)
+ return CompareUtils.compare_dicts(hot_translated_dict,
+ hot_expected_dict)
+
+ @staticmethod
+ def reorder(dic):
+ '''Canonicalize list items in the dictionary for ease of comparison.
+
+ For properties whose value is a list in which the order does not
+ matter, some pre-processing is required to bring those lists into a
+ canonical format. We use sorting just to make sure such differences
+ in ordering would not cause to a mismatch.
+ '''
+
+ if type(dic) is not dict:
+ return None
+
+ reordered = {}
+ for key in dic.keys():
+ value = dic[key]
+ if type(value) is dict:
+ reordered[key] = CompareUtils.reorder(value)
+ elif type(value) is list \
+ and key in CompareUtils.ORDERLESS_LIST_KEYS:
+ reordered[key] = sorted(value)
+ else:
+ reordered[key] = value
+ return reordered
+
+ @staticmethod
+ def diff_dicts(dict1, dict2, reorder=True):
+ '''Compares two dictionaries and returns their differences.
+
+ Returns a dictionary of mismatches between the two dictionaries.
+ An empty dictionary is returned if two dictionaries are equivalent.
+ The reorder parameter indicates whether reordering is required
+ before comparison or not.
+ '''
+
+ if reorder:
+ dict1 = CompareUtils.reorder(dict1)
+ dict2 = CompareUtils.reorder(dict2)
+
+ if dict1 is None and dict2 is None:
+ return {}
+ if dict1 is None or dict2 is None:
+ return {CompareUtils.MISMATCH_VALUE1_LABEL: dict1,
+ CompareUtils.MISMATCH_VALUE2_LABEL: dict2}
+
+ diff = {}
+ keys1 = set(dict1.keys())
+ keys2 = set(dict2.keys())
+ for key in keys1.union(keys2):
+ if key in keys1 and key not in keys2:
+ diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: dict1[key],
+ CompareUtils.MISMATCH_VALUE2_LABEL: None}
+ elif key not in keys1 and key in keys2:
+ diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: None,
+ CompareUtils.MISMATCH_VALUE2_LABEL: dict2[key]}
+ else:
+ val1 = dict1[key]
+ val2 = dict2[key]
+ if val1 != val2:
+ if type(val1) is dict and type(val2) is dict:
+ diff[key] = CompareUtils.diff_dicts(val1, val2, False)
+ else:
+ diff[key] = {CompareUtils.MISMATCH_VALUE1_LABEL: val1,
+ CompareUtils.MISMATCH_VALUE2_LABEL: val2}
+ return diff
+
+
+class YamlUtils(object):
+
+ @staticmethod
+ def get_dict(yaml_file):
+ '''Returns the dictionary representation of the given YAML spec.'''
+ try:
+ return yaml.load(open(yaml_file))
+ except IOError:
+ return None
+
+ @staticmethod
+ def compare_yamls(yaml1_file, yaml2_file):
+ '''Returns true if two dictionaries are equivalent, false otherwise.'''
+ dict1 = YamlUtils.get_dict(yaml1_file)
+ dict2 = YamlUtils.get_dict(yaml2_file)
+ return CompareUtils.compare_dicts(dict1, dict2)
+
+ @staticmethod
+ def compare_yaml_dict(yaml_file, dic):
+ '''Returns true if yaml matches the dictionary, false otherwise.'''
+ return CompareUtils.compare_dicts(YamlUtils.get_dict(yaml_file), dic)
+
+
+class TranslationUtils(object):
+
+ @staticmethod
+ def compare_tosca_translation_with_hot(tosca_file, hot_file, params):
+ '''Verify tosca translation against the given hot specification.
+
+ inputs:
+ tosca_file: relative local path or URL to the tosca input file
+ hot_file: relative path to expected hot output
+ params: dictionary of parameter name value pairs
+
+ Returns as a dictionary the difference between the HOT translation
+ of the given tosca_file and the given hot_file.
+ '''
+
+ from toscaparser.tosca_template import ToscaTemplate
+ from translator.hot.tosca_translator import TOSCATranslator
+
+ tosca_tpl = os.path.normpath(os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), tosca_file))
+ a_file = os.path.isfile(tosca_tpl)
+ if not a_file:
+ tosca_tpl = tosca_file
+
+ expected_hot_tpl = 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)
+
+
+class UrlUtils(object):
+
+ @staticmethod
+ def validate_url(path):
+ """Validates whether the given path is a URL or not.
+
+ If the given path includes a scheme (http, https, ftp, ...) and a net
+ location (a domain name such as www.github.com) it is validated as a
+ URL.
+ """
+ parsed = urlparse(path)
+ return bool(parsed.scheme) and bool(parsed.netloc)
+
+
+def str_to_num(value):
+ """Convert a string representation of a number into a numeric type."""
+ if isinstance(value, numbers.Number):
+ return value
+ try:
+ return int(value)
+ except ValueError:
+ return float(value)
+
+
+def check_for_env_variables():
+ return set(ENV_VARIABLES) < set(os.environ.keys())
+
+
+def get_ks_access_dict():
+ tenant_name = os.getenv('OS_TENANT_NAME')
+ username = os.getenv('OS_USERNAME')
+ password = os.getenv('OS_PASSWORD')
+ auth_url = os.getenv('OS_AUTH_URL')
+
+ auth_dict = {
+ "auth": {
+ "tenantName": tenant_name,
+ "passwordCredentials": {
+ "username": username,
+ "password": password
+ }
+ }
+ }
+ headers = {'Content-Type': 'application/json'}
+ try:
+ keystone_response = requests.post(auth_url + '/tokens',
+ data=json.dumps(auth_dict),
+ headers=headers)
+ if keystone_response.status_code != 200:
+ return None
+ return json.loads(keystone_response.content)
+ except Exception:
+ return None
+
+
+def get_url_for(access_dict, service_type):
+ if access_dict is None:
+ return None
+ service_catalog = access_dict['access']['serviceCatalog']
+ service_url = ''
+ for service in service_catalog:
+ if service['type'] == service_type:
+ service_url = service['endpoints'][0]['publicURL']
+ break
+ return service_url
+
+
+def get_token_id(access_dict):
+ if access_dict is None:
+ return None
+ return access_dict['access']['token']['id']
diff --git a/tosca2heat/heat-translator/translator/conf/__init__.py b/tosca2heat/heat-translator/translator/conf/__init__.py
new file mode 100644
index 0000000..2c61252
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/conf/__init__.py
@@ -0,0 +1,36 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+''' Initialize the global configuration for the translator '''
+
+import os
+
+from translator.conf.config import ConfigProvider
+
+CONF_FILENAME = 'translator.conf'
+
+
+def init_global_conf():
+ '''Initialize the configuration provider.
+
+ Allows the configuration to be shared throughout the translator code.
+ The file used is translator.conf, and is within the conf/ directory. It
+ is a standard ini format, and is prcessed using the ConfigParser module.
+
+ '''
+ conf_path = os.path.dirname(os.path.abspath(__file__))
+ conf_file = os.path.join(conf_path, CONF_FILENAME)
+ ConfigProvider._load_config(conf_file)
+
+
+init_global_conf()
diff --git a/tosca2heat/heat-translator/translator/conf/config.py b/tosca2heat/heat-translator/translator/conf/config.py
new file mode 100644
index 0000000..4e8fe87
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/conf/config.py
@@ -0,0 +1,67 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+''' Provide a global configuration for the TOSCA translator'''
+
+from six.moves import configparser
+
+from toscaparser.utils.gettextutils import _
+import translator.common.exception as exception
+
+
+class ConfigProvider(object):
+ '''Global config proxy that wraps a ConfigParser object.
+
+ Allows for class based access to config values. Should only be initialized
+ once using the corresponding translator.conf file in the conf directory.
+
+ '''
+
+ # List that captures all of the conf file sections.
+ # Append any new sections to this list.
+ _sections = ['DEFAULT']
+ _translator_config = None
+
+ @classmethod
+ def _load_config(cls, conf_file):
+ '''Private method only to be called once from the __init__ module'''
+
+ cls._translator_config = configparser.ConfigParser()
+ try:
+ cls._translator_config.read(conf_file)
+ except configparser.ParsingError:
+ msg = _('Unable to parse translator.conf file.'
+ 'Check to see that it exists in the conf directory.')
+ raise exception.ConfFileParseError(message=msg)
+
+ @classmethod
+ def get_value(cls, section, key):
+ try:
+ value = cls._translator_config.get(section, key)
+ except configparser.NoOptionError:
+ raise exception.ConfOptionNotDefined(key=key, section=section)
+ except configparser.NoSectionError:
+ raise exception.ConfSectionNotDefined(section=section)
+
+ return value
+
+ @classmethod
+ def get_all_values(cls):
+ values = []
+ for section in cls._sections:
+ try:
+ values.extend(cls._translator_config.items(section=section))
+ except configparser.NoOptionError:
+ raise exception.ConfSectionNotDefined(section=section)
+
+ return values
diff --git a/tosca2heat/heat-translator/translator/conf/translator.conf b/tosca2heat/heat-translator/translator/conf/translator.conf
new file mode 100644
index 0000000..6ebf292
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/conf/translator.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+
+# Relative path location for custom types
+custom_types_location=translator/custom/hot \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/custom/__init__.py b/tosca2heat/heat-translator/translator/custom/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/custom/__init__.py
diff --git a/tosca2heat/heat-translator/translator/custom/hot/__init__.py b/tosca2heat/heat-translator/translator/custom/hot/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/custom/hot/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/__init__.py b/tosca2heat/heat-translator/translator/hot/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/__init__.py b/tosca2heat/heat-translator/translator/hot/syntax/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/syntax/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
new file mode 100644
index 0000000..ad77fb3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
@@ -0,0 +1,25 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class HotOutput(object):
+ '''Attributes for HOT output section.'''
+
+ def __init__(self, name, value, description=None):
+ self.name = name
+ self.value = value
+ self.description = description
+
+ def get_dict_output(self):
+ return {self.name: {'value': self.value,
+ 'description': self.description}}
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_parameter.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_parameter.py
new file mode 100644
index 0000000..1ecb2ce
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_parameter.py
@@ -0,0 +1,52 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 logging
+from toscaparser.utils.gettextutils import _
+
+KEYS = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, HIDDEN, LABEL) = \
+ ('type', 'description', 'default', 'constraints', 'hidden', 'label')
+
+log = logging.getLogger('heat-translator')
+
+
+class HotParameter(object):
+ '''Attributes for HOT parameter section.'''
+
+ def __init__(self, name, type, label=None, description=None, default=None,
+ hidden=None, constraints=None):
+ self.name = name
+ self.type = type
+ self.label = label
+ self.description = description
+ self.default = default
+ self.hidden = hidden
+ self.constraints = constraints
+ log.info(_('Initialized the input parameters.'))
+
+ def get_dict_output(self):
+ param_sections = OrderedDict()
+ param_sections[TYPE] = self.type
+ if self.label:
+ param_sections[LABEL] = self.label
+ if self.description:
+ param_sections[DESCRIPTION] = self.description
+ if self.default:
+ param_sections[DEFAULT] = self.default
+ if self.hidden:
+ param_sections[HIDDEN] = self.hidden
+ if self.constraints:
+ param_sections[CONSTRAINTS] = self.constraints
+
+ return {self.name: param_sections}
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
new file mode 100644
index 0000000..d7d0100
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
@@ -0,0 +1,362 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 logging
+import six
+
+from toscaparser.elements.interfaces import InterfacesDef
+from toscaparser.functions import GetInput
+from toscaparser.nodetemplate import NodeTemplate
+from toscaparser.utils.gettextutils import _
+
+
+SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
+ DELETION_POLICY) = \
+ ('type', 'properties', 'metadata',
+ 'depends_on', 'update_policy', 'deletion_policy')
+log = logging.getLogger('heat-translator')
+
+
+class HotResource(object):
+ '''Base class for TOSCA node type translation to Heat resource type.'''
+
+ def __init__(self, nodetemplate, name=None, type=None, properties=None,
+ metadata=None, depends_on=None,
+ update_policy=None, deletion_policy=None):
+ log.debug(_('Translating TOSCA node type to HOT resource type.'))
+ self.nodetemplate = nodetemplate
+ if name:
+ self.name = name
+ else:
+ self.name = nodetemplate.name
+ self.type = type
+ self.properties = properties or {}
+ # special case for HOT softwareconfig
+ if type == 'OS::Heat::SoftwareConfig':
+ self.properties['group'] = 'script'
+ self.metadata = metadata
+
+ # The difference between depends_on and depends_on_nodes is
+ # that depends_on defines dependency in the context of the
+ # HOT template and it is used during the template output.
+ # Depends_on_nodes defines the direct dependency between the
+ # tosca nodes and is not used during the output of the
+ # HOT template but for internal processing only. When a tosca
+ # node depends on another node it will be always added to
+ # depends_on_nodes but not always to depends_on. For example
+ # if the source of dependency is a server, the dependency will
+ # be added as properties.get_resource and not depends_on
+ if depends_on:
+ self.depends_on = depends_on
+ self.depends_on_nodes = depends_on
+ else:
+ self.depends_on = []
+ self.depends_on_nodes = []
+ self.update_policy = update_policy
+ self.deletion_policy = deletion_policy
+ self.group_dependencies = {}
+ # if hide_resource is set to true, then this resource will not be
+ # generated in the output yaml.
+ self.hide_resource = False
+
+ def handle_properties(self):
+ # the property can hold a value or the intrinsic function get_input
+ # for value, copy it
+ # for get_input, convert to get_param
+ for prop in self.nodetemplate.get_properties_objects():
+ pass
+
+ def handle_life_cycle(self):
+ hot_resources = []
+ deploy_lookup = {}
+ # TODO(anyone): sequence for life cycle needs to cover different
+ # scenarios and cannot be fixed or hard coded here
+ operations_deploy_sequence = ['create', 'configure', 'start']
+
+ operations = HotResource._get_all_operations(self.nodetemplate)
+
+ # create HotResource for each operation used for deployment:
+ # create, start, configure
+ # ignore the other operations
+ # observe the order: create, start, configure
+ # use the current HotResource for the first operation in this order
+
+ # hold the original name since it will be changed during
+ # the transformation
+ node_name = self.name
+ reserve_current = 'NONE'
+
+ for operation in operations_deploy_sequence:
+ if operation in operations.keys():
+ reserve_current = operation
+ break
+
+ # create the set of SoftwareDeployment and SoftwareConfig for
+ # the interface operations
+ hosting_server = None
+ if self.nodetemplate.requirements is not None:
+ hosting_server = self._get_hosting_server()
+ 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'
+ 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:
+ deploy_resource = self
+ self.name = deploy_name
+ self.type = 'OS::Heat::SoftwareDeployment'
+ self.properties = {'config': {'get_resource': config_name},
+ 'server': {'get_resource':
+ hosting_on_server}}
+ deploy_lookup[operation.name] = self
+ else:
+ sd_config = {'config': {'get_resource': config_name},
+ 'server': {'get_resource':
+ hosting_on_server}}
+ deploy_resource = \
+ HotResource(self.nodetemplate,
+ deploy_name,
+ 'OS::Heat::SoftwareDeployment',
+ sd_config)
+ hot_resources.append(deploy_resource)
+ deploy_lookup[operation.name] = deploy_resource
+ lifecycle_inputs = self._get_lifecycle_inputs(operation)
+ if lifecycle_inputs:
+ deploy_resource.properties['input_values'] = \
+ lifecycle_inputs
+
+ # 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 = {}
+ for op, hot in deploy_lookup.items():
+ # position to determine potential preceding nodes
+ op_index = operations_deploy_sequence.index(op)
+ for preceding_op in \
+ reversed(operations_deploy_sequence[:op_index]):
+ preceding_hot = deploy_lookup.get(preceding_op)
+ if preceding_hot:
+ hot.depends_on.append(preceding_hot)
+ hot.depends_on_nodes.append(preceding_hot)
+ group[preceding_hot] = hot
+ break
+
+ # 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
+
+ def handle_connectsto(self, tosca_source, tosca_target, hot_source,
+ hot_target, config_location, operation):
+ # The ConnectsTo relationship causes a configuration operation in
+ # the target.
+ # This hot resource is the software config portion in the HOT template
+ # This method adds the matching software deployment with the proper
+ # target server and dependency
+ if config_location == 'target':
+ hosting_server = hot_target._get_hosting_server()
+ hot_depends = hot_target
+ elif config_location == 'source':
+ hosting_server = self._get_hosting_server()
+ hot_depends = hot_source
+ deploy_name = tosca_source.name + '_' + tosca_target.name + \
+ '_connect_deploy'
+ sd_config = {'config': {'get_resource': self.name},
+ 'server': {'get_resource': hosting_server.name}}
+ deploy_resource = \
+ HotResource(self.nodetemplate,
+ deploy_name,
+ 'OS::Heat::SoftwareDeployment',
+ sd_config,
+ depends_on=[hot_depends])
+ connect_inputs = self._get_connect_inputs(config_location, operation)
+ if connect_inputs:
+ deploy_resource.properties['input_values'] = connect_inputs
+
+ return deploy_resource
+
+ def handle_expansion(self):
+ pass
+
+ def handle_hosting(self):
+ # 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':
+ # 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']:
+ raise Exception(_("Internal Error: expecting host "
+ "in software deployment"))
+ elif isinstance(host_server['get_resource'], NodeTemplate):
+ self.properties['server']['get_resource'] = \
+ host_server['get_resource'].name
+
+ def top_of_chain(self):
+ dependent = self.group_dependencies.get(self)
+ if dependent is None:
+ return self
+ else:
+ return dependent.top_of_chain()
+
+ def get_dict_output(self):
+ resource_sections = OrderedDict()
+ resource_sections[TYPE] = self.type
+ if self.properties:
+ resource_sections[PROPERTIES] = self.properties
+ if self.metadata:
+ resource_sections[MEDADATA] = self.metadata
+ if self.depends_on:
+ resource_sections[DEPENDS_ON] = []
+ for depend in self.depends_on:
+ resource_sections[DEPENDS_ON].append(depend.name)
+ if self.update_policy:
+ resource_sections[UPDATE_POLICY] = self.update_policy
+ if self.deletion_policy:
+ resource_sections[DELETION_POLICY] = self.deletion_policy
+
+ return {self.name: resource_sections}
+
+ def _get_lifecycle_inputs(self, operation):
+ # check if this lifecycle operation has input values specified
+ # extract and convert to HOT format
+ if isinstance(operation.value, six.string_types):
+ # the operation has a static string
+ return {}
+ else:
+ # the operation is a dict {'implemenation': xxx, 'input': yyy}
+ inputs = operation.value.get('inputs')
+ deploy_inputs = {}
+ if inputs:
+ for name, value in six.iteritems(inputs):
+ deploy_inputs[name] = value
+ return deploy_inputs
+
+ def _get_connect_inputs(self, config_location, operation):
+ if config_location == 'target':
+ inputs = operation.get('pre_configure_target').get('inputs')
+ elif config_location == 'source':
+ inputs = operation.get('pre_configure_source').get('inputs')
+ deploy_inputs = {}
+ if inputs:
+ for name, value in six.iteritems(inputs):
+ 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
+ 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 check_node in this_node_template.related_nodes:
+ # check if the capability is Container
+ if isinstance(assignment, dict):
+ node_name = assignment.get('node')
+ else:
+ node_name = assignment
+ 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:
+ return self._get_hosting_server(check_node)
+ 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':
+ return True
+ else:
+ return False
+
+ def get_hot_attribute(self, attribute, args):
+ # this is a place holder and should be implemented by the subclass
+ # if translation is needed for the particular attribute
+ raise Exception(_("No translation in TOSCA type {0} for attribute "
+ "{1}").format(self.nodetemplate.type, attribute))
+
+ def get_tosca_props(self):
+ tosca_props = {}
+ for prop in self.nodetemplate.get_properties_objects():
+ if isinstance(prop.value, GetInput):
+ tosca_props[prop.name] = {'get_param': prop.value.input_name}
+ else:
+ tosca_props[prop.name] = prop.value
+ return tosca_props
+
+ @staticmethod
+ def _get_all_operations(node):
+ operations = {}
+ for operation in node.interfaces:
+ operations[operation.name] = operation
+
+ node_type = node.type_definition
+ if isinstance(node_type, str) or \
+ node_type.type == "tosca.policies.Placement":
+ return operations
+
+ while True:
+ type_operations = HotResource._get_interface_operations_from_type(
+ node_type, node, 'Standard')
+ type_operations.update(operations)
+ operations = type_operations
+
+ if node_type.parent_type is not None:
+ node_type = node_type.parent_type
+ else:
+ return operations
+
+ @staticmethod
+ def _get_interface_operations_from_type(node_type, node, lifecycle_name):
+ operations = {}
+ if isinstance(node_type, str) or \
+ node_type.type == "tosca.policies.Placement":
+ return operations
+ if node_type.interfaces and lifecycle_name in node_type.interfaces:
+ for name, elems in node_type.interfaces[lifecycle_name].items():
+ # ignore empty operations (only type)
+ # ignore global interface inputs,
+ # concrete inputs are on the operations themselves
+ if name != 'type' and name != 'inputs':
+ operations[name] = InterfacesDef(node_type,
+ lifecycle_name,
+ node, name, elems)
+ return operations
+
+ @staticmethod
+ def get_base_type(node_type):
+ if node_type.parent_type is not None:
+ if node_type.parent_type.type.endswith('.Root'):
+ return node_type
+ else:
+ return HotResource.get_base_type(node_type.parent_type)
+ else:
+ return node_type
diff --git a/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py b/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
new file mode 100644
index 0000000..4263c4d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
@@ -0,0 +1,83 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 logging
+import textwrap
+from toscaparser.utils.gettextutils import _
+import yaml
+
+log = logging.getLogger('heat-translator')
+
+
+class HotTemplate(object):
+ '''Container for full Heat Orchestration template.'''
+
+ SECTIONS = (VERSION, DESCRIPTION, PARAMETER_GROUPS, PARAMETERS,
+ RESOURCES, OUTPUTS, MAPPINGS) = \
+ ('heat_template_version', 'description', 'parameter_groups',
+ 'parameters', 'resources', 'outputs', '__undefined__')
+
+ VERSIONS = (LATEST,) = ('2013-05-23',)
+
+ def __init__(self):
+ self.resources = []
+ self.outputs = []
+ self.parameters = []
+ self.description = ""
+
+ 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 output_to_yaml(self):
+ log.debug(_('Converting translated output to yaml format.'))
+ dict_output = OrderedDict()
+ # Version
+ version_string = self.VERSION + ": " + self.LATEST + "\n\n"
+
+ # Description
+ desc_str = ""
+ if self.description:
+ # Wrap the text to a new line if the line exceeds 80 characters.
+ wrapped_txt = "\n ".join(textwrap.wrap(self.description, 80))
+ desc_str = self.DESCRIPTION + ": >\n " + wrapped_txt + "\n\n"
+
+ # Parameters
+ all_params = OrderedDict()
+ for parameter in self.parameters:
+ all_params.update(parameter.get_dict_output())
+ dict_output.update({self.PARAMETERS: all_params})
+
+ # Resources
+ all_resources = OrderedDict()
+ for resource in self.resources:
+ if not resource.hide_resource:
+ all_resources.update(resource.get_dict_output())
+ dict_output.update({self.RESOURCES: all_resources})
+
+ # Outputs
+ all_outputs = OrderedDict()
+ for output in self.outputs:
+ all_outputs.update(output.get_dict_output())
+ dict_output.update({self.OUTPUTS: all_outputs})
+
+ yaml.add_representer(OrderedDict, 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('\'', '')
+ return version_string + desc_str + yaml_string
diff --git a/tosca2heat/heat-translator/translator/hot/tests/__init__.py b/tosca2heat/heat-translator/translator/hot/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tests/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/tests/test_hot_parameter.py b/tosca2heat/heat-translator/translator/hot/tests/test_hot_parameter.py
new file mode 100644
index 0000000..8d3f535
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tests/test_hot_parameter.py
@@ -0,0 +1,44 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+
+from toscaparser.tests.base import TestCase
+from translator.hot.syntax.hot_parameter import CONSTRAINTS
+from translator.hot.syntax.hot_parameter import DEFAULT
+from translator.hot.syntax.hot_parameter import DESCRIPTION
+from translator.hot.syntax.hot_parameter import HIDDEN
+from translator.hot.syntax.hot_parameter import HotParameter
+from translator.hot.syntax.hot_parameter import LABEL
+from translator.hot.syntax.hot_parameter import TYPE
+
+TEST_CONSTRAINTS = {'equal': 'allowed_values', 'greater_than': 'range'}
+
+
+class HotParameterTest(TestCase):
+
+ # This test ensures the variables set during the creation of a HotParameter
+ # object are returned in an OrderedDict when calling get_dict_output().
+ def test_dict_output(self):
+ name = 'HotParameterTest'
+ hot_parameter = HotParameter(name, 'Type',
+ label='Label',
+ description='Description',
+ default='Default',
+ hidden=True,
+ constraints=TEST_CONSTRAINTS)
+ expected_dict = OrderedDict([(TYPE, 'Type'), (LABEL, 'Label'),
+ (DESCRIPTION, 'Description'),
+ (DEFAULT, 'Default'), (HIDDEN, True),
+ (CONSTRAINTS, TEST_CONSTRAINTS)])
+
+ self.assertEqual(hot_parameter.get_dict_output()[name], expected_dict)
diff --git a/tosca2heat/heat-translator/translator/hot/tests/test_translate_inputs.py b/tosca2heat/heat-translator/translator/hot/tests/test_translate_inputs.py
new file mode 100644
index 0000000..2b302ab
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tests/test_translate_inputs.py
@@ -0,0 +1,351 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+from toscaparser.parameters import Input
+from toscaparser.tests.base import TestCase
+from toscaparser.utils.gettextutils import _
+import toscaparser.utils.yamlparser
+from translator.common.utils import CompareUtils
+from translator.hot.translate_inputs import TranslateInputs
+
+
+class ToscaTemplateInputValidationTest(TestCase):
+
+ def _translate_input_test(self, tpl_snippet, input_params,
+ expectedmessage=None,
+ expected_hot_params=None):
+ inputs_dict = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['inputs'])
+ inputs = []
+ for name, attrs in inputs_dict.items():
+ input = Input(name, attrs)
+ inputs.append(input)
+
+ translateinput = TranslateInputs(inputs, input_params)
+ try:
+ resulted_hot_params = translateinput.translate()
+ if expected_hot_params:
+ self._compare_hot_params(resulted_hot_params,
+ expected_hot_params)
+ except Exception as err:
+ self.assertEqual(expectedmessage, err.__str__())
+
+ def _compare_hot_params(self, resulted_hot_params,
+ expected_hot_params):
+ for expected_param in expected_hot_params:
+ for resulted_param_obj in resulted_hot_params:
+ resulted_param = resulted_param_obj.get_dict_output()
+ result = CompareUtils.compare_dicts(expected_param,
+ resulted_param)
+ if not result:
+ raise Exception(_("hot input and resulted input "
+ "params are not equal."))
+
+ def test_invalid_input_type(self):
+ tpl_snippet = '''
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ '''
+
+ input_params = {'cpus': '0.3'}
+ expectedmessage = _('"0.3" is not an integer.')
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage)
+
+ def test_invalid_input_constraints_for_equal(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - equal: 1
+ '''
+
+ input_params = {'num_cpus': '0'}
+ expectedmessage = _('The value "0" of property "num_cpus" is not '
+ 'equal to "1".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_greater_or_equal(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - greater_or_equal: 1
+ '''
+
+ input_params = {'num_cpus': '0'}
+ expectedmessage = _('The value "0" of property "num_cpus" must be '
+ 'greater than or equal to "1".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_greater_than(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - greater_than: 1
+ '''
+
+ input_params = {'num_cpus': '0'}
+ expectedmessage = _('The value "0" of property "num_cpus" must be '
+ 'greater than "1".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_less_than(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - less_than: 8
+ '''
+
+ input_params = {'num_cpus': '8'}
+ expectedmessage = _('The value "8" of property "num_cpus" must be '
+ 'less than "8".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_less_or_equal(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - less_or_equal: 8
+ '''
+
+ input_params = {'num_cpus': '9'}
+ expectedmessage = _('The value "9" of property "num_cpus" must be '
+ 'less than or equal to "8".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_valid_values(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ '''
+
+ input_params = {'num_cpus': '3'}
+ expectedmessage = _('The value "3" of property "num_cpus" is not '
+ 'valid. Expected a value from "[1, 2, 4, 8]".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_in_range(self):
+ tpl_snippet = '''
+ inputs:
+ num_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - in_range: [ 1, 8 ]
+ '''
+
+ input_params = {'num_cpus': '10'}
+ expectedmessage = _('The value "10" of property "num_cpus" is out of '
+ 'range "(min:1, max:8)".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_min_length(self):
+ tpl_snippet = '''
+ inputs:
+ user_name:
+ type: string
+ description: Name of the user.
+ constraints:
+ - min_length: 8
+ '''
+
+ input_params = {'user_name': 'abcd'}
+ expectedmessage = _('Length of value "abcd" of property "user_name" '
+ 'must be at least "8".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_max_length(self):
+ tpl_snippet = '''
+ inputs:
+ user_name:
+ type: string
+ description: Name of the user.
+ constraints:
+ - max_length: 6
+ '''
+
+ input_params = {'user_name': 'abcdefg'}
+ expectedmessage = _('Length of value "abcdefg" of property '
+ '"user_name" must be no greater than "6".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_invalid_input_constraints_for_pattern(self):
+ tpl_snippet = '''
+ inputs:
+ user_name:
+ type: string
+ description: Name of the user.
+ constraints:
+ - pattern: '^\w+$'
+ '''
+
+ input_params = {'user_name': '1-abc'}
+ expectedmessage = _('The value "1-abc" of property "user_name" does '
+ 'not match pattern "^\\w+$".')
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage)
+
+ def test_valid_input_storage_size(self):
+ tpl_snippet = '''
+ inputs:
+ storage_size:
+ type: scalar-unit.size
+ description: size of the storage volume.
+ '''
+
+ expectedmessage = _('both equal.')
+ input_params = {'storage_size': '2 GB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 2)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ """ TOSCA 2000 MB => 2 GB HOT conversion"""
+ input_params = {'storage_size': '2000 MB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 2)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ """ TOSCA 2048 MB => 2 GB HOT conversion"""
+ input_params = {'storage_size': '2048 MB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 2)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ """ TOSCA 2 MB => 1 GB HOT conversion"""
+ input_params = {'storage_size': '2 MB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 1)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ """ TOSCA 1024 MB => 1 GB HOT conversion"""
+ input_params = {'storage_size': '1024 MB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 1)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ """ TOSCA 1024 MiB => 1 GB HOT conversion"""
+ input_params = {'storage_size': '1024 MiB'}
+ expected_hot_params = [{'storage_size':
+ OrderedDict([('type', 'number'),
+ ('description',
+ 'size of the storage volume.'),
+ ('default', 1)])}]
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage, expected_hot_params)
+
+ def test_invalid_input_storage_size(self):
+ tpl_snippet = '''
+ inputs:
+ storage_size:
+ type: scalar-unit.size
+ description: size of the storage volume.
+ '''
+
+ input_params = {'storage_size': '0 MB'}
+ expectedmsg = _("Unit value should be > 0.")
+ self._translate_input_test(tpl_snippet, input_params, expectedmsg)
+
+ input_params = {'storage_size': '-2 MB'}
+ expectedmsg = _('"-2 MB" is not a valid scalar-unit.')
+ self._translate_input_test(tpl_snippet, input_params, expectedmsg)
+
+ def test_invalid_input_type_version(self):
+ tpl_snippet = '''
+ inputs:
+ version:
+ type: version
+ '''
+
+ input_params = {'version': '0.a'}
+ expectedmessage = _('Value of TOSCA version property '
+ '"0.a" is invalid.')
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage)
+
+ input_params = {'version': '0.0.0.abc'}
+ expectedmessage = _('Value of TOSCA version property '
+ '"0.0.0.abc" is invalid.')
+ self._translate_input_test(tpl_snippet, input_params,
+ expectedmessage)
+
+ def test_valid_input_type_version(self):
+ tpl_snippet = '''
+ inputs:
+ version:
+ type: version
+ default: 12
+ '''
+
+ expectedmessage = _('both equal.')
+ input_params = {'version': '18'}
+ expected_hot_params = [{'version':
+ OrderedDict([('type', 'string'),
+ ('default', '18.0')])}]
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage,
+ expected_hot_params)
+
+ input_params = {'version': '18.0'}
+ expected_hot_params = [{'version':
+ OrderedDict([('type', 'string'),
+ ('default', '18.0')])}]
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage,
+ expected_hot_params)
+
+ input_params = {'version': '18.0.1'}
+ expected_hot_params = [{'version':
+ OrderedDict([('type', 'string'),
+ ('default', '18.0.1')])}]
+ self._translate_input_test(tpl_snippet, input_params, expectedmessage,
+ expected_hot_params)
diff --git a/tosca2heat/heat-translator/translator/hot/tests/test_translate_outputs.py b/tosca2heat/heat-translator/translator/hot/tests/test_translate_outputs.py
new file mode 100644
index 0000000..955150e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tests/test_translate_outputs.py
@@ -0,0 +1,50 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+from toscaparser.tests.base import TestCase
+from toscaparser.tosca_template import ToscaTemplate
+import toscaparser.utils.yamlparser
+from translator.hot.tosca_translator import TOSCATranslator
+
+
+class ToscaTemplateOutputTest(TestCase):
+
+ def test_translate_output(self):
+ tosca_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "../../tests/data/"
+ "tosca_nodejs_mongodb_two_instances.yaml")
+ tosca = ToscaTemplate(tosca_tpl)
+ translate = TOSCATranslator(tosca, [])
+ hot_translation = translate.translate()
+
+ expected_output = {'nodejs_url':
+ {'description': 'URL for the nodejs '
+ 'server, http://<IP>:3000',
+ 'value':
+ {'get_attr':
+ ['app_server', 'networks', 'private', 0]}},
+ 'mongodb_url':
+ {'description': 'URL for the mongodb server.',
+ 'value':
+ {'get_attr':
+ ['mongo_server', 'networks', 'private', 0]}}}
+
+ hot_translation_dict = \
+ toscaparser.utils.yamlparser.simple_parse(hot_translation)
+
+ outputs = hot_translation_dict.get('outputs')
+ for resource_name in outputs:
+ translated_value = outputs.get(resource_name)
+ expected_value = expected_output.get(resource_name)
+ self.assertEqual(translated_value, expected_value)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/__init__.py b/tosca2heat/heat-translator/translator/hot/tosca/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/__init__.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/__init__.py
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_blockstorage.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_blockstorage.py
new file mode 100644
index 0000000..d4fffe1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_blockstorage.py
@@ -0,0 +1,84 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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.common.exception import InvalidPropertyValueError
+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_block_storage import ToscaBlockStorage
+
+
+class ToscaBlockStoreTest(TestCase):
+
+ def _tosca_blockstore_test(self, tpl_snippet, expectedprops):
+ nodetemplates = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['node_templates'])
+ name = list(nodetemplates.keys())[0]
+ try:
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ tosca_block_store = ToscaBlockStorage(nodetemplate)
+ tosca_block_store.handle_properties()
+ if not self._compare_properties(tosca_block_store.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
+ raise
+
+ def _compare_properties(self, hotprops, expectedprops):
+ return all(item in hotprops.items() for item in expectedprops.items())
+
+ def test_node_blockstorage_with_properties(self):
+ tpl_snippet = '''
+ node_templates:
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: 1024 MiB
+ snapshot_id: abc
+ '''
+ expectedprops = {'snapshot_id': 'abc',
+ 'size': 1}
+ self._tosca_blockstore_test(
+ tpl_snippet,
+ expectedprops)
+
+ tpl_snippet = '''
+ node_templates:
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: 124 MB
+ snapshot_id: abc
+ '''
+ expectedprops = {'snapshot_id': 'abc',
+ 'size': 1}
+ self._tosca_blockstore_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_blockstorage_with_invalid_size_property(self):
+ tpl_snippet = '''
+ node_templates:
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: 0 MB
+ snapshot_id: abc
+ '''
+ expectedprops = {}
+ self.assertRaises(InvalidPropertyValueError,
+ lambda: self._tosca_blockstore_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
new file mode 100644
index 0000000..e0cdbb6
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
@@ -0,0 +1,286 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import 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
+
+
+class ToscaComputeTest(TestCase):
+
+ def _tosca_compute_test(self, tpl_snippet, expectedprops):
+ 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
+
+ def _compare_properties(self, hotprops, expectedprops):
+ return all(item in hotprops.items() for item in expectedprops.items())
+
+ def test_node_compute_with_host_and_os_capabilities(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 4
+ mem_size: 4 GB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ '''
+ expectedprops = {'flavor': 'm1.large',
+ 'image': 'fedora-amd64-heat-config'}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_without_os_capabilities(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 4
+ mem_size: 4 GB
+ #left intentionally
+ '''
+ expectedprops = {'flavor': 'm1.large',
+ 'image': None}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_without_host_capabilities(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ '''
+ expectedprops = {'flavor': None,
+ 'image': 'fedora-amd64-heat-config'}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_without_properties_and_os_capabilities(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ properties:
+ #left intentionally
+ capabilities:
+ #left intentionally
+ '''
+ expectedprops = {'flavor': None,
+ 'image': None}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_with_only_type(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ '''
+ expectedprops = {'flavor': None,
+ 'image': None}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_host_capabilities_without_properties(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ #left intentionally
+ '''
+ expectedprops = {'flavor': 'm1.nano'}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_host_capabilities_without_disk_size(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 4
+ mem_size: 4 GB
+ '''
+ expectedprops = {'flavor': 'm1.large'}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_host_capabilities_without_mem_size(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 4
+ disk_size: 10 GB
+ '''
+ expectedprops = {'flavor': 'm1.large'}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_compute_host_capabilities_without_mem_size_disk_size(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 4
+ '''
+ expectedprops = {'flavor': 'm1.large'}
+ 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):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 1
+ 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'}
+ 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):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 1
+ 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/']
+ mock_ks_response = mock.MagicMock()
+ mock_ks_content = {}
+ mock_ks_response.content = json.dumps(mock_ks_content)
+ expectedprops = {'flavor': 'm1.small',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'image': None}
+ self._tosca_compute_test(
+ tpl_snippet,
+ expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_objectstore.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_objectstore.py
new file mode 100644
index 0000000..4c42794
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_objectstore.py
@@ -0,0 +1,71 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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.tests.base import TestCase
+from toscaparser.utils.gettextutils import _
+import toscaparser.utils.yamlparser
+from translator.hot.tosca.tosca_object_storage import ToscaObjectStorage
+
+
+class ToscaObjectStoreTest(TestCase):
+
+ def _tosca_objectstore_test(self, tpl_snippet, expectedprops):
+ nodetemplates = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['node_templates'])
+ name = list(nodetemplates.keys())[0]
+ try:
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ tosca_object_store = ToscaObjectStorage(nodetemplate)
+ tosca_object_store.handle_properties()
+ if not self._compare_properties(tosca_object_store.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
+ raise
+
+ def _compare_properties(self, hotprops, expectedprops):
+ return all(item in hotprops.items() for item in expectedprops.items())
+
+ def test_node_objectstorage_with_properties(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.ObjectStorage
+ properties:
+ name: test
+ size: 1024 KB
+ maxsize: 1 MB
+ '''
+ expectedprops = {'name': 'test',
+ 'X-Container-Meta': {'Quota-Bytes': 1000000}}
+ self._tosca_objectstore_test(
+ tpl_snippet,
+ expectedprops)
+
+ def test_node_objectstorage_with_few_properties(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.ObjectStorage
+ properties:
+ name: test
+ size: 1024 B
+ '''
+ expectedprops = {'name': 'test',
+ 'X-Container-Meta': {'Quota-Bytes': 1024}}
+ self._tosca_objectstore_test(
+ tpl_snippet,
+ expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_policies.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_policies.py
new file mode 100644
index 0000000..24368ab
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_policies.py
@@ -0,0 +1,80 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 import ToscaPolicies
+
+
+class ToscaPoicyTest(TestCase):
+
+ def _tosca_policy_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"]
+ try:
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ toscacompute = ToscaCompute(nodetemplate)
+ toscacompute.handle_properties()
+
+ policy = Policy(policy_name, tpl, targets,
+ "node_templates")
+ toscapolicy = ToscaPolicies(policy)
+ nodetemplate = [toscacompute]
+ toscapolicy.handle_properties(nodetemplate)
+
+ self.assertEqual(toscacompute.properties, expectedprops)
+ except Exception:
+ raise
+
+ def test_compute_with_policies(self):
+ tpl_snippet = '''
+ node_templates:
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 4
+ mem_size: 4 GB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ policies:
+ - my_compute_placement_policy:
+ type: tosca.policies.Placement
+ description: Apply my placement policy to my application servers
+ targets: [ server ]
+ '''
+ expectedprops = {'flavor': 'm1.large',
+ 'image': 'fedora-amd64-heat-config',
+ 'scheduler_hints': {
+ 'group': {
+ 'get_resource':
+ 'my_compute_placement_policy'}},
+ 'user_data_format': 'SOFTWARE_CONFIG'}
+ self._tosca_policy_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
new file mode 100644
index 0000000..d4b2f44
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
@@ -0,0 +1,71 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+from toscaparser.common.exception import InvalidPropertyValueError
+from toscaparser.elements.scalarunit import ScalarUnit_Size
+from toscaparser.functions import GetInput
+from toscaparser.utils.gettextutils import _
+from translator.hot.syntax.hot_resource import HotResource
+
+log = logging.getLogger('heat-translator')
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaBlockStorage'
+
+
+class ToscaBlockStorage(HotResource):
+ '''Translate TOSCA node type tosca.nodes.BlockStorage.'''
+
+ toscatype = 'tosca.nodes.BlockStorage'
+
+ def __init__(self, nodetemplate):
+ super(ToscaBlockStorage, self).__init__(nodetemplate,
+ type='OS::Cinder::Volume')
+ pass
+
+ def handle_properties(self):
+ tosca_props = {}
+ for prop in self.nodetemplate.get_properties_objects():
+ if isinstance(prop.value, GetInput):
+ tosca_props[prop.name] = {'get_param': prop.value.input_name}
+ else:
+ if prop.name == "size":
+ size_value = (ScalarUnit_Size(prop.value).
+ get_num_from_scalar_unit('GiB'))
+ if size_value == 0:
+ # OpenStack Heat expects size in GB
+ msg = _('Cinder Volume Size unit should be in GB.')
+ log.error(msg)
+ raise InvalidPropertyValueError(
+ what=msg)
+ elif int(size_value) < size_value:
+ size_value = int(size_value) + 1
+ log.warning(_("Cinder unit value should be in "
+ "multiples of GBs. so corrected "
+ " %(prop_val)s to %(size_value)s GB.")
+ % {'prop_val': prop.value,
+ 'size_value': size_value})
+ tosca_props[prop.name] = int(size_value)
+ else:
+ tosca_props[prop.name] = prop.value
+ self.properties = tosca_props
+
+ def get_hot_attribute(self, attribute, args):
+ attr = {}
+ # Convert from a TOSCA attribute for a nodetemplate to a HOT
+ # 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]
+ 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
new file mode 100644
index 0000000..715d5b3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
@@ -0,0 +1,48 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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.functions import GetInput
+from translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaBlockStorageAttachment'
+
+
+class ToscaBlockStorageAttachment(HotResource):
+ '''Translate TOSCA relationship AttachesTo for Compute and BlockStorage.'''
+
+ toscatype = 'tosca.nodes.BlockStorageAttachment'
+
+ def __init__(self, template, nodetemplates, instance_uuid, volume_id):
+ super(ToscaBlockStorageAttachment,
+ self).__init__(template, type='OS::Cinder::VolumeAttachment')
+ self.nodetemplates = nodetemplates
+ self.instance_uuid = {'get_resource': instance_uuid}
+ self.volume_id = {'get_resource': volume_id}
+
+ def handle_properties(self):
+ tosca_props = {}
+ for prop in self.nodetemplate.get_properties_objects():
+ if isinstance(prop.value, GetInput):
+ tosca_props[prop.name] = {'get_param': prop.value.input_name}
+ else:
+ tosca_props[prop.name] = prop.value
+ self.properties = tosca_props
+ # instance_uuid and volume_id for Cinder volume attachment
+ self.properties['instance_uuid'] = self.instance_uuid
+ self.properties['volume_id'] = self.volume_id
+ if 'location' in self.properties:
+ self.properties['mountpoint'] = self.properties.pop('location')
+
+ def handle_life_cycle(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
new file mode 100644
index 0000000..e2ac130
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
@@ -0,0 +1,280 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import logging
+import requests
+
+from toscaparser.utils.gettextutils import _
+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.'''
+
+ COMPUTE_HOST_PROP = (DISK_SIZE, MEM_SIZE, NUM_CPUS) = \
+ ('disk_size', 'mem_size', 'num_cpus')
+
+ COMPUTE_OS_PROP = (ARCHITECTURE, DISTRIBUTION, TYPE, VERSION) = \
+ ('architecture', 'distribution', 'type', 'version')
+ toscatype = 'tosca.nodes.Compute'
+
+ def __init__(self, nodetemplate):
+ super(ToscaCompute, self).__init__(nodetemplate,
+ type='OS::Nova::Server')
+ # List with associated hot port resources with this server
+ self.assoc_port_resources = []
+ pass
+
+ def handle_properties(self):
+ self.properties = self.translate_compute_flavor_and_image(
+ self.nodetemplate.get_capability('host'),
+ self.nodetemplate.get_capability('os'))
+ self.properties['user_data_format'] = 'SOFTWARE_CONFIG'
+ tosca_props = self.get_tosca_props()
+ for key, value in tosca_props.items():
+ self.properties[key] = value
+
+ # To be reorganized later based on new development in Glance and Graffiti
+ def translate_compute_flavor_and_image(self,
+ host_capability,
+ os_capability):
+ hot_properties = {}
+ host_cap_props = {}
+ os_cap_props = {}
+ image = None
+ flavor = None
+ if host_capability:
+ for prop in host_capability.get_properties_objects():
+ host_cap_props[prop.name] = prop.value
+ flavor = self._best_flavor(host_cap_props)
+ if os_capability:
+ for prop in os_capability.get_properties_objects():
+ os_cap_props[prop.name] = prop.value
+ image = self._best_image(os_cap_props)
+ hot_properties['flavor'] = flavor
+ hot_properties['image'] = image
+ 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 _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
+
+ # start with all flavors
+ match_all = flavors.keys()
+
+ # TODO(anyone): Handle the case where the value contains something like
+ # get_input instead of a value.
+ # flavors that fit the CPU count
+ cpu = properties.get(self.NUM_CPUS)
+ if cpu is None:
+ self._log_compute_msg(self.NUM_CPUS, 'flavor')
+ match_cpu = self._match_flavors(match_all, flavors, self.NUM_CPUS, cpu)
+
+ # flavors that fit the mem size
+ mem = properties.get(self.MEM_SIZE)
+ if mem:
+ mem = translator.common.utils.MemoryUnit.convert_unit_size_to_num(
+ mem, 'MB')
+ else:
+ self._log_compute_msg(self.MEM_SIZE, 'flavor')
+ match_cpu_mem = self._match_flavors(match_cpu, flavors,
+ self.MEM_SIZE, mem)
+ # flavors that fit the disk size
+ disk = properties.get(self.DISK_SIZE)
+ if disk:
+ disk = translator.common.utils.MemoryUnit.\
+ convert_unit_size_to_num(disk, 'GB')
+ else:
+ self._log_compute_msg(self.DISK_SIZE, 'flavor')
+ match_cpu_mem_disk = self._match_flavors(match_cpu_mem, flavors,
+ self.DISK_SIZE, disk)
+ # if multiple match, pick the flavor with the least memory
+ # the selection can be based on other heuristic, e.g. pick one with the
+ # least total resource
+ if len(match_cpu_mem_disk) > 1:
+ return self._least_flavor(match_cpu_mem_disk, flavors, 'mem_size')
+ elif len(match_cpu_mem_disk) == 1:
+ return match_cpu_mem_disk[0]
+ else:
+ return None
+
+ def _best_image(self, properties):
+ match_all = IMAGES.keys()
+ architecture = properties.get(self.ARCHITECTURE)
+ if architecture is None:
+ self._log_compute_msg(self.ARCHITECTURE, 'image')
+ match_arch = self._match_images(match_all, IMAGES,
+ self.ARCHITECTURE, architecture)
+ type = properties.get(self.TYPE)
+ if type is None:
+ self._log_compute_msg(self.TYPE, 'image')
+ match_type = self._match_images(match_arch, IMAGES, self.TYPE, type)
+ distribution = properties.get(self.DISTRIBUTION)
+ if distribution is None:
+ self._log_compute_msg(self.DISTRIBUTION, 'image')
+ match_distribution = self._match_images(match_type, IMAGES,
+ self.DISTRIBUTION,
+ distribution)
+ version = properties.get(self.VERSION)
+ if version is None:
+ self._log_compute_msg(self.VERSION, 'image')
+ match_version = self._match_images(match_distribution, IMAGES,
+ self.VERSION, version)
+
+ if len(match_version):
+ return list(match_version)[0]
+
+ def _match_flavors(self, this_list, this_dict, attr, size):
+ '''Return from this list all flavors matching the attribute size.'''
+ if not size:
+ return list(this_list)
+ matching_flavors = []
+ for flavor in this_list:
+ if isinstance(size, int):
+ if this_dict[flavor][attr] >= size:
+ matching_flavors.append(flavor)
+ log.debug(_('Returning list of flavors matching the attribute size.'))
+ return matching_flavors
+
+ def _least_flavor(self, this_list, this_dict, attr):
+ '''Return from this list the flavor with the smallest attr.'''
+ least_flavor = this_list[0]
+ for flavor in this_list:
+ if this_dict[flavor][attr] < this_dict[least_flavor][attr]:
+ least_flavor = flavor
+ return least_flavor
+
+ def _match_images(self, this_list, this_dict, attr, prop):
+ if not prop:
+ return this_list
+ matching_images = []
+ for image in this_list:
+ if this_dict[image][attr].lower() == str(prop).lower():
+ matching_images.append(image)
+ return matching_images
+
+ def get_hot_attribute(self, attribute, args):
+ attr = {}
+ # Convert from a TOSCA attribute for a nodetemplate to a HOT
+ # attribute for the matching resource. Unless there is additional
+ # runtime support, this should be a one to one mapping.
+
+ # Note: We treat private and public IP addresses equally, but
+ # this will change in the future when TOSCA starts to support
+ # multiple private/public IP addresses.
+ log.debug(_('Converting TOSCA attribute for a nodetemplate to a HOT \
+ attriute.'))
+ if attribute == 'private_address' or \
+ attribute == 'public_address':
+ attr['get_attr'] = [self.name, 'networks', 'private', 0]
+
+ return attr
+
+ def _log_compute_msg(self, prop, what):
+ msg = _('No value is provided for Compute capability '
+ 'property "%(prop)s". This may set an undesired "%(what)s" '
+ 'in the template.') % {'prop': prop, 'what': what}
+ log.warn(msg)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
new file mode 100644
index 0000000..26c9d4d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
@@ -0,0 +1,30 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaDatabase'
+
+
+class ToscaDatabase(HotResource):
+ '''Translate TOSCA node type tosca.nodes.Database.'''
+
+ toscatype = 'tosca.nodes.Database'
+
+ def __init__(self, nodetemplate):
+ super(ToscaDatabase, self).__init__(nodetemplate)
+ pass
+
+ def handle_properties(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
new file mode 100644
index 0000000..38c31bd
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
@@ -0,0 +1,30 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaDbms'
+
+
+class ToscaDbms(HotResource):
+ '''Translate TOSCA node type tosca.nodes.DBMS.'''
+
+ toscatype = 'tosca.nodes.DBMS'
+
+ def __init__(self, nodetemplate):
+ super(ToscaDbms, self).__init__(nodetemplate)
+ pass
+
+ def handle_properties(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
new file mode 100644
index 0000000..2b80313
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
@@ -0,0 +1,118 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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.common.exception import InvalidPropertyValueError
+from translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaNetwork'
+
+
+class ToscaNetwork(HotResource):
+ '''Translate TOSCA node type tosca.nodes.network.Network.'''
+
+ toscatype = 'tosca.nodes.network.Network'
+ SUBNET_SUFFIX = '_subnet'
+ NETWORK_PROPS = ['network_name', 'network_id', 'segmentation_id']
+ SUBNET_PROPS = ['ip_version', 'cidr', 'start_ip', 'end_ip', 'gateway_ip']
+
+ existing_resource_id = None
+
+ def __init__(self, nodetemplate):
+ super(ToscaNetwork, self).__init__(nodetemplate,
+ type='OS::Neutron::Net')
+ pass
+
+ def handle_properties(self):
+ tosca_props = self.get_tosca_props()
+
+ net_props = {}
+ for key, value in tosca_props.items():
+ if key in self.NETWORK_PROPS:
+ if key == 'network_name':
+ # If CIDR is specified network_name should
+ # be used as the name for the new network.
+ if 'cidr' in tosca_props.keys():
+ net_props['name'] = value
+ # If CIDR is not specified network_name will be used
+ # to lookup existing network. If network_id is specified
+ # together with network_name then network_id should be
+ # used to lookup the network instead
+ elif 'network_id' not in tosca_props.keys():
+ self.hide_resource = True
+ self.existing_resource_id = value
+ break
+ elif key == 'network_id':
+ self.hide_resource = True
+ 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':
+ value, 'provider:network_type':
+ 'vxlan'}
+ self.properties = net_props
+
+ def handle_expansion(self):
+ # If the network resource should not be output (they are hidden),
+ # there is no need to generate subnet resource
+ if self.hide_resource:
+ return
+
+ tosca_props = self.get_tosca_props()
+
+ subnet_props = {}
+
+ ip_pool_start = None
+ ip_pool_end = None
+
+ for key, value in tosca_props.items():
+ if key in self.SUBNET_PROPS:
+ if key == 'start_ip':
+ ip_pool_start = value
+ elif key == 'end_ip':
+ ip_pool_end = value
+ elif key == 'dhcp_enabled':
+ subnet_props['enable_dhcp'] = value
+ else:
+ subnet_props[key] = value
+
+ if 'network_id' in tosca_props:
+ subnet_props['network'] = tosca_props['network_id']
+ else:
+ subnet_props['network'] = '{ get_resource: %s }' % (self.name)
+
+ # Handle allocation pools
+ # Do this only if both start_ip and end_ip are provided
+ # If one of them is missing throw an exception.
+ if ip_pool_start and ip_pool_end:
+ allocation_pool = {}
+ allocation_pool['start'] = ip_pool_start
+ allocation_pool['end'] = ip_pool_end
+ allocation_pools = [allocation_pool]
+ subnet_props['allocation_pools'] = allocation_pools
+ elif ip_pool_start:
+ raise InvalidPropertyValueError(what=_('start_ip'))
+ elif ip_pool_end:
+ raise InvalidPropertyValueError(what=_('end_ip'))
+
+ subnet_resource_name = self.name + self.SUBNET_SUFFIX
+
+ hot_resources = [HotResource(self.nodetemplate,
+ type='OS::Neutron::Subnet',
+ name=subnet_resource_name,
+ properties=subnet_props)]
+ return hot_resources
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
new file mode 100644
index 0000000..4fd2d70
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
@@ -0,0 +1,114 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaNetworkPort'
+TOSCA_LINKS_TO = 'tosca.relationships.network.LinksTo'
+TOSCA_BINDS_TO = 'tosca.relationships.network.BindsTo'
+
+
+class ToscaNetworkPort(HotResource):
+ '''Translate TOSCA node type tosca.nodes.network.Port.'''
+
+ toscatype = 'tosca.nodes.network.Port'
+
+ def __init__(self, nodetemplate):
+ super(ToscaNetworkPort, self).__init__(nodetemplate,
+ type='OS::Neutron::Port')
+ # Default order
+ self.order = 0
+ pass
+
+ def _generate_networks_for_compute(self, port_resources):
+ '''Generate compute networks property list from the port resources.'''
+ networks = []
+ for resource in port_resources:
+ networks.append({'port': '{ get_resource: %s }' % (resource.name)})
+ return networks
+
+ def _insert_sorted_resource(self, resources, resource):
+ '''Insert a resource in the list of resources and keep the order.'''
+ lo = 0
+ hi = len(resources)
+ while lo < hi:
+ mid = (lo + hi) // 2
+ if resource.order < resources[mid].order:
+ hi = mid
+ else:
+ lo = mid + 1
+ resources.insert(lo, resource)
+
+ def handle_properties(self):
+ tosca_props = self.get_tosca_props()
+ port_props = {}
+ for key, value in tosca_props.items():
+ if key == 'ip_address':
+ fixed_ip = {}
+ fixed_ip['ip_address'] = value
+ port_props['fixed_ips'] = [fixed_ip]
+ elif key == 'order':
+ self.order = value
+ # TODO(sdmonov): Need to implement the properties below
+ elif key == 'is_default':
+ pass
+ elif key == 'ip_range_start':
+ pass
+ elif key == 'ip_range_end':
+ pass
+ else:
+ port_props[key] = value
+
+ links_to = None
+ binds_to = None
+ for rel, node in self.nodetemplate.relationships.items():
+ # Check for LinksTo relations. If found add a network property with
+ # the network name into the port
+ if not links_to and rel.is_derived_from(TOSCA_LINKS_TO):
+ links_to = node
+
+ network_resource = None
+ for hot_resource in self.depends_on_nodes:
+ if links_to.name == hot_resource.name:
+ network_resource = hot_resource
+ self.depends_on.remove(hot_resource)
+ break
+
+ if network_resource.existing_resource_id:
+ port_props['network'] =\
+ str(network_resource.existing_resource_id)
+ else:
+ port_props['network'] = '{ get_resource: %s }'\
+ % (links_to.name)
+
+ # Check for BindsTo relationship. If found add network to the
+ # network property of the corresponding compute resource
+ elif not binds_to and rel.is_derived_from(TOSCA_BINDS_TO):
+ binds_to = node
+ compute_resource = None
+ for hot_resource in self.depends_on_nodes:
+ if binds_to.name == hot_resource.name:
+ compute_resource = hot_resource
+ self.depends_on.remove(hot_resource)
+ break
+ if compute_resource:
+ port_rsrcs = compute_resource.assoc_port_resources
+ self._insert_sorted_resource(port_rsrcs, self)
+ # TODO(sdmonov): Using generate networks every time we add
+ # a network is not the fastest way to do the things. We
+ # should do this only once at the end.
+ networks = self._generate_networks_for_compute(port_rsrcs)
+ compute_resource.properties['networks'] = networks
+
+ self.properties = port_props
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
new file mode 100644
index 0000000..177503f
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
@@ -0,0 +1,57 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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.elements.scalarunit import ScalarUnit_Size
+from translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaObjectStorage'
+
+
+class ToscaObjectStorage(HotResource):
+ '''Translate TOSCA node type tosca.nodes.ObjectStorage.'''
+
+ toscatype = 'tosca.nodes.ObjectStorage'
+
+ def __init__(self, nodetemplate):
+ super(ToscaObjectStorage, self).__init__(nodetemplate,
+ type='OS::Swift::Container')
+ pass
+
+ def handle_properties(self):
+ tosca_props = self.get_tosca_props()
+ objectstore_props = {}
+ container_quota = {}
+ skip_check = False
+
+ for key, value in tosca_props.items():
+ if key == "name":
+ objectstore_props["name"] = value
+ elif key == "size" or key == "maxsize":
+ # currently heat is not supporting dynamically increase
+ # the container quota-size.
+ # if both defined in tosca template, consider store_maxsize.
+ if skip_check:
+ continue
+ quota_size = None
+ if "maxsize" in tosca_props.keys():
+ quota_size = tosca_props["maxsize"]
+ else:
+ quota_size = tosca_props["size"]
+ container_quota["Quota-Bytes"] = \
+ ScalarUnit_Size(quota_size).get_num_from_scalar_unit()
+ objectstore_props["X-Container-Meta"] = container_quota
+ skip_check = True
+
+ objectstore_props["X-Container-Read"] = '".r:*"'
+ self.properties = objectstore_props
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
new file mode 100644
index 0000000..b32fc1d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
@@ -0,0 +1,36 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaPolicies'
+
+
+class ToscaPolicies(HotResource):
+ '''Translate TOSCA policy type tosca.poicies.Placement.'''
+
+ toscatype = 'tosca.policies.Placement'
+
+ def __init__(self, policy):
+ super(ToscaPolicies, self).__init__(policy,
+ type='OS::Nova::ServerGroup')
+ self.policy = policy
+
+ def handle_properties(self, resources):
+ self.properties["name"] = self.name
+ self.properties["policies"] = ["affinity"]
+ for resource in resources:
+ if resource.name in self.policy.targets:
+ resource.properties["scheduler_hints"] = {
+ "group": {"get_resource": self.name}}
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
new file mode 100644
index 0000000..044de43
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
@@ -0,0 +1,30 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaSoftwareComponent'
+
+
+class ToscaSoftwareComponent(HotResource):
+ '''Translate TOSCA node type tosca.nodes.SoftwareComponent.'''
+
+ toscatype = 'tosca.nodes.SoftwareComponent'
+
+ def __init__(self, nodetemplate):
+ super(ToscaSoftwareComponent, self).__init__(nodetemplate)
+ pass
+
+ def handle_properties(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
new file mode 100644
index 0000000..d0a9c5d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
@@ -0,0 +1,30 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaWebApplication'
+
+
+class ToscaWebApplication(HotResource):
+ '''Translate TOSCA node type tosca.nodes.WebApplication.'''
+
+ toscatype = 'tosca.nodes.WebApplication'
+
+ def __init__(self, nodetemplate):
+ super(ToscaWebApplication, self).__init__(nodetemplate)
+ pass
+
+ def handle_properties(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
new file mode 100644
index 0000000..83bda80
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
@@ -0,0 +1,30 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.hot.syntax.hot_resource import HotResource
+
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaWebserver'
+
+
+class ToscaWebserver(HotResource):
+ '''Translate TOSCA node type tosca.nodes.WebServer.'''
+
+ toscatype = 'tosca.nodes.WebServer'
+
+ def __init__(self, nodetemplate):
+ super(ToscaWebserver, self).__init__(nodetemplate)
+ pass
+
+ def handle_properties(self):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca_translator.py b/tosca2heat/heat-translator/translator/hot/tosca_translator.py
new file mode 100644
index 0000000..14ef8a1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca_translator.py
@@ -0,0 +1,68 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+from toscaparser.utils.gettextutils import _
+from translator.hot.syntax.hot_template import HotTemplate
+from translator.hot.translate_inputs import TranslateInputs
+from translator.hot.translate_node_templates import TranslateNodeTemplates
+from translator.hot.translate_outputs import TranslateOutputs
+
+log = logging.getLogger('heat-translator')
+
+
+class TOSCATranslator(object):
+ '''Invokes translation methods.'''
+
+ def __init__(self, tosca, parsed_params, deploy=None):
+ super(TOSCATranslator, self).__init__()
+ self.tosca = tosca
+ self.hot_template = HotTemplate()
+ self.parsed_params = parsed_params
+ self.deploy = deploy
+ self.node_translator = None
+ log.info(_('Initialized parmaters for translation.'))
+
+ def translate(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.outputs = self._translate_outputs()
+ return self.hot_template.output_to_yaml()
+
+ def _translate_inputs(self):
+ translator = TranslateInputs(self.tosca.inputs, self.parsed_params,
+ self.deploy)
+ return translator.translate()
+
+ def _translate_outputs(self):
+ translator = TranslateOutputs(self.tosca.outputs, self.node_translator)
+ return translator.translate()
+
+ # check all properties for all node and ensure they are resolved
+ # to actual value
+ def _resolve_input(self):
+ for n in self.tosca.nodetemplates:
+ for node_prop in n.get_properties_objects():
+ if isinstance(node_prop.value, dict):
+ try:
+ self.parsed_params[node_prop.value['get_input']]
+ except Exception:
+ msg = (_('Must specify all input values in \
+ TOSCA template, missing %s.') %
+ node_prop.value['get_input'])
+ log.error(msg)
+ raise ValueError(msg)
diff --git a/tosca2heat/heat-translator/translator/hot/translate_inputs.py b/tosca2heat/heat-translator/translator/hot/translate_inputs.py
new file mode 100644
index 0000000..6d677d1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/translate_inputs.py
@@ -0,0 +1,167 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+from toscaparser.dataentity import DataEntity
+from toscaparser.elements.scalarunit import ScalarUnit_Size
+from toscaparser.parameters import Input
+from toscaparser.utils.gettextutils import _
+from toscaparser.utils.validateutils import TOSCAVersionProperty
+from translator.hot.syntax.hot_parameter import HotParameter
+
+
+INPUT_CONSTRAINTS = (CONSTRAINTS, DESCRIPTION, LENGTH, RANGE,
+ MIN, MAX, ALLOWED_VALUES, ALLOWED_PATTERN) = \
+ ('constraints', 'description', 'length', 'range',
+ 'min', 'max', 'allowed_values', 'allowed_pattern')
+
+TOSCA_CONSTRAINT_OPERATORS = (EQUAL, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN,
+ LESS_OR_EQUAL, IN_RANGE, VALID_VALUES, LENGTH,
+ MIN_LENGTH, MAX_LENGTH, PATTERN) = \
+ ('equal', 'greater_than', 'greater_or_equal',
+ 'less_than', 'less_or_equal', 'in_range',
+ 'valid_values', 'length', 'min_length',
+ 'max_length', 'pattern')
+
+TOSCA_TO_HOT_CONSTRAINTS_ATTRS = {'equal': 'allowed_values',
+ 'greater_than': 'range',
+ 'greater_or_equal': 'range',
+ 'less_than': 'range',
+ 'less_or_equal': 'range',
+ 'in_range': 'range',
+ 'valid_values': 'allowed_values',
+ 'length': 'length',
+ 'min_length': 'length',
+ 'max_length': 'length',
+ 'pattern': 'allowed_pattern'}
+
+TOSCA_TO_HOT_INPUT_TYPES = {'string': 'string',
+ 'integer': 'number',
+ 'float': 'number',
+ 'boolean': 'boolean',
+ 'timestamp': 'string',
+ 'scalar-unit.size': 'number',
+ 'version': 'string',
+ 'null': 'string',
+ 'PortDef': 'number'}
+
+log = logging.getLogger('heat-translator')
+
+
+class TranslateInputs(object):
+
+ '''Translate TOSCA Inputs to Heat Parameters.'''
+
+ def __init__(self, inputs, parsed_params, deploy=None):
+ self.inputs = inputs
+ self.parsed_params = parsed_params
+ self.deploy = deploy
+
+ def translate(self):
+ return self._translate_inputs()
+
+ def _translate_inputs(self):
+ hot_inputs = []
+ if 'key_name' in self.parsed_params and 'key_name' not in self.inputs:
+ name = 'key_name'
+ type = 'string'
+ default = self.parsed_params[name]
+ schema_dict = {'type': type, 'default': default}
+ input = Input(name, schema_dict)
+ self.inputs.append(input)
+
+ log.info(_('Translating TOSCA input type to HOT input type.'))
+ for input in self.inputs:
+ hot_default = None
+ hot_input_type = TOSCA_TO_HOT_INPUT_TYPES[input.type]
+
+ if input.name in self.parsed_params:
+ hot_default = DataEntity.validate_datatype(
+ input.type, self.parsed_params[input.name])
+ elif input.default is not None:
+ hot_default = DataEntity.validate_datatype(input.type,
+ input.default)
+ else:
+ if self.deploy:
+ msg = _("Need to specify a value "
+ "for input {0}.").format(input.name)
+ log.error(msg)
+ raise Exception(msg)
+ if input.type == "scalar-unit.size":
+ # Assumption here is to use this scalar-unit.size for size of
+ # cinder volume in heat templates and will be in GB.
+ # should add logic to support other types if needed.
+ input_value = hot_default
+ hot_default = (ScalarUnit_Size(hot_default).
+ get_num_from_scalar_unit('GiB'))
+ if hot_default == 0:
+ msg = _('Unit value should be > 0.')
+ log.error(msg)
+ raise Exception(msg)
+ elif int(hot_default) < hot_default:
+ hot_default = int(hot_default) + 1
+ log.warning(_("Cinder unit value should be in multiples"
+ " of GBs. So corrected %(input_value)s "
+ "to %(hot_default)s GB.")
+ % {'input_value': input_value,
+ 'hot_default': hot_default})
+ if input.type == 'version':
+ hot_default = TOSCAVersionProperty(hot_default).get_version()
+
+ hot_constraints = []
+ if input.constraints:
+ for constraint in input.constraints:
+ if hot_default:
+ constraint.validate(hot_default)
+ hc, hvalue = self._translate_constraints(
+ constraint.constraint_key, constraint.constraint_value)
+ hot_constraints.append({hc: hvalue})
+
+ hot_inputs.append(HotParameter(name=input.name,
+ type=hot_input_type,
+ description=input.description,
+ default=hot_default,
+ constraints=hot_constraints))
+ return hot_inputs
+
+ def _translate_constraints(self, name, value):
+ hot_constraint = TOSCA_TO_HOT_CONSTRAINTS_ATTRS[name]
+
+ # Offset used to support less_than and greater_than.
+ # TODO(anyone): when parser supports float, verify this works
+ offset = 1
+
+ if name == EQUAL:
+ hot_value = [value]
+ elif name == GREATER_THAN:
+ hot_value = {"min": value + offset}
+ elif name == GREATER_OR_EQUAL:
+ hot_value = {"min": value}
+ elif name == LESS_THAN:
+ hot_value = {"max": value - offset}
+ elif name == LESS_OR_EQUAL:
+ hot_value = {"max": value}
+ elif name == IN_RANGE:
+ # value is list type here
+ min_value = min(value)
+ max_value = max(value)
+ hot_value = {"min": min_value, "max": max_value}
+ elif name == LENGTH:
+ hot_value = {"min": value, "max": value}
+ elif name == MIN_LENGTH:
+ hot_value = {"min": value}
+ elif name == MAX_LENGTH:
+ hot_value = {"max": value}
+ else:
+ hot_value = value
+ return hot_constraint, hot_value
diff --git a/tosca2heat/heat-translator/translator/hot/translate_node_templates.py b/tosca2heat/heat-translator/translator/hot/translate_node_templates.py
new file mode 100644
index 0000000..46cdd71
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/translate_node_templates.py
@@ -0,0 +1,483 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 importlib
+import logging
+import os
+import six
+
+from toscaparser.functions import GetAttribute
+from toscaparser.functions import GetInput
+from toscaparser.functions import GetProperty
+from toscaparser.properties import Property
+from toscaparser.relationship_template import RelationshipTemplate
+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.conf.config import ConfigProvider as translatorConfig
+from translator.hot.syntax.hot_resource import HotResource
+from translator.hot.tosca.tosca_block_storage_attachment import (
+ ToscaBlockStorageAttachment
+ )
+
+###########################
+# Module utility Functions
+# for dynamic class loading
+###########################
+
+
+def _generate_type_map():
+ '''Generate TOSCA translation types map.
+
+ Load user defined classes from location path specified in conf file.
+ Base classes are located within the tosca directory.
+
+ '''
+
+ # Base types directory
+ BASE_PATH = 'translator/hot/tosca'
+
+ # Custom types directory defined in conf file
+ custom_path = translatorConfig.get_value('DEFAULT',
+ 'custom_types_location')
+
+ # First need to load the parent module, for example 'contrib.hot',
+ # for all of the dynamically loaded classes.
+ classes = []
+ _load_classes((BASE_PATH, custom_path), classes)
+ try:
+ types_map = {clazz.toscatype: clazz for clazz in classes}
+ except AttributeError as e:
+ raise ToscaClassAttributeError(message=e.message)
+
+ return types_map
+
+
+def _load_classes(locations, classes):
+ '''Dynamically load all the classes from the given locations.'''
+
+ for cls_path in locations:
+ # Use the absolute path of the class path
+ abs_path = os.path.dirname(os.path.abspath(__file__))
+ abs_path = abs_path.replace('translator/hot', cls_path)
+
+ # Grab all the tosca type module files in the given path
+ mod_files = [f for f in os.listdir(abs_path) if f.endswith('.py')
+ and not f.startswith('__init__')
+ and f.startswith('tosca_')]
+
+ # For each module, pick out the target translation class
+ for f in mod_files:
+ # NOTE: For some reason the existing code does not use the map to
+ # instantiate ToscaBlockStorageAttachment. Don't add it to the map
+ # here until the dependent code is fixed to use the map.
+ if f == 'tosca_block_storage_attachment.py':
+ continue
+
+ mod_name = cls_path + '/' + f.strip('.py')
+ mod_name = mod_name.replace('/', '.')
+ try:
+ mod = importlib.import_module(mod_name)
+ target_name = getattr(mod, 'TARGET_CLASS_NAME')
+ clazz = getattr(mod, target_name)
+ classes.append(clazz)
+ except ImportError:
+ raise ToscaModImportError(mod_name=mod_name)
+ except AttributeError:
+ if target_name:
+ raise ToscaClassImportError(name=target_name,
+ mod_name=mod_name)
+ else:
+ # TARGET_CLASS_NAME is not defined in module.
+ # Re-raise the exception
+ raise
+
+##################
+# Module constants
+##################
+
+SECTIONS = (TYPE, PROPERTIES, REQUIREMENTS, INTERFACES, LIFECYCLE, INPUT) = \
+ ('type', 'properties', 'requirements',
+ 'interfaces', 'lifecycle', 'input')
+
+# TODO(anyone): the following requirement names should not be hard-coded
+# in the translator. Since they are basically arbitrary names, we have to get
+# them from TOSCA type definitions.
+# To be fixed with the blueprint:
+# https://blueprints.launchpad.net/heat-translator/+spec/tosca-custom-types
+REQUIRES = (CONTAINER, DEPENDENCY, DATABASE_ENDPOINT, CONNECTION, HOST) = \
+ ('container', 'dependency', 'database_endpoint',
+ 'connection', 'host')
+
+INTERFACES_STATE = (CREATE, START, CONFIGURE, START, DELETE) = \
+ ('create', 'stop', 'configure', 'start', 'delete')
+
+
+TOSCA_TO_HOT_REQUIRES = {'container': 'server', 'host': 'server',
+ 'dependency': 'depends_on', "connects": 'depends_on'}
+
+TOSCA_TO_HOT_PROPERTIES = {'properties': 'input'}
+log = logging.getLogger('heat-translator')
+
+TOSCA_TO_HOT_TYPE = _generate_type_map()
+
+
+class TranslateNodeTemplates(object):
+ '''Translate TOSCA NodeTemplates to Heat Resources.'''
+
+ def __init__(self, tosca, hot_template):
+ self.tosca = tosca
+ self.nodetemplates = self.tosca.nodetemplates
+ self.hot_template = hot_template
+ # 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
+
+ def translate(self):
+ return self._translate_nodetemplates()
+
+ def _recursive_handle_properties(self, resource):
+ '''Recursively handle the properties of the depends_on_nodes nodes.'''
+ # Use of hashtable (dict) here should be faster?
+ if resource in self.processed_resources:
+ return
+ self.processed_resources.append(resource)
+ for depend_on in resource.depends_on_nodes:
+ self._recursive_handle_properties(depend_on)
+
+ if resource.type == "OS::Nova::ServerGroup":
+ resource.handle_properties(self.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)
+ 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":
+ volume_name = None
+ requirements = node.requirements
+ if requirements:
+ # Find the name of associated BlockStorage node
+ for requires in requirements:
+ for value in requires.values():
+ if isinstance(value, dict):
+ for node_name in value.values():
+ for n in self.nodetemplates:
+ if n.name == node_name:
+ volume_name = node_name
+ break
+ else: # unreachable code !
+ for n in self.nodetemplates:
+ if n.name == node_name:
+ volume_name = node_name
+ break
+
+ suffix = suffix + 1
+ 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:
+ if (i.name == 'key_name' and
+ node.get_property_value('key_name') is None):
+ schema = {'type': i.type, 'default': i.default}
+ value = {"get_param": "key_name"}
+ prop = Property(i.name, value, schema)
+ node._properties.append(prop)
+
+ for policy in self.policies:
+ policy_type = policy.type_definition
+ policy_node = TOSCA_TO_HOT_TYPE[policy_type.type](policy)
+ self.hot_resources.append(policy_node)
+
+ # Handle life cycle operations: this may expand each node
+ # 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
+ self.hot_resources += lifecycle_resources
+
+ # Handle configuration from ConnectsTo relationship in the TOSCA node:
+ # this will generate multiple HOT resources, set of 2 for each
+ # configuration
+ connectsto_resources = []
+ for node in self.nodetemplates:
+ for requirement in node.requirements:
+ for endpoint, details in six.iteritems(requirement):
+ relation = None
+ if isinstance(details, dict):
+ target = details.get('node')
+ relation = details.get('relationship')
+ else:
+ target = details
+ if (target and relation and
+ not isinstance(relation, six.string_types)):
+ interfaces = relation.get('interfaces')
+ connectsto_resources += \
+ self._create_connect_configs(node,
+ target,
+ interfaces)
+ self.hot_resources += connectsto_resources
+
+ # Copy the initial dependencies based on the relationship in
+ # the TOSCA template
+ for node in self.nodetemplates:
+ for node_depend in node.related_nodes:
+ # 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 \
+ node.related[node_depend].type == \
+ node.type_definition.HOSTEDON:
+ self.hot_lookup[node].properties['server'] = \
+ {'get_resource': self.hot_lookup[node_depend].name}
+ # for all others, add dependency as depends_on
+ else:
+ self.hot_lookup[node].depends_on.append(
+ self.hot_lookup[node_depend].top_of_chain())
+
+ self.hot_lookup[node].depends_on_nodes.append(
+ self.hot_lookup[node_depend].top_of_chain())
+
+ # handle hosting relationship
+ for resource in self.hot_resources:
+ resource.handle_hosting()
+
+ # handle built-in properties of HOT resources
+ # if a resource depends on other resources,
+ # their properties need to be handled first.
+ # Use recursion to handle the properties of the
+ # dependent nodes in correct order
+ self.processed_resources = []
+ for resource in self.hot_resources:
+ self._recursive_handle_properties(resource)
+
+ # handle resources that need to expand to more than one HOT resource
+ expansion_resources = []
+ for resource in self.hot_resources:
+ expanded = resource.handle_expansion()
+ if expanded:
+ expansion_resources += expanded
+ self.hot_resources += expansion_resources
+
+ # Resolve function calls: GetProperty, GetAttribute, GetInput
+ # at this point, all the HOT resources should have been created
+ # in the graph.
+ for resource in self.hot_resources:
+ # 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)
+
+ return self.hot_resources
+
+ def _translate_input(self, input_value, resource):
+ get_property_args = None
+ if isinstance(input_value, GetProperty):
+ get_property_args = input_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']
+ 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):
+ # for the attribute
+ # get the proper target type to perform the translation
+ args = input_value.result()
+ 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]}
+ else:
+ return {'get_param': input_value.args}
+
+ return input_value
+
+ @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)
+
+ return artifacts
+
+ def _get_attachment_node(self, node, suffix, volume_name):
+ attach = False
+ ntpl = self.nodetemplates
+ for key, value in node.relationships.items():
+ if key.is_derived_from('tosca.relationships.AttachesTo'):
+ if value.is_derived_from('tosca.nodes.BlockStorage'):
+ attach = True
+ if attach:
+ relationship_tpl = None
+ for req in node.requirements:
+ for key, val in req.items():
+ attach = val
+ relship = val.get('relationship')
+ for rkey, rval in val.items():
+ if relship and isinstance(relship, dict):
+ for rkey, rval in relship.items():
+ if rkey == 'type':
+ relationship_tpl = val
+ attach = rval
+ elif rkey == 'template':
+ rel_tpl_list = \
+ (self.tosca.topology_template.
+ _tpl_relationship_templates())
+ relationship_tpl = rel_tpl_list[rval]
+ attach = rval
+ else:
+ continue
+ elif isinstance(relship, str):
+ attach = relship
+ relationship_tpl = val
+ relationship_templates = \
+ self.tosca._tpl_relationship_templates()
+ if 'relationship' in relationship_tpl and \
+ attach not in \
+ self.tosca._tpl_relationship_types() and \
+ attach in relationship_templates:
+ relationship_tpl['relationship'] = \
+ relationship_templates[attach]
+ break
+ if relationship_tpl:
+ rval_new = attach + "_" + str(suffix)
+ att = RelationshipTemplate(
+ relationship_tpl, rval_new,
+ self.tosca._tpl_relationship_types())
+ hot_node = ToscaBlockStorageAttachment(att, ntpl,
+ node.name,
+ volume_name
+ )
+ return hot_node
+
+ def find_hot_resource(self, name):
+ for resource in self.hot_resources:
+ 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):
+ 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:
+ if 'host' in req:
+ return self._find_hot_resource_for_tosca(req['host'])
+
+ for node in self.nodetemplates:
+ if node.name == tosca_name:
+ return self.hot_lookup[node]
+
+ return None
+
+ def _create_connect_configs(self, source_node, target_name,
+ connect_interfaces):
+ connectsto_resources = []
+ if connect_interfaces:
+ for iname, interface in six.iteritems(connect_interfaces):
+ connectsto_resources += \
+ self._create_connect_config(source_node, target_name,
+ interface)
+ return connectsto_resources
+
+ def _create_connect_config(self, source_node, target_name,
+ connect_interface):
+ connectsto_resources = []
+ target_node = self._find_tosca_node(target_name)
+ # the configuration can occur on the source or the target
+ connect_config = connect_interface.get('pre_configure_target')
+ if connect_config is not None:
+ config_location = 'target'
+ else:
+ connect_config = connect_interface.get('pre_configure_source')
+ if connect_config is not None:
+ config_location = 'source'
+ else:
+ msg = _("Template error: "
+ "no configuration found for ConnectsTo "
+ "in {1}").format(self.nodetemplate.name)
+ log.error(msg)
+ raise Exception(msg)
+ config_name = source_node.name + '_' + target_name + '_connect_config'
+ implement = connect_config.get('implementation')
+ if config_location == 'target':
+ hot_config = HotResource(target_node,
+ config_name,
+ 'OS::Heat::SoftwareConfig',
+ {'config': {'get_file': implement}})
+ elif config_location == 'source':
+ hot_config = HotResource(source_node,
+ config_name,
+ 'OS::Heat::SoftwareConfig',
+ {'config': {'get_file': implement}})
+ 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)
+ connectsto_resources.append(hot_config.
+ handle_connectsto(source_node,
+ target_node,
+ hot_source,
+ hot_target,
+ config_location,
+ connect_interface))
+ return connectsto_resources
diff --git a/tosca2heat/heat-translator/translator/hot/translate_outputs.py b/tosca2heat/heat-translator/translator/hot/translate_outputs.py
new file mode 100644
index 0000000..4197cdd
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/translate_outputs.py
@@ -0,0 +1,48 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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
+
+from toscaparser.utils.gettextutils import _
+from translator.hot.syntax.hot_output import HotOutput
+
+log = logging.getLogger('heat-translator')
+
+
+class TranslateOutputs(object):
+ '''Translate TOSCA Outputs to Heat Outputs.'''
+
+ def __init__(self, outputs, node_translator):
+ log.debug(_('Translating TOSCA outputs to HOT outputs.'))
+ self.outputs = outputs
+ self.nodes = node_translator
+
+ def translate(self):
+ return self._translate_outputs()
+
+ 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,
+ output.description))
+ return hot_outputs
diff --git a/tosca2heat/heat-translator/translator/osc/__init__.py b/tosca2heat/heat-translator/translator/osc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/__init__.py
diff --git a/tosca2heat/heat-translator/translator/osc/osc_plugin.py b/tosca2heat/heat-translator/translator/osc/osc_plugin.py
new file mode 100644
index 0000000..6d3d25a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/osc_plugin.py
@@ -0,0 +1,41 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 translator.osc import utils
+
+DEFAULT_TRANSLATOR_API_VERSION = '1'
+API_VERSION_OPTION = 'os_translator_api_version'
+API_NAME = 'translator'
+API_VERSIONS = {
+ '1': 'translator.v1.client.Client',
+}
+
+
+def make_client(instance):
+ # NOTE(stevemar): We don't need a client because
+ # heat-translator itself is a command line tool
+ pass
+
+
+def build_option_parser(parser):
+ """Hook to add global options."""
+
+ parser.add_argument(
+ '--os-translator-api-version',
+ metavar='<translator-api-version>',
+ default=utils.env(
+ 'OS_TRANSLATOR_API_VERSION',
+ default=DEFAULT_TRANSLATOR_API_VERSION),
+ help='Translator API version, default=' +
+ DEFAULT_TRANSLATOR_API_VERSION +
+ ' (Env: OS_TRANSLATOR_API_VERSION)')
+ return parser
diff --git a/tosca2heat/heat-translator/translator/osc/utils.py b/tosca2heat/heat-translator/translator/osc/utils.py
new file mode 100644
index 0000000..e8a6814
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/utils.py
@@ -0,0 +1,45 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+"""Common client utilities"""
+
+import argparse
+import os
+
+
+def env(*vars, **kwargs):
+ """Search for the first defined of possibly many env vars
+
+ Returns the first environment variable defined in vars, or
+ returns the default defined in kwargs.
+ """
+ for v in vars:
+ value = os.environ.get(v, None)
+ if value:
+ return value
+ return kwargs.get('default', '')
+
+
+class KeyValueAction(argparse.Action):
+ """A custom action to parse arguments as key=value pairs. """
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ # Make sure we have an empty dict rather than None
+ if getattr(namespace, self.dest, None) is None:
+ setattr(namespace, self.dest, {})
+
+ # Add value if an assignment else remove it
+ if '=' in values:
+ getattr(namespace, self.dest, {}).update([values.split('=', 1)])
+ else:
+ getattr(namespace, self.dest, {}).pop(values, None)
diff --git a/tosca2heat/heat-translator/translator/osc/v1/__init__.py b/tosca2heat/heat-translator/translator/osc/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/__init__.py
diff --git a/tosca2heat/heat-translator/translator/osc/v1/tests/__init__.py b/tosca2heat/heat-translator/translator/osc/v1/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/tests/__init__.py
diff --git a/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py b/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py
new file mode 100644
index 0000000..a08c3ac
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/tests/fakes.py
@@ -0,0 +1,32 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import sys
+
+
+class FakeApp(object):
+ def __init__(self):
+ self.client_manager = None
+ self.stdin = sys.stdin
+ self.stdout = sys.stdout
+ self.stderr = sys.stderr
+
+
+class FakeClientManager(object):
+ def __init__(self):
+ self.compute = None
+ self.identity = None
+ self.image = None
+ self.object_store = None
+ self.volume = None
+ self.network = None
+ self.session = None
diff --git a/tosca2heat/heat-translator/translator/osc/v1/tests/test_translate.py b/tosca2heat/heat-translator/translator/osc/v1/tests/test_translate.py
new file mode 100644
index 0000000..6a5f115
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/tests/test_translate.py
@@ -0,0 +1,448 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import mock
+import testtools
+
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
+import toscaparser.utils.yamlparser
+
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import URLException
+from toscaparser.common.exception import ValidationError
+from toscaparser.utils.gettextutils import _
+from translator.common.utils import CompareUtils
+from translator.common.utils import YamlUtils
+from translator.osc.v1.tests import fakes
+from translator.osc.v1.tests import utils
+from translator.osc.v1 import translate
+
+
+class TestTranslateTemplate(testtools.TestCase):
+
+ def setUp(self):
+ super(TestTranslateTemplate, self).setUp()
+ self.app = fakes.FakeApp()
+ self.app.client_manager = fakes.FakeClientManager()
+ self.app.client_manager.translator = None
+ self.cmd = translate.TranslateTemplate(self.app, None)
+
+ def check_parser(self, cmd, args, verify_args):
+ cmd_parser = cmd.get_parser('check_parser')
+ try:
+ parsed_args = cmd_parser.parse_args(args)
+ except SystemExit:
+ raise Exception("Argument parse failed")
+ for av in verify_args:
+ attr, value = av
+ if attr:
+ self.assertIn(attr, parsed_args)
+ self.assertEqual(getattr(parsed_args, attr), value)
+ return parsed_args
+
+ def _check_error(self, tosca_file, hot_file, params, assert_error,
+ expected_msg, c_error):
+ arglist = ["--template-file", tosca_file,
+ "--template-type", "tosca"]
+ parsed_args = self.check_parser(self.cmd, arglist, [])
+ parsed_args.parameter = params
+ self.assertRaises(assert_error, self.cmd.take_action,
+ parsed_args)
+ ExceptionCollector.assertExceptionMessage(c_error, expected_msg)
+
+ @mock.patch('sys.stdout', new_callable=StringIO)
+ def _check_success(self, tosca_file, hot_file, params, mock_stdout):
+ arglist = ["--template-file", tosca_file,
+ "--template-type", "tosca"]
+ parsed_args = self.check_parser(self.cmd, arglist, [])
+ parsed_args.parameter = params
+ self.cmd.take_action(parsed_args)
+ expected_output = YamlUtils.get_dict(hot_file)
+ mock_stdout_yaml = "\n".join(mock_stdout.getvalue().split("\n"))
+ actual_output = toscaparser.utils.yamlparser.simple_parse(
+ mock_stdout_yaml)
+ self.assertEqual({}, CompareUtils.diff_dicts(
+ actual_output, expected_output))
+
+ def test_osc_translate_single_server(self):
+ tosca_file = utils.get_template_path("tosca_single_server.yaml")
+
+ hot_file = utils.get_template_path("hot_output/hot_single_server.yaml")
+
+ params = {'cpus': 1}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_single_server_defaults_with_input(self):
+ tosca_file = utils.get_template_path(
+ "tosca_single_server_with_defaults.yaml")
+
+ hot_file = utils.get_template_path(
+ "hot_output/hot_single_server_with_defaults_with_input.yaml")
+
+ params = {'cpus': '1'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_single_server_defaults_without_input(self):
+ tosca_file = utils.get_template_path(
+ "tosca_single_server_with_defaults.yaml")
+
+ hot_file = utils.get_template_path(
+ "hot_output/hot_single_server_with_defaults_without_input.yaml")
+
+ self._check_success(tosca_file, hot_file, {})
+
+ def test_osc_translate_wordpress_single_instance(self):
+ tosca_file = utils.get_template_path(
+ "tosca_single_instance_wordpress.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_single_instance_wordpress.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_helloworld(self):
+ tosca_file = utils.get_template_path(
+ "tosca_helloworld.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_hello_world.yaml")
+ self._check_success(tosca_file, hot_file, {})
+
+ def test_osc_translate_host_assignment(self):
+ tosca_file = utils.get_template_path(
+ "test_host_assignment.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_host_assignment.yaml")
+ self._check_success(tosca_file, hot_file, {})
+
+ def test_osc_translate_elk(self):
+ tosca_file = utils.get_template_path(
+ "tosca_elk.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_elk.yaml")
+ params = {'github_url':
+ 'http://github.com/paypal/rest-api-sample-app-nodejs.git',
+ 'my_cpus': 4}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_nodejs_mongodb_two_instances(self):
+ tosca_file = utils.get_template_path(
+ "tosca_nodejs_mongodb_two_instances.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_nodejs_mongodb_two_instances.yaml")
+ params = {'github_url':
+ 'http://github.com/paypal/rest-api-sample-app-nodejs.git',
+ 'my_cpus': 4}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_blockstorage_with_attachment(self):
+ tosca_file = utils.get_template_path(
+ "storage/tosca_blockstorage_with_attachment.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/storage/hot_blockstorage_with_attachment.yaml")
+ params = {'cpus': 1,
+ 'storage_location': '/dev/vdc',
+ 'storage_size': '2000 MB',
+ 'storage_snapshot_id': 'ssid'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_blockstorage_with_custom_relationship_type(self):
+ tosca_file = utils.get_template_path(
+ "storage/tosca_blockstorage_with_custom_relationship_type.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/storage/"
+ "hot_blockstorage_with_custom_relationship_type.yaml")
+ params = {'cpus': 1,
+ 'storage_location': '/dev/vdc',
+ 'storage_size': '1 GB',
+ 'storage_snapshot_id': 'ssid'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_blockstorage_with_relationship_template(self):
+ tosca_file = utils.get_template_path(
+ "storage/" +
+ "tosca_blockstorage_with_relationship_template.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_blockstorage_with_relationship_template.yaml")
+ params = {'cpus': 1,
+ 'storage_location': '/dev/vdc',
+ 'storage_size': '1 GB'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_blockstorage_with_attachment_notation1(self):
+ tosca_file = utils.get_template_path(
+ "storage/" +
+ "tosca_blockstorage_with_attachment_notation1.yaml")
+ hot_file1 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_blockstorage_with_attachment_notation1_alt1.yaml")
+ hot_file2 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_blockstorage_with_attachment_notation1_alt2.yaml")
+ params = {'cpus': 1,
+ 'storage_location': 'some_folder',
+ 'storage_size': '1 GB',
+ 'storage_snapshot_id': 'ssid'}
+ try:
+ self._check_success(tosca_file, hot_file1, params)
+ except Exception:
+ self._check_success(tosca_file, hot_file2, params)
+
+ def test_osc_translate_blockstorage_with_attachment_notation2(self):
+ tosca_file = utils.get_template_path(
+ "storage/" +
+ "tosca_blockstorage_with_attachment_notation2.yaml")
+ hot_file1 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_blockstorage_with_attachment_notation2_alt1.yaml")
+ hot_file2 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_blockstorage_with_attachment_notation2_alt2.yaml")
+ params = {'cpus': 1,
+ 'storage_location': '/dev/vdc',
+ 'storage_size': '1 GB',
+ 'storage_snapshot_id': 'ssid'}
+ try:
+ self._check_success(tosca_file, hot_file1, params)
+ except Exception:
+ self._check_success(tosca_file, hot_file2, params)
+
+ def test_osc_translate_multiple_blockstorage_with_attachment(self):
+ tosca_file = utils.get_template_path(
+ "storage/" +
+ "tosca_multiple_blockstorage_with_attachment.yaml")
+ hot_file1 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_multiple_blockstorage_with_attachment_alt1.yaml")
+ hot_file2 = utils.get_template_path(
+ "hot_output/storage/" +
+ "hot_multiple_blockstorage_with_attachment_alt2.yaml")
+ params = {'cpus': 1,
+ 'storage_location': '/dev/vdc',
+ 'storage_size': '1 GB',
+ 'storage_snapshot_id': 'ssid'}
+ try:
+ self._check_success(tosca_file, hot_file1, params)
+ except Exception:
+ self._check_success(tosca_file, hot_file2, params)
+
+ def test_osc_translate_single_object_store(self):
+ tosca_file = utils.get_template_path(
+ "storage/tosca_single_object_store.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_single_object_store.yaml")
+ params = {'objectstore_name': 'myobjstore'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_one_server_one_network(self):
+ tosca_file = utils.get_template_path(
+ "network/tosca_one_server_one_network.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/network/" +
+ "hot_one_server_one_network.yaml")
+ params = {'network_name': 'private_net'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_server_on_existing_network(self):
+ tosca_file = utils.get_template_path(
+ "network/" +
+ "tosca_server_on_existing_network.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/network/" +
+ "hot_server_on_existing_network.yaml")
+ params = {'network_name': 'private_net'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_two_servers_one_network(self):
+ tosca_file = utils.get_template_path(
+ "network/tosca_two_servers_one_network.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/network/" +
+ "hot_two_servers_one_network.yaml")
+ params = {'network_name': 'my_private_net',
+ 'network_cidr': '10.0.0.0/24',
+ 'network_start_ip': '10.0.0.100',
+ 'network_end_ip': '10.0.0.150'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_one_server_three_networks(self):
+ tosca_file = utils.get_template_path(
+ "network/" +
+ "tosca_one_server_three_networks.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/network/" +
+ "hot_one_server_three_networks.yaml")
+ self._check_success(tosca_file, hot_file, {})
+
+ def test_osc_translate_software_component(self):
+ tosca_file = utils.get_template_path("tosca_software_component.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_software_component.yaml")
+ params = {'cpus': '1',
+ 'download_url': 'http://www.software.com/download'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_web_application(self):
+ tosca_file = utils.get_template_path("tosca_web_application.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_web_application.yaml")
+ params = {'cpus': '2', 'context_root': 'my_web_app'}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_template_with_url_import(self):
+ tosca_file = utils.get_template_path(
+ "tosca_single_instance_wordpress_with_url_import.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_single_instance_wordpress.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_template_by_url_with_local_import(self):
+ tosca_file = ("https://raw.githubusercontent.com/openstack/" +
+ "heat-translator/master/translator/tests/data/" +
+ "tosca_single_instance_wordpress.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/" +
+ "hot_single_instance_wordpress.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_template_by_url_with_local_abspath_import(self):
+ tosca_file = ("https://raw.githubusercontent.com/openstack/" +
+ "heat-translator/master/translator/tests/data/" +
+ "tosca_single_instance_wordpress_with_local_abspath" +
+ "_import.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/" +
+ "hot_single_instance_wordpress.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+
+ 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".')
+ self._check_error(tosca_file, hot_file, params, ValidationError,
+ expected_msg, ImportError)
+
+ def test_osc_translate_template_by_url_with_url_import(self):
+ tosca_url = ("https://raw.githubusercontent.com/openstack/" +
+ "heat-translator/master/translator/tests/data/" +
+ "tosca_single_instance_wordpress_with_url_import.yaml")
+ hot_file = utils.get_template_path(
+ "hot_output/" +
+ "hot_single_instance_wordpress.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+ self._check_success(tosca_url, hot_file, params)
+
+ def test_osc_translate_hello_world_csar(self):
+ tosca_file = utils.get_template_path("csar_hello_world.zip")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_hello_world.yaml")
+ self._check_success(tosca_file, hot_file, {})
+
+ def test_osc_single_instance_wordpress_csar(self):
+ tosca_file = utils.get_template_path(
+ "csar_single_instance_wordpress.zip")
+ hot_file = utils.get_template_path(
+ "hot_output/" +
+ "hot_single_instance_wordpress_from_csar.yaml")
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ 'db_root_pwd': 'passw0rd',
+ 'db_port': 3366,
+ 'cpus': 8}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_elk_csar_from_url(self):
+ tosca_file = ("https://github.com/openstack/heat-translator/raw/" +
+ "master/translator/tests/data/csar_elk.zip")
+ hot_file = utils.get_template_path(
+ "hot_output/hot_elk_from_csar.yaml")
+ params = {'github_url':
+ 'http://github.com/paypal/rest-api-sample-app-nodejs.git',
+ 'my_cpus': 4}
+ self._check_success(tosca_file, hot_file, params)
+
+ def test_osc_translate_csar_not_zip(self):
+ tosca_file = utils.get_template_path("csar_not_zip.zip")
+ hot_file = ''
+ expected_msg = _('"%s" is not a valid zip file.') % tosca_file
+ self._check_error(tosca_file, hot_file, {}, ValidationError,
+ expected_msg, ValidationError)
+
+ def test_osc_translate_csar_metadata_not_yaml(self):
+ tosca_file = utils.get_template_path("csar_metadata_not_yaml.zip")
+ hot_file = ''
+ expected_msg = _('The file "TOSCA-Metadata/TOSCA.meta" in the CSAR '
+ '"%s" does not contain valid YAML'
+ ' content.') % tosca_file
+ self._check_error(tosca_file, hot_file, {}, ValidationError,
+ expected_msg, ValidationError)
+
+ def test_osc_translate_csar_wrong_metadata_file(self):
+ tosca_file = utils.get_template_path("csar_wrong_metadata_file.zip")
+ hot_file = ''
+
+ expected_msg = _('"%s" is not a valid CSAR as it does not contain the '
+ 'required file "TOSCA.meta" in the folder '
+ '"TOSCA-Metadata".') % tosca_file
+ self._check_error(tosca_file, hot_file, {}, ValidationError,
+ expected_msg, ValidationError)
+
+ def test_osc_translate_csar_wordpress_invalid_import_path(self):
+ tosca_file = utils.get_template_path(
+ "csar_wordpress_invalid_import_path.zip")
+ hot_file = ''
+ expected_msg = _('Import '
+ '"Invalid_import_path/wordpress.yaml" is not valid.')
+ self._check_error(tosca_file, hot_file, {}, ValidationError,
+ expected_msg, ImportError)
+
+ def test_osc_translate_csar_wordpress_invalid_script_url(self):
+ tosca_file = utils.get_template_path(
+ "csar_wordpress_invalid_script_url.zip")
+ hot_file = ''
+ expected_msg = _('The resource at '
+ '"https://raw.githubusercontent.com/openstack/'
+ 'heat-translator/master/translator/tests/data/'
+ 'custom_types/wordpress1.yaml" cannot be accessed.')
+ self._check_error(tosca_file, hot_file, {}, ValidationError,
+ expected_msg, URLException)
diff --git a/tosca2heat/heat-translator/translator/osc/v1/tests/utils.py b/tosca2heat/heat-translator/translator/osc/v1/tests/utils.py
new file mode 100644
index 0000000..edd45a7
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/tests/utils.py
@@ -0,0 +1,19 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+
+
+def get_template_path(path):
+ data_folder = "../../../tests/data/"
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ data_folder + path)
diff --git a/tosca2heat/heat-translator/translator/osc/v1/translate.py b/tosca2heat/heat-translator/translator/osc/v1/translate.py
new file mode 100644
index 0000000..eeaaa18
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/osc/v1/translate.py
@@ -0,0 +1,106 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Translate action implementations"""
+
+import logging
+import logging.config
+import os
+import sys
+
+from cliff import command
+
+from toscaparser.tosca_template import ToscaTemplate
+from toscaparser.utils.gettextutils import _
+from translator.common.utils import UrlUtils
+from translator.hot.tosca_translator import TOSCATranslator
+from translator.osc import utils
+
+
+logging.config.fileConfig('heat_translator_logging.conf')
+log = logging.getLogger('heat-translator')
+
+
+class TranslateTemplate(command.Command):
+
+ """Translate a template"""
+
+ auth_required = False
+
+ def get_parser(self, prog_name):
+ parser = super(TranslateTemplate, self).get_parser(prog_name)
+ parser.add_argument(
+ '--template-file',
+ metavar='<template-file>',
+ required=True,
+ help='Path to the file that needs to be translated.')
+ parser.add_argument(
+ '--template-type',
+ metavar='<template-type>',
+ required=True,
+ choices=['tosca'],
+ help='Format of the template file.')
+ parser.add_argument(
+ '--output-file',
+ metavar='<output-file>',
+ help='Path to place the translated content.')
+ parser.add_argument(
+ '--parameter',
+ metavar='<key=value>',
+ action=utils.KeyValueAction,
+ help='Set a property for this template '
+ '(repeat option to set multiple properties)',
+ )
+ parser.add_argument(
+ '--validate-only',
+ metavar='<true or false>',
+ help='Set to true to only validate a template file.',
+ default='false')
+ return parser
+
+ def take_action(self, parsed_args):
+ log.debug(_('Translating the template with input parameters'
+ '(%s).'), parsed_args)
+ output = None
+
+ if parsed_args.parameter:
+ parsed_params = parsed_args.parameter
+ else:
+ parsed_params = {}
+
+ if parsed_args.template_type == "tosca":
+ path = parsed_args.template_file
+ a_file = os.path.isfile(path)
+ a_url = UrlUtils.validate_url(path) if not a_file else False
+ if a_file or a_url:
+ validate = parsed_args.validate_only
+ if validate and validate.lower() == "true":
+ ToscaTemplate(path, parsed_params, a_file)
+ msg = (_('The input "%(path)s" successfully passed '
+ 'validation.') % {'path': path})
+ print(msg)
+ else:
+ tosca = ToscaTemplate(path, parsed_params, a_file)
+ translator = TOSCATranslator(tosca, parsed_params)
+ output = translator.translate()
+ else:
+ msg = _('Could not find template file.')
+ log.error(msg)
+ sys.stdout.write(msg)
+ raise SystemExit
+
+ if output:
+ if parsed_args.output_file:
+ with open(parsed_args.output_file, 'w+') as f:
+ f.write(output)
+ else:
+ print(output)
diff --git a/tosca2heat/heat-translator/translator/shell.py b/tosca2heat/heat-translator/translator/shell.py
new file mode 100644
index 0000000..92d92d9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/shell.py
@@ -0,0 +1,238 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 ast
+import json
+import logging
+import logging.config
+import os
+import prettytable
+import requests
+import sys
+import uuid
+import yaml
+
+from toscaparser.tosca_template import ToscaTemplate
+from toscaparser.utils.gettextutils import _
+from toscaparser.utils.urlutils import UrlUtils
+from translator.common import utils
+from translator.hot.tosca_translator import TOSCATranslator
+
+"""
+Test the heat-translator translation from command line as:
+#heat-translator
+ --template-file=<path to the YAML template>
+ --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)
+3. Input parameters (optional)
+
+In order to use heat-translator to only validate template,
+without actual translation, pass --validate-only=true along with
+other required arguments.
+
+"""
+
+logging.config.fileConfig('heat_translator_logging.conf')
+log = logging.getLogger("heat-translator")
+
+
+class TranslatorShell(object):
+
+ SUPPORTED_TYPES = ['tosca']
+
+ def _validate(self, args):
+ if len(args) < 2:
+ msg = _("The program requires minimum two arguments. "
+ "Please refer to the usage documentation.")
+ log.error(msg)
+ raise ValueError(msg)
+ if "--template-file=" not in args[0]:
+ msg = _("The program expects --template-file as first argument. "
+ "Please refer to the usage documentation.")
+ log.error(msg)
+ raise ValueError(msg)
+ if "--template-type=" not in args[1]:
+ msg = _("The program expects --template-type as second argument. "
+ "Please refer to the usage documentation.")
+ log.error(msg)
+ raise ValueError(msg)
+
+ def main(self, args):
+ # TODO(spzala): set self.deploy based on passed args once support for
+ # --deploy argument is enabled.
+ self.deploy = False
+ self._validate(args)
+ path = args[0].split('--template-file=')[1]
+ # e.g. --template_file=translator/tests/data/tosca_helloworld.yaml
+ template_type = args[1].split('--template-type=')[1]
+ # e.g. --template_type=tosca
+ if not template_type:
+ msg = _("Template type is needed. For example, 'tosca'")
+ log.error(msg)
+ raise ValueError(msg)
+ elif template_type not in self.SUPPORTED_TYPES:
+ msg = _("%(value)s is not a valid template type.") % {
+ 'value': template_type}
+ log.error(msg)
+ raise ValueError(msg)
+ parsed_params = {}
+ validate_only = None
+ output_file = None
+ if len(args) > 2:
+ parameters = None
+ for arg in args:
+ if "--validate-only=" in arg:
+ validate_only = arg
+ if "--parameters=" in arg:
+ parameters = arg
+ if "--output-file=" in arg:
+ output = arg
+ output_file = output.split('--output-file=')[1]
+ if "--deploy" in arg:
+ self.deploy = True
+ if parameters:
+ parsed_params = self._parse_parameters(parameters)
+ a_file = os.path.isfile(path)
+ a_url = UrlUtils.validate_url(path) if not a_file else False
+ if a_file or a_url:
+ run_only_validation = False
+ if validate_only:
+ value = validate_only.split('-validate-only=')[1].lower()
+ if template_type == 'tosca' and value == 'true':
+ run_only_validation = True
+ if run_only_validation:
+ ToscaTemplate(path, parsed_params, a_file)
+ msg = (_('The input "%(path)s" successfully passed '
+ 'validation.') % {'path': path})
+ print(msg)
+ else:
+ log.info(
+ _('Checked whether template path is a file or url path.'))
+ heat_tpl = self._translate(template_type, path, parsed_params,
+ a_file)
+ if heat_tpl:
+ if utils.check_for_env_variables() and self.deploy:
+ try:
+ heatclient(heat_tpl, parsed_params)
+ except Exception:
+ log.error(_("Unable to launch the heat stack"))
+
+ self._write_output(heat_tpl, output_file)
+ else:
+ msg = _("The path %(path)s is not a valid file or URL.") % {
+ 'path': path}
+ log.error(msg)
+ raise ValueError(msg)
+
+ def _parse_parameters(self, parameter_list):
+ parsed_inputs = {}
+ if parameter_list.startswith('--parameters'):
+ # Parameters are semi-colon separated
+ inputs = parameter_list.split('--parameters=')[1].\
+ replace('"', '').split(';')
+ # Each parameter should be an assignment
+ for param in inputs:
+ keyvalue = param.split('=')
+ # Validate the parameter has both a name and value
+ msg = _("'%(param)s' is not a well-formed parameter.") % {
+ 'param': param}
+ if keyvalue.__len__() is 2:
+ # Assure parameter name is not zero-length or whitespace
+ stripped_name = keyvalue[0].strip()
+ if not stripped_name:
+ log.error(msg)
+ raise ValueError(msg)
+ # Add the valid parameter to the dictionary
+ parsed_inputs[keyvalue[0]] = keyvalue[1]
+ else:
+ log.error(msg)
+ raise ValueError(msg)
+ else:
+ msg = _("'%(list)s' is not a valid parameter list.") % {
+ 'list': parameter_list}
+ log.error(msg)
+ raise ValueError(msg)
+ return parsed_inputs
+
+ def _translate(self, sourcetype, path, parsed_params, a_file):
+ output = None
+ if sourcetype == "tosca":
+ log.debug(_('Loading the tosca template.'))
+ tosca = ToscaTemplate(path, parsed_params, a_file)
+ translator = TOSCATranslator(tosca, parsed_params, self.deploy)
+ 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, 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 = "heat_" + 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)
+
+
+def main(args=None):
+ if args is None:
+ args = sys.argv[1:]
+ TranslatorShell().main(args)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tosca2heat/heat-translator/translator/tests/__init__.py b/tosca2heat/heat-translator/translator/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/__init__.py
diff --git a/tosca2heat/heat-translator/translator/tests/base.py b/tosca2heat/heat-translator/translator/tests/base.py
new file mode 100644
index 0000000..6e93268
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/base.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2010-2011 OpenStack Foundation
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+
+import fixtures
+import testtools
+
+_TRUE_VALUES = ('True', 'true', '1', 'yes')
+
+
+class TestCase(testtools.TestCase):
+
+ """Test case base class for all unit tests."""
+
+ def setUp(self):
+ """Run before each test method to initialize test environment."""
+
+ super(TestCase, self).setUp()
+ test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
+ try:
+ test_timeout = int(test_timeout)
+ except ValueError:
+ # If timeout value is invalid do not set a timeout.
+ test_timeout = 0
+ if test_timeout > 0:
+ self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
+
+ self.useFixture(fixtures.NestedTempfile())
+ self.useFixture(fixtures.TempHomeDir())
+
+ if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
+ stdout = self.useFixture(fixtures.StringStream('stdout')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
+ if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
+ stderr = self.useFixture(fixtures.StringStream('stderr')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
+
+ self.log_fixture = self.useFixture(fixtures.FakeLogger())
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/config.py b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/config.py
new file mode 100644
index 0000000..686bbd1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/config.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This script configures collectd to send metric data to the
+# logstash server port 25826
+# The environment variable logstash_ip is expected to be set up
+import os
+with open("/etc/collectd/collectd.conf.d/tosca_elk.conf", "w") as fh:
+ fh.write("""
+ LoadPlugin network
+ <Plugin network>
+ Server "%s" "25826"
+ </Plugin>
+ """ % (os.environ['logstash_ip']))
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/create.sh
new file mode 100644
index 0000000..a483b88
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/create.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# This script install collectd for monitoring data
+
+apt-get update
+apt-get install -y collectd
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/start.sh
new file mode 100644
index 0000000..7e8e033
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/collectd/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# This script starts collectd as a service in init.d
+service collectd stop
+service collectd start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/create.sh
new file mode 100644
index 0000000..c34126c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/create.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# This script installs java and elasticsearch
+
+apt-get update
+apt-get install -y openjdk-7-jre-headless
+
+wget -qO - https://packages.elasticsearch.org/GPG-KEY-elasticsearch | apt-key add -
+echo "deb http://packages.elasticsearch.org/elasticsearch/1.5/debian stable main" | tee -a /etc/apt/sources.list
+
+apt-get update
+apt-get install -y elasticsearch
+
+# set up to run as service
+update-rc.d elasticsearch defaults 95 10
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/start.sh
new file mode 100644
index 0000000..bbc0347
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/elasticsearch/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# This script starts elasticsearch as a service in init.d
+service elasticsearch stop
+service elasticsearch start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/config.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/config.sh
new file mode 100644
index 0000000..f28215a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/config.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# This script configures kibana to connect to the elasticsearch server
+# to access data and to export the app url on port 5601:
+# The environment variable elasticsearch_ip and kibana_ip are expected
+# to be set up.
+sed -i 's/localhost/'$elasticsearch_ip'/' /opt/kibana/config/kibana.yml
+sed -i 's/0.0.0.0/'$kibana_ip'/' /opt/kibana/config/kibana.yml
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/create.sh
new file mode 100644
index 0000000..41914b1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/create.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# This script installs kibana and sets it up to run as a service in init.d
+cd /opt
+wget https://download.elastic.co/kibana/kibana/kibana-4.1.0-linux-x64.tar.gz
+tar xzvf kibana-4.1.0-linux-x64.tar.gz
+mv kibana-4.1.0-linux-x64 kibana
+
+# set up to run as service
+cd /etc/init.d
+wget https://gist.githubusercontent.com/thisismitch/8b15ac909aed214ad04a/raw/bce61d85643c2dcdfbc2728c55a41dab444dca20/kibana4
+chmod +x kibana4
+update-rc.d kibana4 defaults 96 9
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/start.sh
new file mode 100644
index 0000000..5149bb3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/kibana/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# This script starts kibana as a service in init.d
+service kibana4 stop
+service kibana4 start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_collectd.py b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_collectd.py
new file mode 100644
index 0000000..18fdacf
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_collectd.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This script configures the logstash input using the udp protocol on
+# port 25826. This is intended to receive data from collectd from
+# any source
+with open("/etc/logstash/conf.d/collectd.conf", "w") as fh:
+ fh.write("""
+ input {
+ udp {
+ port => 25826 # 25826 is the default for collectd
+ buffer_size => 1452 # 1452 is the default for collectd
+ codec => collectd { }
+ tags => ["metrics"]
+ type => "collectd"
+ }
+ }""")
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_elasticsearch.py b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_elasticsearch.py
new file mode 100644
index 0000000..2e5389c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_elasticsearch.py
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This script configures the logstash output to forward to elasticsearch
+# The environment variable elasticsearch_ip is expected to be set up
+import os
+with open("/etc/logstash/conf.d/elasticsearch.conf", 'w') as fh:
+ fh.write("""
+ output {
+ elasticsearch {
+ action => index
+ host => "%s"
+ protocol => "http"
+ }
+ }""" % (os.environ['elasticsearch_ip']))
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_rsyslog.py b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_rsyslog.py
new file mode 100644
index 0000000..fc610c2
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/configure_rsyslog.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This script configures the logstash input using the RELP protocol on
+# port 2514 This is intended to receive logs from rsyslog from
+# any source
+with open("/etc/logstash/conf.d/rsyslog.conf", "w") as fh:
+ fh.write("""
+ input {
+ relp {
+ port => 2514
+ tags => ["logs"]
+ }
+ }""")
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/create.sh
new file mode 100644
index 0000000..77cc8fd
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/create.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# This script installs java, logstash and the contrib package for logstash
+# install java as prereq
+
+apt-get update
+apt-get install -y openjdk-7-jre-headless
+mkdir /etc/logstash
+
+# install by apt-get from repo
+wget -O - http://packages.elasticsearch.org/GPG-KEY-elasticsearch | apt-key add -
+echo "deb http://packages.elasticsearch.org/logstash/1.4/debian stable main" | tee -a /etc/apt/sources.list
+
+apt-get update
+apt-get install -y logstash
+
+# install contrib to get the relp plugin
+/opt/logstash/bin/plugin install contrib
+
+# set up to run as service
+update-rc.d logstash defaults 95 10
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/start.sh
new file mode 100644
index 0000000..a73cf61
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/logstash/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# Run logstash as service in init.d
+service logstash stop
+service logstash start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/config.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/config.sh
new file mode 100644
index 0000000..78f484e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/config.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Edit the file /etc/mongod.conf, update with real IP of Mongo server
+# This script configures the mongodb server to export its service on
+# the server IP
+# bind_ip = 127.0.0.1 -> bind_ip = <IP for Mongo server>
+# The environment variable mongodb_ip is expected to be set up
+sed -i "s/= 127.0.0.1/= $mongodb_ip,127.0.0.1/" /etc/mongod.conf
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create.sh
new file mode 100644
index 0000000..d84c275
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+# This script installs mongodb
+
+apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
+echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.0.list
+
+apt-get update
+apt-get install -y mongodb-org
+
+#Wait for mongodb initialization
+while [[ ! -d "/var/lib/mongodb/_tmp" ]]; do
+ echo "Waiting for mongodb initialization ..."
+ sleep 5
+done
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create_database.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create_database.sh
new file mode 100644
index 0000000..16f1358
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/create_database.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+echo "conn = new Mongo();" > setup.js
+echo "db = conn.getDB('paypal_pizza');" >> setup.js
+echo "db.about.insert({'name': 'PayPal Pizza Store'});" >> setup.js
+mongo setup.js
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/start.sh
new file mode 100644
index 0000000..ac200a5
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mongodb/start.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# This script starts mongodb
+service mongod stop
+rm /var/lib/mongodb/mongod.lock
+service mongod start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_database_configure.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_database_configure.sh
new file mode 100644
index 0000000..092136a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_database_configure.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+cat << EOF | mysql -u root --password=$db_root_password
+CREATE DATABASE $db_name;
+GRANT ALL PRIVILEGES ON $db_name.* TO "$db_user"@"localhost"
+IDENTIFIED BY "$db_password";
+FLUSH PRIVILEGES;
+EXIT
+EOF \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_configure.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_configure.sh
new file mode 100644
index 0000000..d4ef6b4
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_configure.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+sed --regexp-extended "s/(port\s*=\s*)[0-9]*/\1$db_port/g" </etc/mysql/my.cnf >/tmp/my.cnf
+mv -f /tmp/my.cnf /etc/mysql/my.cnf
+/etc/init.d/mysql stop
+/etc/init.d/mysql start \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_install.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_install.sh
new file mode 100644
index 0000000..38628b9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_install.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+#This script installs mysql server
+
+apt-get update
+
+debconf-set-selections <<< "mysql-server mysql-server/root_password password $db_root_password"
+debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $db_root_password"
+
+apt-get -y install --fix-missing mysql-server \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_start.sh
new file mode 100644
index 0000000..3378670
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/mysql/mysql_dbms_start.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+/etc/init.d/mysql start \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/config.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/config.sh
new file mode 100644
index 0000000..1e149a2
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/config.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# This script installs an app for nodejs: the app intended is the paypal app
+# and it is configured to connect to the mongodb server
+# The environment variables github_url and mongodb_ip are expected to be set up
+export app_dir=/opt/app
+git clone $github_url /opt/app
+if [ -f /opt/app/package.json ]; then
+ cd /opt/app/ && npm install
+ sed -i "s/localhost/$mongodb_ip/" config.json
+fi
+
+cat > /etc/init/nodeapp.conf <<EOS
+description "node.js app"
+
+start on (net-device-up
+ and local-filesystems
+ and runlevel [2345])
+stop on runlevel [!2345]
+
+expect fork
+respawn
+
+script
+ export HOME=/
+ export NODE_PATH=/usr/lib/node
+ exec /usr/bin/node ${app_dir}/app.js >> /var/log/nodeapp.log 2>&1 &
+end script
+EOS
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/create.sh
new file mode 100644
index 0000000..04fd6c6
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/create.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# This script installs nodejs and the prereq
+
+add-apt-repository ppa:chris-lea/node.js
+
+apt-get update
+apt-get install -y nodejs build-essential
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/start.sh
new file mode 100644
index 0000000..6939cb7
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/nodejs/start.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+# This script starts the nodejs application
+start nodeapp
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/config.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/config.sh
new file mode 100644
index 0000000..630767d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/config.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# This script configures the output for rsyslogd to send logs to the
+# logstash server port 2514 using the RELP protocol
+# The environment variable logstash_ip is expected to be set up
+echo "module(load=\"omrelp\")
+action(type=\"omrelp\" target=\"$logstash_ip\" port=\"2514\")" > /etc/rsyslog.d/tosca_elk.conf
+
+# Remove the /dev/xconsole configuration as xconsole
+# is not available by default
+l=`awk '/=warn.*\|.*\/dev\/xconsole/{print NR - 1}' /etc/rsyslog.d/50-default.conf`
+if [ ! -z $l ]; then
+ l=`expr $l + 1`
+ line=`cat /etc/rsyslog.d/50-default.conf | head -n $l | tail -1`
+ if [[ ! $line == \#* ]]; then
+ l0=`expr $l - 3`
+ sed -i -r -e "${l0},${l}s/^.{0}/&#/" /etc/rsyslog.d/50-default.conf
+ fi
+fi
+
+# Enable nodejs logs for rsyslog
+if ! grep -q nodeapp "/etc/rsyslog.conf"; then
+ sed -i 's/\$PrivDropToGroup\ syslog/\$PrivDropToGroup adm/' /etc/rsyslog.conf
+ echo "\$ModLoad imfile.so
+\$InputFileName /var/log/nodeapp.log
+\$InputFileTag paypal_pizza:
+\$InputFileStateFile stat-nodeapp
+\$InputRunFileMonitor
+\$InputFilePollInterval 1" >> /etc/rsyslog.conf
+fi
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/create.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/create.sh
new file mode 100644
index 0000000..affdd6e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/create.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# This script installs rsyslog and the library for RELP
+
+apt-get update
+apt-get install -y rsyslog rsyslog-relp
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/start.sh
new file mode 100644
index 0000000..3de82d1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/rsyslog/start.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# This script starts rsyslogd as a service in init.d
+service rsyslog stop
+service rsyslog start
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_install.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_install.sh
new file mode 100644
index 0000000..4ca9b4e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_install.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+#This script installs apache web server
+
+apt-get update
+apt-get install -y apache2 \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_start.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_start.sh
new file mode 100644
index 0000000..e962ca5
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/webserver/webserver_start.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+service apache2 start \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_configure.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_configure.sh
new file mode 100644
index 0000000..5598b4f
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_configure.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+ln -s /usr/share/wordpress /var/www/html/wordpress
+gzip -d /usr/share/doc/wordpress/examples/setup-mysql.gz
+echo $wp_db_password | bash /usr/share/doc/wordpress/examples/setup-mysql -e $wp_db_name -u $wp_db_user localhost \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_install.sh b/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_install.sh
new file mode 100644
index 0000000..1320443
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/artifacts/wordpress/wordpress_install.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+#This script installs wordpress
+
+apt-get update
+apt-get install -y wordpress \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_elk.zip b/tosca2heat/heat-translator/translator/tests/data/csar_elk.zip
new file mode 100644
index 0000000..5fae801
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_elk.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_hello_world.zip b/tosca2heat/heat-translator/translator/tests/data/csar_hello_world.zip
new file mode 100644
index 0000000..43ffbbc
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_hello_world.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_metadata_not_yaml.zip b/tosca2heat/heat-translator/translator/tests/data/csar_metadata_not_yaml.zip
new file mode 100644
index 0000000..3e6120b
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_metadata_not_yaml.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_not_zip.zip b/tosca2heat/heat-translator/translator/tests/data/csar_not_zip.zip
new file mode 100644
index 0000000..43b7f5f
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_not_zip.zip
@@ -0,0 +1 @@
+This is an invalid CSAR file. \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_single_instance_wordpress.zip b/tosca2heat/heat-translator/translator/tests/data/csar_single_instance_wordpress.zip
new file mode 100644
index 0000000..17e655e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_single_instance_wordpress.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_import_path.zip b/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_import_path.zip
new file mode 100644
index 0000000..9dc6c9a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_import_path.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_script_url.zip b/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_script_url.zip
new file mode 100644
index 0000000..6014f92
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_wordpress_invalid_script_url.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/csar_wrong_metadata_file.zip b/tosca2heat/heat-translator/translator/tests/data/csar_wrong_metadata_file.zip
new file mode 100644
index 0000000..85d660a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/csar_wrong_metadata_file.zip
Binary files differ
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/collectd.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/collectd.yaml
new file mode 100644
index 0000000..1ac0935
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/collectd.yaml
@@ -0,0 +1,13 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ collectd is a daemon which gathers statistics about the system it is running on.
+
+node_types:
+ tosca.nodes.SoftwareComponent.Collectd:
+ derived_from: tosca.nodes.SoftwareComponent
+ requirements:
+ - log_endpoint:
+ capability: tosca.capabilities.Endpoint
+ node: tosca.nodes.SoftwareComponent.Logstash
+ relationship: tosca.relationships.ConnectsTo \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/elasticsearch.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/elasticsearch.yaml
new file mode 100644
index 0000000..b140a32
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/elasticsearch.yaml
@@ -0,0 +1,12 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Elasticsearch is an open-source search engine built on top of Apache Lucene,
+ a full-text search-engine library.
+
+node_types:
+ tosca.nodes.SoftwareComponent.Elasticsearch:
+ derived_from: tosca.nodes.SoftwareComponent
+ capabilities:
+ search_endpoint:
+ type: tosca.capabilities.Endpoint
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/kibana.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/kibana.yaml
new file mode 100644
index 0000000..5701e69
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/kibana.yaml
@@ -0,0 +1,14 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Kibana is an open source analytics and visualization platform designed to work with Elasticsearch.
+ You use Kibana to search, view, and interact with data stored in Elasticsearch.
+
+node_types:
+ tosca.nodes.SoftwareComponent.Kibana:
+ derived_from: tosca.nodes.SoftwareComponent
+ requirements:
+ - search_endpoint:
+ capability: tosca.capabilities.Endpoint
+ node: tosca.nodes.SoftwareComponent.Elasticsearch
+ relationship: tosca.relationships.ConnectsTo
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/logstash.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/logstash.yaml
new file mode 100644
index 0000000..cf60521
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/logstash.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Logstash is a tool for receiving, processing and outputting logs. All kinds
+ of logs. System logs, webserver logs, error logs, application logs, and just
+ about anything you can throw at it.
+
+node_types:
+ tosca.nodes.SoftwareComponent.Logstash:
+ derived_from: tosca.nodes.SoftwareComponent
+ requirements:
+ - search_endpoint:
+ capability: tosca.capabilities.Endpoint
+ node: tosca.nodes.SoftwareComponent.Elasticsearch
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ interfaces:
+ Configure:
+ pre_configure_source:
+ inputs:
+ elasticsearch_ip:
+ type: string
+ capabilities:
+ log_endpoint:
+ type: tosca.capabilities.Endpoint
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/paypalpizzastore_nodejs_app.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/paypalpizzastore_nodejs_app.yaml
new file mode 100644
index 0000000..d62c4c1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/paypalpizzastore_nodejs_app.yaml
@@ -0,0 +1,29 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Pizza store app that allows you to explore the features provided by PayPal's REST APIs.
+ More detail can be found at https://github.com/paypal/rest-api-sample-app-nodejs/
+
+node_types:
+ tosca.nodes.WebApplication.PayPalPizzaStore:
+ derived_from: tosca.nodes.WebApplication
+ properties:
+ github_url:
+ required: no
+ type: string
+ description: location of the application on the github.
+ default: https://github.com/sample.git
+ requirements:
+ #WebApplication inherits Computer, so host implied.
+ - database_connection:
+ capability: tosca.capabilities.Endpoint.Database
+ node: tosca.nodes.Database
+ relationship: tosca.relationships.ConnectsTo
+ interfaces:
+ Standard:
+ configure:
+ inputs:
+ github_url:
+ type: string
+ mongodb_ip:
+ type: string
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/rsyslog.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/rsyslog.yaml
new file mode 100644
index 0000000..4614ee7
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/rsyslog.yaml
@@ -0,0 +1,13 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ RSYSLOG is the Rocket-fast SYStem for LOG processing.
+
+node_types:
+ tosca.nodes.SoftwareComponent.Rsyslog:
+ derived_from: tosca.nodes.SoftwareComponent
+ requirements:
+ - log_endpoint:
+ capability: tosca.capabilities.Endpoint
+ node: tosca.nodes.SoftwareComponent.Logstash
+ relationship: tosca.relationships.ConnectsTo
diff --git a/tosca2heat/heat-translator/translator/tests/data/custom_types/wordpress.yaml b/tosca2heat/heat-translator/translator/tests/data/custom_types/wordpress.yaml
new file mode 100644
index 0000000..5899ed9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/custom_types/wordpress.yaml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+node_types:
+ tosca.nodes.WebApplication.WordPress:
+ derived_from: tosca.nodes.WebApplication
+ requirements:
+ - database_endpoint:
+ capability: tosca.capabilities.Endpoint.Database
+ node: tosca.nodes.Database
+ relationship: tosca.relationships.ConnectsTo
+ interfaces:
+ Standard:
+ inputs:
+ wp_db_name:
+ type: string
+ wp_db_user:
+ type: string
+ wp_db_password:
+ type: string
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
new file mode 100644
index 0000000..7284116
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_artifact.yaml
@@ -0,0 +1,30 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA template to test artifact usage
+
+parameters: {}
+resources:
+ customwebserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: customwebserver_create_config
+ input_values:
+ content:
+ get_file: http://www.mycompany.org/content.tgz
+ server:
+ get_resource: server
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ customwebserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: install.sh
+ group: script
+outputs: {}
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
new file mode 100644
index 0000000..9f722cc
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type.yaml
@@ -0,0 +1,34 @@
+
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA template to test custom type with an interface defined on it
+
+parameters:
+ install_path:
+ type: string
+ default: /home/custom/other
+resources:
+ customwebserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: customwebserver_create_config
+ input_values:
+ path:
+ get_param: install_path
+ server:
+ get_resource: server
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ customwebserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: install.sh
+ group: script
+outputs: {}
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
new file mode 100644
index 0000000..24a2893
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_override.yaml
@@ -0,0 +1,34 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA template to test custom type with an interface defined on it,
+ and an interface overriding the type's one on the template itself
+
+parameters:
+ install_path:
+ type: string
+ default: /home/custom/other
+resources:
+ customwebserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: customwebserver_create_config
+ input_values:
+ path:
+ get_param: install_path
+ server:
+ get_resource: server
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ customwebserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: install_override.sh
+ group: script
+outputs: {}
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
new file mode 100644
index 0000000..b166d7c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_custom_type_with_param_override.yaml
@@ -0,0 +1,34 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA template to test custom type with an interface defined on it,
+ and an interface overriding the type's one on the template itself
+
+parameters:
+ install_path:
+ type: string
+ default: /home/custom/from/cli
+resources:
+ customwebserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: customwebserver_create_config
+ input_values:
+ path:
+ get_param: install_path
+ server:
+ get_resource: server
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+ customwebserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: install_override.sh
+ group: script
+outputs: {} \ No newline at end of file
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
new file mode 100644
index 0000000..a298745
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk.yaml
@@ -0,0 +1,551 @@
+heat_template_version: 2013-05-23
+
+description: >
+ This TOSCA simple profile deploys nodejs, mongodb, elasticsearch, logstash and
+ kibana each on a separate server with monitoring enabled for nodejs server where
+ a sample nodejs application is running. The rsyslog and collectd are installed
+ on a nodejs server.
+
+parameters:
+ github_url:
+ type: string
+ description: The URL to download nodejs.
+ default: http://github.com/paypal/rest-api-sample-app-nodejs.git
+
+ my_cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 4
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+
+ nodejs_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: nodejs_create_config
+ server:
+ get_resource: app_server
+
+ nodejs_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/create.sh
+ group: script
+
+ paypal_pizzastore_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_configure_config
+ input_values:
+ github_url:
+ get_param: github_url
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - nodejs_create_deploy
+ - mongo_db_create_deploy
+
+ paypal_pizzastore_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/config.sh
+ group: script
+
+ paypal_pizzastore_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - paypal_pizzastore_configure_deploy
+
+ paypal_pizzastore_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/start.sh
+ group: script
+
+
+ mongo_dbms_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_create_config
+ server:
+ get_resource: mongo_server
+
+ mongo_dbms_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/create.sh
+ group: script
+
+ mongo_dbms_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_configure_config
+ input_values:
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_create_deploy
+
+ mongo_dbms_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/config.sh
+ group: script
+
+ mongo_dbms_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_start_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_configure_deploy
+
+ mongo_dbms_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/start.sh
+ group: script
+
+ mongo_db_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_db_create_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_start_deploy
+
+ mongo_db_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/create_database.sh
+ group: script
+
+
+ app_collectd_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_create_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - logstash_start_deploy
+
+ app_collectd_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/create.sh
+ group: script
+
+ app_collectd_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_configure_config
+ input_values:
+ logstash_ip:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_create_deploy
+
+ app_collectd_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/config.py
+ group: script
+
+ app_collectd_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_configure_deploy
+
+ app_collectd_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/start.sh
+ group: script
+
+ app_collectd_logstash_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_logstash_connect_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ app_collectd_logstash_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/configure_collectd.py
+ group: script
+
+
+ app_rsyslog_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_create_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - logstash_start_deploy
+
+ app_rsyslog_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: rsyslog/create.sh
+ group: script
+
+ app_rsyslog_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_rsyslog_configure_deploy
+
+ app_rsyslog_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: rsyslog/start.sh
+ group: script
+
+ app_rsyslog_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_configure_config
+ input_values:
+ logstash_ip:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_rsyslog_create_deploy
+
+ app_rsyslog_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: rsyslog/config.sh
+ group: script
+
+ app_rsyslog_logstash_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_logstash_connect_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ app_rsyslog_logstash_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/configure_rsyslog.py
+ group: script
+
+
+ logstash_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_create_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - elasticsearch_start_deploy
+
+ logstash_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/create.sh
+ group: script
+
+ logstash_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_start_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ logstash_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/start.sh
+ group: script
+
+ logstash_elasticsearch_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_elasticsearch_connect_config
+ input_values:
+ elasticsearch_ip:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ logstash_elasticsearch_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/configure_elasticsearch.py
+ group: script
+
+
+ elasticsearch_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: elasticsearch_create_config
+ server:
+ get_resource: elasticsearch_server
+
+ elasticsearch_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: elasticsearch/create.sh
+ group: script
+
+ elasticsearch_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: elasticsearch_start_config
+ server:
+ get_resource: elasticsearch_server
+ depends_on:
+ - elasticsearch_create_deploy
+
+ elasticsearch_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: elasticsearch/start.sh
+ group: script
+
+
+ kibana_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_create_config
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - elasticsearch_start_deploy
+
+ kibana_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: kibana/create.sh
+ group: script
+
+ kibana_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_configure_config
+ input_values:
+ elasticsearch_ip:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+ kibana_ip:
+ get_attr:
+ - kibana_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - kibana_create_deploy
+
+ kibana_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: kibana/config.sh
+ group: script
+
+ kibana_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_start_config
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - kibana_configure_deploy
+
+ kibana_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: kibana/start.sh
+ group: script
+
+
+ app_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ mongo_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ logstash_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ elasticsearch_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ kibana_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ nodejs_url:
+ description: URL for the nodejs server, http://<IP>:3000
+ value:
+ get_attr:
+ - app_server
+ - networks
+ - private
+ - 0
+
+ mongodb_url:
+ description: URL for the mongodb server.
+ value:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+
+ logstash_url:
+ description: URL for the logstash server.
+ value:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+
+ elasticsearch_url:
+ description: URL for the elasticsearch server.
+ value:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+
+ kibana_url:
+ description: URL for the kibana server.
+ value:
+ get_attr:
+ - kibana_server
+ - networks
+ - private
+ - 0
+
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
new file mode 100644
index 0000000..5eb1701
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_elk_from_csar.yaml
@@ -0,0 +1,551 @@
+heat_template_version: 2013-05-23
+
+description: >
+ This TOSCA simple profile deploys nodejs, mongodb, elasticsearch, logstash and
+ kibana each on a separate server with monitoring enabled for nodejs server where
+ a sample nodejs application is running. The rsyslog and collectd are installed
+ on a nodejs server.
+
+parameters:
+ github_url:
+ type: string
+ description: The URL to download nodejs.
+ default: http://github.com/paypal/rest-api-sample-app-nodejs.git
+
+ my_cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 4
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+
+ nodejs_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: nodejs_create_config
+ server:
+ get_resource: app_server
+
+ nodejs_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/nodejs/create.sh
+ group: script
+
+ paypal_pizzastore_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_configure_config
+ input_values:
+ github_url:
+ get_param: github_url
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - nodejs_create_deploy
+ - mongo_db_create_deploy
+
+ paypal_pizzastore_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/nodejs/config.sh
+ group: script
+
+ paypal_pizzastore_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - paypal_pizzastore_configure_deploy
+
+ paypal_pizzastore_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/nodejs/start.sh
+ group: script
+
+
+ mongo_dbms_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_create_config
+ server:
+ get_resource: mongo_server
+
+ mongo_dbms_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/mongodb/create.sh
+ group: script
+
+ mongo_dbms_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_configure_config
+ input_values:
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_create_deploy
+
+ mongo_dbms_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/mongodb/config.sh
+ group: script
+
+ mongo_dbms_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_start_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_configure_deploy
+
+ mongo_dbms_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/mongodb/start.sh
+ group: script
+
+ mongo_db_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_db_create_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_start_deploy
+
+ mongo_db_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/mongodb/create_database.sh
+ group: script
+
+
+ app_collectd_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_create_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - logstash_start_deploy
+
+ app_collectd_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/collectd/create.sh
+ group: script
+
+ app_collectd_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_configure_config
+ input_values:
+ logstash_ip:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_create_deploy
+
+ app_collectd_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Python/collectd/config.py
+ group: script
+
+ app_collectd_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_configure_deploy
+
+ app_collectd_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/collectd/start.sh
+ group: script
+
+ app_collectd_logstash_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_logstash_connect_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ app_collectd_logstash_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Python/logstash/configure_collectd.py
+ group: script
+
+
+ app_rsyslog_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_create_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - logstash_start_deploy
+
+ app_rsyslog_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/rsyslog/create.sh
+ group: script
+
+ app_rsyslog_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_rsyslog_configure_deploy
+
+ app_rsyslog_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/rsyslog/start.sh
+ group: script
+
+ app_rsyslog_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_configure_config
+ input_values:
+ logstash_ip:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_rsyslog_create_deploy
+
+ app_rsyslog_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/rsyslog/config.sh
+ group: script
+
+ app_rsyslog_logstash_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_rsyslog_logstash_connect_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ app_rsyslog_logstash_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Python/logstash/configure_rsyslog.py
+ group: script
+
+
+ logstash_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_create_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - elasticsearch_start_deploy
+
+ logstash_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/logstash/create.sh
+ group: script
+
+ logstash_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_start_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ logstash_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/logstash/start.sh
+ group: script
+
+ logstash_elasticsearch_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_elasticsearch_connect_config
+ input_values:
+ elasticsearch_ip:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ logstash_elasticsearch_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Python/logstash/configure_elasticsearch.py
+ group: script
+
+
+ elasticsearch_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: elasticsearch_create_config
+ server:
+ get_resource: elasticsearch_server
+
+ elasticsearch_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/elasticsearch/create.sh
+ group: script
+
+ elasticsearch_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: elasticsearch_start_config
+ server:
+ get_resource: elasticsearch_server
+ depends_on:
+ - elasticsearch_create_deploy
+
+ elasticsearch_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/elasticsearch/start.sh
+ group: script
+
+
+ kibana_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_create_config
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - elasticsearch_start_deploy
+
+ kibana_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/kibana/create.sh
+ group: script
+
+ kibana_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_configure_config
+ input_values:
+ elasticsearch_ip:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+ kibana_ip:
+ get_attr:
+ - kibana_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - kibana_create_deploy
+
+ kibana_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/kibana/config.sh
+ group: script
+
+ kibana_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: kibana_start_config
+ server:
+ get_resource: kibana_server
+ depends_on:
+ - kibana_configure_deploy
+
+ kibana_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/kibana/start.sh
+ group: script
+
+
+ app_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ mongo_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ logstash_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ elasticsearch_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ kibana_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ nodejs_url:
+ description: URL for the nodejs server, http://<IP>:3000
+ value:
+ get_attr:
+ - app_server
+ - networks
+ - private
+ - 0
+
+ mongodb_url:
+ description: URL for the mongodb server.
+ value:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+
+ logstash_url:
+ description: URL for the logstash server.
+ value:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+
+ elasticsearch_url:
+ description: URL for the elasticsearch server.
+ value:
+ get_attr:
+ - elasticsearch_server
+ - networks
+ - private
+ - 0
+
+ kibana_url:
+ description: URL for the kibana server.
+ value:
+ get_attr:
+ - kibana_server
+ - networks
+ - private
+ - 0
+
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
new file mode 100644
index 0000000..da8285e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image.yaml
@@ -0,0 +1,18 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying a server with custom properties for image, flavor and key_name.
+
+parameters:
+ key_name:
+ type: string
+ default: inputkey
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ key_name: {get_param: key_name}
+ user_data_format: SOFTWARE_CONFIG
+outputs: {}
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
new file mode 100644
index 0000000..679461c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_flavor_and_image_params.yaml
@@ -0,0 +1,18 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying a server with custom properties for image, flavor and key_name.
+
+parameters:
+ key_name:
+ type: string
+ default: paramkey
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ key_name: {get_param: key_name}
+ user_data_format: SOFTWARE_CONFIG
+outputs: {}
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
new file mode 100644
index 0000000..8cb4081
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world.yaml
@@ -0,0 +1,14 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying a single server with predefined properties.
+
+parameters: {}
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ user_data_format: SOFTWARE_CONFIG
+outputs: {}
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
new file mode 100644
index 0000000..e5fadb0
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_hello_world_userkey.yaml
@@ -0,0 +1,19 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying a single server with predefined properties.
+
+parameters:
+ key_name:
+ type: string
+ default: userkey
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ key_name: { get_param: key_name }
+ user_data_format: SOFTWARE_CONFIG
+outputs: {}
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
new file mode 100644
index 0000000..33f3059
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_host_assignment.yaml
@@ -0,0 +1,135 @@
+heat_template_version: 2013-05-23
+
+description: >
+ A template to test host assignment for translated hot resources.
+ It makes sure if a resource depends on multiple hosts only the
+ one with the "HostedOn" relationship is picked as the host. In
+ this template, the translated resource 'app_collectd_create_deploy'
+ would depend on 'logstash_server' and 'app_server'. But it would
+ have "HostedOn" relationship with 'app_server', and that server
+ would be its host.
+
+parameters: {}
+resources:
+ app_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ logstash_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ app_collectd_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/create.sh
+ group: script
+
+ app_collectd_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_create_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - logstash_start_deploy
+
+ app_collectd_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/config.py
+ group: script
+
+ app_collectd_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_configure_config
+ input_values:
+ logstash_ip:
+ get_attr:
+ - logstash_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_create_deploy
+
+ app_collectd_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: collectd/start.sh
+ group: script
+
+ app_collectd_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - app_collectd_configure_deploy
+
+ logstash_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/create.sh
+ group: script
+
+ logstash_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_create_config
+ server:
+ get_resource: logstash_server
+
+ logstash_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/start.sh
+ group: script
+
+ logstash_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: logstash_start_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+ app_collectd_logstash_connect_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: logstash/configure_collectd.py
+ group: script
+
+ app_collectd_logstash_connect_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: app_collectd_logstash_connect_config
+ server:
+ get_resource: logstash_server
+ depends_on:
+ - logstash_create_deploy
+
+outputs: {}
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml
new file mode 100644
index 0000000..2103d43
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nfv_sample.yaml
@@ -0,0 +1,35 @@
+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.medium
+ image: rhel-6.5-test-image
+ networks:
+ - port: { get_resource: CP1 }
+ user_data_format: SOFTWARE_CONFIG
+ CP1:
+ type: OS::Neutron::Port
+ properties:
+ fixed_ips:
+ - ip_address: '192.168.0.55'
+ network: { get_resource: VL1 }
+ VL1:
+ type: OS::Neutron::Net
+ VL1_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ ip_version: 4
+ allocation_pools:
+ - end: 192.168.0.200
+ start: 192.168.0.50
+ gateway_ip: 192.168.0.1
+ cidr: 192.168.0.0/24
+ network: { get_resource: VL1 }
+outputs: {}
+
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
new file mode 100644
index 0000000..b95120b
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_nodejs_mongodb_two_instances.yaml
@@ -0,0 +1,185 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with nodejs and mongodb.
+
+parameters:
+ github_url:
+ type: string
+ description: The URL to download nodejs.
+ default: http://github.com/paypal/rest-api-sample-app-nodejs.git
+
+ my_cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 4
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ mongo_dbms_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_create_config
+ server:
+ get_resource: mongo_server
+
+ mongo_dbms_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/create.sh
+ group: script
+
+ mongo_dbms_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_configure_config
+ input_values:
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_create_deploy
+
+ mongo_dbms_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/config.sh
+ group: script
+
+ mongo_dbms_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_dbms_start_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_configure_deploy
+
+ mongo_dbms_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/start.sh
+ group: script
+
+ mongo_db_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mongo_db_create_config
+ server:
+ get_resource: mongo_server
+ depends_on:
+ - mongo_dbms_start_deploy
+
+ mongo_db_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mongodb/create_database.sh
+ group: script
+
+ nodejs_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: nodejs_create_config
+ server:
+ get_resource: app_server
+
+ nodejs_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/create.sh
+ group: script
+
+ paypal_pizzastore_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_configure_config
+ input_values:
+ github_url: http://github.com/paypal/rest-api-sample-app-nodejs.git
+ mongodb_ip:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ server:
+ get_resource: app_server
+ depends_on:
+ - mongo_db_create_deploy
+ - nodejs_create_deploy
+
+ paypal_pizzastore_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/config.sh
+ group: script
+
+ paypal_pizzastore_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: paypal_pizzastore_start_config
+ server:
+ get_resource: app_server
+ depends_on:
+ - paypal_pizzastore_configure_deploy
+
+ paypal_pizzastore_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: nodejs/start.sh
+ group: script
+
+ mongo_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ app_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ mongodb_url:
+ description: URL for the mongodb server.
+ value:
+ get_attr:
+ - mongo_server
+ - networks
+ - private
+ - 0
+ nodejs_url:
+ description: URL for the nodejs server, http://<IP>:3000
+ value:
+ get_attr:
+ - app_server
+ - networks
+ - private
+ - 0
diff --git a/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml
new file mode 100644
index 0000000..c7cfa44
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_policies.yaml
@@ -0,0 +1,25 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Template for deploying the nodes based on given policies.
+
+parameters: {}
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ scheduler_hints:
+ group:
+ get_resource: my_compute_placement_policy
+ user_data_format: SOFTWARE_CONFIG
+ my_compute_placement_policy:
+ type: OS::Nova::ServerGroup
+ properties:
+ name: my_compute_placement_policy
+ policies:
+ - affinity
+
+outputs: {} \ No newline at end of file
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
new file mode 100644
index 0000000..8c10a93
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress.yaml
@@ -0,0 +1,209 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with wordpress, web server and mysql on the same server.
+
+parameters:
+ db_name:
+ type: string
+ description: The name of the database.
+ default: wordpress
+ db_user:
+ type: string
+ description: The user name of the DB user.
+ default: wp_user
+ db_pwd:
+ type: string
+ description: The WordPress database admin account password.
+ default: wp_pass
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 8
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ db_root_pwd:
+ type: string
+ description: Root password for MySQL.
+ default: passw0rd
+ db_port:
+ type: number
+ description: Port for the MySQL database.
+ default: 3366
+
+resources:
+
+ mysql_dbms_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mysql/mysql_dbms_install.sh
+ group: script
+
+ mysql_dbms_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_create_config
+ input_values:
+ db_root_password:
+ get_param: db_root_pwd
+ server:
+ get_resource: server
+
+ mysql_dbms_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mysql/mysql_dbms_start.sh
+ group: script
+
+ mysql_dbms_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_configure_deploy
+
+ mysql_dbms_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mysql/mysql_dbms_configure.sh
+ group: script
+
+ mysql_dbms_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_configure_config
+ input_values:
+ db_port: 3366
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_create_deploy
+
+ mysql_database_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: mysql/mysql_database_configure.sh
+ group: script
+
+ mysql_database_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_database_configure_config
+ input_values:
+ db_name:
+ get_param: db_name
+ db_password:
+ get_param: db_pwd
+ db_root_password:
+ get_param: db_root_pwd
+ db_user:
+ get_param: db_user
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_start_deploy
+
+ webserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: webserver/webserver_install.sh
+ group: script
+
+ webserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: webserver_create_config
+ server:
+ get_resource: server
+
+ webserver_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: webserver/webserver_start.sh
+ group: script
+
+ webserver_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: webserver_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - webserver_create_deploy
+
+ wordpress_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: wordpress/wordpress_install.sh
+ group: script
+
+ wordpress_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: wordpress_create_config
+ server:
+ get_resource: server
+ depends_on:
+ - webserver_start_deploy
+ - mysql_database_configure_deploy
+
+ wordpress_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: wordpress/wordpress_configure.sh
+ group: script
+
+ wordpress_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: wordpress_configure_config
+ input_values:
+ wp_db_name:
+ get_param: db_name
+ wp_db_password:
+ get_param: db_pwd
+ wp_db_user:
+ get_param: db_user
+ server:
+ get_resource: server
+ depends_on:
+ - wordpress_create_deploy
+
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.xlarge
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ website_url:
+ description: URL for Wordpress wiki.
+ value:
+ get_attr:
+ - server
+ - networks
+ - private
+ - 0
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
new file mode 100644
index 0000000..3598540
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_instance_wordpress_from_csar.yaml
@@ -0,0 +1,207 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with wordpress, web server and mysql on the same server.
+
+parameters:
+ db_name:
+ type: string
+ description: The name of the database.
+ default: wordpress
+ db_user:
+ type: string
+ description: The user name of the DB user.
+ default: wp_user
+ db_pwd:
+ type: string
+ description: The WordPress database admin account password.
+ default: wp_pass
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 8
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ db_root_pwd:
+ type: string
+ description: Root password for MySQL.
+ default: passw0rd
+ db_port:
+ type: number
+ description: Port for the MySQL database.
+ default: 3366
+
+resources:
+
+ mysql_dbms_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/MYSQLDBMS/install.sh
+ group: script
+
+ mysql_dbms_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_create_config
+ server:
+ get_resource: server
+
+ mysql_dbms_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/MYSQLDBMS/start.sh
+ group: script
+
+ mysql_dbms_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_configure_deploy
+
+ mysql_dbms_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/MYSQLDBMS/configure.sh
+ group: script
+
+ mysql_dbms_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_dbms_configure_config
+ input_values:
+ db_root_password:
+ get_param: db_root_pwd
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_create_deploy
+
+ mysql_database_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/MYSQLDatabase/configure.sh
+ group: script
+
+ mysql_database_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: mysql_database_configure_config
+ input_values:
+ db_name:
+ get_param: db_name
+ db_password:
+ get_param: db_pwd
+ db_root_password:
+ get_param: db_root_pwd
+ db_user:
+ get_param: db_user
+ server:
+ get_resource: server
+ depends_on:
+ - mysql_dbms_start_deploy
+
+ webserver_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/WebServer/install.sh
+ group: script
+
+ webserver_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: webserver_create_config
+ server:
+ get_resource: server
+
+ webserver_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/WebServer/start.sh
+ group: script
+
+ webserver_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: webserver_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - webserver_create_deploy
+
+ wordpress_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/WordPress/install.sh
+ group: script
+
+ wordpress_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: wordpress_create_config
+ server:
+ get_resource: server
+ depends_on:
+ - webserver_start_deploy
+ - mysql_database_configure_deploy
+
+ wordpress_configure_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: ../Scripts/WordPress/configure.sh
+ group: script
+
+ wordpress_configure_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: wordpress_configure_config
+ input_values:
+ wp_db_name:
+ get_param: db_name
+ wp_db_password:
+ get_param: db_pwd
+ wp_db_user:
+ get_param: db_user
+ server:
+ get_resource: server
+ depends_on:
+ - wordpress_create_deploy
+
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.xlarge
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ website_url:
+ description: IP address for Wordpress wiki.
+ value:
+ get_attr:
+ - server
+ - networks
+ - private
+ - 0
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
new file mode 100644
index 0000000..91491e3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_object_store.yaml
@@ -0,0 +1,21 @@
+heat_template_version: 2013-05-23
+
+description: >
+ Tosca template for creating an object storage service.
+
+parameters:
+ objectstore_name:
+ type: string
+ default: myobjstore
+
+resources:
+ obj_store_server:
+ type: OS::Swift::Container
+ properties:
+ X-Container-Meta:
+ Quota-Bytes: 1000000000
+ X-Container-Read: ".r:*"
+ name:
+ get_param: objectstore_name
+
+outputs: {}
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
new file mode 100644
index 0000000..5cffb43
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server.yaml
@@ -0,0 +1,36 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a
+ (guest) host Operating System from the Compute node's properties. Note, this
+ example does not include default values on inputs properties.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ private_ip:
+ description: The private IP address of the deployed server instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
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
new file mode 100644
index 0000000..1eb88a7
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_with_input.yaml
@@ -0,0 +1,36 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a
+ (guest) host Operating System from the Compute node's properties. Note, this
+ example includes default values on inputs properties.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ private_ip:
+ description: The private IP address of the deployed server instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
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
new file mode 100644
index 0000000..4e7e6b5
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_with_defaults_without_input.yaml
@@ -0,0 +1,36 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a
+ (guest) host Operating System from the Compute node's properties. Note, this
+ example includes default values on inputs properties.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 4
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.large
+ image: ubuntu-12.04-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+outputs:
+ private_ip:
+ description: The private IP address of the deployed server instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
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
new file mode 100644
index 0000000..d2828cf
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_single_server_without_tosca_os_version.yaml
@@ -0,0 +1,17 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a
+ flavor and host Operating System for the Compute node. Note, this is just a test
+ template showing Compute without optional 'version' property of OS capability.
+ In general, you should have version to narrow down your image selection.
+
+parameters: {}
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ user_data_format: SOFTWARE_CONFIG
+outputs: {}
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
new file mode 100644
index 0000000..b1bbe49
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_software_component.yaml
@@ -0,0 +1,58 @@
+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:
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ my_software_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: my_software_create_config
+ server:
+ get_resource: server
+
+ my_software_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: software_install.sh
+ group: script
+
+ my_software_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: my_software_start_config
+ server:
+ get_resource: server
+ 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
new file mode 100644
index 0000000..38f12e6
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/hot_web_application.yaml
@@ -0,0 +1,100 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a web application.
+
+parameters:
+ context_root:
+ type: string
+ description: Context root for installing the application.
+ default: my_web_app
+
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 2
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+
+resources:
+ server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: ubuntu-software-config-os-init
+ user_data_format: SOFTWARE_CONFIG
+
+ web_server_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: web_server_create_config
+ server:
+ get_resource: server
+
+ web_server_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: web_server_install.sh
+ group: script
+
+ web_server_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: web_server_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - web_server_create_deploy
+
+ web_server_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: web_server_start.sh
+ group: script
+
+ web_app_create_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: web_app_create_config
+ input_values:
+ context_root:
+ get_param: context_root
+ server:
+ get_resource: server
+ depends_on:
+ - web_server_start_deploy
+
+ web_app_create_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: web_app_install.sh
+ group: script
+
+ web_app_start_deploy:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: web_app_start_config
+ server:
+ get_resource: server
+ depends_on:
+ - web_app_create_deploy
+
+ web_app_start_config:
+ type: OS::Heat::SoftwareConfig
+ properties:
+ config:
+ get_file: web_app_start.sh
+ group: script
+
+outputs: {}
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
new file mode 100644
index 0000000..556dcf4
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_custom_network_nodes.yaml
@@ -0,0 +1,33 @@
+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.medium
+ image: rhel-6.5-test-image
+ networks:
+ - port: { get_resource: CP1 }
+ user_data_format: SOFTWARE_CONFIG
+ CP1:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: VL1 }
+ VL1:
+ type: OS::Neutron::Net
+ VL1_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ ip_version: 4
+ allocation_pools:
+ - end: 192.168.0.200
+ start: 192.168.0.50
+ gateway_ip: 192.168.0.1
+ cidr: 192.168.0.0/24
+ network: { get_resource: VL1 }
+outputs: {}
+
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
new file mode 100644
index 0000000..cfcd290
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_one_network.yaml
@@ -0,0 +1,44 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 1 server bound to a new network
+
+parameters:
+ network_name:
+ type: string
+ description: Network name
+ default: private_net
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: cirros-0.3.2-x86_64-uec
+ networks:
+ - port: { get_resource: my_port }
+ user_data_format: SOFTWARE_CONFIG
+
+ my_network:
+ type: OS::Neutron::Net
+ properties:
+ name:
+ get_param: network_name
+
+ my_network_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ allocation_pools:
+ - end: 192.168.0.200
+ start: 192.168.0.50
+ cidr: 192.168.0.0/24
+ gateway_ip: 192.168.0.1
+ ip_version: 4
+ network: { get_resource: my_network }
+
+ my_port:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network }
+
+outputs: {}
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
new file mode 100644
index 0000000..f8674e1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_one_server_three_networks.yaml
@@ -0,0 +1,71 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 1 server bound to 3 networks
+
+parameters: {}
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: cirros-0.3.2-x86_64-uec
+ networks:
+ - port: { get_resource: my_port1 }
+ - port: { get_resource: my_port2 }
+ - port: { get_resource: my_port3 }
+ user_data_format: SOFTWARE_CONFIG
+
+ my_network1:
+ type: OS::Neutron::Net
+ properties:
+ name: net1
+
+ my_network2:
+ type: OS::Neutron::Net
+ properties:
+ name: net2
+
+ my_network3:
+ type: OS::Neutron::Net
+ properties:
+ name: net3
+
+ my_network1_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ cidr: 192.168.1.0/24
+ ip_version: 4
+ network: { get_resource: my_network1 }
+
+ my_network2_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ cidr: 192.168.2.0/24
+ ip_version: 4
+ network: { get_resource: my_network2 }
+
+ my_network3_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ cidr: 192.168.3.0/24
+ ip_version: 4
+ network: { get_resource: my_network3 }
+
+ my_port1:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network1 }
+
+ my_port2:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network2 }
+
+ my_port3:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network3 }
+
+outputs: {}
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
new file mode 100644
index 0000000..b8282b5
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_server_on_existing_network.yaml
@@ -0,0 +1,27 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 1 server bound to an existing network
+
+parameters:
+ network_name:
+ type: string
+ description: Network name
+ default: private_net
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: cirros-0.3.2-x86_64-uec
+ networks:
+ - port: { get_resource: my_port }
+ user_data_format: SOFTWARE_CONFIG
+
+ my_port:
+ type: OS::Neutron::Port
+ properties:
+ network: {get_param: network_name}
+
+outputs: {}
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
new file mode 100644
index 0000000..21157bb
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/network/hot_two_servers_one_network.yaml
@@ -0,0 +1,72 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 2 servers bound to the 1 network
+
+parameters:
+ network_name:
+ type: string
+ description: Network name
+ default: my_private_net
+ network_cidr:
+ type: string
+ description: CIDR for the network
+ default: 10.0.0.0/24
+ network_start_ip:
+ type: string
+ description: Start IP for the allocation pool
+ default: 10.0.0.100
+ network_end_ip:
+ type: string
+ description: End IP for the allocation pool
+ default: 10.0.0.150
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: cirros-0.3.2-x86_64-uec
+ networks:
+ - port: { get_resource: my_port }
+ user_data_format: SOFTWARE_CONFIG
+
+ my_server2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: cirros-0.3.2-x86_64-uec
+ networks:
+ - port: { get_resource: my_port2 }
+ user_data_format: SOFTWARE_CONFIG
+
+ my_network:
+ type: OS::Neutron::Net
+ properties:
+ name:
+ get_param: network_name
+
+ my_network_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ allocation_pools:
+ - end:
+ get_param: network_end_ip
+ start:
+ get_param: network_start_ip
+ cidr:
+ get_param: network_cidr
+ ip_version: 4
+ network: { get_resource: my_network }
+
+ my_port:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network }
+
+ my_port2:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_resource: my_network }
+
+outputs: {}
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
new file mode 100644
index 0000000..5ff5382
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment.yaml
@@ -0,0 +1,71 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with server and attached block storage using the normative
+ AttachesTo Relationship Type.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 2
+ storage_snapshot_id:
+ type: string
+ description: "Optional identifier for an existing snapshot to use when creating storage."
+ default: ssid
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ attachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server
+ mountpoint:
+ get_param: storage_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..9ffaf23
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt1.yaml
@@ -0,0 +1,92 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a Single Block Storage node shared by 2-Tier
+ Application with custom AttachesTo Type and implied relationships.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ my_web_app_tier_1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ myattachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_1
+ mountpoint: /default_location
+ volume_id:
+ get_resource: my_storage
+
+ my_web_app_tier_2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ myattachesto_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_2
+ mountpoint: /some_other_data_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip_1:
+ description: The private IP address of the applications first tier.
+ value:
+ get_attr:
+ - my_web_app_tier_1
+ - networks
+ - private
+ - 0
+ private_ip_2:
+ description: The private IP address of the applications second tier.
+ value:
+ get_attr:
+ - my_web_app_tier_2
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..9b5e71c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation1_alt2.yaml
@@ -0,0 +1,92 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a Single Block Storage node shared by 2-Tier
+ Application with custom AttachesTo Type and implied relationships.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ my_web_app_tier_1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ myattachesto_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_1
+ mountpoint: /default_location
+ volume_id:
+ get_resource: my_storage
+
+ my_web_app_tier_2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ myattachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_2
+ mountpoint: /some_other_data_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip_1:
+ description: The private IP address of the applications first tier.
+ value:
+ get_attr:
+ - my_web_app_tier_1
+ - networks
+ - private
+ - 0
+ private_ip_2:
+ description: The private IP address of the applications second tier.
+ value:
+ get_attr:
+ - my_web_app_tier_2
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..1b4eb73
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt1.yaml
@@ -0,0 +1,96 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a single Block Storage node shared by 2-Tier
+ Application with custom AttachesTo Type and explicit Relationship Templates.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ my_web_app_tier_1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ storage_attachesto_1_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_1
+ mountpoint: /my_data_location
+ volume_id:
+ get_resource: my_storage
+
+ my_web_app_tier_2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ storage_attachesto_2_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_2
+ mountpoint: /some_other_data_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip_1:
+ description: The private IP address of the applications first tier.
+ value:
+ get_attr:
+ - my_web_app_tier_1
+ - networks
+ - private
+ - 0
+ private_ip_2:
+ description: The private IP address of the applications second tier.
+ value:
+ get_attr:
+ - my_web_app_tier_2
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..0311a55
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_attachment_notation2_alt2.yaml
@@ -0,0 +1,96 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with a single Block Storage node shared by 2-Tier
+ Application with custom AttachesTo Type and explicit Relationship Templates.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ my_web_app_tier_1:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ storage_attachesto_1_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_1
+ mountpoint: /my_data_location
+ volume_id:
+ get_resource: my_storage
+
+ my_web_app_tier_2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ storage_attachesto_2_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_web_app_tier_2
+ mountpoint: /some_other_data_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip_1:
+ description: The private IP address of the applications first tier.
+ value:
+ get_attr:
+ - my_web_app_tier_1
+ - networks
+ - private
+ - 0
+ private_ip_2:
+ description: The private IP address of the applications second tier.
+ value:
+ get_attr:
+ - my_web_app_tier_2
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..bce4603
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_custom_relationship_type.yaml
@@ -0,0 +1,72 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with server and attached block storage using a custom
+ AttachesTo Relationship Type.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ mycustomattachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server
+ volume_id:
+ get_resource: my_storage
+ mountpoint:
+ get_param: storage_location
+
+
+outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..e17dff9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_blockstorage_with_relationship_template.yaml
@@ -0,0 +1,65 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with server and attached block storage using a named
+ Relationship Template for the storage attachment.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.small
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+
+ storage_attachment_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server
+ mountpoint:
+ get_input: storage_location
+ volume_id:
+ get_resource: my_storage
+
+outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
+ volume_id:
+ description: The volume id of the block storage instance.
+ value:
+ get_resource: my_storage
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
new file mode 100644
index 0000000..55ada08
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt1.yaml
@@ -0,0 +1,109 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 2 servers each with different attached block storage.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ attachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server
+ mountpoint:
+ get_param: storage_location
+ volume_id:
+ get_resource: my_storage
+
+ my_server2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage2
+
+ my_storage2:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ attachesto_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server2
+ mountpoint:
+ get_param: storage_location
+ volume_id:
+ get_resource: my_storage2
+
+outputs:
+ server_ip_1:
+ description: The private IP address of the applications first server.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
+ server_ip_2:
+ description: The private IP address of the applications second server.
+ value:
+ get_attr:
+ - my_server2
+ - networks
+ - private
+ - 0
+ volume_id_1:
+ description: The volume id of the first block storage instance.
+ value:
+ get_resource: my_storage
+ volume_id_2:
+ description: The volume id of the second block storage instance.
+ value:
+ get_resource: my_storage2
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
new file mode 100644
index 0000000..3386d79
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/hot_output/storage/hot_multiple_blockstorage_with_attachment_alt2.yaml
@@ -0,0 +1,109 @@
+heat_template_version: 2013-05-23
+
+description: >
+ TOSCA simple profile with 2 servers each with different attached block storage.
+
+parameters:
+ cpus:
+ type: number
+ description: Number of CPUs for the server.
+ default: 1
+ constraints:
+ - allowed_values:
+ - 1
+ - 2
+ - 4
+ - 8
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+ default: /dev/vdc
+ storage_size:
+ type: number
+ description: Size of the storage to be created.
+ default: 1
+ storage_snapshot_id:
+ type: string
+ description: Optional identifier for an existing snapshot to use when creating storage.
+ default: ssid
+
+resources:
+ my_server:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage
+
+ my_storage:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ attachesto_2:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server
+ mountpoint:
+ get_param: storage_location
+ volume_id:
+ get_resource: my_storage
+
+ my_server2:
+ type: OS::Nova::Server
+ properties:
+ flavor: m1.medium
+ image: fedora-amd64-heat-config
+ user_data_format: SOFTWARE_CONFIG
+ depends_on:
+ - my_storage2
+
+ my_storage2:
+ type: OS::Cinder::Volume
+ properties:
+ size:
+ get_param: storage_size
+ snapshot_id:
+ get_param: storage_snapshot_id
+
+ attachesto_1:
+ type: OS::Cinder::VolumeAttachment
+ properties:
+ instance_uuid:
+ get_resource: my_server2
+ mountpoint:
+ get_param: storage_location
+ volume_id:
+ get_resource: my_storage2
+
+outputs:
+ server_ip_1:
+ description: The private IP address of the applications first server.
+ value:
+ get_attr:
+ - my_server
+ - networks
+ - private
+ - 0
+ server_ip_2:
+ description: The private IP address of the applications second server.
+ value:
+ get_attr:
+ - my_server2
+ - networks
+ - private
+ - 0
+ volume_id_1:
+ description: The volume id of the first block storage instance.
+ value:
+ get_resource: my_storage
+ volume_id_2:
+ description: The volume id of the second block storage instance.
+ value:
+ get_resource: my_storage2
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_defs.yaml b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_defs.yaml
new file mode 100644
index 0000000..552ae07
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_defs.yaml
@@ -0,0 +1,41 @@
+node_types:
+ tosca.nodes.vendor.VDU:
+ derived_from: tosca.nodes.Compute
+ capabilities:
+ virtualbinding:
+ type: tosca.capabilities.vendor.VendorBindable
+
+ tosca.nodes.vendor.CP:
+ derived_from: tosca.nodes.network.Port
+ requirements:
+ - virtualLink:
+ capability: tosca.capabilities.VendorLinkable
+ relationship: tosca.relationships.vendor.VendorLinksTo
+ node: tosca.nodes.vendor.VL
+ - virtualBinding:
+ capability: tosca.capabilities.vendor.VendorBindable
+ node: tosca.nodes.vendor.VDU
+ relationship: tosca.relationships.vendor.VendorBindsTo
+
+ tosca.nodes.vendor.VL:
+ derived_from: tosca.nodes.network.Network
+ capabilities:
+ virtual_linkable:
+ type: tosca.capabilities.vendor.VendorLinkable
+
+relationship_types:
+ tosca.relationships.vendor.VendorLinksTo:
+ derived_from: tosca.relationships.network.LinksTo
+ valid_target_types: [ tosca.capabilities.vendor.VendorLinkable ]
+
+ tosca.relationships.vendor.VendorBindsTo:
+ derived_from: tosca.relationships.network.BindsTo
+ valid_target_types: [ tosca.capabilities.vendor.VendorBindable ]
+
+capability_types:
+ tosca.capabilities.vendor.VendorLinkable:
+ derived_from: tosca.capabilities.network.Linkable
+
+ tosca.capabilities.vendor.VendorBindable:
+ derived_from: tosca.capabilities.network.Bindable
+
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_imports.yaml b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_imports.yaml
new file mode 100644
index 0000000..ea473b1
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_imports.yaml
@@ -0,0 +1,41 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+ - test_tosca_custom_network_nodes_defs.yaml
+
+topology_template:
+ node_templates:
+
+ VDU1:
+ type: tosca.nodes.vendor.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.vendor.CP
+ requirements:
+ - virtualLink:
+ node: VL1
+ - virtualBinding:
+ node: VDU1
+
+ VL1:
+ type: tosca.nodes.vendor.VL
+ properties:
+ cidr: '192.168.0.0/24'
+ start_ip: '192.168.0.50'
+ end_ip: '192.168.0.200'
+ gateway_ip: '192.168.0.1'
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_inline.yaml b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_inline.yaml
new file mode 100644
index 0000000..509aab4
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/test_tosca_custom_network_nodes_inline.yaml
@@ -0,0 +1,82 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+
+node_types:
+ tosca.nodes.vendor.VDU:
+ derived_from: tosca.nodes.Compute
+ capabilities:
+ virtualbinding:
+ type: tosca.capabilities.vendor.VendorBindable
+
+ tosca.nodes.vendor.CP:
+ derived_from: tosca.nodes.network.Port
+ requirements:
+ - virtualLink:
+ capability: tosca.capabilities.VendorLinkable
+ relationship: tosca.relationships.vendor.VendorLinksTo
+ node: tosca.nodes.vendor.VL
+ - virtualBinding:
+ capability: tosca.capabilities.vendor.VendorBindable
+ node: tosca.nodes.vendor.VDU
+ relationship: tosca.relationships.vendor.VendorBindsTo
+
+ tosca.nodes.vendor.VL:
+ derived_from: tosca.nodes.network.Network
+ capabilities:
+ virtual_linkable:
+ type: tosca.capabilities.vendor.VendorLinkable
+
+relationship_types:
+ tosca.relationships.vendor.VendorLinksTo:
+ derived_from: tosca.relationships.network.LinksTo
+ valid_target_types: [ tosca.capabilities.vendor.VendorLinkable ]
+
+ tosca.relationships.vendor.VendorBindsTo:
+ derived_from: tosca.relationships.network.BindsTo
+ valid_target_types: [ tosca.capabilities.vendor.VendorBindable ]
+
+capability_types:
+ tosca.capabilities.vendor.VendorLinkable:
+ derived_from: tosca.capabilities.network.Linkable
+
+ tosca.capabilities.vendor.VendorBindable:
+ derived_from: tosca.capabilities.network.Bindable
+
+topology_template:
+ node_templates:
+
+ VDU1:
+ type: tosca.nodes.vendor.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.vendor.CP
+ requirements:
+ - virtualLink:
+ node: VL1
+ relationship: tosca.relationships.vendor.VendorLinksTo
+ - virtualBinding:
+ node: VDU1
+ relationship: tosca.relationships.vendor.VendorBindsTo
+
+ VL1:
+ type: tosca.nodes.vendor.VL
+ properties:
+ cidr: '192.168.0.0/24'
+ start_ip: '192.168.0.50'
+ end_ip: '192.168.0.200'
+ gateway_ip: '192.168.0.1'
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_one_network.yaml b/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_one_network.yaml
new file mode 100644
index 0000000..8e58fa9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_one_network.yaml
@@ -0,0 +1,43 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with 1 server bound to a new network
+
+topology_template:
+
+ inputs:
+ network_name:
+ type: string
+ description: Network name
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 512 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: CirrOS
+ version: 0.3.2
+
+ my_network:
+ type: tosca.nodes.network.Network
+ properties:
+ network_name: { get_input: network_name }
+ ip_version: 4
+ cidr: '192.168.0.0/24'
+ start_ip: '192.168.0.50'
+ end_ip: '192.168.0.200'
+ gateway_ip: '192.168.0.1'
+
+ my_port:
+ type: tosca.nodes.network.Port
+ requirements:
+ - binding: my_server
+ - link: my_network
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_three_networks.yaml b/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_three_networks.yaml
new file mode 100644
index 0000000..d791b17
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/tosca_one_server_three_networks.yaml
@@ -0,0 +1,64 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with 1 server bound to 3 networks
+
+topology_template:
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 512 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: CirrOS
+ version: 0.3.2
+
+ my_network1:
+ type: tosca.nodes.network.Network
+ properties:
+ cidr: '192.168.1.0/24'
+ network_name: net1
+
+ my_network2:
+ type: tosca.nodes.network.Network
+ properties:
+ cidr: '192.168.2.0/24'
+ network_name: net2
+
+ my_network3:
+ type: tosca.nodes.network.Network
+ properties:
+ cidr: '192.168.3.0/24'
+ network_name: net3
+
+ my_port1:
+ type: tosca.nodes.network.Port
+ properties:
+ order: 0
+ requirements:
+ - binding: my_server
+ - link: my_network1
+
+ my_port2:
+ type: tosca.nodes.network.Port
+ properties:
+ order: 1
+ requirements:
+ - binding: my_server
+ - link: my_network2
+
+ my_port3:
+ type: tosca.nodes.network.Port
+ properties:
+ order: 2
+ requirements:
+ - binding: my_server
+ - link: my_network3
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/tosca_server_on_existing_network.yaml b/tosca2heat/heat-translator/translator/tests/data/network/tosca_server_on_existing_network.yaml
new file mode 100644
index 0000000..7fedc13
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/tosca_server_on_existing_network.yaml
@@ -0,0 +1,39 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with 1 server bound to an existing network
+
+topology_template:
+ inputs:
+ network_name:
+ type: string
+ description: Network name
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 512 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: CirrOS
+ version: 0.3.2
+
+ my_network:
+ type: tosca.nodes.network.Network
+ properties:
+ network_name: { get_input: network_name }
+
+ my_port:
+ type: tosca.nodes.network.Port
+ requirements:
+ - binding:
+ node: my_server
+ - link:
+ node: my_network
diff --git a/tosca2heat/heat-translator/translator/tests/data/network/tosca_two_servers_one_network.yaml b/tosca2heat/heat-translator/translator/tests/data/network/tosca_two_servers_one_network.yaml
new file mode 100644
index 0000000..1473a8d
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/network/tosca_two_servers_one_network.yaml
@@ -0,0 +1,79 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with 2 servers bound to the 1 network
+
+topology_template:
+
+ inputs:
+ network_name:
+ type: string
+ description: Network name
+ network_cidr:
+ type: string
+ default: 10.0.0.0/24
+ description: CIDR for the network
+ network_start_ip:
+ type: string
+ default: 10.0.0.100
+ description: Start IP for the allocation pool
+ network_end_ip:
+ type: string
+ default: 10.0.0.150
+ description: End IP for the allocation pool
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 512 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: CirrOS
+ version: 0.3.2
+
+ my_server2:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 512 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: CirrOS
+ version: 0.3.2
+
+ my_network:
+ type: tosca.nodes.network.Network
+ properties:
+ ip_version: 4
+ cidr: { get_input: network_cidr }
+ network_name: { get_input: network_name }
+ start_ip: { get_input: network_start_ip }
+ end_ip: { get_input: network_end_ip }
+
+ my_port:
+ type: tosca.nodes.network.Port
+ requirements:
+ - binding:
+ node: my_server
+ - link:
+ node: my_network
+
+ my_port2:
+ type: tosca.nodes.network.Port
+ requirements:
+ - binding:
+ node: my_server2
+ - link:
+ node: my_network
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment.yaml
new file mode 100644
index 0000000..460fa4c
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment.yaml
@@ -0,0 +1,61 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with server and attached block storage using the normative AttachesTo Relationship Type.
+
+topology_template:
+
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ description: Size of the storage to be created.
+ default: 1 GB
+ storage_snapshot_id:
+ type: string
+ description: >
+ Optional identifier for an existing snapshot to use when creating storage.
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 kB
+ os:
+ properties:
+ architecture: x86_64
+ type: linux
+ distribution: fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship:
+ type: AttachesTo
+ properties:
+ location: { get_input: storage_location }
+
+ my_storage:
+ type: BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value: { get_attribute: [my_server, private_address] }
+ volume_id:
+ description: The volume id of the block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation1.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation1.yaml
new file mode 100644
index 0000000..df22d72
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation1.yaml
@@ -0,0 +1,87 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with a Single Block Storage node shared by 2-Tier Application with custom AttachesTo Type and implied relationships.
+
+relationship_types:
+ MyAttachesTo:
+ derived_from: tosca.relationships.AttachesTo
+ properties:
+ location:
+ type: string
+ default: /default_location
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ default: 1 GB
+ description: Size of the storage to be created.
+ storage_snapshot_id:
+ type: string
+ description: >
+ Optional identifier for an existing snapshot to use when creating storage.
+
+ node_templates:
+ my_web_app_tier_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship: MyAttachesTo
+
+ my_web_app_tier_2:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship:
+ type: MyAttachesTo
+ properties:
+ location: /some_other_data_location
+
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ outputs:
+ private_ip_1:
+ description: The private IP address of the application's first tier.
+ value: { get_attribute: [my_web_app_tier_1, private_address] }
+ private_ip_2:
+ description: The private IP address of the application's second tier.
+ value: { get_attribute: [my_web_app_tier_2, private_address] }
+ volume_id:
+ description: The volume id of the block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation2.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation2.yaml
new file mode 100644
index 0000000..cb1c17a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_attachment_notation2.yaml
@@ -0,0 +1,99 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with a single Block Storage node shared by 2-Tier Application with custom AttachesTo Type and explicit Relationship Templates.
+
+relationship_types:
+ MyAttachesTo:
+ derived_from: tosca.relationships.AttachesTo
+ properties:
+ location:
+ type: string
+ default: /default_location
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ default: 1 GB
+ description: Size of the storage to be created.
+ storage_snapshot_id:
+ type: string
+ description: >
+ Optional identifier for an existing snapshot to use when creating storage.
+ storage_location:
+ type: string
+ description: >
+ Block storage mount point (filesystem path).
+
+ node_templates:
+
+ my_web_app_tier_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 kB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship: storage_attachesto_1
+
+ my_web_app_tier_2:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 kB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship: storage_attachesto_2
+
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ relationship_templates:
+ storage_attachesto_1:
+ type: MyAttachesTo
+ properties:
+ location: /my_data_location
+
+ storage_attachesto_2:
+ type: MyAttachesTo
+ properties:
+ location: /some_other_data_location
+ outputs:
+ private_ip_1:
+ description: The private IP address of the application's first tier.
+ value: { get_attribute: [my_web_app_tier_1, private_address] }
+ private_ip_2:
+ description: The private IP address of the application's second tier.
+ value: { get_attribute: [my_web_app_tier_2, private_address] }
+ volume_id:
+ description: The volume id of the block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_custom_relationship_type.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_custom_relationship_type.yaml
new file mode 100644
index 0000000..932f89e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_custom_relationship_type.yaml
@@ -0,0 +1,64 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with server and attached block storage using a custom AttachesTo Relationship Type.
+
+relationship_types:
+ MyCustomAttachesTo:
+ derived_from: AttachesTo
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ description: Size of the storage to be created.
+ default: 1 GB
+ storage_snapshot_id:
+ type: string
+ description: >
+ Optional identifier for an existing snapshot to use when creating storage.
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ # Declare custom AttachesTo type using the 'relationship' keyword
+ relationship:
+ type: MyCustomAttachesTo
+ properties:
+ location: { get_input: storage_location }
+ my_storage:
+ type: BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value: { get_attribute: [my_server, private_address] }
+ volume_id:
+ description: The volume id of the block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_relationship_template.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_relationship_template.yaml
new file mode 100644
index 0000000..c31a4da
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_blockstorage_with_relationship_template.yaml
@@ -0,0 +1,59 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with server and attached block storage using a named Relationship Template for the storage attachment.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ description: Size of the storage to be created.
+ default: 1 GB
+ storage_location:
+ type: string
+ description: Block storage mount point (filesystem path).
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ # Declare template to use with 'relationship' keyword
+ relationship: storage_attachment
+
+ my_storage:
+ type: BlockStorage
+ properties:
+ size: { get_input: storage_size }
+
+ relationship_templates:
+ storage_attachment:
+ type: AttachesTo
+ properties:
+ location: { get_input: storage_location }
+
+ outputs:
+ private_ip:
+ description: The private IP address of the newly created compute instance.
+ value: { get_attribute: [my_server, private_address] }
+ volume_id:
+ description: The volume id of the block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_multiple_blockstorage_with_attachment.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_multiple_blockstorage_with_attachment.yaml
new file mode 100644
index 0000000..aa4647e
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_multiple_blockstorage_with_attachment.yaml
@@ -0,0 +1,93 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with 2 servers each with different attached block storage.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ storage_size:
+ type: scalar-unit.size
+ default: 1 GB
+ description: Size of the storage to be created.
+ storage_snapshot_id:
+ type: string
+ description: >
+ Optional identifier for an existing snapshot to use when creating storage.
+ storage_location:
+ type: string
+ description: >
+ Block storage mount point (filesystem path).
+
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage
+ relationship:
+ type: AttachesTo
+ properties:
+ location: { get_input: storage_location }
+ my_storage:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ my_server2:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fedora
+ version: 18.0
+ requirements:
+ - local_storage:
+ node: my_storage2
+ relationship:
+ type: AttachesTo
+ properties:
+ location: { get_input: storage_location }
+ my_storage2:
+ type: tosca.nodes.BlockStorage
+ properties:
+ size: { get_input: storage_size }
+ snapshot_id: { get_input: storage_snapshot_id }
+
+ outputs:
+ server_ip_1:
+ description: The private IP address of the application's first server.
+ value: { get_attribute: [my_server, private_address] }
+ server_ip_2:
+ description: The private IP address of the application's second server.
+ value: { get_attribute: [my_server2, private_address] }
+ volume_id_1:
+ description: The volume id of the first block storage instance.
+ value: { get_attribute: [my_storage, volume_id] }
+ volume_id_2:
+ description: The volume id of the second block storage instance.
+ value: { get_attribute: [my_storage2, volume_id] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/storage/tosca_single_object_store.yaml b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_single_object_store.yaml
new file mode 100644
index 0000000..869af48
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/storage/tosca_single_object_store.yaml
@@ -0,0 +1,17 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ Tosca template for creating an object storage service.
+
+topology_template:
+ inputs:
+ objectstore_name:
+ type: string
+
+ node_templates:
+ obj_store_server:
+ type: tosca.nodes.ObjectStorage
+ properties:
+ name: { get_input: objectstore_name }
+ size: 1024 kB
+ maxsize: 1 GB
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_host_assignment.yaml b/tosca2heat/heat-translator/translator/tests/data/test_host_assignment.yaml
new file mode 100644
index 0000000..acffd24
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_host_assignment.yaml
@@ -0,0 +1,80 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ A template to test host assignment for translated hot resources.
+ It makes sure if a resource depends on multiple hosts only the
+ one with the "HostedOn" relationship is picked as the host. In
+ this template, the translated resource 'app_collectd_create_deploy'
+ would depend on 'logstash_server' and 'app_server'. But it would
+ have "HostedOn" relationship with 'app_server', and that server
+ would be its host.
+
+imports:
+ - custom_types/logstash.yaml
+ - custom_types/collectd.yaml
+ - custom_types/rsyslog.yaml
+ - custom_types/elasticsearch.yaml
+
+dsl_definitions:
+ host_capabilities: &host_capabilities
+ # compute properties (flavor)
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 4096 MB
+ os_capabilities: &os_capabilities
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+topology_template:
+ node_templates:
+ app_collectd:
+ type: tosca.nodes.SoftwareComponent.Collectd
+ requirements:
+ - host:
+ node: app_server
+ - log_endpoint:
+ node: logstash
+ capability: log_endpoint
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ interfaces:
+ Configure:
+ pre_configure_target:
+ implementation: logstash/configure_collectd.py
+ interfaces:
+ Standard:
+ create: collectd/create.sh
+ configure:
+ implementation: collectd/config.py
+ inputs:
+ logstash_ip: { get_attribute: [logstash_server, private_address] }
+ start: collectd/start.sh
+
+ logstash:
+ type: tosca.nodes.SoftwareComponent.Logstash
+ requirements:
+ - host:
+ node: logstash_server
+ interfaces:
+ Standard:
+ create: logstash/create.sh
+ start: logstash/start.sh
+
+ app_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ os:
+ properties: *os_capabilities
+ host:
+ properties: *host_capabilities
+
+ logstash_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ os:
+ properties: *os_capabilities
+ host:
+ properties: *host_capabilities
+
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_single_server_without_optional_version_prop.yaml b/tosca2heat/heat-translator/translator/tests/data/test_single_server_without_optional_version_prop.yaml
new file mode 100644
index 0000000..8cf5255
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_single_server_without_optional_version_prop.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a
+ flavor and host Operating System for the Compute node. Note, this is just a test
+ template showing Compute without optional 'version' property of OS capability. In
+ general, you should have version to narrow down your image selection.
+
+topology_template:
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 40 GB
+ num_cpus: 2
+ mem_size: 4 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml
new file mode 100644
index 0000000..be2caca
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_artifact.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: TOSCA template to test artifact usage
+
+node_types:
+ tosca.nodes.CustomWebServer:
+ derived_from: tosca.nodes.WebServer
+ artifacts:
+ web_content:
+ file: http://www.mycompany.org/content.tgz
+ type: tosca.artifacts.File
+ interfaces:
+ Standard:
+ create:
+ inputs:
+ content: { get_artifact: [ SELF, web_content ] }
+ implementation: install.sh
+
+topology_template:
+ node_templates:
+
+ customwebserver:
+ type: tosca.nodes.CustomWebServer
+ requirements:
+ - host: server
+
+ 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/test_tosca_custom_type.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type.yaml
new file mode 100644
index 0000000..c427ef0
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type.yaml
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: TOSCA template to test custom type with an interface defined on it
+
+node_types:
+ tosca.nodes.CustomWebServer:
+ derived_from: tosca.nodes.WebServer
+ properties:
+ custom_install_path:
+ type: string
+ default: /home/custom/custom
+ interfaces:
+ Standard:
+ create:
+ implementation: install.sh
+ inputs:
+ path: { get_property: [ SELF, custom_install_path ] }
+
+topology_template:
+ inputs:
+ install_path:
+ type: string
+ default: /home/custom/other
+
+ node_templates:
+
+ customwebserver:
+ type: tosca.nodes.CustomWebServer
+ requirements:
+ - host: server
+ properties:
+ custom_install_path : { get_input: install_path }
+
+ 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/test_tosca_custom_type_with_override.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type_with_override.yaml
new file mode 100644
index 0000000..d398c63
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_custom_type_with_override.yaml
@@ -0,0 +1,45 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA template to test custom type with an interface defined on it,
+ and an interface overriding the type's one on the template itself
+
+node_types:
+ tosca.nodes.CustomWebServer:
+ derived_from: tosca.nodes.WebServer
+ interfaces:
+ Standard:
+ create:
+ implementation: install.sh
+
+topology_template:
+ inputs:
+ install_path:
+ type: string
+ default: /home/custom/other
+
+ node_templates:
+ customwebserver:
+ type: tosca.nodes.CustomWebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: install_override.sh
+ inputs:
+ path: { get_input: install_path }
+
+ 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/test_tosca_flavor_and_image.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml
new file mode 100644
index 0000000..3247589
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_flavor_and_image.yaml
@@ -0,0 +1,29 @@
+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:
+ 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.nfv.VDU
+ properties:
+ flavor: m1.medium
+ image: rhel-6.5-test-image
+ key_name:
+ get_input: key_name
diff --git a/tosca2heat/heat-translator/translator/tests/data/test_tosca_nfv_sample.yaml b/tosca2heat/heat-translator/translator/tests/data/test_tosca_nfv_sample.yaml
new file mode 100644
index 0000000..1112234
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/test_tosca_nfv_sample.yaml
@@ -0,0 +1,43 @@
+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
+ 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
+
+ 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'
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_elk.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_elk.yaml
new file mode 100644
index 0000000..a074aa6
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_elk.yaml
@@ -0,0 +1,219 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ This TOSCA simple profile deploys nodejs, mongodb, elasticsearch, logstash
+ and kibana each on a separate server with monitoring enabled for nodejs
+ server where a sample nodejs application is running. The rsyslog and collectd
+ are installed on a nodejs server.
+
+imports:
+ - custom_types/paypalpizzastore_nodejs_app.yaml
+ - custom_types/elasticsearch.yaml
+ - custom_types/logstash.yaml
+ - custom_types/kibana.yaml
+ - custom_types/collectd.yaml
+ - custom_types/rsyslog.yaml
+
+dsl_definitions:
+ host_capabilities: &host_capabilities
+ disk_size: 10 GB
+ num_cpus: { get_input: my_cpus }
+ mem_size: 4096 MB
+ os_capabilities: &os_capabilities
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+topology_template:
+ inputs:
+ my_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ github_url:
+ type: string
+ description: The URL to download nodejs.
+ default: http://github.com/paypal/rest-api-sample-app-nodejs.git
+
+ node_templates:
+ paypal_pizzastore:
+ type: tosca.nodes.WebApplication.PayPalPizzaStore
+ properties:
+ github_url: { get_input: github_url }
+ requirements:
+ - host: nodejs
+ - database_connection: mongo_db
+ interfaces:
+ Standard:
+ configure:
+ implementation: nodejs/config.sh
+ inputs:
+ github_url: { get_property: [ SELF, github_url ] }
+ mongodb_ip: { get_attribute: [mongo_server, private_address] }
+ start: nodejs/start.sh
+ nodejs:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: app_server
+ interfaces:
+ Standard:
+ create: nodejs/create.sh
+ mongo_db:
+ type: tosca.nodes.Database
+ requirements:
+ - host: mongo_dbms
+ interfaces:
+ Standard:
+ create: mongodb/create_database.sh
+ mongo_dbms:
+ type: tosca.nodes.DBMS
+ requirements:
+ - host: mongo_server
+ interfaces:
+ Standard:
+ create: mongodb/create.sh
+ configure:
+ implementation: mongodb/config.sh
+ inputs:
+ mongodb_ip: { get_attribute: [mongo_server, private_address] }
+ start: mongodb/start.sh
+ elasticsearch:
+ type: tosca.nodes.SoftwareComponent.Elasticsearch
+ requirements:
+ - host: elasticsearch_server
+ interfaces:
+ Standard:
+ create: elasticsearch/create.sh
+ start: elasticsearch/start.sh
+ logstash:
+ type: tosca.nodes.SoftwareComponent.Logstash
+ requirements:
+ - host: logstash_server
+ - search_endpoint:
+ node: elasticsearch
+ capability: search_endpoint
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ interfaces:
+ Configure:
+ pre_configure_source:
+ implementation: logstash/configure_elasticsearch.py
+ inputs:
+ elasticsearch_ip: { get_attribute: [elasticsearch_server, private_address] }
+ interfaces:
+ Standard:
+ create: logstash/create.sh
+ start: logstash/start.sh
+ kibana:
+ type: tosca.nodes.SoftwareComponent.Kibana
+ requirements:
+ - host: kibana_server
+ - search_endpoint:
+ node: elasticsearch
+ capability: search_endpoint
+ interfaces:
+ Standard:
+ create: kibana/create.sh
+ configure:
+ implementation: kibana/config.sh
+ inputs:
+ elasticsearch_ip: { get_attribute: [elasticsearch_server, private_address] }
+ kibana_ip: { get_attribute: [kibana_server, private_address] }
+ start: kibana/start.sh
+ app_collectd:
+ type: tosca.nodes.SoftwareComponent.Collectd
+ requirements:
+ - host: app_server
+ - log_endpoint:
+ node: logstash
+ capability: log_endpoint
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ interfaces:
+ Configure:
+ pre_configure_target:
+ implementation: logstash/configure_collectd.py
+ interfaces:
+ Standard:
+ create: collectd/create.sh
+ configure:
+ implementation: collectd/config.py
+ inputs:
+ logstash_ip: { get_attribute: [logstash_server, private_address] }
+ start: collectd/start.sh
+ app_rsyslog:
+ type: tosca.nodes.SoftwareComponent.Rsyslog
+ requirements:
+ - host: app_server
+ - log_endpoint:
+ node: logstash
+ capability: log_endpoint
+ relationship:
+ type: tosca.relationships.ConnectsTo
+ interfaces:
+ Configure:
+ pre_configure_target:
+ implementation: logstash/configure_rsyslog.py
+ interfaces:
+ Standard:
+ create: rsyslog/create.sh
+ configure:
+ implementation: rsyslog/config.sh
+ inputs:
+ logstash_ip: { get_attribute: [logstash_server, private_address] }
+ start: rsyslog/start.sh
+ app_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+ mongo_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+ elasticsearch_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+ logstash_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+ kibana_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+
+ outputs:
+ nodejs_url:
+ description: URL for the nodejs server, http://<IP>:3000
+ value: { get_attribute: [ app_server, private_address ] }
+ mongodb_url:
+ description: URL for the mongodb server.
+ value: { get_attribute: [ mongo_server, private_address ] }
+ elasticsearch_url:
+ description: URL for the elasticsearch server.
+ value: { get_attribute: [ elasticsearch_server, private_address ] }
+ logstash_url:
+ description: URL for the logstash server.
+ value: { get_attribute: [ logstash_server, private_address ] }
+ kibana_url:
+ description: URL for the kibana server.
+ value: { get_attribute: [ kibana_server, private_address ] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld.yaml
new file mode 100644
index 0000000..5b913ff
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld.yaml
@@ -0,0 +1,23 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+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
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld_invalid.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld_invalid.yaml
new file mode 100644
index 0000000..ea60733
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_helloworld_invalid.yaml
@@ -0,0 +1,23 @@
+tosca_definitions: tosca_simple_yaml_1_0
+
+description: Template with invalid version and topology_template section.
+
+topology_template:
+ node_temp:
+ 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
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_nodejs_mongodb_two_instances.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_nodejs_mongodb_two_instances.yaml
new file mode 100644
index 0000000..f611071
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_nodejs_mongodb_two_instances.yaml
@@ -0,0 +1,96 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with nodejs and mongodb.
+
+imports:
+ - custom_types/paypalpizzastore_nodejs_app.yaml
+
+dsl_definitions:
+ host_capabilities: &host_capabilities
+ disk_size: 10 GB
+ num_cpus: 1
+ mem_size: 4096 MB
+ os_capabilities: &os_capabilities
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+topology_template:
+ inputs:
+ my_cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ github_url:
+ type: string
+ description: The URL to download nodejs.
+ default: http://github.com/paypal/rest-api-sample-app-nodejs.git
+
+ node_templates:
+ paypal_pizzastore:
+ type: tosca.nodes.WebApplication.PayPalPizzaStore
+ properties:
+ github_url: { get_input: github_url }
+ requirements:
+ - host: nodejs
+ - database_connection: mongo_db
+ interfaces:
+ Standard:
+ configure:
+ implementation: nodejs/config.sh
+ inputs:
+ github_url: http://github.com/paypal/rest-api-sample-app-nodejs.git
+ mongodb_ip: { get_attribute: [mongo_server, private_address] }
+ start: nodejs/start.sh
+ nodejs:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: app_server
+ interfaces:
+ Standard:
+ create: nodejs/create.sh
+ mongo_db:
+ type: tosca.nodes.Database
+ requirements:
+ - host: mongo_dbms
+ interfaces:
+ Standard:
+ create: mongodb/create_database.sh
+ mongo_dbms:
+ type: tosca.nodes.DBMS
+ requirements:
+ - host: mongo_server
+ interfaces:
+ Standard:
+ create: mongodb/create.sh
+ configure:
+ implementation: mongodb/config.sh
+ inputs:
+ mongodb_ip: { get_attribute: [mongo_server, private_address] }
+ start: mongodb/start.sh
+ mongo_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+ app_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties: *host_capabilities
+ os:
+ properties: *os_capabilities
+
+ outputs:
+ nodejs_url:
+ description: URL for the nodejs server, http://<IP>:3000
+ value: { get_attribute: [app_server, private_address] }
+ mongodb_url:
+ description: URL for the mongodb server.
+ value: { get_attribute: [mongo_server, private_address] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_policies.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_policies.yaml
new file mode 100644
index 0000000..26417d3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/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/tosca_single_instance_wordpress.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress.yaml
new file mode 100644
index 0000000..8c907db
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress.yaml
@@ -0,0 +1,120 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with wordpress, web server and mysql on the same server.
+
+imports:
+ - custom_types/wordpress.yaml
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ db_name:
+ type: string
+ description: The name of the database.
+ default: wordpress
+ db_user:
+ type: string
+ description: The user name of the DB user.
+ default: wp_user
+ db_pwd:
+ type: string
+ description: The WordPress database admin account password.
+ default: wp_pass
+ db_root_pwd:
+ type: string
+ description: Root password for MySQL.
+ db_port:
+ type: PortDef
+ description: Port for the MySQL database.
+ default: 3306
+
+ node_templates:
+ wordpress:
+ type: tosca.nodes.WebApplication.WordPress
+ requirements:
+ - host: webserver
+ - database_endpoint: mysql_database
+ interfaces:
+ Standard:
+ create: wordpress/wordpress_install.sh
+ configure:
+ implementation: wordpress/wordpress_configure.sh
+ inputs:
+ wp_db_name: { get_property: [ mysql_database, name ] }
+ wp_db_user: { get_property: [ mysql_database, user ] }
+ wp_db_password: { get_property: [ mysql_database, password ] }
+
+ mysql_database:
+ type: tosca.nodes.Database
+ properties:
+ name: { get_input: db_name }
+ user: { get_input: db_user }
+ password: { get_input: db_pwd }
+ capabilities:
+ database_endpoint:
+ properties:
+ port: { get_input: db_port }
+ requirements:
+ - host:
+ node: mysql_dbms
+ interfaces:
+ Standard:
+ configure:
+ implementation: mysql/mysql_database_configure.sh
+ inputs:
+ db_name: { get_property: [ SELF, name ] }
+ db_user: { get_property: [ SELF, user ] }
+ db_password: { get_property: [ SELF, password ] }
+ db_root_password: { get_property: [ mysql_dbms, root_password ] }
+ mysql_dbms:
+ type: tosca.nodes.DBMS
+ properties:
+ root_password: { get_input: db_root_pwd }
+ port: { get_input: db_port }
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: mysql/mysql_dbms_install.sh
+ inputs:
+ db_root_password: { get_property: [ SELF, root_password ] }
+ start: mysql/mysql_dbms_start.sh
+ configure:
+ implementation: mysql/mysql_dbms_configure.sh
+ inputs:
+ db_port: 3366
+
+ webserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create: webserver/webserver_install.sh
+ start: webserver/webserver_start.sh
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+ outputs:
+ website_url:
+ description: URL for Wordpress wiki.
+ value: { get_attribute: [server, private_address] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
new file mode 100644
index 0000000..af2e7a3
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
@@ -0,0 +1,125 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with wordpress, web server and mysql on the same server.
+ This template was added to test an 'invalid' scenario where the input template
+ to heat-translator is provided as a URL and that template is referencing an
+ import using an absolute path. The translation of this template would work
+ only if it is tried locally (not via a URL link but via a file system
+ reference) and the referenced import exists in the path below.
+
+imports:
+ - /tmp/wordpress.yaml
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ db_name:
+ type: string
+ description: The name of the database.
+ default: wordpress
+ db_user:
+ type: string
+ description: The user name of the DB user.
+ default: wp_user
+ db_pwd:
+ type: string
+ description: The WordPress database admin account password.
+ default: wp_pass
+ db_root_pwd:
+ type: string
+ description: Root password for MySQL.
+ db_port:
+ type: PortDef
+ description: Port for the MySQL database.
+ default: 3306
+
+ node_templates:
+ wordpress:
+ type: tosca.nodes.WebApplication.WordPress
+ requirements:
+ - host: webserver
+ - database_endpoint: mysql_database
+ interfaces:
+ Standard:
+ create: wordpress/wordpress_install.sh
+ configure:
+ implementation: wordpress/wordpress_configure.sh
+ inputs:
+ wp_db_name: { get_input: db_name }
+ wp_db_user: { get_input: db_user }
+ wp_db_password: { get_input: db_pwd }
+
+ mysql_database:
+ type: tosca.nodes.Database
+ properties:
+ name: { get_input: db_name }
+ user: { get_input: db_user }
+ password: { get_input: db_pwd }
+ capabilities:
+ database_endpoint:
+ properties:
+ port: { get_input: db_port }
+ requirements:
+ - host:
+ node: mysql_dbms
+ interfaces:
+ Standard:
+ configure:
+ implementation: mysql/mysql_database_configure.sh
+ inputs:
+ db_name: { get_input: db_name }
+ db_user: { get_input: db_user }
+ db_password: { get_input: db_pwd }
+ db_root_password: { get_input: db_root_pwd }
+ mysql_dbms:
+ type: tosca.nodes.DBMS
+ properties:
+ root_password: { get_input: db_root_pwd }
+ port: { get_input: db_port }
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: mysql/mysql_dbms_install.sh
+ inputs:
+ db_root_password: passw0rd
+ start: mysql/mysql_dbms_start.sh
+ configure:
+ implementation: mysql/mysql_dbms_configure.sh
+ inputs:
+ db_port: 3366
+
+ webserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create: webserver/webserver_install.sh
+ start: webserver/webserver_start.sh
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+ outputs:
+ website_url:
+ description: URL for Wordpress wiki.
+ value: { get_attribute: [server, private_address] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_url_import.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
new file mode 100644
index 0000000..69dbfeb
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
@@ -0,0 +1,120 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with wordpress, web server and mysql on the same server.
+
+imports:
+ - https://raw.githubusercontent.com/openstack/heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ db_name:
+ type: string
+ description: The name of the database.
+ default: wordpress
+ db_user:
+ type: string
+ description: The user name of the DB user.
+ default: wp_user
+ db_pwd:
+ type: string
+ description: The WordPress database admin account password.
+ default: wp_pass
+ db_root_pwd:
+ type: string
+ description: Root password for MySQL.
+ db_port:
+ type: PortDef
+ description: Port for the MySQL database.
+ default: 3306
+
+ node_templates:
+ wordpress:
+ type: tosca.nodes.WebApplication.WordPress
+ requirements:
+ - host: webserver
+ - database_endpoint: mysql_database
+ interfaces:
+ Standard:
+ create: wordpress/wordpress_install.sh
+ configure:
+ implementation: wordpress/wordpress_configure.sh
+ inputs:
+ wp_db_name: { get_property: [ mysql_database, name ] }
+ wp_db_user: { get_property: [ mysql_database, user ] }
+ wp_db_password: { get_property: [ mysql_database, password ] }
+
+ mysql_database:
+ type: tosca.nodes.Database
+ properties:
+ name: { get_input: db_name }
+ user: { get_input: db_user }
+ password: { get_input: db_pwd }
+ capabilities:
+ database_endpoint:
+ properties:
+ port: { get_input: db_port }
+ requirements:
+ - host:
+ node: mysql_dbms
+ interfaces:
+ Standard:
+ configure:
+ implementation: mysql/mysql_database_configure.sh
+ inputs:
+ db_name: { get_property: [ SELF, name ] }
+ db_user: { get_property: [ SELF, user ] }
+ db_password: { get_property: [ SELF, password ] }
+ db_root_password: { get_property: [ mysql_dbms, root_password ] }
+ mysql_dbms:
+ type: tosca.nodes.DBMS
+ properties:
+ root_password: { get_input: db_root_pwd }
+ port: { get_input: db_port }
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create:
+ implementation: mysql/mysql_dbms_install.sh
+ inputs:
+ db_root_password: { get_property: [ SELF, root_password ] }
+ start: mysql/mysql_dbms_start.sh
+ configure:
+ implementation: mysql/mysql_dbms_configure.sh
+ inputs:
+ db_port: 3366
+
+ webserver:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create: webserver/webserver_install.sh
+ start: webserver/webserver_start.sh
+ server:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4096 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Ubuntu
+ version: 14.04
+
+ outputs:
+ website_url:
+ description: URL for Wordpress wiki.
+ value: { get_attribute: [server, private_address] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_single_server.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_single_server.yaml
new file mode 100644
index 0000000..67a0161
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_single_server.yaml
@@ -0,0 +1,32 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and selects a (guest) host Operating System from the Compute node's properties. Note, this example does not include default values on inputs properties.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: ubuntu
+ version: 12.04
+ outputs:
+ private_ip:
+ description: The private IP address of the deployed server instance.
+ value: { get_attribute: [my_server, private_address] }
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_single_server_with_defaults.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_single_server_with_defaults.yaml
new file mode 100644
index 0000000..68933e2
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_single_server_with_defaults.yaml
@@ -0,0 +1,35 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile that just defines a single compute instance and
+ selects a (guest) host Operating System from the Compute node's properties.
+ Note, this example includes default values on inputs properties.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 4
+
+ node_templates:
+ my_server:
+ type: Compute
+ capabilities:
+ host:
+ properties:
+ disk_size: 10 GB
+ num_cpus: { get_input: cpus }
+ mem_size: 4 MB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: ubuntu
+ version: 12.04
+ outputs:
+ private_ip:
+ description: The private IP address of the deployed server instance.
+ value: { get_attribute: [my_server, private_address] } \ No newline at end of file
diff --git a/tosca2heat/heat-translator/translator/tests/data/tosca_software_component.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_software_component.yaml
new file mode 100644
index 0000000..88186a5
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_software_component.yaml
@@ -0,0 +1,40 @@
+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: server
+ interfaces:
+ Standard:
+ create: software_install.sh
+ start: software_start.sh
+
+ server:
+ 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/tosca_web_application.yaml b/tosca2heat/heat-translator/translator/tests/data/tosca_web_application.yaml
new file mode 100644
index 0000000..d5ab038
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/data/tosca_web_application.yaml
@@ -0,0 +1,56 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+ TOSCA simple profile with a web application.
+
+topology_template:
+ inputs:
+ cpus:
+ type: integer
+ description: Number of CPUs for the server.
+ constraints:
+ - valid_values: [ 1, 2, 4, 8 ]
+ default: 1
+ context_root:
+ type: string
+ description: Context root for installing the application.
+ default: app
+
+ node_templates:
+ web_app:
+ type: tosca.nodes.WebApplication
+ properties:
+ context_root: { get_input: context_root }
+ requirements:
+ - host: web_server
+ interfaces:
+ Standard:
+ create:
+ implementation: web_app_install.sh
+ inputs:
+ context_root: { get_input: context_root }
+ start: web_app_start.sh
+
+ web_server:
+ type: tosca.nodes.WebServer
+ requirements:
+ - host: server
+ interfaces:
+ Standard:
+ create: web_server_install.sh
+ start: web_server_start.sh
+
+ server:
+ 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/test_conf.py b/tosca2heat/heat-translator/translator/tests/test_conf.py
new file mode 100644
index 0000000..6506c27
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/test_conf.py
@@ -0,0 +1,57 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import mock
+import os
+
+from translator.conf.config import ConfigProvider as translatorConfig
+from translator.tests.base import TestCase
+
+
+def reload_config(func):
+ '''Decorator to reload config.
+
+ Set to default values defined in translator.conf file
+
+ '''
+
+ def reload(*args):
+ func(*args)
+ path = os.path.dirname(os.path.abspath(__file__)) + '/../conf/'
+ conf_file = os.path.join(path, 'translator.conf')
+ translatorConfig._load_config(conf_file)
+
+ return reload
+
+
+class ConfTest(TestCase):
+
+ @reload_config
+ @mock.patch('six.moves.configparser.ConfigParser')
+ def test_load_config(self, mock_config_parser):
+ translatorConfig._translator_config.read = mock.MagicMock()
+ translatorConfig._load_config('fake_file.conf')
+ self.assertTrue(translatorConfig._translator_config.read.called)
+
+ def test_get_value(self):
+ ret_value = mock.MagicMock(return_value='hot')
+ translatorConfig._translator_config.get = ret_value
+ value = translatorConfig.get_value('DEFAULT', 'language')
+ self.assertTrue(translatorConfig._translator_config.get.called)
+ self.assertEqual(value, 'hot')
+
+ def test_get_all_values(self):
+ ret_value = mock.MagicMock(return_value=['hot'])
+ translatorConfig._translator_config.items = ret_value
+ values = translatorConfig.get_all_values()
+ self.assertTrue(translatorConfig._translator_config.items.called)
+ self.assertEqual(values[0], 'hot')
diff --git a/tosca2heat/heat-translator/translator/tests/test_shell.py b/tosca2heat/heat-translator/translator/tests/test_shell.py
new file mode 100644
index 0000000..b001c1a
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/test_shell.py
@@ -0,0 +1,191 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 ast
+import json
+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
+from translator.tests.base import TestCase
+
+
+class ShellTest(TestCase):
+ tosca_helloworld = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/tosca_helloworld.yaml")
+ template_file = '--template-file=' + tosca_helloworld
+ template_type = '--template-type=tosca'
+ template_validation = "--validate-only=true"
+ failure_msg = _('The program raised an exception unexpectedly.')
+
+ def test_missing_arg(self):
+ error = self.assertRaises(ValueError, shell.main, '')
+ err_msg = _('The program requires minimum two arguments. '
+ 'Please refer to the usage documentation.')
+ self.assertEqual(err_msg, str(error))
+
+ def test_invalid_file_arg(self):
+ error = self.assertRaises(ValueError, shell.main, 'translate me')
+ err_msg = _('The program expects --template-file as first '
+ 'argument. Please refer to the usage documentation.')
+ self.assertEqual(err_msg, str(error))
+
+ def test_invalid_type_arg(self):
+ error = self.assertRaises(ValueError,
+ shell.main, ('--template-file=', 'xyz'))
+ err_msg = _('The program expects --template-type as second argument. '
+ 'Please refer to the usage documentation.')
+ self.assertEqual(err_msg, str(error))
+
+ def test_invalid_file_value(self):
+ error = self.assertRaises(ValueError,
+ shell.main, ('--template-file=template.txt',
+ self.template_type))
+ err_msg = _('The path template.txt is not a valid file or URL.')
+ self.assertEqual(err_msg, str(error))
+
+ def test_invalid_type_value(self):
+ error = self.assertRaises(ValueError, shell.main,
+ (self.template_file, '--template-type=xyz'))
+ err_msg = _('xyz is not a valid template type.')
+ self.assertEqual(err_msg, str(error))
+
+ def test_invalid_parameters(self):
+ error = self.assertRaises(ValueError, shell.main,
+ (self.template_file, self.template_type,
+ '--parameters=key'))
+ err_msg = _("'key' is not a well-formed parameter.")
+ self.assertEqual(err_msg, str(error))
+
+ def test_valid_template(self):
+ try:
+ shell.main([self.template_file, self.template_type])
+ except Exception:
+ self.fail(self.failure_msg)
+
+ def test_valid_template_with_parameters(self):
+ tosca_single_instance_wordpress = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/tosca_single_instance_wordpress.yaml")
+ parameters = '--parameters="cpus=2;db_name=wpdb;db_user=test;'\
+ 'db_port=2000;db_root_pwd=fun2test;db_pwd=fun2test"'
+ template = '--template-file=' + tosca_single_instance_wordpress
+ try:
+ shell.main([template, self.template_type, parameters])
+ except Exception:
+ self.fail(self.failure_msg)
+
+ def test_validate_only(self):
+ try:
+ shell.main([self.template_file, self.template_type,
+ self.template_validation])
+ except Exception:
+ self.fail(self.failure_msg)
+
+ template = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/tosca_helloworld_invalid.yaml")
+ invalid_template = '--template-file=' + template
+ self.assertRaises(exception.ValidationError, shell.main,
+ [invalid_template, self.template_type,
+ self.template_validation])
+
+ def test_output_file(self):
+ temp_dir = tempfile.mkdtemp()
+ temp_file = "/test_translation_output.txt"
+ output_file = "--output-file=" + temp_dir + temp_file
+ try:
+ shell.main([self.template_file, self.template_type, output_file])
+ except Exception:
+ self.fail(self.failure_msg)
+ finally:
+ if temp_dir:
+ shutil.rmtree(temp_dir)
+ 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')
+ def test_template_deploy_with_credentials(self, mock_flavor_dict,
+ mock_os_getenv,
+ mock_token,
+ mock_url, mock_post,
+ mock_env,
+ 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}
+ }
+ 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_abcXXX',
+ 'parameters': {},
+ 'template': {
+ 'outputs': {},
+ 'heat_template_version': '2013-05-23',
+ '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',
+ 'image': 'rhel-6.5-test-image'
+ }
+ }
+ }
+ }
+ }
+
+ mock_heat_res = {
+ "stack": {
+ "id": 1234
+ }
+ }
+ headers = {
+ 'Content-Type': 'application/json',
+ 'X-Auth-Token': 'mock_token'
+ }
+
+ class mock_response(object):
+ def __init__(self, status_code, _content):
+ self.status_code = status_code
+ 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)
diff --git a/tosca2heat/heat-translator/translator/tests/test_template.py b/tosca2heat/heat-translator/translator/tests/test_template.py
new file mode 100644
index 0000000..7cced36
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/test_template.py
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+from toscaparser.tosca_template import ToscaTemplate
+from translator.tests.base import TestCase
+
+
+class ToscaMongoNodejsTest(TestCase):
+ parsed_params = {'storage_snapshot_id': 'test_id',
+ 'storage_location': '/test', 'cpus': '1',
+ 'storage_size': '1'}
+
+ '''TOSCA template with nodejs, app and mongodb on 2 servers.'''
+ tosca_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "../tests/data/tosca_nodejs_mongodb_two_instances.yaml")
+ tosca = ToscaTemplate(tosca_tpl, parsed_params)
+
+ def test_relationship_def(self):
+ expected_relationship = 'tosca.relationships.HostedOn'
+ expected_capabilities_names = 'node'
+ for tpl in self.tosca.nodetemplates:
+ if tpl.name == 'nodejs':
+ def_keys = tpl.type_definition.relationship.keys()
+ self.assertIn(
+ expected_relationship,
+ sorted([x.type for x in def_keys]))
+ self.assertIn(
+ expected_capabilities_names,
+ sorted([x.capability_name for x in def_keys]))
+
+ def test_relationships(self):
+ expected_relationship = ['tosca.relationships.HostedOn']
+ expected_relatednodes = ['app_server']
+ for tpl in self.tosca.nodetemplates:
+ rels = tpl.relationships
+ if rels:
+ if tpl.name == 'nodejs':
+ self.assertEqual(
+ expected_relationship,
+ sorted([x.type for x in tpl.relationships.keys()]))
+ self.assertEqual(
+ expected_relatednodes,
+ sorted([y.name for y in tpl.relationships.values()]))
+
+ def test_related_nodes(self):
+ expected_nodejs = ['app_server']
+ actual_nodejs = []
+ for tpl in self.tosca.nodetemplates:
+ if tpl.name == 'nodejs':
+ for node in tpl.related_nodes:
+ actual_nodejs.append(node.name)
+ self.assertEqual(sorted(actual_nodejs), expected_nodejs)
diff --git a/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py b/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
new file mode 100644
index 0000000..e58d842
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
@@ -0,0 +1,633 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import json
+import os
+
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import URLException
+from toscaparser.common.exception import ValidationError
+from toscaparser.utils.gettextutils import _
+from translator.common.utils import TranslationUtils
+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}
+ diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+ hot_file,
+ params)
+ self.assertEqual({}, diff, '<difference> : ' +
+ json.dumps(diff, indent=4, separators=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_wordpress_single_instance(self):
+ tosca_file = '../tests/data/tosca_single_instance_wordpress.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_elk(self):
+ tosca_file = '../tests/data/tosca_elk.yaml'
+ hot_file = '../tests/data/hot_output/hot_elk.yaml'
+ 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=(', ', ': ')))
+
+ def test_hot_translate_nodejs_mongodb_two_instances(self):
+ tosca_file = '../tests/data/tosca_nodejs_mongodb_two_instances.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_nodejs_mongodb_two_instances.yaml'
+ 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=(', ', ': ')))
+
+ def test_hot_translate_blockstorage_with_attachment(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_blockstorage_with_attachment.yaml'
+ hot_file = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_attachment.yaml'
+ params = {'cpus': 1,
+ '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=(', ', ': ')))
+
+ def test_hot_translate_blockstorage_with_custom_relationship_type(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_blockstorage_with_custom_relationship_type.yaml'
+ hot_file = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_custom_relationship_type.yaml'
+ params = {'cpus': 1,
+ '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=(', ', ': ')))
+
+ def test_hot_translate_blockstorage_with_relationship_template(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_blockstorage_with_relationship_template.yaml'
+ hot_file = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_relationship_template.yaml'
+ 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=(', ', ': ')))
+
+ def test_hot_translate_blockstorage_with_attachment_notation1(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_blockstorage_with_attachment_notation1.yaml'
+ hot_file1 = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_attachment_notation1_alt1.yaml'
+ hot_file2 = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_attachment_notation1_alt2.yaml'
+ params = {'cpus': 1,
+ '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=(', ', ': ')))
+ except Exception:
+ diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+ tosca_file, hot_file2, params)
+ self.assertEqual({}, diff2, '<difference> : ' +
+ json.dumps(diff2, indent=4,
+ separators=(', ', ': ')))
+
+ def test_hot_translate_blockstorage_with_attachment_notation2(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_blockstorage_with_attachment_notation2.yaml'
+ hot_file1 = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_attachment_notation2_alt1.yaml'
+ hot_file2 = '../tests/data/hot_output/storage/' \
+ 'hot_blockstorage_with_attachment_notation2_alt2.yaml'
+ params = {'cpus': 1,
+ '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=(', ', ': ')))
+ except Exception:
+ diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+ tosca_file, hot_file2, params)
+ self.assertEqual({}, diff2, '<difference> : ' +
+ json.dumps(diff2, indent=4,
+ separators=(', ', ': ')))
+
+ def test_hot_translate_multiple_blockstorage_with_attachment(self):
+ tosca_file = '../tests/data/storage/' \
+ 'tosca_multiple_blockstorage_with_attachment.yaml'
+ hot_file1 = '../tests/data/hot_output/storage/' \
+ 'hot_multiple_blockstorage_with_attachment_alt1.yaml'
+ hot_file2 = '../tests/data/hot_output/storage/' \
+ 'hot_multiple_blockstorage_with_attachment_alt2.yaml'
+ params = {'cpus': 1,
+ '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=(', ', ': ')))
+ except Exception:
+ diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+ tosca_file, hot_file2, params)
+ self.assertEqual({}, diff2, '<difference> : ' +
+ json.dumps(diff2, indent=4,
+ separators=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_server_on_existing_network(self):
+ tosca_file = '../tests/data/network/' \
+ 'tosca_server_on_existing_network.yaml'
+ 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=(', ', ': ')))
+
+ def test_hot_translate_two_servers_one_network(self):
+ tosca_file = '../tests/data/network/tosca_two_servers_one_network.yaml'
+ hot_file = '../tests/data/hot_output/network/' \
+ 'hot_two_servers_one_network.yaml'
+ params = {'network_name': 'my_private_net',
+ '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=(', ', ': ')))
+
+ def test_hot_translate_one_server_three_networks(self):
+ tosca_file = '../tests/data/network/' \
+ 'tosca_one_server_three_networks.yaml'
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_template_with_url_import(self):
+ tosca_file = '../tests/data/' \
+ 'tosca_single_instance_wordpress_with_url_import.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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=(', ', ': ')))
+
+ def test_hot_translate_template_by_url_with_local_import(self):
+ tosca_file = 'https://raw.githubusercontent.com/openstack/' \
+ 'heat-translator/master/translator/tests/data/' \
+ 'tosca_single_instance_wordpress.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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=(', ', ': ')))
+
+ def test_hot_translate_template_by_url_with_local_abspath_import(self):
+ tosca_file = 'https://raw.githubusercontent.com/openstack/' \
+ 'heat-translator/master/translator/tests/data/' \
+ 'tosca_single_instance_wordpress_with_local_abspath' \
+ '_import.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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)
+
+ def test_hot_translate_template_by_url_with_url_import(self):
+ tosca_url = 'https://raw.githubusercontent.com/openstack/' \
+ 'heat-translator/master/translator/tests/data/' \
+ 'tosca_single_instance_wordpress_with_url_import.yaml'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_translate_single_instance_wordpress_csar(self):
+ tosca_file = '../tests/data/csar_single_instance_wordpress.zip'
+ hot_file = '../tests/data/hot_output/' \
+ 'hot_single_instance_wordpress_from_csar.yaml'
+ params = {'db_name': 'wordpress',
+ 'db_user': 'wp_user',
+ 'db_pwd': 'wp_pass',
+ '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=(', ', ': ')))
+
+ def test_translate_elk_csar_from_url(self):
+ tosca_file = 'https://github.com/openstack/heat-translator/raw/' \
+ 'master/translator/tests/data/csar_elk.zip'
+ hot_file = '../tests/data/hot_output/hot_elk_from_csar.yaml'
+ 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=(', ', ': ')))
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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)
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_without_tosca_os_version(self):
+ tosca_file = '../tests/data/' \
+ 'test_single_server_without_optional_version_prop.yaml'
+ 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=(', ', ': ')))
+
+ 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=(', ', ': ')))
+
+ def test_hot_translate_custom_networks_nodes_inline(self):
+ tosca_file = '../tests/data/network/' \
+ 'test_tosca_custom_network_nodes_inline.yaml'
+ 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=(', ', ': ')))
+
+ def test_hot_translate_custom_networks_nodes_imports(self):
+ tosca_file = '../tests/data/network/' \
+ 'test_tosca_custom_network_nodes_imports.yaml'
+ 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=(', ', ': ')))
+
+ 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'
+ params = {}
+ diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+ hot_file,
+ params)
+ self.assertEqual({}, diff, '<difference> : ' +
+ json.dumps(diff, indent=4, separators=(', ', ': ')))
+
+ def test_hot_translate_policy(self):
+ tosca_file = '../tests/data/tosca_policies.yaml'
+ hot_file = '../tests/data/hot_output/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=(', ', ': ')))
diff --git a/tosca2heat/heat-translator/translator/tests/test_utils.py b/tosca2heat/heat-translator/translator/tests/test_utils.py
new file mode 100644
index 0000000..b6d75d9
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/tests/test_utils.py
@@ -0,0 +1,236 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+from toscaparser.tests.base import TestCase
+import translator.common.utils
+
+
+class CommonUtilsTest(TestCase):
+
+ MemoryUnit = translator.common.utils.MemoryUnit
+ cmpUtils = translator.common.utils.CompareUtils
+ yamlUtils = translator.common.utils.YamlUtils
+ UrlUtils = translator.common.utils.UrlUtils
+
+ def test_convert_unit_size_to_num(self):
+ size = '1 TB'
+ num_to_convert = 'GB'
+ expected_output = 1000
+ output = self.MemoryUnit.convert_unit_size_to_num(size, num_to_convert)
+ self.assertEqual(output, expected_output)
+
+ size = '40 GB'
+ num_to_convert = 'MB'
+ expected_output = 40000
+ output = self.MemoryUnit.convert_unit_size_to_num(size, num_to_convert)
+ self.assertEqual(output, expected_output)
+
+ size = '20 B'
+ num_to_convert = None
+ expected_output = 20
+ output = self.MemoryUnit.convert_unit_size_to_num(size, num_to_convert)
+ self.assertEqual(output, expected_output)
+
+ def test_validate_unit(self):
+ unit = 'AB'
+ exp_msg = ('Provided unit "{0}" is not valid. The valid units are '
+ '{1}').format(unit, self.MemoryUnit.UNIT_SIZE_DICT.keys())
+ try:
+ self.MemoryUnit.validate_unit(unit)
+ except Exception as err:
+ self.assertTrue(
+ isinstance(err, ValueError))
+ self.assertEqual(exp_msg, err.__str__())
+
+ def test_unit_size_conversion_to_GNU_standard(self):
+ unit = 'gB'
+ standard_unit = 'GB'
+ converted_unit = self.MemoryUnit.validate_unit(unit)
+ self.assertEqual(converted_unit, standard_unit)
+
+ unit = 'KB'
+ standard_unit = 'kB'
+ converted_unit = self.MemoryUnit.validate_unit(unit)
+ self.assertEqual(converted_unit, standard_unit)
+
+ unit = 'kb'
+ standard_unit = 'kB'
+ converted_unit = self.MemoryUnit.validate_unit(unit)
+ self.assertEqual(converted_unit, standard_unit)
+
+ unit = 'kB'
+ standard_unit = 'kB'
+ converted_unit = self.MemoryUnit.validate_unit(unit)
+ self.assertEqual(converted_unit, standard_unit)
+
+ unit = 'MIB'
+ standard_unit = 'MiB'
+ converted_unit = self.MemoryUnit.validate_unit(unit)
+ self.assertEqual(converted_unit, standard_unit)
+
+ def test_str_to_num_value_error(self):
+ str_to_convert = '55063.000000'
+ expected_output = 55063.0
+ output = translator.common.utils.str_to_num(str_to_convert)
+ self.assertEqual(output, expected_output)
+
+ def test_compare_dicts_unequal(self):
+ dict1 = {'allowed_values': [1, 2, 4, 8],
+ 'server3': {'depends_on': ['server1', 'server2']}}
+ dict2 = {'allowed_values': [1, 2, 4, 8],
+ 'server3': {'depends_on': ['server2', 'server1']}}
+ self.assertFalse(self.cmpUtils.compare_dicts(dict1, dict2))
+
+ def test_dicts_equivalent_empty_dicts(self):
+ self.assertTrue(self.cmpUtils.compare_dicts(None, None))
+ self.assertFalse(self.cmpUtils.compare_dicts(None, {}))
+ self.assertFalse(self.cmpUtils.compare_dicts(None, {'x': '2'}))
+
+ def test_compareutils_reorder(self):
+ dic = {'output': {'website_url': {'value': {'get_attr':
+ ['server', 'networks',
+ 'private', 0]}}},
+ 'allowed_values': [2, 8, 1, 4],
+ 'server3': {'depends_on': ['server2', 'server1']}}
+ reordered_dic = {'output': {'website_url': {'value': {'get_attr':
+ ['server', 'networks',
+ 'private', 0]}}},
+ 'allowed_values': [1, 2, 4, 8],
+ 'server3': {'depends_on': ['server1', 'server2']}}
+ self.assertEqual(reordered_dic, self.cmpUtils.reorder(dic))
+
+ def test_compareutils_diff_dicts_both_null(self):
+ expected = None
+ provided = None
+ self.assertEqual({},
+ self.cmpUtils.diff_dicts(expected, provided))
+
+ def test_compareutils_diff_dicts_one_null(self):
+ expected = {'keyname': 'userkey'}
+ provided = None
+ self.assertEqual(
+ {self.cmpUtils.MISMATCH_VALUE1_LABEL: {'keyname': 'userkey'},
+ self.cmpUtils.MISMATCH_VALUE2_LABEL: None},
+ self.cmpUtils.diff_dicts(expected, provided))
+
+ def test_compareutils_diff_dicts_missing_key(self):
+ expected = {'server3': {'depends_on': ['server1', 'server2'],
+ 'keyname': 'userkey'}}
+ provided = {'server3': {'depends_on': ['server2', 'server1']}}
+ self.assertEqual(
+ {'server3': {'keyname':
+ {self.cmpUtils.MISMATCH_VALUE1_LABEL: 'userkey',
+ self.cmpUtils.MISMATCH_VALUE2_LABEL: None}}},
+ self.cmpUtils.diff_dicts(expected, provided))
+
+ def test_compareutils_diff_dicts_missing_key_other_dict(self):
+ expected = {'server3': {'depends_on': ['server1', 'server2']}}
+ provided = {'server3': {'depends_on': ['server2', 'server1'],
+ 'keyname': 'userkey'}}
+ self.assertEqual(
+ {'server3': {'keyname':
+ {self.cmpUtils.MISMATCH_VALUE1_LABEL: None,
+ self.cmpUtils.MISMATCH_VALUE2_LABEL: 'userkey'}}},
+ self.cmpUtils.diff_dicts(expected, provided))
+
+ def test_compareutils_diff_dicts_value_diff(self):
+ expected = \
+ {'output':
+ {'website_url':
+ {'value':
+ {'get_attr': ['server', 'networks', 'private', 0]}}},
+ 'server3': {'depends_on': ['server2', 'server1']}}
+ provided = \
+ {'output':
+ {'website_url':
+ {'value':
+ {'get_attr': ['server', 'networks', 'public', 0]}}},
+ 'server3': {'depends_on': ['server2', 'server1']}}
+ self.assertEqual(
+ {'output':
+ {'website_url':
+ {'value':
+ {'get_attr':
+ {self.cmpUtils.MISMATCH_VALUE1_LABEL:
+ ['server', 'networks', 'private', 0],
+ self.cmpUtils.MISMATCH_VALUE2_LABEL:
+ ['server', 'networks', 'public', 0]}}}}},
+ self.cmpUtils.diff_dicts(expected, provided))
+
+ def test_yamlutils_get_dict_missing_file(self):
+ self.assertIsNone(self.yamlUtils.get_dict('./no_file.yaml'))
+
+ def test_yamlutils_get_dict(self):
+ yaml_file = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ '../tests/data/custom_types/rsyslog.yaml')
+ dict = \
+ {'tosca_definitions_version': 'tosca_simple_yaml_1_0',
+ 'description':
+ 'RSYSLOG is the Rocket-fast SYStem for LOG processing.\n',
+ 'node_types':
+ {'tosca.nodes.SoftwareComponent.Rsyslog':
+ {'derived_from': 'tosca.nodes.SoftwareComponent',
+ 'requirements':
+ [{'log_endpoint':
+ {'capability': 'tosca.capabilities.Endpoint',
+ 'node': 'tosca.nodes.SoftwareComponent.Logstash',
+ 'relationship': 'tosca.relationships.ConnectsTo'}}]}}}
+ self.assertEqual(dict, self.yamlUtils.get_dict(yaml_file))
+
+ def test_yamlutils_compare_yamls(self):
+ yaml_file1 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ '../tests/data/custom_types/kibana.yaml')
+ yaml_file2 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ '../tests/data/custom_types/collectd.yaml')
+ self.assertTrue(self.yamlUtils.compare_yamls(yaml_file1, yaml_file1))
+ self.assertFalse(self.yamlUtils.compare_yamls(yaml_file1, yaml_file2))
+
+ def test_yamlutils_compare_yaml_dict(self):
+ yaml_file1 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ '../tests/data/custom_types/rsyslog.yaml')
+ yaml_file2 = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ '../tests/data/custom_types/collectd.yaml')
+ dict = \
+ {'tosca_definitions_version': 'tosca_simple_yaml_1_0',
+ 'description':
+ 'RSYSLOG is the Rocket-fast SYStem for LOG processing.\n',
+ 'node_types':
+ {'tosca.nodes.SoftwareComponent.Rsyslog':
+ {'derived_from': 'tosca.nodes.SoftwareComponent',
+ 'requirements':
+ [{'log_endpoint':
+ {'capability': 'tosca.capabilities.Endpoint',
+ 'node': 'tosca.nodes.SoftwareComponent.Logstash',
+ 'relationship': 'tosca.relationships.ConnectsTo'}}]}}}
+ self.assertEqual({}, self.cmpUtils.diff_dicts(
+ self.yamlUtils.get_dict(yaml_file1), dict))
+ self.assertFalse(self.yamlUtils.compare_yaml_dict(yaml_file2, dict))
+
+ def test_assert_value_is_num(self):
+ value = 1
+ output = translator.common.utils.str_to_num(value)
+ self.assertEqual(value, output)
+
+ def test_urlutils_validate_url(self):
+ self.assertTrue(self.UrlUtils.validate_url("http://www.github.com/"))
+ self.assertTrue(
+ self.UrlUtils.validate_url("https://github.com:81/a/2/a.b"))
+ self.assertTrue(self.UrlUtils.validate_url("ftp://github.com"))
+ self.assertFalse(self.UrlUtils.validate_url("github.com"))
+ self.assertFalse(self.UrlUtils.validate_url("123"))
+ self.assertFalse(self.UrlUtils.validate_url("a/b/c"))