Merge "Implemented Scaling policies in heat translator"
This commit is contained in:
commit
cba5bc9ef5
@ -26,6 +26,8 @@ SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
|
|||||||
DELETION_POLICY) = \
|
DELETION_POLICY) = \
|
||||||
('type', 'properties', 'metadata',
|
('type', 'properties', 'metadata',
|
||||||
'depends_on', 'update_policy', 'deletion_policy')
|
'depends_on', 'update_policy', 'deletion_policy')
|
||||||
|
|
||||||
|
policy_type = ['tosca.policies.Placement', 'tosca.policies.Scaling']
|
||||||
log = logging.getLogger('heat-translator')
|
log = logging.getLogger('heat-translator')
|
||||||
|
|
||||||
|
|
||||||
@ -400,7 +402,7 @@ class HotResource(object):
|
|||||||
def get_all_artifacts(nodetemplate):
|
def get_all_artifacts(nodetemplate):
|
||||||
# workaround bug in the parser
|
# workaround bug in the parser
|
||||||
base_type = HotResource.get_base_type_str(nodetemplate.type_definition)
|
base_type = HotResource.get_base_type_str(nodetemplate.type_definition)
|
||||||
if base_type == "tosca.policies.Placement":
|
if base_type in policy_type:
|
||||||
artifacts = {}
|
artifacts = {}
|
||||||
else:
|
else:
|
||||||
artifacts = nodetemplate.type_definition.get_value('artifacts',
|
artifacts = nodetemplate.type_definition.get_value('artifacts',
|
||||||
@ -421,7 +423,7 @@ class HotResource(object):
|
|||||||
|
|
||||||
# workaround bug in the parser
|
# workaround bug in the parser
|
||||||
base_type = HotResource.get_base_type_str(node.type_definition)
|
base_type = HotResource.get_base_type_str(node.type_definition)
|
||||||
if base_type == "tosca.policies.Placement":
|
if base_type in policy_type:
|
||||||
return operations
|
return operations
|
||||||
|
|
||||||
node_type = node.type_definition
|
node_type = node.type_definition
|
||||||
@ -441,7 +443,7 @@ class HotResource(object):
|
|||||||
def _get_interface_operations_from_type(node_type, node, lifecycle_name):
|
def _get_interface_operations_from_type(node_type, node, lifecycle_name):
|
||||||
operations = {}
|
operations = {}
|
||||||
base_type = HotResource.get_base_type_str(node_type)
|
base_type = HotResource.get_base_type_str(node_type)
|
||||||
if base_type == "tosca.policies.Placement":
|
if base_type in policy_type:
|
||||||
return operations
|
return operations
|
||||||
if node_type.interfaces and lifecycle_name in node_type.interfaces:
|
if node_type.interfaces and lifecycle_name in node_type.interfaces:
|
||||||
for name, elems in node_type.interfaces[lifecycle_name].items():
|
for name, elems in node_type.interfaces[lifecycle_name].items():
|
||||||
|
95
translator/hot/tosca/tests/test_tosca_autoscaling.py
Normal file
95
translator/hot/tosca/tests/test_tosca_autoscaling.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# 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 = {'default_instances': 3,
|
||||||
|
'max_size': 10,
|
||||||
|
'min_size': 2,
|
||||||
|
'resources': {'properties': {
|
||||||
|
'flavor': 'm1.medium',
|
||||||
|
'image': 'rhel-6.5-test-image',
|
||||||
|
'user_data_format': 'SOFTWARE_CONFIG'},
|
||||||
|
'type': 'OS::Nova::Server'}}
|
||||||
|
|
||||||
|
self._tosca_scaling_test(
|
||||||
|
tpl_snippet,
|
||||||
|
expectedprops)
|
74
translator/hot/tosca/tosca_policies_scaling.py
Normal file
74
translator/hot/tosca/tosca_policies_scaling.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#
|
||||||
|
# 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 = 'ToscaAutoscaling'
|
||||||
|
|
||||||
|
|
||||||
|
class ToscaAutoscaling(HotResource):
|
||||||
|
'''Translate TOSCA node type tosca.policies.Scaling'''
|
||||||
|
|
||||||
|
toscatype = 'tosca.policies.Scaling'
|
||||||
|
|
||||||
|
def __init__(self, policy):
|
||||||
|
hot_type = "OS::Heat::ScalingPolicy"
|
||||||
|
super(ToscaAutoscaling, self).__init__(policy,
|
||||||
|
type=hot_type)
|
||||||
|
self.policy = policy
|
||||||
|
|
||||||
|
def handle_expansion(self):
|
||||||
|
sample = self.policy.\
|
||||||
|
entity_tpl["triggers"]["resize_compute"]["condition"]
|
||||||
|
prop = {}
|
||||||
|
prop["description"] = self.policy.entity_tpl['description']
|
||||||
|
prop["meter_name"] = "cpu_util"
|
||||||
|
prop["statistic"] = sample["method"]
|
||||||
|
prop["period"] = sample["period"]
|
||||||
|
prop["threshold"] = sample["evaluations"]
|
||||||
|
prop["comparison_operator"] = "gt"
|
||||||
|
ceilometer_resources = HotResource(self.nodetemplate,
|
||||||
|
type='OS::Ceilometer::Alarm',
|
||||||
|
name=self.name + '_alarm',
|
||||||
|
properties=prop)
|
||||||
|
hot_resources = [ceilometer_resources]
|
||||||
|
return hot_resources
|
||||||
|
|
||||||
|
def handle_properties(self, resources):
|
||||||
|
for node in self.policy.targets:
|
||||||
|
self.properties = {}
|
||||||
|
self.properties["auto_scaling_group_id"] = {'get_resource': node}
|
||||||
|
self.properties["adjustment_type"] = "change_in_capacity "
|
||||||
|
self.properties["scaling_adjustment"] = self.\
|
||||||
|
policy.entity_tpl["properties"]["increment"]
|
||||||
|
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["default_instances"] = temp["default_instances"]
|
||||||
|
props['type'] = resource.type
|
||||||
|
props['properties'] = resource.properties
|
||||||
|
res['resources'] = props
|
||||||
|
scaling_resources = \
|
||||||
|
HotResource(resource,
|
||||||
|
type='OS::Heat::AutoScalingGroup',
|
||||||
|
name=resource.name,
|
||||||
|
properties=res)
|
||||||
|
resources.pop(index)
|
||||||
|
resources.insert(index, scaling_resources)
|
||||||
|
return resources
|
@ -169,11 +169,12 @@ class TranslateNodeTemplates(object):
|
|||||||
|
|
||||||
if resource.type == "OS::Nova::ServerGroup":
|
if resource.type == "OS::Nova::ServerGroup":
|
||||||
resource.handle_properties(self.hot_resources)
|
resource.handle_properties(self.hot_resources)
|
||||||
|
elif resource.type == "OS::Heat::ScalingPolicy":
|
||||||
|
self.hot_resources = resource.handle_properties(self.hot_resources)
|
||||||
else:
|
else:
|
||||||
resource.handle_properties()
|
resource.handle_properties()
|
||||||
|
|
||||||
def _translate_nodetemplates(self):
|
def _translate_nodetemplates(self):
|
||||||
|
|
||||||
log.debug(_('Translating the node templates.'))
|
log.debug(_('Translating the node templates.'))
|
||||||
suffix = 0
|
suffix = 0
|
||||||
# Copy the TOSCA graph: nodetemplate
|
# Copy the TOSCA graph: nodetemplate
|
||||||
@ -205,9 +206,8 @@ class TranslateNodeTemplates(object):
|
|||||||
break
|
break
|
||||||
|
|
||||||
suffix = suffix + 1
|
suffix = suffix + 1
|
||||||
attachment_node = self._get_attachment_node(node,
|
attachment_node = self._get_attachment_node(
|
||||||
suffix,
|
node, suffix, volume_name)
|
||||||
volume_name)
|
|
||||||
if attachment_node:
|
if attachment_node:
|
||||||
self.hot_resources.append(attachment_node)
|
self.hot_resources.append(attachment_node)
|
||||||
for i in self.tosca.inputs:
|
for i in self.tosca.inputs:
|
||||||
@ -299,7 +299,8 @@ class TranslateNodeTemplates(object):
|
|||||||
# dependent nodes in correct order
|
# dependent nodes in correct order
|
||||||
self.processed_resources = []
|
self.processed_resources = []
|
||||||
for resource in self.hot_resources:
|
for resource in self.hot_resources:
|
||||||
self._recursive_handle_properties(resource)
|
if resource.type != "OS::Heat::AutoScalingGroup":
|
||||||
|
self._recursive_handle_properties(resource)
|
||||||
|
|
||||||
# handle resources that need to expand to more than one HOT resource
|
# handle resources that need to expand to more than one HOT resource
|
||||||
expansion_resources = []
|
expansion_resources = []
|
||||||
|
36
translator/tests/data/hot_output/hot_autoscaling.yaml
Normal file
36
translator/tests/data/hot_output/hot_autoscaling.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
heat_template_version: 2013-05-23
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Template for deploying servers based on policies.
|
||||||
|
|
||||||
|
parameters: {}
|
||||||
|
resources:
|
||||||
|
my_server_1:
|
||||||
|
type: OS::Heat::AutoScalingGroup
|
||||||
|
properties:
|
||||||
|
min_size: 2
|
||||||
|
default_instances: 3
|
||||||
|
resources:
|
||||||
|
type: OS::Nova::Server
|
||||||
|
properties:
|
||||||
|
flavor: m1.medium
|
||||||
|
user_data_format: SOFTWARE_CONFIG
|
||||||
|
image: rhel-6.5-test-image
|
||||||
|
max_size: 10
|
||||||
|
asg:
|
||||||
|
type: OS::Heat::ScalingPolicy
|
||||||
|
properties:
|
||||||
|
auto_scaling_group_id:
|
||||||
|
get_resource: my_server_1
|
||||||
|
adjustment_type: change_in_capacity
|
||||||
|
scaling_adjustment: 1
|
||||||
|
asg_alarm:
|
||||||
|
type: OS::Ceilometer::Alarm
|
||||||
|
properties:
|
||||||
|
meter_name: cpu_util
|
||||||
|
description: Simple node autoscaling
|
||||||
|
period: 60
|
||||||
|
statistic: average
|
||||||
|
threshold: 1
|
||||||
|
comparison_operator: gt
|
||||||
|
outputs: {}
|
40
translator/tests/data/tosca_autoscaling.yaml
Normal file
40
translator/tests/data/tosca_autoscaling.yaml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Template for deploying servers based on policies.
|
||||||
|
|
||||||
|
topology_template:
|
||||||
|
node_templates:
|
||||||
|
my_server_1:
|
||||||
|
type: tosca.nodes.Compute
|
||||||
|
capabilities:
|
||||||
|
host:
|
||||||
|
properties:
|
||||||
|
num_cpus: 2
|
||||||
|
disk_size: 10 GB
|
||||||
|
mem_size: 512 MB
|
||||||
|
os:
|
||||||
|
properties:
|
||||||
|
# host Operating System image properties
|
||||||
|
architecture: x86_64
|
||||||
|
type: Linux
|
||||||
|
distribution: RHEL
|
||||||
|
version: 6.5
|
||||||
|
policies:
|
||||||
|
- asg:
|
||||||
|
type: tosca.policies.Scaling
|
||||||
|
description: Simple node autoscaling
|
||||||
|
targets: [my_server_1]
|
||||||
|
triggers:
|
||||||
|
resize_compute:
|
||||||
|
description: trigger
|
||||||
|
condition:
|
||||||
|
constraint: utilization greater_than 50%
|
||||||
|
period: 60
|
||||||
|
evaluations: 1
|
||||||
|
method: average
|
||||||
|
properties:
|
||||||
|
min_instances: 2
|
||||||
|
max_instances: 10
|
||||||
|
default_instances: 3
|
||||||
|
increment: 1
|
@ -489,3 +489,9 @@ class ToscaHotTranslationTest(TestCase):
|
|||||||
hot_file = '../tests/data/hot_output/hot_exchange_public_ssh_key.yaml'
|
hot_file = '../tests/data/hot_output/hot_exchange_public_ssh_key.yaml'
|
||||||
params = {}
|
params = {}
|
||||||
self._test_successful_translation(tosca_file, hot_file, params)
|
self._test_successful_translation(tosca_file, hot_file, params)
|
||||||
|
|
||||||
|
def test_hot_translate_scaling_policy(self):
|
||||||
|
tosca_file = '../tests/data/tosca_autoscaling.yaml'
|
||||||
|
hot_file = '../tests/data/hot_output/hot_autoscaling.yaml'
|
||||||
|
params = {}
|
||||||
|
self._test_successful_translation(tosca_file, hot_file, params)
|
||||||
|
Loading…
Reference in New Issue
Block a user