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