cb741181991c095078b5b1df416f0c4f8ec912ab
[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 "vim_account": {},
44 "sdn": {},
45 }
46
47 def register(self, topic, _id, op_id, task_name, task):
48 """
49 Register a new task
50 :param topic: Can be "ns", "vim_account", "sdn"
51 :param _id: _id of the related item
52 :param op_id: id of the operation of the related item
53 :param task_name: Task descriptive name, as create, instantiate, terminate. Must be unique in this op_id
54 :param task: Task class
55 :return: none
56 """
57 if _id not in self.task_registry[topic]:
58 self.task_registry[topic][_id] = OrderedDict()
59 if op_id not in self.task_registry[topic][_id]:
60 self.task_registry[topic][_id][op_id] = {task_name: task}
61 else:
62 self.task_registry[topic][_id][op_id][task_name] = task
63 # print("registering task", topic, _id, op_id, task_name, task)
64
65 def remove(self, topic, _id, op_id, task_name=None):
66 """
67 When task is ended, it should removed. It ignores missing tasks
68 :param topic: Can be "ns", "vim_account", "sdn"
69 :param _id: _id of the related item
70 :param op_id: id of the operation of the related item
71 :param task_name: Task descriptive name. If note it deletes all
72 :return:
73 """
74 if not self.task_registry[topic].get(_id) or not self.task_registry[topic][_id].get(op_id):
75 return
76 if not task_name:
77 # print("deleting tasks", topic, _id, op_id, self.task_registry[topic][_id][op_id])
78 del self.task_registry[topic][_id][op_id]
79 elif task_name in self.task_registry[topic][_id][op_id]:
80 # print("deleting tasks", topic, _id, op_id, task_name, self.task_registry[topic][_id][op_id][task_name])
81 del self.task_registry[topic][_id][op_id][task_name]
82 if not self.task_registry[topic][_id][op_id]:
83 del self.task_registry[topic][_id][op_id]
84 if not self.task_registry[topic][_id]:
85 del self.task_registry[topic][_id]
86
87 def lookfor_related(self, topic, _id, my_op_id=None):
88 task_list = []
89 task_name_list = []
90 if _id not in self.task_registry[topic]:
91 return "", task_name_list
92 for op_id in reversed(self.task_registry[topic][_id]):
93 if my_op_id:
94 if my_op_id == op_id:
95 my_op_id = None # so that the next task is taken
96 continue
97
98 for task_name, task in self.task_registry[topic][_id][op_id].items():
99 task_list.append(task)
100 task_name_list.append(task_name)
101 break
102 return ", ".join(task_name_list), task_list
103
104 def cancel(self, topic, _id, target_op_id=None, target_task_name=None):
105 """
106 Cancel all active tasks of a concrete ns, vim_account, sdn identified for _id. If op_id is supplied only this is
107 cancelled, and the same with task_name
108 """
109 if not self.task_registry[topic].get(_id):
110 return
111 for op_id in reversed(self.task_registry[topic][_id]):
112 if target_op_id and target_op_id != op_id:
113 continue
114 for task_name, task in self.task_registry[topic][_id][op_id].items():
115 if target_task_name and target_task_name != task_name:
116 continue
117 # result =
118 task.cancel()
119 # if result:
120 # self.logger.debug("{} _id={} order_id={} task={} cancelled".format(topic, _id, op_id, task_name))
121
122
123 class LcmBase:
124
125 def __init__(self, db, msg, fs, logger):
126 """
127
128 :param db: database connection
129 """
130 self.db = db
131 self.msg = msg
132 self.fs = fs
133 self.logger = logger
134
135 def update_db_2(self, item, _id, _desc):
136 """
137 Updates database with _desc information. Upon success _desc is cleared
138 :param item:
139 :param _id:
140 :param _desc:
141 :return:
142 """
143 if not _desc:
144 return
145 try:
146 self.db.set_one(item, {"_id": _id}, _desc)
147 _desc.clear()
148 except DbException as e:
149 self.logger.error("Updating {} _id={} with '{}'. Error: {}".format(item, _id, _desc, e))