summaryrefslogtreecommitdiffstats
path: root/tosca2heat/heat-translator/translator/hot/tosca
diff options
context:
space:
mode:
authorjulien zhang <zhang.jun3g@zte.com.cn>2016-04-22 08:43:26 +0000
committerGerrit Code Review <gerrit@172.30.200.206>2016-04-22 08:43:26 +0000
commit2fa4785aa218cf655f3405d832d2200d64fd033e (patch)
tree0061edccecca9a99aa9a50c6c0e2783c07370112 /tosca2heat/heat-translator/translator/hot/tosca
parent56c2a5d3ba6193c9a98870a264bc5e3aca19a086 (diff)
parentc8201c119ec686e79797721156767685fe848aca (diff)
Merge "Update tosca lib to version 0.5"
Diffstat (limited to 'tosca2heat/heat-translator/translator/hot/tosca')
-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
18 files changed, 1395 insertions, 0 deletions
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