summaryrefslogtreecommitdiffstats
path: root/tosca2heat/heat-translator/translator/hot/tosca
diff options
context:
space:
mode:
Diffstat (limited to 'tosca2heat/heat-translator/translator/hot/tosca')
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py91
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py134
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py7
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py8
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py167
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py4
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py4
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py7
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py131
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py5
-rw-r--r--tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py5
15 files changed, 323 insertions, 260 deletions
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py
new file mode 100644
index 0000000..978e965
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_autoscaling.py
@@ -0,0 +1,91 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from toscaparser.nodetemplate import NodeTemplate
+from toscaparser.policy import Policy
+from toscaparser.tests.base import TestCase
+import toscaparser.utils.yamlparser
+from translator.hot.tosca.tosca_compute import ToscaCompute
+from translator.hot.tosca.tosca_policies_scaling import ToscaAutoscaling
+
+
+class AutoscalingTest(TestCase):
+
+ def _tosca_scaling_test(self, tpl_snippet, expectedprops):
+ nodetemplates = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['node_templates'])
+ policies = (toscaparser.utils.yamlparser.
+ simple_parse(tpl_snippet)['policies'])
+ name = list(nodetemplates.keys())[0]
+ policy_name = list(policies[0].keys())[0]
+ for policy in policies:
+ tpl = policy[policy_name]
+ targets = tpl["targets"]
+ properties = tpl["properties"]
+ try:
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ toscacompute = ToscaCompute(nodetemplate)
+ toscacompute.handle_properties()
+ policy = Policy(policy_name, tpl, targets,
+ properties, "node_templates")
+ toscascaling = ToscaAutoscaling(policy)
+ parameters = toscascaling.handle_properties([toscacompute])
+ self.assertEqual(parameters[0].properties, expectedprops)
+ except Exception:
+ raise
+
+ def test_compute_with_scaling(self):
+ tpl_snippet = '''
+ node_templates:
+ my_server_1:
+ type: tosca.nodes.Compute
+ capabilities:
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
+ policies:
+ - asg:
+ type: tosca.policies.Scaling
+ description: Simple node autoscaling
+ targets: [my_server_1]
+ triggers:
+ resize_compute:
+ description: trigger
+ condition:
+ constraint: utilization greater_than 50%
+ period: 60
+ evaluations: 1
+ method: average
+ properties:
+ min_instances: 2
+ max_instances: 10
+ default_instances: 3
+ increment: 1
+ '''
+
+ expectedprops = {'desired_capacity': 3,
+ 'max_size': 10,
+ 'min_size': 2,
+ 'resource': {'type': 'asg_res.yaml'}}
+
+ self._tosca_scaling_test(
+ tpl_snippet,
+ expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
index 408ee8b..1a135f4 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
@@ -10,13 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
import mock
-from mock import patch
from toscaparser.nodetemplate import NodeTemplate
from toscaparser.tests.base import TestCase
-from toscaparser.utils.gettextutils import _
import toscaparser.utils.yamlparser
from translator.hot.tosca.tosca_compute import ToscaCompute
@@ -27,22 +24,12 @@ class ToscaComputeTest(TestCase):
nodetemplates = (toscaparser.utils.yamlparser.
simple_parse(tpl_snippet)['node_templates'])
name = list(nodetemplates.keys())[0]
- try:
- nodetemplate = NodeTemplate(name, nodetemplates)
- nodetemplate.validate()
- toscacompute = ToscaCompute(nodetemplate)
- toscacompute.handle_properties()
- if not self._compare_properties(toscacompute.properties,
- expectedprops):
- raise Exception(_("Hot Properties are not"
- " same as expected properties"))
- except Exception:
- # for time being rethrowing. Will be handled future based
- # on new development in Glance and Graffiti
- raise
+ nodetemplate = NodeTemplate(name, nodetemplates)
+ nodetemplate.validate()
+ toscacompute = ToscaCompute(nodetemplate)
+ toscacompute.handle_properties()
- def _compare_properties(self, hotprops, expectedprops):
- return all(item in hotprops.items() for item in expectedprops.items())
+ self.assertEqual(expectedprops, toscacompute.properties)
def test_node_compute_with_host_and_os_capabilities(self):
tpl_snippet = '''
@@ -84,7 +71,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -123,7 +109,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -137,7 +122,6 @@ class ToscaComputeTest(TestCase):
type: tosca.nodes.Compute
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -155,7 +139,6 @@ class ToscaComputeTest(TestCase):
#left intentionally
'''
expectedprops = {'flavor': None,
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -174,7 +157,6 @@ class ToscaComputeTest(TestCase):
mem_size: 4 GB
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -193,7 +175,6 @@ class ToscaComputeTest(TestCase):
disk_size: 10 GB
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
@@ -211,18 +192,14 @@ class ToscaComputeTest(TestCase):
num_cpus: 4
'''
expectedprops = {'flavor': 'm1.large',
- 'image': None,
'user_data_format': 'SOFTWARE_CONFIG',
'software_config_transport': 'POLL_SERVER_HEAT'}
self._tosca_compute_test(
tpl_snippet,
expectedprops)
- @patch('requests.post')
- @patch('requests.get')
- @patch('os.getenv')
- def test_node_compute_with_nova_flavor(self, mock_os_getenv,
- mock_get, mock_post):
+ @mock.patch('translator.common.flavors.get_flavors')
+ def test_node_compute_with_nova_flavor(self, mock_flavor):
tpl_snippet = '''
node_templates:
server:
@@ -234,56 +211,19 @@ class ToscaComputeTest(TestCase):
disk_size: 1 GB
mem_size: 1 GB
'''
- with patch('translator.common.utils.'
- 'check_for_env_variables') as mock_check_env:
- mock_check_env.return_value = True
- mock_os_getenv.side_effect = ['demo', 'demo',
- 'demo', 'http://abc.com/5000/',
- 'demo', 'demo',
- 'demo', 'http://abc.com/5000/']
- mock_ks_response = mock.MagicMock()
- mock_ks_response.status_code = 200
- mock_ks_content = {
- 'access': {
- 'token': {
- 'id': 'd1dfa603-3662-47e0-b0b6-3ae7914bdf76'
- },
- 'serviceCatalog': [{
- 'type': 'compute',
- 'endpoints': [{
- 'publicURL': 'http://abc.com'
- }]
- }]
- }
- }
- mock_ks_response.content = json.dumps(mock_ks_content)
- mock_nova_response = mock.MagicMock()
- mock_nova_response.status_code = 200
- mock_flavor_content = {
- 'flavors': [{
- 'name': 'm1.mock_flavor',
- 'ram': 1024,
- 'disk': 1,
- 'vcpus': 1
- }]
- }
- mock_nova_response.content = \
- json.dumps(mock_flavor_content)
- mock_post.return_value = mock_ks_response
- mock_get.return_value = mock_nova_response
- expectedprops = {'flavor': 'm1.mock_flavor',
- 'image': None,
- 'user_data_format': 'SOFTWARE_CONFIG',
- 'software_config_transport': 'POLL_SERVER_HEAT'}
- self._tosca_compute_test(
- tpl_snippet,
- expectedprops)
+ mock_flavor.return_value = {
+ 'm1.mock_flavor': {
+ 'mem_size': 1024,
+ 'disk_size': 1,
+ 'num_cpus': 1}
+ }
+ expectedprops = {'flavor': 'm1.mock_flavor',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'software_config_transport': 'POLL_SERVER_HEAT'}
+ self._tosca_compute_test(tpl_snippet, expectedprops)
- @patch('requests.post')
- @patch('requests.get')
- @patch('os.getenv')
- def test_node_compute_without_nova_flavor(self, mock_os_getenv,
- mock_get, mock_post):
+ @mock.patch('translator.common.images.get_images')
+ def test_node_compute_with_glance_image(self, mock_images):
tpl_snippet = '''
node_templates:
server:
@@ -294,19 +234,25 @@ class ToscaComputeTest(TestCase):
num_cpus: 1
disk_size: 1 GB
mem_size: 1 GB
+ os:
+ properties:
+ architecture: x86_64
+ type: Linux
+ distribution: Fake Distribution
+ version: 19.0
'''
- with patch('translator.common.utils.'
- 'check_for_env_variables') as mock_check_env:
- mock_check_env.return_value = True
- mock_os_getenv.side_effect = ['demo', 'demo',
- 'demo', 'http://abc.com/5000/']
- mock_ks_response = mock.MagicMock()
- mock_ks_content = {}
- mock_ks_response.content = json.dumps(mock_ks_content)
- expectedprops = {'flavor': 'm1.small',
- 'image': None,
- 'user_data_format': 'SOFTWARE_CONFIG',
- 'software_config_transport': 'POLL_SERVER_HEAT'}
- self._tosca_compute_test(
- tpl_snippet,
- expectedprops)
+ mock_images.return_value = {
+ 'fake-image-foobar': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fake Distribution',
+ 'version': '19.0'},
+ 'fake-image-foobar-old': {'architecture': 'x86_64',
+ 'type': 'Linux',
+ 'distribution': 'Fake Distribution',
+ 'version': '18.0'}
+ }
+ expectedprops = {'flavor': 'm1.small',
+ 'image': 'fake-image-foobar',
+ 'user_data_format': 'SOFTWARE_CONFIG',
+ 'software_config_transport': 'POLL_SERVER_HEAT'}
+ self._tosca_compute_test(tpl_snippet, expectedprops)
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
index d4b2f44..27c1033 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
@@ -29,9 +29,10 @@ class ToscaBlockStorage(HotResource):
toscatype = 'tosca.nodes.BlockStorage'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaBlockStorage, self).__init__(nodetemplate,
- type='OS::Cinder::Volume')
+ type='OS::Cinder::Volume',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
@@ -67,5 +68,5 @@ class ToscaBlockStorage(HotResource):
# attribute for the matching resource. Unless there is additional
# runtime support, this should be a one to one mapping.
if attribute == 'volume_id':
- attr['get_resource'] = args[0]
+ attr['get_resource'] = self.name
return attr
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
index 71b9822..f471b83 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
@@ -23,9 +23,11 @@ class ToscaBlockStorageAttachment(HotResource):
toscatype = 'tosca.nodes.BlockStorageAttachment'
- def __init__(self, template, nodetemplates, instance_uuid, volume_id):
+ def __init__(self, template, nodetemplates, instance_uuid, volume_id,
+ csar_dir=None):
super(ToscaBlockStorageAttachment,
- self).__init__(template, type='OS::Cinder::VolumeAttachment')
+ self).__init__(template, type='OS::Cinder::VolumeAttachment',
+ csar_dir=csar_dir)
self.nodetemplates = nodetemplates
self.instance_uuid = {'get_resource': instance_uuid}
self.volume_id = {'get_resource': volume_id}
@@ -50,4 +52,4 @@ class ToscaBlockStorageAttachment(HotResource):
self.properties.pop('device')
def handle_life_cycle(self):
- pass
+ return None, None, None
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
index 9d6a459..85f312d 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
@@ -11,68 +11,21 @@
# License for the specific language governing permissions and limitations
# under the License.
-import json
import logging
-import requests
from toscaparser.utils.gettextutils import _
+from translator.common import flavors as nova_flavors
+from translator.common import images as glance_images
import translator.common.utils
from translator.hot.syntax.hot_resource import HotResource
+
log = logging.getLogger('heat-translator')
# Name used to dynamically load appropriate map class.
TARGET_CLASS_NAME = 'ToscaCompute'
-# A design issue to be resolved is how to translate the generic TOSCA server
-# properties to OpenStack flavors and images. At the Atlanta design summit,
-# there was discussion on using Glance to store metadata and Graffiti to
-# describe artifacts. We will follow these projects to see if they can be
-# leveraged for this TOSCA translation.
-# For development purpose at this time, we temporarily hardcode a list of
-# flavors and images here
-FLAVORS = {'m1.xlarge': {'mem_size': 16384, 'disk_size': 160, 'num_cpus': 8},
- 'm1.large': {'mem_size': 8192, 'disk_size': 80, 'num_cpus': 4},
- 'm1.medium': {'mem_size': 4096, 'disk_size': 40, 'num_cpus': 2},
- 'm1.small': {'mem_size': 2048, 'disk_size': 20, 'num_cpus': 1},
- 'm1.tiny': {'mem_size': 512, 'disk_size': 1, 'num_cpus': 1},
- 'm1.micro': {'mem_size': 128, 'disk_size': 0, 'num_cpus': 1},
- 'm1.nano': {'mem_size': 64, 'disk_size': 0, 'num_cpus': 1}}
-
-IMAGES = {'ubuntu-software-config-os-init': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Ubuntu',
- 'version': '14.04'},
- 'ubuntu-12.04-software-config-os-init': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Ubuntu',
- 'version': '12.04'},
- 'fedora-amd64-heat-config': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '18.0'},
- 'F18-x86_64-cfntools': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '19'},
- 'Fedora-x86_64-20-20131211.1-sda': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'Fedora',
- 'version': '20'},
- 'cirros-0.3.1-x86_64-uec': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'CirrOS',
- 'version': '0.3.1'},
- 'cirros-0.3.2-x86_64-uec': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'CirrOS',
- 'version': '0.3.2'},
- 'rhel-6.5-test-image': {'architecture': 'x86_64',
- 'type': 'Linux',
- 'distribution': 'RHEL',
- 'version': '6.5'}}
-
class ToscaCompute(HotResource):
'''Translate TOSCA node type tosca.nodes.Compute.'''
@@ -84,9 +37,18 @@ class ToscaCompute(HotResource):
('architecture', 'distribution', 'type', 'version')
toscatype = 'tosca.nodes.Compute'
- def __init__(self, nodetemplate):
+ ALLOWED_NOVA_SERVER_PROPS = \
+ ('admin_pass', 'availability_zone', 'block_device_mapping',
+ 'block_device_mapping_v2', 'config_drive', 'diskConfig', 'flavor',
+ 'flavor_update_policy', 'image', 'image_update_policy', 'key_name',
+ 'metadata', 'name', 'networks', 'personality', 'reservation_id',
+ 'scheduler_hints', 'security_groups', 'software_config_transport',
+ 'user_data', 'user_data_format', 'user_data_update_policy')
+
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaCompute, self).__init__(nodetemplate,
- type='OS::Nova::Server')
+ type='OS::Nova::Server',
+ csar_dir=csar_dir)
# List with associated hot port resources with this server
self.assoc_port_resources = []
pass
@@ -99,7 +61,8 @@ class ToscaCompute(HotResource):
self.properties['software_config_transport'] = 'POLL_SERVER_HEAT'
tosca_props = self.get_tosca_props()
for key, value in tosca_props.items():
- self.properties[key] = value
+ if key in self.ALLOWED_NOVA_SERVER_PROPS:
+ self.properties[key] = value
# To be reorganized later based on new development in Glance and Graffiti
def translate_compute_flavor_and_image(self,
@@ -125,91 +88,16 @@ class ToscaCompute(HotResource):
if os_cap_props:
image = self._best_image(os_cap_props)
hot_properties['flavor'] = flavor
- hot_properties['image'] = image
+ if image:
+ hot_properties['image'] = image
+ else:
+ hot_properties.pop('image', None)
return hot_properties
- def _create_nova_flavor_dict(self):
- '''Populates and returns the flavors dict using Nova ReST API'''
- try:
- access_dict = translator.common.utils.get_ks_access_dict()
- access_token = translator.common.utils.get_token_id(access_dict)
- if access_token is None:
- return None
- nova_url = translator.common.utils.get_url_for(access_dict,
- 'compute')
- if not nova_url:
- return None
- nova_response = requests.get(nova_url + '/flavors/detail',
- headers={'X-Auth-Token':
- access_token})
- if nova_response.status_code != 200:
- return None
- flavors = json.loads(nova_response.content)['flavors']
- flavor_dict = dict()
- for flavor in flavors:
- flavor_name = str(flavor['name'])
- flavor_dict[flavor_name] = {
- 'mem_size': flavor['ram'],
- 'disk_size': flavor['disk'],
- 'num_cpus': flavor['vcpus'],
- }
- except Exception as e:
- # Handles any exception coming from openstack
- log.warn(_('Choosing predefined flavors since received '
- 'Openstack Exception: %s') % str(e))
- return None
- return flavor_dict
-
- def _populate_image_dict(self):
- '''Populates and returns the images dict using Glance ReST API'''
- images_dict = {}
- try:
- access_dict = translator.common.utils.get_ks_access_dict()
- access_token = translator.common.utils.get_token_id(access_dict)
- if access_token is None:
- return None
- glance_url = translator.common.utils.get_url_for(access_dict,
- 'image')
- if not glance_url:
- return None
- glance_response = requests.get(glance_url + '/v2/images',
- headers={'X-Auth-Token':
- access_token})
- if glance_response.status_code != 200:
- return None
- images = json.loads(glance_response.content)["images"]
- for image in images:
- image_resp = requests.get(glance_url + '/v2/images/' +
- image["id"],
- headers={'X-Auth-Token':
- access_token})
- if image_resp.status_code != 200:
- continue
- metadata = ["architecture", "type", "distribution", "version"]
- image_data = json.loads(image_resp.content)
- if any(key in image_data.keys() for key in metadata):
- images_dict[image_data["name"]] = dict()
- for key in metadata:
- if key in image_data.keys():
- images_dict[image_data["name"]][key] = \
- image_data[key]
- else:
- continue
-
- except Exception as e:
- # Handles any exception coming from openstack
- log.warn(_('Choosing predefined flavors since received '
- 'Openstack Exception: %s') % str(e))
- return images_dict
-
def _best_flavor(self, properties):
log.info(_('Choosing the best flavor for given attributes.'))
# Check whether user exported all required environment variables.
- flavors = FLAVORS
- if translator.common.utils.check_for_env_variables():
- resp = self._create_nova_flavor_dict()
- if resp:
- flavors = resp
+ flavors = nova_flavors.get_flavors()
# start with all flavors
match_all = flavors.keys()
@@ -252,11 +140,7 @@ class ToscaCompute(HotResource):
def _best_image(self, properties):
# Check whether user exported all required environment variables.
- images = IMAGES
- if translator.common.utils.check_for_env_variables():
- resp = self._populate_image_dict()
- if resp and len(resp.keys()) > 0:
- images = resp
+ images = glance_images.get_images()
match_all = images.keys()
architecture = properties.get(self.ARCHITECTURE)
if architecture is None:
@@ -307,7 +191,10 @@ class ToscaCompute(HotResource):
return this_list
matching_images = []
for image in this_list:
- if this_dict[image][attr].lower() == str(prop).lower():
+ if attr in this_dict[image]:
+ if this_dict[image][attr].lower() == str(prop).lower():
+ matching_images.insert(0, image)
+ else:
matching_images.append(image)
return matching_images
@@ -324,7 +211,7 @@ class ToscaCompute(HotResource):
attriute.'))
if attribute == 'private_address' or \
attribute == 'public_address':
- attr['get_attr'] = [self.name, 'first_address']
+ attr['get_attr'] = [self.name, 'networks', 'private', 0]
return attr
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
index 26c9d4d..7c8bc45 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_database.py
@@ -22,8 +22,8 @@ class ToscaDatabase(HotResource):
toscatype = 'tosca.nodes.Database'
- def __init__(self, nodetemplate):
- super(ToscaDatabase, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaDatabase, self).__init__(nodetemplate, csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
index 38c31bd..3136792 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_dbms.py
@@ -22,8 +22,8 @@ class ToscaDbms(HotResource):
toscatype = 'tosca.nodes.DBMS'
- def __init__(self, nodetemplate):
- super(ToscaDbms, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaDbms, self).__init__(nodetemplate, csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
index a4e565e..10e6405 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_network.py
@@ -28,9 +28,10 @@ class ToscaNetwork(HotResource):
existing_resource_id = None
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaNetwork, self).__init__(nodetemplate,
- type='OS::Neutron::Net')
+ type='OS::Neutron::Net',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
@@ -57,8 +58,6 @@ class ToscaNetwork(HotResource):
self.existing_resource_id = value
break
elif key == 'segmentation_id':
- # net_props['segmentation_id'] = \
- # tosca_props['segmentation_id']
# Hardcode to vxlan for now until we add the network type
# and physical network to the spec.
net_props['value_specs'] = {'provider:segmentation_id':
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
index 4fd2d70..86733e4 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_network_port.py
@@ -24,9 +24,10 @@ class ToscaNetworkPort(HotResource):
toscatype = 'tosca.nodes.network.Port'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaNetworkPort, self).__init__(nodetemplate,
- type='OS::Neutron::Port')
+ type='OS::Neutron::Port',
+ csar_dir=csar_dir)
# Default order
self.order = 0
pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
index 177503f..e30c46c 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_object_storage.py
@@ -23,9 +23,10 @@ class ToscaObjectStorage(HotResource):
toscatype = 'tosca.nodes.ObjectStorage'
- def __init__(self, nodetemplate):
+ def __init__(self, nodetemplate, csar_dir=None):
super(ToscaObjectStorage, self).__init__(nodetemplate,
- type='OS::Swift::Container')
+ type='OS::Swift::Container',
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
index b32fc1d..12b40d5 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies.py
@@ -22,9 +22,10 @@ class ToscaPolicies(HotResource):
toscatype = 'tosca.policies.Placement'
- def __init__(self, policy):
+ def __init__(self, policy, csar_dir=None):
super(ToscaPolicies, self).__init__(policy,
- type='OS::Nova::ServerGroup')
+ type='OS::Nova::ServerGroup',
+ csar_dir=csar_dir)
self.policy = policy
def handle_properties(self, resources):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py
new file mode 100644
index 0000000..1b63f24
--- /dev/null
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_policies_scaling.py
@@ -0,0 +1,131 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from collections import OrderedDict
+import yaml
+
+from translator.hot.syntax.hot_resource import HotResource
+# Name used to dynamically load appropriate map class.
+TARGET_CLASS_NAME = 'ToscaAutoscaling'
+HEAT_TEMPLATE_BASE = """
+heat_template_version: 2013-05-23
+"""
+ALARM_STATISTIC = {'average': 'avg'}
+SCALING_RESOURCES = ["OS::Heat::ScalingPolicy", "OS::Heat::AutoScalingGroup",
+ "OS::Aodh::Alarm"]
+
+
+class ToscaAutoscaling(HotResource):
+ '''Translate TOSCA node type tosca.policies.Scaling'''
+
+ toscatype = 'tosca.policies.Scaling'
+
+ def __init__(self, policy, csar_dir=None):
+ hot_type = "OS::Heat::ScalingPolicy"
+ super(ToscaAutoscaling, self).__init__(policy,
+ type=hot_type,
+ csar_dir=csar_dir)
+ self.policy = policy
+
+ def handle_expansion(self):
+ if self.policy.entity_tpl.get('triggers'):
+ sample = self.policy.\
+ entity_tpl["triggers"]["resize_compute"]["condition"]
+ prop = {}
+ prop["description"] = self.policy.entity_tpl.get('description')
+ prop["meter_name"] = "cpu_util"
+ if sample:
+ prop["statistic"] = ALARM_STATISTIC[sample["method"]]
+ prop["period"] = sample["period"]
+ prop["threshold"] = sample["evaluations"]
+ prop["comparison_operator"] = "gt"
+ alarm_name = self.name.replace('_scale_in', '').\
+ replace('_scale_out', '')
+ ceilometer_resources = HotResource(self.nodetemplate,
+ type='OS::Aodh::Alarm',
+ name=alarm_name + '_alarm',
+ properties=prop)
+ hot_resources = [ceilometer_resources]
+ return hot_resources
+
+ def represent_ordereddict(self, dumper, data):
+ nodes = []
+ for key, value in data.items():
+ node_key = dumper.represent_data(key)
+ node_value = dumper.represent_data(value)
+ nodes.append((node_key, node_value))
+ return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes)
+
+ def _handle_nested_template(self, scale_res):
+ template_dict = yaml.safe_load(HEAT_TEMPLATE_BASE)
+ template_dict['description'] = 'Tacker Scaling template'
+ template_dict["resources"] = {}
+ dict_res = OrderedDict()
+ for res in scale_res:
+ dict_res = res.get_dict_output()
+ res_name = list(dict_res.keys())[0]
+ template_dict["resources"][res_name] = \
+ dict_res[res_name]
+
+ yaml.add_representer(OrderedDict, self.represent_ordereddict)
+ yaml.add_representer(dict, self.represent_ordereddict)
+ yaml_string = yaml.dump(template_dict, default_flow_style=False)
+ yaml_string = yaml_string.replace('\'', '') .replace('\n\n', '\n')
+ self.nested_template = {
+ self.policy.name + '_res.yaml': yaml_string
+ }
+
+ def handle_properties(self, resources):
+ self.properties = {}
+ self.properties["auto_scaling_group_id"] = {
+ 'get_resource': self.policy.name + '_group'
+ }
+ self.properties["adjustment_type"] = "change_in_capacity "
+ self.properties["scaling_adjustment"] = self.\
+ policy.entity_tpl["properties"]["increment"]
+ delete_res_names = []
+ scale_res = []
+ for index, resource in enumerate(resources):
+ if resource.name in self.policy.targets and \
+ resource.type != 'OS::Heat::AutoScalingGroup':
+ temp = self.policy.entity_tpl["properties"]
+ props = {}
+ res = {}
+ res["min_size"] = temp["min_instances"]
+ res["max_size"] = temp["max_instances"]
+ res["desired_capacity"] = temp["default_instances"]
+ props['type'] = resource.type
+ props['properties'] = resource.properties
+ res['resource'] = {'type': self.policy.name + '_res.yaml'}
+ scaling_resources = \
+ HotResource(resource,
+ type='OS::Heat::AutoScalingGroup',
+ name=self.policy.name + '_group',
+ properties=res)
+
+ if resource.type not in SCALING_RESOURCES:
+ delete_res_names.append(resource.name)
+ scale_res.append(resource)
+ self._handle_nested_template(scale_res)
+ resources = [tmp_res
+ for tmp_res in resources
+ if tmp_res.name not in delete_res_names]
+ resources.append(scaling_resources)
+ return resources
+
+ def extract_substack_templates(self, base_filename, hot_template_version):
+ return self.nested_template
+
+ def embed_substack_templates(self, hot_template_version):
+ pass
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
index 044de43..9b0819e 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_software_component.py
@@ -22,8 +22,9 @@ class ToscaSoftwareComponent(HotResource):
toscatype = 'tosca.nodes.SoftwareComponent'
- def __init__(self, nodetemplate):
- super(ToscaSoftwareComponent, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaSoftwareComponent, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
index d0a9c5d..03474aa 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_web_application.py
@@ -22,8 +22,9 @@ class ToscaWebApplication(HotResource):
toscatype = 'tosca.nodes.WebApplication'
- def __init__(self, nodetemplate):
- super(ToscaWebApplication, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir=None):
+ super(ToscaWebApplication, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):
diff --git a/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
index 83bda80..32b80c5 100644
--- a/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
+++ b/tosca2heat/heat-translator/translator/hot/tosca/tosca_webserver.py
@@ -22,8 +22,9 @@ class ToscaWebserver(HotResource):
toscatype = 'tosca.nodes.WebServer'
- def __init__(self, nodetemplate):
- super(ToscaWebserver, self).__init__(nodetemplate)
+ def __init__(self, nodetemplate, csar_dir):
+ super(ToscaWebserver, self).__init__(nodetemplate,
+ csar_dir=csar_dir)
pass
def handle_properties(self):