Revision 87ed6b79 lib/cmdlib/base.py
b/lib/cmdlib/base.py | ||
---|---|---|
53 | 53 |
self.other = kwargs |
54 | 54 |
|
55 | 55 |
|
56 |
class LUWConfdClient(object): |
|
57 |
"""Wrapper class for wconfd client calls from LUs. |
|
58 |
|
|
59 |
Correctly updates the cache of the LU's owned locks |
|
60 |
when leaving. Also transparently adds the context |
|
61 |
for resource requests. |
|
62 |
|
|
63 |
""" |
|
64 |
def __init__(self, lu): |
|
65 |
self.lu = lu |
|
66 |
|
|
67 |
def TryUpdateLocks(self, req): |
|
68 |
jid, livelockfile = self.lu.wconfdcontext |
|
69 |
self.lu.wconfd.Client().TryUpdateLocks(jid, livelockfile, req) |
|
70 |
self.lu.wconfdlocks = self.lu.wconfd.Client().ListLocks(jid, livelockfile) |
|
71 |
|
|
72 |
def DownGradeLocksLevel(self, level): |
|
73 |
jid, livelockfile = self.lu.wconfdcontext |
|
74 |
self.lu.wconfd.Client().DownGradeLocksLevel(jid, livelockfile, level) |
|
75 |
self.lu.wconfdlocks = self.lu.wconfd.Client().ListLocks(jid, livelockfile) |
|
76 |
|
|
77 |
def FreeLocksLevel(self, level): |
|
78 |
jid, livelockfile = self.lu.wconfdcontext |
|
79 |
self.lu.wconfd.Client().FreeLocksLevel(jid, livelockfile, level) |
|
80 |
self.lu.wconfdlocks = self.lu.wconfd.Client().ListLocks(jid, livelockfile) |
|
81 |
|
|
82 |
|
|
56 | 83 |
class LogicalUnit(object): |
57 | 84 |
"""Logical Unit base class. |
58 | 85 |
|
... | ... | |
76 | 103 |
HTYPE = None |
77 | 104 |
REQ_BGL = True |
78 | 105 |
|
79 |
def __init__(self, processor, op, context, rpc_runner): |
|
106 |
def __init__(self, processor, op, context, rpc_runner, wconfdcontext, wconfd):
|
|
80 | 107 |
"""Constructor for LogicalUnit. |
81 | 108 |
|
82 | 109 |
This needs to be overridden in derived classes in order to check op |
83 | 110 |
validity. |
84 | 111 |
|
112 |
@type wconfdcontext: (int, string) |
|
113 |
@param wconfdcontext: the identity of the logical unit to represent itself |
|
114 |
to wconfd when asking for resources; it is given as job id and livelock |
|
115 |
file. |
|
116 |
@param wconfd: the wconfd class to use; dependency injection to allow |
|
117 |
testability. |
|
118 |
|
|
85 | 119 |
""" |
86 | 120 |
self.proc = processor |
87 | 121 |
self.op = op |
88 | 122 |
self.cfg = context.cfg |
89 |
self.glm = context.glm |
|
90 |
# readability alias |
|
91 |
self.owned_locks = context.glm.list_owned |
|
123 |
self.wconfdlocks = [] |
|
124 |
self.wconfdcontext = wconfdcontext |
|
92 | 125 |
self.context = context |
93 | 126 |
self.rpc = rpc_runner |
127 |
self.wconfd = wconfd # wconfd module to use, for testing |
|
94 | 128 |
|
95 | 129 |
# Dictionaries used to declare locking needs to mcpu |
96 | 130 |
self.needed_locks = None |
... | ... | |
123 | 157 |
|
124 | 158 |
self.CheckArguments() |
125 | 159 |
|
160 |
def WConfdClient(self): |
|
161 |
return LUWConfdClient(self) |
|
162 |
|
|
163 |
def owned_locks(self, level): |
|
164 |
"""Return the list of locks owned by the LU at a given level. |
|
165 |
|
|
166 |
This method assumes that is field wconfdlocks is set correctly |
|
167 |
by mcpu. |
|
168 |
|
|
169 |
""" |
|
170 |
levelprefix = "%s/" % (locking.LEVEL_NAMES[level],) |
|
171 |
locks = set([lock[0][len(levelprefix):] |
|
172 |
for lock in self.wconfdlocks |
|
173 |
if lock[0].startswith(levelprefix)]) |
|
174 |
expand_fns = { |
|
175 |
locking.LEVEL_CLUSTER: (lambda: [locking.BGL]), |
|
176 |
locking.LEVEL_INSTANCE: self.cfg.GetInstanceList, |
|
177 |
locking.LEVEL_NODE_ALLOC: (lambda: [locking.NAL]), |
|
178 |
locking.LEVEL_NODEGROUP: self.cfg.GetNodeGroupList, |
|
179 |
locking.LEVEL_NODE: self.cfg.GetNodeList, |
|
180 |
locking.LEVEL_NODE_RES: self.cfg.GetNodeList, |
|
181 |
locking.LEVEL_NETWORK: self.cfg.GetNetworkList, |
|
182 |
} |
|
183 |
if locking.LOCKSET_NAME in locks: |
|
184 |
return expand_fns[level]() |
|
185 |
else: |
|
186 |
return locks |
|
187 |
|
|
188 |
def release_request(self, level, names): |
|
189 |
"""Return a request to release the specified locks of the given level. |
|
190 |
|
|
191 |
Correctly break up the group lock to do so. |
|
192 |
|
|
193 |
""" |
|
194 |
levelprefix = "%s/" % (locking.LEVEL_NAMES[level],) |
|
195 |
release = [[levelprefix + lock, "release"] for lock in names] |
|
196 |
|
|
197 |
# if we break up the set-lock, make sure we ask for the rest of it. |
|
198 |
setlock = levelprefix + locking.LOCKSET_NAME |
|
199 |
if [setlock, "exclusive"] in self.wconfdlocks: |
|
200 |
owned = self.owned_locks(level) |
|
201 |
request = [[levelprefix + lock, "exclusive"] |
|
202 |
for lock in owned |
|
203 |
if lock not in names] |
|
204 |
elif [setlock, "shared"] in self.wconfdlocks: |
|
205 |
owned = self.owned_locks(level) |
|
206 |
request = [[levelprefix + lock, "shared"] |
|
207 |
for lock in owned |
|
208 |
if lock not in names] |
|
209 |
else: |
|
210 |
request = [] |
|
211 |
|
|
212 |
return release + [[setlock, "release"]] + request |
|
213 |
|
|
126 | 214 |
def CheckArguments(self): |
127 | 215 |
"""Check syntactic validity for the opcode arguments. |
128 | 216 |
|
... | ... | |
515 | 603 |
|
516 | 604 |
# caller specified names and we must keep the same order |
517 | 605 |
assert self.names |
518 |
assert not self.do_locking or lu.glm.is_owned(lock_level) |
|
519 | 606 |
|
520 | 607 |
missing = set(self.wanted).difference(names) |
521 | 608 |
if missing: |
Also available in: Unified diff