Synchronize upstream version of 0.9
[parser.git] / tosca2heat / heat-translator / translator / hot / tosca / tosca_cluster_policies_scaling.py
1 #
2 # Licensed under the Apache License, Version 2.0 (the "License"); you may
3 # not use this file except in compliance with the License. You may obtain
4 # a copy of the License at
5 #
6 # http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 # License for the specific language governing permissions and limitations
12 # under the License.
13
14 from collections import defaultdict
15
16 from translator.hot.syntax.hot_resource import HotResource
17 # Name used to dynamically load appropriate map class.
18 TARGET_CLASS_NAME = 'ToscaClusterAutoscaling'
19
20 SCALE_POLICY = 'senlin.policy.scaling-1.0'
21 SERVER_TYPE = 'os.nova.server-1.0'
22 SCALE_TYPE = {'SCALE_IN': 'CLUSTER_SCALE_IN',
23               'SCALE_OUT': 'CLUSTER_SCALE_OUT'}
24
25 ALARM_METER_NAME = {'utilization': 'cpu_util'}
26 ALARM_COMPARISON_OPERATOR = {'greater_than': 'gt', 'gerater_equal': 'ge',
27                              'less_than': 'lt', 'less_equal': 'le',
28                              'equal': 'eq', 'not_equal': 'ne'}
29 ALARM_STATISTIC = {'average': 'avg'}
30
31
32 class ToscaClusterAutoscaling(HotResource):
33     '''Translate TOSCA node type tosca.policies.Scaling.Cluster'''
34
35     toscatype = 'tosca.policies.Scaling.Cluster'
36
37     def __init__(self, policy, csar_dir=None):
38         hot_type = "OS::Senlin::Policy"
39         super(ToscaClusterAutoscaling, self).__init__(policy,
40                                                       type=hot_type,
41                                                       csar_dir=csar_dir)
42         self.policy = policy
43
44     def _generate_scale_properties(self,
45                                    target_cluster_nodes,
46                                    cluster_scale_type):
47         properties = {}
48         bindings = []
49         policy_res = {}
50         adjustment = {}
51         properties["type"] = SCALE_POLICY
52         for cluster_node in target_cluster_nodes:
53             bindings.append({'cluster': cluster_node})
54         properties["bindings"] = bindings
55         policy_res["event"] = cluster_scale_type
56         adjustment["type"] = "CHANGE_IN_CAPACITY"
57         adjustment["number"] = self.\
58             policy.entity_tpl["properties"]["increment"]
59         policy_res["adjustment"] = adjustment
60         properties["properties"] = policy_res
61         return properties
62
63     def handle_expansion(self):
64         hot_resources = []
65         trigger_receivers = defaultdict(list)
66         for node in self.policy.targets:
67             for trigger in self.policy.entity_tpl['triggers']:
68                 for action in self.policy.\
69                     entity_tpl['triggers'][trigger]['action']:
70                     scale_name = action
71                     action_sample = self.policy.\
72                         entity_tpl['triggers'][trigger]['action'][action]
73                     scale_type = action_sample['type']
74                     scale_implement = action_sample['implementation']
75                 (entity, method) = scale_implement.split('.')
76                 receiver_prop = {}
77                 receiver_prop['cluster'] = {
78                     "get_resource": "%s_cluster" % node
79                     }
80                 receiver_prop['action'] = SCALE_TYPE[scale_type]
81                 receiver_prop['type'] = method
82                 receiver_name = node + '_' + scale_name + '_receiver'
83                 trigger_receivers[trigger].append(receiver_name)
84                 receiver_resources = HotResource(self.nodetemplate,
85                                                  type='OS::Senlin::Receiver',
86                                                  name=receiver_name,
87                                                  properties=receiver_prop)
88                 hot_resources.append(receiver_resources)
89
90         for trigger in self.policy.entity_tpl['triggers']:
91             sample = self.policy.\
92                 entity_tpl['triggers'][trigger]['condition']
93             (meter_name, comparison_operator, threshold) = \
94                 sample["constraint"].split()
95             threshold = threshold.strip("%")
96             alarm_prop = {}
97             alarm_prop["description"] = self.policy.entity_tpl['description']
98             alarm_prop["meter_name"] = self.policy.\
99                 entity_tpl['triggers'][trigger]['event_type']['metrics']
100             alarm_prop["statistic"] = ALARM_STATISTIC[sample['method']]
101             alarm_prop["period"] = sample["period"]
102             alarm_prop["evaluation_periods"] = sample["evaluations"]
103             alarm_prop["threshold"] = threshold
104             alarm_prop["comparison_operator"] = \
105                 ALARM_COMPARISON_OPERATOR[comparison_operator]
106             alarm_prop["repeat_actions"] = "True"
107             alarm_prop["alarm_actions"] = []
108             for index in range(len(trigger_receivers[trigger])):
109                 alarm_prop["alarm_actions"].\
110                     append({'get_attr': [trigger_receivers[trigger][index],
111                                          'channel',
112                                          'alarm_url']})
113             ceilometer_resources = HotResource(self.nodetemplate,
114                                                type='OS::Aodh::Alarm',
115                                                name=trigger + '_alarm',
116                                                properties=alarm_prop)
117             hot_resources.append(ceilometer_resources)
118         return hot_resources
119
120     def handle_properties(self, resources):
121         remove_resources = []
122         networks = defaultdict(list)
123         for index, resource in enumerate(resources):
124             if resource.type == 'OS::Neutron::Port':
125                 for hot_resource in resource.depends_on_nodes:
126                     if hot_resource.type != 'OS::Neutron::Net':
127                         networks[hot_resource.name].\
128                             append(
129                             {'network': '%s' % resource.properties['network']}
130                             )
131                 remove_resources.append(resource)
132             elif resource.type == 'OS::Neutron::Net':
133                 remove_resources.append(resource)
134             elif resource.name in self.policy.targets and \
135                 resource.type != 'OS::Senlin::Policy':
136                 props = {}
137                 del resource.properties['user_data_format']
138                 del resource.properties['networks']
139                 props['type'] = SERVER_TYPE
140                 props['properties'] = resource.properties
141                 profile_resources = \
142                     HotResource(resource,
143                                 type='OS::Senlin::Profile',
144                                 name=resource.name,
145                                 properties=props)
146                 resources.pop(index)
147                 resources.insert(index, profile_resources)
148         for remove_resource in remove_resources:
149             resources.remove(remove_resource)
150
151         for index, resource in enumerate(resources):
152             if resource.name in self.policy.targets:
153                 resource.properties['properties']['networks'] = \
154                     networks[resource.name]
155
156         for node in self.policy.targets:
157             props = {}
158             props["profile"] = {'get_resource': '%s' % node}
159             temp = self.policy.entity_tpl["properties"]
160             props["min_size"] = temp["min_instances"]
161             props["max_size"] = temp["max_instances"]
162             props["desired_capacity"] = temp["default_instances"]
163             self.cluster_name = '%s_cluster' % node
164             cluster_resources = \
165                 HotResource(self.nodetemplate,
166                             type='OS::Senlin::Cluster',
167                             name=self.cluster_name,
168                             properties=props)
169             resources.append(cluster_resources)
170
171         trigger_num = len(self.policy.entity_tpl['triggers'])
172         for num, trigger in enumerate(self.policy.entity_tpl['triggers']):
173             target_cluster_nodes = []
174             for action in self.policy.\
175                 entity_tpl['triggers'][trigger]['action']:
176                 scale_type = self.policy.\
177                     entity_tpl['triggers'][trigger]['action'][action]['type']
178             for node in self.policy.targets:
179                 target_cluster_nodes.\
180                     append({"get_resource": "%s_cluster" % node})
181             cluster_scale_type = SCALE_TYPE[scale_type]
182             scale_in_props = \
183                 self._generate_scale_properties(target_cluster_nodes,
184                                                 cluster_scale_type)
185             if num == trigger_num - 1:
186                 self.name = self.name + '_' + trigger
187                 self.properties = scale_in_props
188                 break
189             policy_resources = \
190                 HotResource(self.nodetemplate,
191                             type='OS::Senlin::Policy',
192                             name=self.name + '_' + trigger,
193                             properties=scale_in_props)
194             resources.append(policy_resources)
195         return resources