Network Slice Manager: Instantiate and Terminate actions
[osm/LCM.git] / osm_lcm / lcm_utils.py
1 #!/usr/bin/python3
2 # -*- coding: utf-8 -*-
3
4
5 from collections import OrderedDict
6 from osm_common.dbbase import DbException
7
8 __author__ = "Alfonso Tierno"
9
10
11 class LcmException(Exception):
12 pass
13
14
15 class LcmExceptionNoMgmtIP(LcmException):
16 pass
17
18
19 def versiontuple(v):
20 """utility for compare dot separate versions. Fills with zeros to proper number comparison
21 package version will be something like 4.0.1.post11+gb3f024d.dirty-1. Where 4.0.1 is the git tag, postXX is the
22 number of commits from this tag, and +XXXXXXX is the git commit short id. Total length is 16 with until 999 commits
23 """
24 filled = []
25 for point in v.split("."):
26 filled.append(point.zfill(16))
27 return tuple(filled)
28
29
30 class TaskRegistry:
31 """
32 Implements a registry of task needed for later cancelation, look for related tasks that must be completed before
33 etc. It stores a four level dict
34 First level is the topic, ns, vim_account, sdn
35 Second level is the _id
36 Third level is the operation id
37 Fourth level is a descriptive name, the value is the task class
38 """
39
40 def __init__(self):
41 self.task_registry = {
42 "ns": {},
43 "nsi": {},
44 "vim_account": {},
45 "sdn": {},
46 }
47
48 def register(self, topic, _id, op_id, task_name, task):
49 """
50 Register a new task
51 :param topic: Can be "ns", "nsi", "vim_account", "sdn"
52 :param _id: _id of the related item
53 :param op_id: id of the operation of the related item
54 :param task_name: Task descriptive name, as create, instantiate, terminate. Must be unique in this op_id
55 :param task: Task class
56 :return: none
57 """
58 if _id not in self.task_registry[topic]:
59 self.task_registry[topic][_id] = OrderedDict()
60 if op_id not in self.task_registry[topic][_id]:
61 self.task_registry[topic][_id][op_id] = {task_name: task}
62 else:
63 self.task_registry[topic][_id][op_id][task_name] = task
64 # print("registering task", topic, _id, op_id, task_name, task)
65
66 def remove(self, topic, _id, op_id, task_name=None):
67 """
68 When task is ended, it should removed. It ignores missing tasks
69 :param topic: Can be "ns", "nsi", "vim_account", "sdn"
70 :param _id: _id of the related item
71 :param op_id: id of the operation of the related item
72 :param task_name: Task descriptive name. If note it deletes all
73 :return:
74 """
75 if not self.task_registry[topic].get(_id) or not self.task_registry[topic][_id].get(op_id):
76 return
77 if not task_name:
78 # print("deleting tasks", topic, _id, op_id, self.task_registry[topic][_id][op_id])
79 del self.task_registry[topic][_id][op_id]
80 elif task_name in self.task_registry[topic][_id][op_id]:
81 # print("deleting tasks", topic, _id, op_id, task_name, self.task_registry[topic][_id][op_id][task_name])
82 del self.task_registry[topic][_id][op_id][task_name]
83 if not self.task_registry[topic][_id][op_id]:
84 del self.task_registry[topic][_id][op_id]
85 if not self.task_registry[topic][_id]:
86 del self.task_registry[topic][_id]
87
88 def lookfor_related(self, topic, _id, my_op_id=None):
89 task_list = []
90 task_name_list = []
91 if _id not in self.task_registry[topic]:
92 return "", task_name_list
93 for op_id in reversed(self.task_registry[topic][_id]):
94 if my_op_id:
95 if my_op_id == op_id:
96 my_op_id = None # so that the next task is taken
97 continue
98
99 for task_name, task in self.task_registry[topic][_id][op_id].items():
100 task_list.append(task)
101 task_name_list.append(task_name)
102 break
103 return ", ".join(task_name_list), task_list
104
105 def cancel(self, topic, _id, target_op_id=None, target_task_name=None):
106 """
107 Cancel all active tasks of a concrete ns, nsi, vim_account, sdn identified for _id. If op_id is supplied only
108 this is cancelled, and the same with task_name
109 """
110 if not self.task_registry[topic].get(_id):
111 return
112 for op_id in reversed(self.task_registry[topic][_id]):
113 if target_op_id and target_op_id != op_id:
114 continue
115 for task_name, task in self.task_registry[topic][_id][op_id].items():
116 if target_task_name and target_task_name != task_name:
117 continue
118 # result =
119 task.cancel()
120 # if result:
121 # self.logger.debug("{} _id={} order_id={} task={} cancelled".format(topic, _id, op_id, task_name))
122
123
124 class LcmBase:
125
126 def __init__(self, db, msg, fs, logger):
127 """
128
129 :param db: database connection
130 """
131 self.db = db
132 self.msg = msg
133 self.fs = fs
134 self.logger = logger
135
136 def update_db_2(self, item, _id, _desc):
137 """
138 Updates database with _desc information. Upon success _desc is cleared
139 :param item:
140 :param _id:
141 :param _desc:
142 :return:
143 """
144 if not _desc:
145 return
146 try:
147 self.db.set_one(item, {"_id": _id}, _desc)
148 _desc.clear()
149 except DbException as e:
150 self.logger.error("Updating {} _id={} with '{}'. Error: {}".format(item, _id, _desc, e))