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