split code into several files
[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 def versiontuple(v):
16 """utility for compare dot separate versions. Fills with zeros to proper number comparison"""
17 filled = []
18 for point in v.split("."):
19 filled.append(point.zfill(8))
20 return tuple(filled)
21
22
23 class TaskRegistry:
24 """
25 Implements a registry of task needed for later cancelation, look for related tasks that must be completed before
26 etc. It stores a four level dict
27 First level is the topic, ns, vim_account, sdn
28 Second level is the _id
29 Third level is the operation id
30 Fourth level is a descriptive name, the value is the task class
31 """
32
33 def __init__(self):
34 self.task_registry = {
35 "ns": {},
36 "vim_account": {},
37 "sdn": {},
38 }
39
40 def register(self, topic, _id, op_id, task_name, task):
41 """
42 Register a new task
43 :param topic: Can be "ns", "vim_account", "sdn"
44 :param _id: _id of the related item
45 :param op_id: id of the operation of the related item
46 :param task_name: Task descriptive name, as create, instantiate, terminate. Must be unique in this op_id
47 :param task: Task class
48 :return: none
49 """
50 if _id not in self.task_registry[topic]:
51 self.task_registry[topic][_id] = OrderedDict()
52 if op_id not in self.task_registry[topic][_id]:
53 self.task_registry[topic][_id][op_id] = {task_name: task}
54 else:
55 self.task_registry[topic][_id][op_id][task_name] = task
56 # print("registering task", topic, _id, op_id, task_name, task)
57
58 def remove(self, topic, _id, op_id, task_name=None):
59 """
60 When task is ended, it should removed. It ignores missing tasks
61 :param topic: Can be "ns", "vim_account", "sdn"
62 :param _id: _id of the related item
63 :param op_id: id of the operation of the related item
64 :param task_name: Task descriptive name. If note it deletes all
65 :return:
66 """
67 if not self.task_registry[topic].get(_id) or not self.task_registry[topic][_id].get(op_id):
68 return
69 if not task_name:
70 # print("deleting tasks", topic, _id, op_id, self.task_registry[topic][_id][op_id])
71 del self.task_registry[topic][_id][op_id]
72 elif task_name in self.task_registry[topic][_id][op_id]:
73 # print("deleting tasks", topic, _id, op_id, task_name, self.task_registry[topic][_id][op_id][task_name])
74 del self.task_registry[topic][_id][op_id][task_name]
75 if not self.task_registry[topic][_id][op_id]:
76 del self.task_registry[topic][_id][op_id]
77 if not self.task_registry[topic][_id]:
78 del self.task_registry[topic][_id]
79
80 def lookfor_related(self, topic, _id, my_op_id=None):
81 task_list = []
82 task_name_list = []
83 if _id not in self.task_registry[topic]:
84 return "", task_name_list
85 for op_id in reversed(self.task_registry[topic][_id]):
86 if my_op_id:
87 if my_op_id == op_id:
88 my_op_id = None # so that the next task is taken
89 continue
90
91 for task_name, task in self.task_registry[topic][_id][op_id].items():
92 task_list.append(task)
93 task_name_list.append(task_name)
94 break
95 return ", ".join(task_name_list), task_list
96
97 def cancel(self, topic, _id, target_op_id=None, target_task_name=None):
98 """
99 Cancel all active tasks of a concrete ns, vim_account, sdn identified for _id. If op_id is supplied only this is
100 cancelled, and the same with task_name
101 """
102 if not self.task_registry[topic].get(_id):
103 return
104 for op_id in reversed(self.task_registry[topic][_id]):
105 if target_op_id and target_op_id != op_id:
106 continue
107 for task_name, task in self.task_registry[topic][_id][op_id].items():
108 if target_task_name and target_task_name != task_name:
109 continue
110 # result =
111 task.cancel()
112 # if result:
113 # self.logger.debug("{} _id={} order_id={} task={} cancelled".format(topic, _id, op_id, task_name))
114
115
116 class LcmBase:
117
118 def __init__(self, db, msg, fs, logger):
119 """
120
121 :param db: database connection
122 """
123 self.db = db
124 self.msg = msg
125 self.fs = fs
126 self.logger = logger
127
128 def update_db_2(self, item, _id, _desc):
129 """
130 Updates database with _desc information. Upon success _desc is cleared
131 :param item:
132 :param _id:
133 :param _desc:
134 :return:
135 """
136 if not _desc:
137 return
138 try:
139 self.db.set_one(item, {"_id": _id}, _desc)
140 _desc.clear()
141 except DbException as e:
142 self.logger.error("Updating {} _id={} with '{}'. Error: {}".format(item, _id, _desc, e))