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