Merge "Implemented Scaling policies in heat translator"

This commit is contained in:
Jenkins 2016-08-11 14:20:08 +00:00 committed by Gerrit Code Review
commit cba5bc9ef5
7 changed files with 262 additions and 8 deletions

View File

@ -26,6 +26,8 @@ SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
DELETION_POLICY) = \
('type', 'properties', 'metadata',
'depends_on', 'update_policy', 'deletion_policy')
policy_type = ['tosca.policies.Placement', 'tosca.policies.Scaling']
log = logging.getLogger('heat-translator')
@ -400,7 +402,7 @@ class HotResource(object):
def get_all_artifacts(nodetemplate):
# workaround bug in the parser
base_type = HotResource.get_base_type_str(nodetemplate.type_definition)
if base_type == "tosca.policies.Placement":
if base_type in policy_type:
artifacts = {}
else:
artifacts = nodetemplate.type_definition.get_value('artifacts',
@ -421,7 +423,7 @@ class HotResource(object):
# workaround bug in the parser
base_type = HotResource.get_base_type_str(node.type_definition)
if base_type == "tosca.policies.Placement":
if base_type in policy_type:
return operations
node_type = node.type_definition
@ -441,7 +443,7 @@ class HotResource(object):
def _get_interface_operations_from_type(node_type, node, lifecycle_name):
operations = {}
base_type = HotResource.get_base_type_str(node_type)
if base_type == "tosca.policies.Placement":
if base_type in policy_type:
return operations
if node_type.interfaces and lifecycle_name in node_type.interfaces:
for name, elems in node_type.interfaces[lifecycle_name].items():

View 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)

View 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

View File

@ -169,11 +169,12 @@ class TranslateNodeTemplates(object):
if resource.type == "OS::Nova::ServerGroup":
resource.handle_properties(self.hot_resources)
elif resource.type == "OS::Heat::ScalingPolicy":
self.hot_resources = resource.handle_properties(self.hot_resources)
else:
resource.handle_properties()
def _translate_nodetemplates(self):
log.debug(_('Translating the node templates.'))
suffix = 0
# Copy the TOSCA graph: nodetemplate
@ -205,9 +206,8 @@ class TranslateNodeTemplates(object):
break
suffix = suffix + 1
attachment_node = self._get_attachment_node(node,
suffix,
volume_name)
attachment_node = self._get_attachment_node(
node, suffix, volume_name)
if attachment_node:
self.hot_resources.append(attachment_node)
for i in self.tosca.inputs:
@ -299,6 +299,7 @@ class TranslateNodeTemplates(object):
# dependent nodes in correct order
self.processed_resources = []
for resource in self.hot_resources:
if resource.type != "OS::Heat::AutoScalingGroup":
self._recursive_handle_properties(resource)
# handle resources that need to expand to more than one HOT resource

View 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: {}

View 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

View File

@ -489,3 +489,9 @@ class ToscaHotTranslationTest(TestCase):
hot_file = '../tests/data/hot_output/hot_exchange_public_ssh_key.yaml'
params = {}
self._test_successful_translation(tosca_file, hot_file, params)
def test_hot_translate_scaling_policy(self):
tosca_file = '../tests/data/tosca_autoscaling.yaml'
hot_file = '../tests/data/hot_output/hot_autoscaling.yaml'
params = {}
self._test_successful_translation(tosca_file, hot_file, params)