8bbf894f057452bc6e7e6e2c86fd04dd79157d01
[osm/SO.git] / rwlaunchpad / plugins / rwnsm / rift / tasklets / rwnsmtasklet / scale_group.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import time
19
20 from enum import Enum
21
22 from gi.repository import NsdYang, NsrYang
23
24
25 class ScalingGroupIndexExists(Exception):
26 pass
27
28
29 class ScaleGroupTrigger(Enum):
30 """ Trigger for scaling config """
31 PRE_SCALE_IN = 1
32 POST_SCALE_IN = 2
33 PRE_SCALE_OUT = 3
34 POST_SCALE_OUT = 4
35
36
37 class ScaleGroupState(Enum):
38 """ Scaling group state """
39 RUNNING = 1
40 SCALING_IN = 2
41 SCALING_OUT = 3
42
43
44 class ScalingGroup(object):
45 """ This represents a configured NSR scaling group """
46 def __init__(self, log, group_msg):
47 """ Create a ScalingGroup instance
48
49 This class is responsible for representing a configured scaling group
50 which is present within an NSR.
51
52 :param log: A logger instance
53 :param group_msg: A NSD scaling group pb message
54 """
55 self._log = log
56 self._group_msg = group_msg
57
58 self._instances = {}
59
60 def __str__(self):
61 return "ScalingGroup(%s)" % self.name
62
63 @property
64 def name(self):
65 """ Name of the scaling group """
66 return self._group_msg.name
67
68 @property
69 def state(self):
70 """ State of the scaling group """
71 state = ScaleGroupState.RUNNING
72 for instance in self._instances.values():
73 if instance.operational_status in ["init", "vnf_init_phase"]:
74 self._log.debug("Scaling instance %s in scaling-out state: %s",
75 instance, instance.operational_status)
76 state = ScaleGroupState.SCALING_OUT
77
78 elif instance.operational_status in ["terminate", "vnf_terminate_phase"]:
79 self._log.debug("Scaling instance %s in scaling-in state: %s",
80 instance, instance.operational_status)
81 state = ScaleGroupState.SCALING_IN
82
83 return state
84
85 @property
86 def vnf_index_count_map(self):
87 """ The mapping of member_vnf_index_ref to count"""
88 return {mbr.member_vnf_index_ref: mbr.count for mbr in self._group_msg.vnfd_member}
89
90 @property
91 def group_msg(self):
92 """ Return the scale group PB message """
93 return self._group_msg
94
95 @property
96 def min_instance_count(self):
97 """ Minimum (and default) number of instance of the scaling group """
98 return self._group_msg.min_instance_count
99
100 @property
101 def max_instance_count(self):
102 """ Maximum number of instance of the scaling group """
103 return self._group_msg.max_instance_count
104
105 def create_record_msg(self):
106 """ Returns a NSR Scaling group record """
107 msg = NsrYang.YangData_Nsr_NsInstanceOpdata_Nsr_ScalingGroupRecord(
108 scaling_group_name_ref=self.name,
109 )
110
111 for instance in self.instances:
112 msg.instance.append(instance.create_record_msg())
113
114 return msg
115
116 @property
117 def instances(self):
118 return self._instances.values()
119
120 def get_instance(self, instance_id):
121 """ Get a scaling group instance
122
123 :param instance_id: The instance's instance_id
124 """
125 return self._instances[instance_id]
126
127 def create_instance(self, instance_id, is_default=False):
128 """ Create a scaling group instance
129
130 :param instance_id: The new instance's instance_id
131 """
132 self._log.debug("Creating %s instance instance_id %s ", self, instance_id)
133
134 if instance_id in self._instances:
135 raise ScalingGroupIndexExists("%s instance_id %s already exists" % (self, instance_id))
136
137 instance = ScalingGroupInstance(
138 log=self._log,
139 group_name=self.name,
140 instance_id=instance_id,
141 is_default=is_default,
142 )
143
144 self._instances[instance_id] = instance
145
146 return instance
147
148 def delete_instance(self, instance_id):
149 self._log.debug("Deleting %s instance instance_id %s ", self, instance_id)
150 del self._instances[instance_id]
151
152 def trigger_map(self, trigger):
153 trig_map = {
154 NsdYang.ScalingTrigger.PRE_SCALE_IN : 'pre_scale_in',
155 NsdYang.ScalingTrigger.POST_SCALE_IN : 'post_scale_in',
156 NsdYang.ScalingTrigger.PRE_SCALE_OUT : 'pre_scale_out',
157 NsdYang.ScalingTrigger.POST_SCALE_OUT : 'post_scale_out',
158 }
159
160 try:
161 return trig_map[trigger]
162 except Exception as e:
163 self._log.error("Unknown scaling group trigger passed: {}".format(trigger))
164 self._log.exception(e)
165
166 def trigger_config(self, trigger):
167 """ Get the config action for the trigger """
168 self._log.debug("Trigger config {}: {}".format(trigger, self._group_msg))
169 trig = self.trigger_map(trigger)
170 if trig is None:
171 return
172
173 for config in self._group_msg.scaling_config_action:
174 if trig == config.trigger:
175 return config
176
177
178 class ScalingGroupInstance(object):
179 """ This class represents a configured NSR Scaling Group instance"""
180
181 valid_status_list = (
182 "init",
183 "vnf_init_phase",
184 "running",
185 "terminate",
186 "vnf_terminate_phase",
187 "terminated",
188 "failed",
189 )
190
191 valid_config_status_list = (
192 "configuring",
193 "configured",
194 "failed",
195 )
196
197 def __init__(self, log, group_name, instance_id, is_default=False):
198 self._log = log
199 self._group_name = group_name
200 self._instance_id = instance_id
201 self._is_default = is_default
202
203 self._vnfrs = {}
204
205 self._create_time = int(time.time())
206 self._op_status = "init"
207 self._config_status = "configuring"
208 self._config_err_msg = None
209
210 def __str__(self):
211 return "ScalingGroupInstance(%s #%s)" % (self._group_name, self.instance_id)
212
213 @property
214 def operational_status(self):
215 return self._op_status
216
217 @operational_status.setter
218 def operational_status(self, op_status):
219 if op_status not in ScalingGroupInstance.valid_status_list:
220 raise ValueError("Invalid scaling group instance status: %s", op_status)
221
222 self._op_status = op_status
223
224 @property
225 def config_status(self):
226 return self._config_status
227
228 @config_status.setter
229 def config_status(self, status):
230 if status not in ScalingGroupInstance.valid_config_status_list:
231 raise ValueError("%s, invalid status: %s",
232 self, status)
233
234 self._config_status = status
235
236 @property
237 def config_err_msg(self):
238 return self._config_err_msg
239
240 @config_err_msg.setter
241 def config_err_msg(self, msg):
242 if self.config_err_msg is not None:
243 self._log.info("%s, overwriting previous config error msg '%s' with '%s'",
244 self, self.config_err_msg, msg)
245
246 self._config_err_msg = msg
247
248 @property
249 def instance_id(self):
250 return self._instance_id
251
252 @property
253 def is_default(self):
254 return self._is_default
255
256 @property
257 def vnfrs(self):
258 """ Return all VirtualNetworkFunctionRecord's that have been added"""
259 return self._vnfrs.values()
260
261 def create_record_msg(self):
262 msg = NsrYang.YangData_Nsr_NsInstanceOpdata_Nsr_ScalingGroupRecord_Instance(
263 instance_id=self._instance_id,
264 create_time=self._create_time,
265 op_status=self._op_status,
266 config_status=self._config_status,
267 error_msg=self._config_err_msg,
268 is_default=self._is_default
269 )
270
271 for vnfr in self.vnfrs:
272 msg.vnfrs.append(vnfr.id)
273
274 return msg
275
276 def add_vnfr(self, vnfr):
277 """ Add a VirtualNetworkFunctionRecord"""
278 self._log.debug("Added %s to %s", vnfr, self)
279 self._vnfrs[vnfr.id] = vnfr
280