# # 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 defaultdict from translator.hot.syntax.hot_resource import HotResource # Name used to dynamically load appropriate map class. TARGET_CLASS_NAME = 'ToscaClusterAutoscaling' SCALE_POLICY = 'senlin.policy.scaling-1.0' SERVER_TYPE = 'os.nova.server-1.0' SCALE_TYPE = {'SCALE_IN': 'CLUSTER_SCALE_IN', 'SCALE_OUT': 'CLUSTER_SCALE_OUT'} ALARM_METER_NAME = {'utilization': 'cpu_util'} ALARM_COMPARISON_OPERATOR = {'greater_than': 'gt', 'gerater_equal': 'ge', 'less_than': 'lt', 'less_equal': 'le', 'equal': 'eq', 'not_equal': 'ne'} ALARM_STATISTIC = {'average': 'avg'} class ToscaClusterAutoscaling(HotResource): '''Translate TOSCA node type tosca.policies.Scaling.Cluster''' toscatype = 'tosca.policies.Scaling.Cluster' def __init__(self, policy, csar_dir=None): hot_type = "OS::Senlin::Policy" super(ToscaClusterAutoscaling, self).__init__(policy, type=hot_type, csar_dir=csar_dir) self.policy = policy def _generate_scale_properties(self, target_cluster_nodes, cluster_scale_type): properties = {} bindings = [] policy_res = {} adjustment = {} properties["type"] = SCALE_POLICY for cluster_node in target_cluster_nodes: bindings.append({'cluster': cluster_node}) properties["bindings"] = bindings policy_res["event"] = cluster_scale_type adjustment["type"] = "CHANGE_IN_CAPACITY" adjustment["number"] = self.\ policy.entity_tpl["properties"]["increment"] policy_res["adjustment"] = adjustment properties["properties"] = policy_res return properties def handle_expansion(self): hot_resources = [] trigger_receivers = defaultdict(list) for node in self.policy.targets: for trigger in self.policy.entity_tpl['triggers']: for action in self.policy.\ entity_tpl['triggers'][trigger]['action']: scale_name = action action_sample = self.policy.\ entity_tpl['triggers'][trigger]['action'][action] scale_type = action_sample['type'] scale_implement = action_sample['implementation'] (entity, method) = scale_implement.split('.') receiver_prop = {} receiver_prop['cluster'] = { "get_resource": "%s_cluster" % node } receiver_prop['action'] = SCALE_TYPE[scale_type] receiver_prop['type'] = method receiver_name = node + '_' + scale_name + '_receiver' trigger_receivers[trigger].append(receiver_name) receiver_resources = HotResource(self.nodetemplate, type='OS::Senlin::Receiver', name=receiver_name, properties=receiver_prop) hot_resources.append(receiver_resources) for trigger in self.policy.entity_tpl['triggers']: sample = self.policy.\ entity_tpl['triggers'][trigger]['condition'] (meter_name, comparison_operator, threshold) = \ sample["constraint"].split() threshold = threshold.strip("%") alarm_prop = {} alarm_prop["description"] = self.policy.entity_tpl['description'] alarm_prop["meter_name"] = self.policy.\ entity_tpl['triggers'][trigger]['event_type']['metrics'] alarm_prop["statistic"] = ALARM_STATISTIC[sample['method']] alarm_prop["period"] = sample["period"] alarm_prop["evaluation_periods"] = sample["evaluations"] alarm_prop["threshold"] = threshold alarm_prop["comparison_operator"] = \ ALARM_COMPARISON_OPERATOR[comparison_operator] alarm_prop["repeat_actions"] = "True" alarm_prop["alarm_actions"] = [] for index in range(len(trigger_receivers[trigger])): alarm_prop["alarm_actions"].\ append({'get_attr': [trigger_receivers[trigger][index], 'channel', 'alarm_url']}) ceilometer_resources = HotResource(self.nodetemplate, type='OS::Aodh::Alarm', name=trigger + '_alarm', properties=alarm_prop) hot_resources.append(ceilometer_resources) return hot_resources def handle_properties(self, resources): remove_resources = [] networks = defaultdict(list) for index, resource in enumerate(resources): if resource.type == 'OS::Neutron::Port': for hot_resource in resource.depends_on_nodes: if hot_resource.type != 'OS::Neutron::Net': networks[hot_resource.name].\ append( {'network': '%s' % resource.properties['network']} ) remove_resources.append(resource) elif resource.type == 'OS::Neutron::Net': remove_resources.append(resource) elif resource.name in self.policy.targets and \ resource.type != 'OS::Senlin::Policy': props = {} del resource.properties['user_data_format'] del resource.properties['networks'] props['type'] = SERVER_TYPE props['properties'] = resource.properties profile_resources = \ HotResource(resource, type='OS::Senlin::Profile', name=resource.name, properties=props) resources.pop(index) resources.insert(index, profile_resources) for remove_resource in remove_resources: resources.remove(remove_resource) for index, resource in enumerate(resources): if resource.name in self.policy.targets: resource.properties['properties']['networks'] = \ networks[resource.name] for node in self.policy.targets: props = {} props["profile"] = {'get_resource': '%s' % node} temp = self.policy.entity_tpl["properties"] props["min_size"] = temp["min_instances"] props["max_size"] = temp["max_instances"] props["desired_capacity"] = temp["default_instances"] self.cluster_name = '%s_cluster' % node cluster_resources = \ HotResource(self.nodetemplate, type='OS::Senlin::Cluster', name=self.cluster_name, properties=props) resources.append(cluster_resources) trigger_num = len(self.policy.entity_tpl['triggers']) for num, trigger in enumerate(self.policy.entity_tpl['triggers']): target_cluster_nodes = [] for action in self.policy.\ entity_tpl['triggers'][trigger]['action']: scale_type = self.policy.\ entity_tpl['triggers'][trigger]['action'][action]['type'] for node in self.policy.targets: target_cluster_nodes.\ append({"get_resource": "%s_cluster" % node}) cluster_scale_type = SCALE_TYPE[scale_type] scale_in_props = \ self._generate_scale_properties(target_cluster_nodes, cluster_scale_type) if num == trigger_num - 1: self.name = self.name + '_' + trigger self.properties = scale_in_props break policy_resources = \ HotResource(self.nodetemplate, type='OS::Senlin::Policy', name=self.name + '_' + trigger, properties=scale_in_props) resources.append(policy_resources) return resources