Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 355d1f32

History | View | Annotate | Download (30.8 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 91c17910 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 3ef3c771 Iustin Pop
"""Inter-node RPC library.
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
"""
25 a8083063 Iustin Pop
26 b459a848 Andrea Spadaccini
# pylint: disable=C0103,R0201,R0904
27 72737a7f Iustin Pop
# C0103: Invalid name, since call_ are not valid
28 72737a7f Iustin Pop
# R0201: Method could be a function, we keep all rpcs instance methods
29 72737a7f Iustin Pop
# as not to change them back and forth between static/instance methods
30 72737a7f Iustin Pop
# if they need to start using instance attributes
31 72737a7f Iustin Pop
# R0904: Too many public methods
32 a8083063 Iustin Pop
33 58b311ca Iustin Pop
import logging
34 12bce260 Michael Hanselmann
import zlib
35 12bce260 Michael Hanselmann
import base64
36 33231500 Michael Hanselmann
import pycurl
37 33231500 Michael Hanselmann
import threading
38 cbe4a0a5 Dimitris Aragiorgis
import copy
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
from ganeti import utils
41 a8083063 Iustin Pop
from ganeti import objects
42 ecfe9491 Michael Hanselmann
from ganeti import http
43 7c28c575 Michael Hanselmann
from ganeti import serializer
44 eafd8762 Michael Hanselmann
from ganeti import constants
45 781de953 Iustin Pop
from ganeti import errors
46 a744b676 Manuel Franceschini
from ganeti import netutils
47 eb202c13 Manuel Franceschini
from ganeti import ssconf
48 9a914f7a René Nussbaumer
from ganeti import runtime
49 00267bfe Michael Hanselmann
from ganeti import compat
50 cd40dc53 Michael Hanselmann
from ganeti import rpc_defs
51 80ec9f96 Michael Hanselmann
from ganeti import pathutils
52 cffbbae7 Michael Hanselmann
from ganeti import vcluster
53 a8083063 Iustin Pop
54 200de241 Michael Hanselmann
# Special module generated at build time
55 200de241 Michael Hanselmann
from ganeti import _generated_rpc
56 200de241 Michael Hanselmann
57 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
58 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
59 ae88ef45 Michael Hanselmann
60 a8083063 Iustin Pop
61 33231500 Michael Hanselmann
_RPC_CLIENT_HEADERS = [
62 33231500 Michael Hanselmann
  "Content-type: %s" % http.HTTP_APP_JSON,
63 8e29563f Iustin Pop
  "Expect:",
64 33231500 Michael Hanselmann
  ]
65 4331f6cd Michael Hanselmann
66 00267bfe Michael Hanselmann
#: Special value to describe an offline host
67 00267bfe Michael Hanselmann
_OFFLINE = object()
68 00267bfe Michael Hanselmann
69 4331f6cd Michael Hanselmann
70 4331f6cd Michael Hanselmann
def Init():
71 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
72 4331f6cd Michael Hanselmann

73 33231500 Michael Hanselmann
  Must be called before using any RPC function and while exactly one thread is
74 33231500 Michael Hanselmann
  running.
75 4331f6cd Michael Hanselmann

76 4331f6cd Michael Hanselmann
  """
77 33231500 Michael Hanselmann
  # curl_global_init(3) and curl_global_cleanup(3) must be called with only
78 33231500 Michael Hanselmann
  # one thread running. This check is just a safety measure -- it doesn't
79 33231500 Michael Hanselmann
  # cover all cases.
80 33231500 Michael Hanselmann
  assert threading.activeCount() == 1, \
81 33231500 Michael Hanselmann
         "Found more than one active thread when initializing pycURL"
82 4331f6cd Michael Hanselmann
83 33231500 Michael Hanselmann
  logging.info("Using PycURL %s", pycurl.version)
84 8d0a4f99 Michael Hanselmann
85 33231500 Michael Hanselmann
  pycurl.global_init(pycurl.GLOBAL_ALL)
86 4331f6cd Michael Hanselmann
87 4331f6cd Michael Hanselmann
88 4331f6cd Michael Hanselmann
def Shutdown():
89 4331f6cd Michael Hanselmann
  """Stops the module-global HTTP client manager.
90 4331f6cd Michael Hanselmann

91 33231500 Michael Hanselmann
  Must be called before quitting the program and while exactly one thread is
92 33231500 Michael Hanselmann
  running.
93 4331f6cd Michael Hanselmann

94 4331f6cd Michael Hanselmann
  """
95 33231500 Michael Hanselmann
  pycurl.global_cleanup()
96 33231500 Michael Hanselmann
97 33231500 Michael Hanselmann
98 33231500 Michael Hanselmann
def _ConfigRpcCurl(curl):
99 80ec9f96 Michael Hanselmann
  noded_cert = str(pathutils.NODED_CERT_FILE)
100 4331f6cd Michael Hanselmann
101 33231500 Michael Hanselmann
  curl.setopt(pycurl.FOLLOWLOCATION, False)
102 33231500 Michael Hanselmann
  curl.setopt(pycurl.CAINFO, noded_cert)
103 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYHOST, 0)
104 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYPEER, True)
105 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERTTYPE, "PEM")
106 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERT, noded_cert)
107 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEYTYPE, "PEM")
108 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEY, noded_cert)
109 2ff587d4 Agata Murawska
  curl.setopt(pycurl.CONNECTTIMEOUT, constants.RPC_CONNECT_TIMEOUT)
110 33231500 Michael Hanselmann
111 33231500 Michael Hanselmann
112 e0e916fe Iustin Pop
def RunWithRPC(fn):
113 e0e916fe Iustin Pop
  """RPC-wrapper decorator.
114 e0e916fe Iustin Pop

115 e0e916fe Iustin Pop
  When applied to a function, it runs it with the RPC system
116 e0e916fe Iustin Pop
  initialized, and it shutsdown the system afterwards. This means the
117 e0e916fe Iustin Pop
  function must be called without RPC being initialized.
118 e0e916fe Iustin Pop

119 e0e916fe Iustin Pop
  """
120 e0e916fe Iustin Pop
  def wrapper(*args, **kwargs):
121 e0e916fe Iustin Pop
    Init()
122 e0e916fe Iustin Pop
    try:
123 e0e916fe Iustin Pop
      return fn(*args, **kwargs)
124 e0e916fe Iustin Pop
    finally:
125 e0e916fe Iustin Pop
      Shutdown()
126 e0e916fe Iustin Pop
  return wrapper
127 e0e916fe Iustin Pop
128 e0e916fe Iustin Pop
129 30474135 Michael Hanselmann
def _Compress(data):
130 30474135 Michael Hanselmann
  """Compresses a string for transport over RPC.
131 30474135 Michael Hanselmann

132 30474135 Michael Hanselmann
  Small amounts of data are not compressed.
133 30474135 Michael Hanselmann

134 30474135 Michael Hanselmann
  @type data: str
135 30474135 Michael Hanselmann
  @param data: Data
136 30474135 Michael Hanselmann
  @rtype: tuple
137 30474135 Michael Hanselmann
  @return: Encoded data to send
138 30474135 Michael Hanselmann

139 30474135 Michael Hanselmann
  """
140 30474135 Michael Hanselmann
  # Small amounts of data are not compressed
141 30474135 Michael Hanselmann
  if len(data) < 512:
142 30474135 Michael Hanselmann
    return (constants.RPC_ENCODING_NONE, data)
143 30474135 Michael Hanselmann
144 30474135 Michael Hanselmann
  # Compress with zlib and encode in base64
145 30474135 Michael Hanselmann
  return (constants.RPC_ENCODING_ZLIB_BASE64,
146 30474135 Michael Hanselmann
          base64.b64encode(zlib.compress(data, 3)))
147 30474135 Michael Hanselmann
148 30474135 Michael Hanselmann
149 781de953 Iustin Pop
class RpcResult(object):
150 781de953 Iustin Pop
  """RPC Result class.
151 781de953 Iustin Pop

152 781de953 Iustin Pop
  This class holds an RPC result. It is needed since in multi-node
153 05325a35 Bernardo Dal Seno
  calls we can't raise an exception just because one out of many
154 781de953 Iustin Pop
  failed, and therefore we use this class to encapsulate the result.
155 781de953 Iustin Pop

156 5bbd3f7f Michael Hanselmann
  @ivar data: the data payload, for successful results, or None
157 ed83f5cc Iustin Pop
  @ivar call: the name of the RPC call
158 ed83f5cc Iustin Pop
  @ivar node: the name of the node to which we made the call
159 ed83f5cc Iustin Pop
  @ivar offline: whether the operation failed because the node was
160 ed83f5cc Iustin Pop
      offline, as opposed to actual failure; offline=True will always
161 ed83f5cc Iustin Pop
      imply failed=True, in order to allow simpler checking if
162 ed83f5cc Iustin Pop
      the user doesn't care about the exact failure mode
163 4c4e4e1e Iustin Pop
  @ivar fail_msg: the error message if the call failed
164 ed83f5cc Iustin Pop

165 781de953 Iustin Pop
  """
166 ed83f5cc Iustin Pop
  def __init__(self, data=None, failed=False, offline=False,
167 ed83f5cc Iustin Pop
               call=None, node=None):
168 ed83f5cc Iustin Pop
    self.offline = offline
169 ed83f5cc Iustin Pop
    self.call = call
170 ed83f5cc Iustin Pop
    self.node = node
171 1645d22d Michael Hanselmann
172 ed83f5cc Iustin Pop
    if offline:
173 4c4e4e1e Iustin Pop
      self.fail_msg = "Node is marked offline"
174 f2def43a Iustin Pop
      self.data = self.payload = None
175 ed83f5cc Iustin Pop
    elif failed:
176 4c4e4e1e Iustin Pop
      self.fail_msg = self._EnsureErr(data)
177 f2def43a Iustin Pop
      self.data = self.payload = None
178 781de953 Iustin Pop
    else:
179 781de953 Iustin Pop
      self.data = data
180 d3c8b360 Iustin Pop
      if not isinstance(self.data, (tuple, list)):
181 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result type (%s)" %
182 4c4e4e1e Iustin Pop
                         type(self.data))
183 1645d22d Michael Hanselmann
        self.payload = None
184 d3c8b360 Iustin Pop
      elif len(data) != 2:
185 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result length (%d), "
186 4c4e4e1e Iustin Pop
                         "expected 2" % len(self.data))
187 1645d22d Michael Hanselmann
        self.payload = None
188 d3c8b360 Iustin Pop
      elif not self.data[0]:
189 4c4e4e1e Iustin Pop
        self.fail_msg = self._EnsureErr(self.data[1])
190 1645d22d Michael Hanselmann
        self.payload = None
191 f2def43a Iustin Pop
      else:
192 d3c8b360 Iustin Pop
        # finally success
193 4c4e4e1e Iustin Pop
        self.fail_msg = None
194 d3c8b360 Iustin Pop
        self.payload = data[1]
195 d3c8b360 Iustin Pop
196 2c0f74f2 Iustin Pop
    for attr_name in ["call", "data", "fail_msg",
197 2c0f74f2 Iustin Pop
                      "node", "offline", "payload"]:
198 2c0f74f2 Iustin Pop
      assert hasattr(self, attr_name), "Missing attribute %s" % attr_name
199 1645d22d Michael Hanselmann
200 d3c8b360 Iustin Pop
  @staticmethod
201 d3c8b360 Iustin Pop
  def _EnsureErr(val):
202 d3c8b360 Iustin Pop
    """Helper to ensure we return a 'True' value for error."""
203 d3c8b360 Iustin Pop
    if val:
204 d3c8b360 Iustin Pop
      return val
205 d3c8b360 Iustin Pop
    else:
206 d3c8b360 Iustin Pop
      return "No error information"
207 781de953 Iustin Pop
208 045dd6d9 Iustin Pop
  def Raise(self, msg, prereq=False, ecode=None):
209 781de953 Iustin Pop
    """If the result has failed, raise an OpExecError.
210 781de953 Iustin Pop

211 781de953 Iustin Pop
    This is used so that LU code doesn't have to check for each
212 781de953 Iustin Pop
    result, but instead can call this function.
213 781de953 Iustin Pop

214 781de953 Iustin Pop
    """
215 4c4e4e1e Iustin Pop
    if not self.fail_msg:
216 4c4e4e1e Iustin Pop
      return
217 4c4e4e1e Iustin Pop
218 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
219 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
220 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
221 4c4e4e1e Iustin Pop
    else:
222 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
223 4c4e4e1e Iustin Pop
    if prereq:
224 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
225 4c4e4e1e Iustin Pop
    else:
226 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
227 045dd6d9 Iustin Pop
    if ecode is not None:
228 27137e55 Iustin Pop
      args = (msg, ecode)
229 045dd6d9 Iustin Pop
    else:
230 045dd6d9 Iustin Pop
      args = (msg, )
231 b459a848 Andrea Spadaccini
    raise ec(*args) # pylint: disable=W0142
232 781de953 Iustin Pop
233 95e7e85e Klaus Aehlig
  def Warn(self, msg, feedback_fn):
234 95e7e85e Klaus Aehlig
    """If the result has failed, call the feedback_fn.
235 95e7e85e Klaus Aehlig

236 95e7e85e Klaus Aehlig
    This is used to in cases were LU wants to warn the
237 95e7e85e Klaus Aehlig
    user about a failure, but continue anyway.
238 95e7e85e Klaus Aehlig

239 95e7e85e Klaus Aehlig
    """
240 95e7e85e Klaus Aehlig
    if not self.fail_msg:
241 95e7e85e Klaus Aehlig
      return
242 95e7e85e Klaus Aehlig
243 95e7e85e Klaus Aehlig
    msg = "%s: %s" % (msg, self.fail_msg)
244 95e7e85e Klaus Aehlig
    feedback_fn(msg)
245 95e7e85e Klaus Aehlig
246 781de953 Iustin Pop
247 bd6d1202 René Nussbaumer
def _SsconfResolver(ssconf_ips, node_list, _,
248 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
249 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
250 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
251 eb202c13 Manuel Franceschini

252 bd6d1202 René Nussbaumer
  @type ssconf_ips: bool
253 bd6d1202 René Nussbaumer
  @param ssconf_ips: Use the ssconf IPs
254 eb202c13 Manuel Franceschini
  @type node_list: list
255 eb202c13 Manuel Franceschini
  @param node_list: List of node names
256 eb202c13 Manuel Franceschini
  @type ssc: class
257 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
258 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
259 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
260 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
261 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
262 eb202c13 Manuel Franceschini

263 eb202c13 Manuel Franceschini
  """
264 b43dcc5a Manuel Franceschini
  ss = ssc()
265 b43dcc5a Manuel Franceschini
  family = ss.GetPrimaryIPFamily()
266 bd6d1202 René Nussbaumer
267 bd6d1202 René Nussbaumer
  if ssconf_ips:
268 bd6d1202 René Nussbaumer
    iplist = ss.GetNodePrimaryIPList()
269 bd6d1202 René Nussbaumer
    ipmap = dict(entry.split() for entry in iplist)
270 bd6d1202 René Nussbaumer
  else:
271 bd6d1202 René Nussbaumer
    ipmap = {}
272 00267bfe Michael Hanselmann
273 00267bfe Michael Hanselmann
  result = []
274 b705c7a6 Manuel Franceschini
  for node in node_list:
275 00267bfe Michael Hanselmann
    ip = ipmap.get(node)
276 00267bfe Michael Hanselmann
    if ip is None:
277 00267bfe Michael Hanselmann
      ip = nslookup_fn(node, family=family)
278 1c3231aa Thomas Thrainer
    result.append((node, ip, node))
279 00267bfe Michael Hanselmann
280 00267bfe Michael Hanselmann
  return result
281 00267bfe Michael Hanselmann
282 00267bfe Michael Hanselmann
283 00267bfe Michael Hanselmann
class _StaticResolver:
284 00267bfe Michael Hanselmann
  def __init__(self, addresses):
285 00267bfe Michael Hanselmann
    """Initializes this class.
286 00267bfe Michael Hanselmann

287 00267bfe Michael Hanselmann
    """
288 00267bfe Michael Hanselmann
    self._addresses = addresses
289 00267bfe Michael Hanselmann
290 fce5efd1 Michael Hanselmann
  def __call__(self, hosts, _):
291 00267bfe Michael Hanselmann
    """Returns static addresses for hosts.
292 00267bfe Michael Hanselmann

293 00267bfe Michael Hanselmann
    """
294 00267bfe Michael Hanselmann
    assert len(hosts) == len(self._addresses)
295 1c3231aa Thomas Thrainer
    return zip(hosts, self._addresses, hosts)
296 00267bfe Michael Hanselmann
297 eb202c13 Manuel Franceschini
298 1c3231aa Thomas Thrainer
def _CheckConfigNode(node_uuid_or_name, node, accept_offline_node):
299 00267bfe Michael Hanselmann
  """Checks if a node is online.
300 eb202c13 Manuel Franceschini

301 1c3231aa Thomas Thrainer
  @type node_uuid_or_name: string
302 1c3231aa Thomas Thrainer
  @param node_uuid_or_name: Node UUID
303 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
304 00267bfe Michael Hanselmann
  @param node: Node object
305 eb202c13 Manuel Franceschini

306 00267bfe Michael Hanselmann
  """
307 00267bfe Michael Hanselmann
  if node is None:
308 1c3231aa Thomas Thrainer
    # Assume that the passed parameter was actually a node name, so depend on
309 1c3231aa Thomas Thrainer
    # DNS for name resolution
310 1c3231aa Thomas Thrainer
    return (node_uuid_or_name, node_uuid_or_name, node_uuid_or_name)
311 00267bfe Michael Hanselmann
  else:
312 1c3231aa Thomas Thrainer
    if node.offline and not accept_offline_node:
313 1c3231aa Thomas Thrainer
      ip = _OFFLINE
314 1c3231aa Thomas Thrainer
    else:
315 1c3231aa Thomas Thrainer
      ip = node.primary_ip
316 1c3231aa Thomas Thrainer
    return (node.name, ip, node_uuid_or_name)
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
319 1c3231aa Thomas Thrainer
def _NodeConfigResolver(single_node_fn, all_nodes_fn, node_uuids, opts):
320 00267bfe Michael Hanselmann
  """Calculate node addresses using configuration.
321 a8083063 Iustin Pop

322 1c3231aa Thomas Thrainer
  Note that strings in node_uuids are treated as node names if the UUID is not
323 1c3231aa Thomas Thrainer
  found in the configuration.
324 1c3231aa Thomas Thrainer

325 a8083063 Iustin Pop
  """
326 890ea4ce Michael Hanselmann
  accept_offline_node = (opts is rpc_defs.ACCEPT_OFFLINE_NODE)
327 890ea4ce Michael Hanselmann
328 890ea4ce Michael Hanselmann
  assert accept_offline_node or opts is None, "Unknown option"
329 890ea4ce Michael Hanselmann
330 00267bfe Michael Hanselmann
  # Special case for single-host lookups
331 1c3231aa Thomas Thrainer
  if len(node_uuids) == 1:
332 1c3231aa Thomas Thrainer
    (uuid, ) = node_uuids
333 1c3231aa Thomas Thrainer
    return [_CheckConfigNode(uuid, single_node_fn(uuid), accept_offline_node)]
334 00267bfe Michael Hanselmann
  else:
335 00267bfe Michael Hanselmann
    all_nodes = all_nodes_fn()
336 1c3231aa Thomas Thrainer
    return [_CheckConfigNode(uuid, all_nodes.get(uuid, None),
337 890ea4ce Michael Hanselmann
                             accept_offline_node)
338 1c3231aa Thomas Thrainer
            for uuid in node_uuids]
339 00267bfe Michael Hanselmann
340 00267bfe Michael Hanselmann
341 00267bfe Michael Hanselmann
class _RpcProcessor:
342 aea5caef Michael Hanselmann
  def __init__(self, resolver, port, lock_monitor_cb=None):
343 00267bfe Michael Hanselmann
    """Initializes this class.
344 00267bfe Michael Hanselmann

345 1c3231aa Thomas Thrainer
    @param resolver: callable accepting a list of node UUIDs or hostnames,
346 1c3231aa Thomas Thrainer
      returning a list of tuples containing name, IP address and original name
347 1c3231aa Thomas Thrainer
      of the resolved node. IP address can be the name or the special value
348 1c3231aa Thomas Thrainer
      L{_OFFLINE} to mark offline machines.
349 00267bfe Michael Hanselmann
    @type port: int
350 00267bfe Michael Hanselmann
    @param port: TCP port
351 aea5caef Michael Hanselmann
    @param lock_monitor_cb: Callable for registering with lock monitor
352 3ef3c771 Iustin Pop

353 a8083063 Iustin Pop
    """
354 00267bfe Michael Hanselmann
    self._resolver = resolver
355 00267bfe Michael Hanselmann
    self._port = port
356 aea5caef Michael Hanselmann
    self._lock_monitor_cb = lock_monitor_cb
357 eb202c13 Manuel Franceschini
358 00267bfe Michael Hanselmann
  @staticmethod
359 00267bfe Michael Hanselmann
  def _PrepareRequests(hosts, port, procedure, body, read_timeout):
360 00267bfe Michael Hanselmann
    """Prepares requests by sorting offline hosts into separate list.
361 eb202c13 Manuel Franceschini

362 d9de612c Iustin Pop
    @type body: dict
363 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
364 d9de612c Iustin Pop

365 00267bfe Michael Hanselmann
    """
366 00267bfe Michael Hanselmann
    results = {}
367 00267bfe Michael Hanselmann
    requests = {}
368 bdf7d8c0 Iustin Pop
369 d9de612c Iustin Pop
    assert isinstance(body, dict)
370 d9de612c Iustin Pop
    assert len(body) == len(hosts)
371 d9de612c Iustin Pop
    assert compat.all(isinstance(v, str) for v in body.values())
372 1c3231aa Thomas Thrainer
    assert frozenset(map(lambda x: x[2], hosts)) == frozenset(body.keys()), \
373 d9de612c Iustin Pop
        "%s != %s" % (hosts, body.keys())
374 d9de612c Iustin Pop
375 1c3231aa Thomas Thrainer
    for (name, ip, original_name) in hosts:
376 00267bfe Michael Hanselmann
      if ip is _OFFLINE:
377 00267bfe Michael Hanselmann
        # Node is marked as offline
378 1c3231aa Thomas Thrainer
        results[original_name] = RpcResult(node=name,
379 1c3231aa Thomas Thrainer
                                           offline=True,
380 1c3231aa Thomas Thrainer
                                           call=procedure)
381 00267bfe Michael Hanselmann
      else:
382 1c3231aa Thomas Thrainer
        requests[original_name] = \
383 00267bfe Michael Hanselmann
          http.client.HttpClientRequest(str(ip), port,
384 7530364d Iustin Pop
                                        http.HTTP_POST, str("/%s" % procedure),
385 00267bfe Michael Hanselmann
                                        headers=_RPC_CLIENT_HEADERS,
386 1c3231aa Thomas Thrainer
                                        post_data=body[original_name],
387 7cb2d205 Michael Hanselmann
                                        read_timeout=read_timeout,
388 abbf2cd9 Michael Hanselmann
                                        nicename="%s/%s" % (name, procedure),
389 abbf2cd9 Michael Hanselmann
                                        curl_config_fn=_ConfigRpcCurl)
390 a8083063 Iustin Pop
391 00267bfe Michael Hanselmann
    return (results, requests)
392 00267bfe Michael Hanselmann
393 00267bfe Michael Hanselmann
  @staticmethod
394 00267bfe Michael Hanselmann
  def _CombineResults(results, requests, procedure):
395 00267bfe Michael Hanselmann
    """Combines pre-computed results for offline hosts with actual call results.
396 bdf7d8c0 Iustin Pop

397 a8083063 Iustin Pop
    """
398 00267bfe Michael Hanselmann
    for name, req in requests.items():
399 00267bfe Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
400 00267bfe Michael Hanselmann
        host_result = RpcResult(data=serializer.LoadJson(req.resp_body),
401 00267bfe Michael Hanselmann
                                node=name, call=procedure)
402 00267bfe Michael Hanselmann
      else:
403 00267bfe Michael Hanselmann
        # TODO: Better error reporting
404 00267bfe Michael Hanselmann
        if req.error:
405 00267bfe Michael Hanselmann
          msg = req.error
406 00267bfe Michael Hanselmann
        else:
407 00267bfe Michael Hanselmann
          msg = req.resp_body
408 eb202c13 Manuel Franceschini
409 00267bfe Michael Hanselmann
        logging.error("RPC error in %s on node %s: %s", procedure, name, msg)
410 00267bfe Michael Hanselmann
        host_result = RpcResult(data=msg, failed=True, node=name,
411 00267bfe Michael Hanselmann
                                call=procedure)
412 ecfe9491 Michael Hanselmann
413 00267bfe Michael Hanselmann
      results[name] = host_result
414 92fd2250 Iustin Pop
415 00267bfe Michael Hanselmann
    return results
416 a8083063 Iustin Pop
417 1c3231aa Thomas Thrainer
  def __call__(self, nodes, procedure, body, read_timeout, resolver_opts,
418 065be3f0 Michael Hanselmann
               _req_process_fn=None):
419 00267bfe Michael Hanselmann
    """Makes an RPC request to a number of nodes.
420 ecfe9491 Michael Hanselmann

421 1c3231aa Thomas Thrainer
    @type nodes: sequence
422 1c3231aa Thomas Thrainer
    @param nodes: node UUIDs or Hostnames
423 00267bfe Michael Hanselmann
    @type procedure: string
424 00267bfe Michael Hanselmann
    @param procedure: Request path
425 d9de612c Iustin Pop
    @type body: dictionary
426 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
427 00267bfe Michael Hanselmann
    @type read_timeout: int or None
428 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
429 05325a35 Bernardo Dal Seno
    @rtype: dictionary
430 05325a35 Bernardo Dal Seno
    @return: a dictionary mapping host names to rpc.RpcResult objects
431 a8083063 Iustin Pop

432 a8083063 Iustin Pop
    """
433 83e7af18 Michael Hanselmann
    assert read_timeout is not None, \
434 83e7af18 Michael Hanselmann
      "Missing RPC read timeout for procedure '%s'" % procedure
435 a8083063 Iustin Pop
436 065be3f0 Michael Hanselmann
    if _req_process_fn is None:
437 065be3f0 Michael Hanselmann
      _req_process_fn = http.client.ProcessRequests
438 065be3f0 Michael Hanselmann
439 00267bfe Michael Hanselmann
    (results, requests) = \
440 1c3231aa Thomas Thrainer
      self._PrepareRequests(self._resolver(nodes, resolver_opts), self._port,
441 fce5efd1 Michael Hanselmann
                            procedure, body, read_timeout)
442 a8083063 Iustin Pop
443 abbf2cd9 Michael Hanselmann
    _req_process_fn(requests.values(), lock_monitor_cb=self._lock_monitor_cb)
444 a8083063 Iustin Pop
445 00267bfe Michael Hanselmann
    assert not frozenset(results).intersection(requests)
446 ecfe9491 Michael Hanselmann
447 00267bfe Michael Hanselmann
    return self._CombineResults(results, requests, procedure)
448 a8083063 Iustin Pop
449 a8083063 Iustin Pop
450 cd40dc53 Michael Hanselmann
class _RpcClientBase:
451 065be3f0 Michael Hanselmann
  def __init__(self, resolver, encoder_fn, lock_monitor_cb=None,
452 065be3f0 Michael Hanselmann
               _req_process_fn=None):
453 cd40dc53 Michael Hanselmann
    """Initializes this class.
454 cd40dc53 Michael Hanselmann

455 cd40dc53 Michael Hanselmann
    """
456 065be3f0 Michael Hanselmann
    proc = _RpcProcessor(resolver,
457 065be3f0 Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED),
458 065be3f0 Michael Hanselmann
                         lock_monitor_cb=lock_monitor_cb)
459 065be3f0 Michael Hanselmann
    self._proc = compat.partial(proc, _req_process_fn=_req_process_fn)
460 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
461 cd40dc53 Michael Hanselmann
462 cd40dc53 Michael Hanselmann
  @staticmethod
463 cd40dc53 Michael Hanselmann
  def _EncodeArg(encoder_fn, (argkind, value)):
464 cd40dc53 Michael Hanselmann
    """Encode argument.
465 cd40dc53 Michael Hanselmann

466 cd40dc53 Michael Hanselmann
    """
467 cd40dc53 Michael Hanselmann
    if argkind is None:
468 cd40dc53 Michael Hanselmann
      return value
469 cd40dc53 Michael Hanselmann
    else:
470 cd40dc53 Michael Hanselmann
      return encoder_fn(argkind)(value)
471 cd40dc53 Michael Hanselmann
472 f7d9b3aa Michael Hanselmann
  def _Call(self, cdef, node_list, args):
473 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
474 cd40dc53 Michael Hanselmann

475 cd40dc53 Michael Hanselmann
    """
476 dd6d2d09 Michael Hanselmann
    (procedure, _, resolver_opts, timeout, argdefs,
477 dd6d2d09 Michael Hanselmann
     prep_fn, postproc_fn, _) = cdef
478 f7d9b3aa Michael Hanselmann
479 f7d9b3aa Michael Hanselmann
    if callable(timeout):
480 f7d9b3aa Michael Hanselmann
      read_timeout = timeout(args)
481 f7d9b3aa Michael Hanselmann
    else:
482 f7d9b3aa Michael Hanselmann
      read_timeout = timeout
483 cd40dc53 Michael Hanselmann
484 dd6d2d09 Michael Hanselmann
    if callable(resolver_opts):
485 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts(args)
486 dd6d2d09 Michael Hanselmann
    else:
487 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts
488 dd6d2d09 Michael Hanselmann
489 e78667fe Michael Hanselmann
    if len(args) != len(argdefs):
490 e78667fe Michael Hanselmann
      raise errors.ProgrammerError("Number of passed arguments doesn't match")
491 e78667fe Michael Hanselmann
492 d9de612c Iustin Pop
    enc_args = map(self._encoder, zip(map(compat.snd, argdefs), args))
493 d9de612c Iustin Pop
    if prep_fn is None:
494 d9de612c Iustin Pop
      # for a no-op prep_fn, we serialise the body once, and then we
495 d9de612c Iustin Pop
      # reuse it in the dictionary values
496 d9de612c Iustin Pop
      body = serializer.DumpJson(enc_args)
497 d9de612c Iustin Pop
      pnbody = dict((n, body) for n in node_list)
498 d9de612c Iustin Pop
    else:
499 d9de612c Iustin Pop
      # for a custom prep_fn, we pass the encoded arguments and the
500 d9de612c Iustin Pop
      # node name to the prep_fn, and we serialise its return value
501 764ff2eb Michael Hanselmann
      assert callable(prep_fn)
502 d9de612c Iustin Pop
      pnbody = dict((n, serializer.DumpJson(prep_fn(n, enc_args)))
503 d9de612c Iustin Pop
                    for n in node_list)
504 d9de612c Iustin Pop
505 fce5efd1 Michael Hanselmann
    result = self._proc(node_list, procedure, pnbody, read_timeout,
506 fce5efd1 Michael Hanselmann
                        req_resolver_opts)
507 26d502d0 Michael Hanselmann
508 26d502d0 Michael Hanselmann
    if postproc_fn:
509 d9da5065 Michael Hanselmann
      return dict(map(lambda (key, value): (key, postproc_fn(value)),
510 d9da5065 Michael Hanselmann
                      result.items()))
511 26d502d0 Michael Hanselmann
    else:
512 26d502d0 Michael Hanselmann
      return result
513 cd40dc53 Michael Hanselmann
514 cd40dc53 Michael Hanselmann
515 cd40dc53 Michael Hanselmann
def _ObjectToDict(value):
516 cd40dc53 Michael Hanselmann
  """Converts an object to a dictionary.
517 cd40dc53 Michael Hanselmann

518 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
519 cd40dc53 Michael Hanselmann

520 cd40dc53 Michael Hanselmann
  """
521 cd40dc53 Michael Hanselmann
  return value.ToDict()
522 cd40dc53 Michael Hanselmann
523 cd40dc53 Michael Hanselmann
524 cd40dc53 Michael Hanselmann
def _ObjectListToDict(value):
525 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
526 cd40dc53 Michael Hanselmann

527 cd40dc53 Michael Hanselmann
  """
528 cd40dc53 Michael Hanselmann
  return map(_ObjectToDict, value)
529 cd40dc53 Michael Hanselmann
530 cd40dc53 Michael Hanselmann
531 cd40dc53 Michael Hanselmann
def _EncodeNodeToDiskDict(value):
532 cd40dc53 Michael Hanselmann
  """Encodes a dictionary with node name as key and disk objects as values.
533 cd40dc53 Michael Hanselmann

534 cd40dc53 Michael Hanselmann
  """
535 cd40dc53 Michael Hanselmann
  return dict((name, _ObjectListToDict(disks))
536 cd40dc53 Michael Hanselmann
              for name, disks in value.items())
537 cd40dc53 Michael Hanselmann
538 cd40dc53 Michael Hanselmann
539 601dfcbb Michael Hanselmann
def _PrepareFileUpload(getents_fn, filename):
540 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
541 cd40dc53 Michael Hanselmann

542 cd40dc53 Michael Hanselmann
  """
543 2ce40421 Michael Hanselmann
  statcb = utils.FileStatHelper()
544 2ce40421 Michael Hanselmann
  data = _Compress(utils.ReadFile(filename, preread=statcb))
545 2ce40421 Michael Hanselmann
  st = statcb.st
546 601dfcbb Michael Hanselmann
547 601dfcbb Michael Hanselmann
  if getents_fn is None:
548 601dfcbb Michael Hanselmann
    getents_fn = runtime.GetEnts
549 601dfcbb Michael Hanselmann
550 601dfcbb Michael Hanselmann
  getents = getents_fn()
551 601dfcbb Michael Hanselmann
552 cffbbae7 Michael Hanselmann
  virt_filename = vcluster.MakeVirtualPath(filename)
553 cffbbae7 Michael Hanselmann
554 cffbbae7 Michael Hanselmann
  return [virt_filename, data, st.st_mode, getents.LookupUid(st.st_uid),
555 cd40dc53 Michael Hanselmann
          getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
556 cd40dc53 Michael Hanselmann
557 cd40dc53 Michael Hanselmann
558 cd40dc53 Michael Hanselmann
def _PrepareFinalizeExportDisks(snap_disks):
559 cd40dc53 Michael Hanselmann
  """Encodes disks for finalizing export.
560 cd40dc53 Michael Hanselmann

561 cd40dc53 Michael Hanselmann
  """
562 cd40dc53 Michael Hanselmann
  flat_disks = []
563 cd40dc53 Michael Hanselmann
564 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
565 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
566 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
567 cd40dc53 Michael Hanselmann
    else:
568 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
569 cd40dc53 Michael Hanselmann
570 cd40dc53 Michael Hanselmann
  return flat_disks
571 cd40dc53 Michael Hanselmann
572 cd40dc53 Michael Hanselmann
573 cd40dc53 Michael Hanselmann
def _EncodeImportExportIO((ieio, ieioargs)):
574 cd40dc53 Michael Hanselmann
  """Encodes import/export I/O information.
575 cd40dc53 Michael Hanselmann

576 cd40dc53 Michael Hanselmann
  """
577 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_RAW_DISK:
578 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 1
579 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ))
580 cd40dc53 Michael Hanselmann
581 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_SCRIPT:
582 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 2
583 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ieioargs[1]))
584 cd40dc53 Michael Hanselmann
585 cd40dc53 Michael Hanselmann
  return (ieio, ieioargs)
586 cd40dc53 Michael Hanselmann
587 cd40dc53 Michael Hanselmann
588 cd40dc53 Michael Hanselmann
def _EncodeBlockdevRename(value):
589 cd40dc53 Michael Hanselmann
  """Encodes information for renaming block devices.
590 cd40dc53 Michael Hanselmann

591 cd40dc53 Michael Hanselmann
  """
592 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
593 cd40dc53 Michael Hanselmann
594 cd40dc53 Michael Hanselmann
595 32389d91 Helga Velroyen
def _AddSpindlesToLegacyNodeInfo(result, space_info):
596 32389d91 Helga Velroyen
  """Extracts the spindle information from the space info and adds
597 32389d91 Helga Velroyen
  it to the result dictionary.
598 32389d91 Helga Velroyen

599 32389d91 Helga Velroyen
  @type result: dict of strings
600 32389d91 Helga Velroyen
  @param result: dictionary holding the result of the legacy node info
601 32389d91 Helga Velroyen
  @type space_info: list of dicts of strings
602 32389d91 Helga Velroyen
  @param space_info: list, each row holding space information of one storage
603 32389d91 Helga Velroyen
    unit
604 32389d91 Helga Velroyen
  @rtype: None
605 32389d91 Helga Velroyen
  @return: does not return anything, manipulates the C{result} variable
606 32389d91 Helga Velroyen

607 32389d91 Helga Velroyen
  """
608 32389d91 Helga Velroyen
  lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
609 32389d91 Helga Velroyen
      space_info, constants.ST_LVM_PV)
610 32389d91 Helga Velroyen
  if lvm_pv_info:
611 32389d91 Helga Velroyen
    result["spindles_free"] = lvm_pv_info["storage_free"]
612 32389d91 Helga Velroyen
    result["spindles_total"] = lvm_pv_info["storage_size"]
613 20faaa74 Helga Velroyen
  else:
614 20faaa74 Helga Velroyen
    raise errors.OpExecError("No spindle storage information available.")
615 06fb92cf Bernardo Dal Seno
616 06fb92cf Bernardo Dal Seno
617 20faaa74 Helga Velroyen
def _AddDefaultStorageInfoToLegacyNodeInfo(result, space_info):
618 32389d91 Helga Velroyen
  """Extracts the storage space information of the default storage type from
619 32389d91 Helga Velroyen
  the space info and adds it to the result dictionary.
620 32389d91 Helga Velroyen

621 32389d91 Helga Velroyen
  @see: C{_AddSpindlesToLegacyNodeInfo} for parameter information.
622 06fb92cf Bernardo Dal Seno

623 06fb92cf Bernardo Dal Seno
  """
624 32389d91 Helga Velroyen
  # Check if there is at least one row for non-spindle storage info.
625 32389d91 Helga Velroyen
  no_defaults = (len(space_info) < 1) or \
626 32389d91 Helga Velroyen
      (space_info[0]["type"] == constants.ST_LVM_PV and len(space_info) == 1)
627 32389d91 Helga Velroyen
628 32389d91 Helga Velroyen
  default_space_info = None
629 32389d91 Helga Velroyen
  if no_defaults:
630 32389d91 Helga Velroyen
    logging.warning("No storage info provided for default storage type.")
631 06fb92cf Bernardo Dal Seno
  else:
632 32389d91 Helga Velroyen
    default_space_info = space_info[0]
633 32389d91 Helga Velroyen
634 32389d91 Helga Velroyen
  if default_space_info:
635 32389d91 Helga Velroyen
    result["name"] = default_space_info["name"]
636 32389d91 Helga Velroyen
    result["storage_free"] = default_space_info["storage_free"]
637 32389d91 Helga Velroyen
    result["storage_size"] = default_space_info["storage_size"]
638 06fb92cf Bernardo Dal Seno
639 06fb92cf Bernardo Dal Seno
640 20faaa74 Helga Velroyen
def MakeLegacyNodeInfo(data, require_spindles=False):
641 b112bfc4 René Nussbaumer
  """Formats the data returned by L{rpc.RpcRunner.call_node_info}.
642 b112bfc4 René Nussbaumer

643 b112bfc4 René Nussbaumer
  Converts the data into a single dictionary. This is fine for most use cases,
644 b112bfc4 René Nussbaumer
  but some require information from more than one volume group or hypervisor.
645 b112bfc4 René Nussbaumer

646 20faaa74 Helga Velroyen
  @param require_spindles: add spindle storage information to the legacy node
647 20faaa74 Helga Velroyen
      info
648 91c17910 Iustin Pop

649 b112bfc4 René Nussbaumer
  """
650 32389d91 Helga Velroyen
  (bootid, space_info, (hv_info, )) = data
651 91c17910 Iustin Pop
652 91c17910 Iustin Pop
  ret = utils.JoinDisjointDicts(hv_info, {"bootid": bootid})
653 91c17910 Iustin Pop
654 20faaa74 Helga Velroyen
  if require_spindles:
655 20faaa74 Helga Velroyen
    _AddSpindlesToLegacyNodeInfo(ret, space_info)
656 20faaa74 Helga Velroyen
  _AddDefaultStorageInfoToLegacyNodeInfo(ret, space_info)
657 b112bfc4 René Nussbaumer
658 91c17910 Iustin Pop
  return ret
659 b112bfc4 René Nussbaumer
660 b112bfc4 René Nussbaumer
661 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
662 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
663 cd46491f René Nussbaumer

664 cd46491f René Nussbaumer
  """
665 cd3b4ff4 Helga Velroyen
  assert disk.dev_type == constants.DT_DRBD8
666 cd46491f René Nussbaumer
667 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
668 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
669 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
670 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
671 cd46491f René Nussbaumer
672 cd46491f René Nussbaumer
  return disk
673 cd46491f René Nussbaumer
674 cd46491f René Nussbaumer
675 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
676 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
677 cd46491f René Nussbaumer

678 cd46491f René Nussbaumer
  """
679 cd3b4ff4 Helga Velroyen
  assert disk.dev_type != constants.DT_DRBD8
680 cd46491f René Nussbaumer
681 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
682 cd46491f René Nussbaumer
683 cd46491f René Nussbaumer
  return disk
684 cd46491f René Nussbaumer
685 cd46491f René Nussbaumer
686 cd46491f René Nussbaumer
def AnnotateDiskParams(template, disks, disk_params):
687 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
688 cd46491f René Nussbaumer

689 cd46491f René Nussbaumer
  @param template: The disk template used
690 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
691 cd46491f René Nussbaumer
  @param disk_params: The disk paramaters for annotation
692 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
693 cd46491f René Nussbaumer

694 cd46491f René Nussbaumer
  """
695 cd46491f René Nussbaumer
  ld_params = objects.Disk.ComputeLDParams(template, disk_params)
696 cd46491f René Nussbaumer
697 cd46491f René Nussbaumer
  if template == constants.DT_DRBD8:
698 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsDRBD
699 cd46491f René Nussbaumer
  elif template == constants.DT_DISKLESS:
700 cd46491f René Nussbaumer
    annotation_fn = lambda disk, _: disk
701 cd46491f René Nussbaumer
  else:
702 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsGeneric
703 cd46491f René Nussbaumer
704 52f93ffd Michael Hanselmann
  return [annotation_fn(disk.Copy(), ld_params) for disk in disks]
705 cd46491f René Nussbaumer
706 cd46491f René Nussbaumer
707 da803ff1 Helga Velroyen
def _GetExclusiveStorageFlag(cfg, node_uuid):
708 1c3231aa Thomas Thrainer
  ni = cfg.GetNodeInfo(node_uuid)
709 319322a7 Bernardo Dal Seno
  if ni is None:
710 1c3231aa Thomas Thrainer
    raise errors.OpPrereqError("Invalid node name %s" % node_uuid,
711 319322a7 Bernardo Dal Seno
                               errors.ECODE_NOENT)
712 319322a7 Bernardo Dal Seno
  return cfg.GetNdParams(ni)[constants.ND_EXCLUSIVE_STORAGE]
713 319322a7 Bernardo Dal Seno
714 319322a7 Bernardo Dal Seno
715 da803ff1 Helga Velroyen
def _AddExclusiveStorageFlagToLvmStorageUnits(storage_units, es_flag):
716 da803ff1 Helga Velroyen
  """Adds the exclusive storage flag to lvm units.
717 da803ff1 Helga Velroyen

718 da803ff1 Helga Velroyen
  This function creates a copy of the storage_units lists, with the
719 da803ff1 Helga Velroyen
  es_flag being added to all lvm storage units.
720 da803ff1 Helga Velroyen

721 da803ff1 Helga Velroyen
  @type storage_units: list of pairs (string, string)
722 da803ff1 Helga Velroyen
  @param storage_units: list of 'raw' storage units, consisting only of
723 da803ff1 Helga Velroyen
    (storage_type, storage_key)
724 da803ff1 Helga Velroyen
  @type es_flag: boolean
725 da803ff1 Helga Velroyen
  @param es_flag: exclusive storage flag
726 da803ff1 Helga Velroyen
  @rtype: list of tuples (string, string, list)
727 da803ff1 Helga Velroyen
  @return: list of storage units (storage_type, storage_key, params) with
728 da803ff1 Helga Velroyen
    the params containing the es_flag for lvm-vg storage units
729 da803ff1 Helga Velroyen

730 da803ff1 Helga Velroyen
  """
731 da803ff1 Helga Velroyen
  result = []
732 da803ff1 Helga Velroyen
  for (storage_type, storage_key) in storage_units:
733 52a8a6ae Helga Velroyen
    if storage_type in [constants.ST_LVM_VG, constants.ST_LVM_PV]:
734 52a8a6ae Helga Velroyen
      result.append((storage_type, storage_key, [es_flag]))
735 da803ff1 Helga Velroyen
    else:
736 da803ff1 Helga Velroyen
      result.append((storage_type, storage_key, []))
737 da803ff1 Helga Velroyen
  return result
738 da803ff1 Helga Velroyen
739 da803ff1 Helga Velroyen
740 1c3231aa Thomas Thrainer
def GetExclusiveStorageForNodes(cfg, node_uuids):
741 319322a7 Bernardo Dal Seno
  """Return the exclusive storage flag for all the given nodes.
742 319322a7 Bernardo Dal Seno

743 319322a7 Bernardo Dal Seno
  @type cfg: L{config.ConfigWriter}
744 319322a7 Bernardo Dal Seno
  @param cfg: cluster configuration
745 1c3231aa Thomas Thrainer
  @type node_uuids: list or tuple
746 1c3231aa Thomas Thrainer
  @param node_uuids: node UUIDs for which to read the flag
747 319322a7 Bernardo Dal Seno
  @rtype: dict
748 da803ff1 Helga Velroyen
  @return: mapping from node uuids to exclusive storage flags
749 1c3231aa Thomas Thrainer
  @raise errors.OpPrereqError: if any given node name has no corresponding
750 1c3231aa Thomas Thrainer
  node
751 319322a7 Bernardo Dal Seno

752 319322a7 Bernardo Dal Seno
  """
753 da803ff1 Helga Velroyen
  getflag = lambda n: _GetExclusiveStorageFlag(cfg, n)
754 1c3231aa Thomas Thrainer
  flags = map(getflag, node_uuids)
755 1c3231aa Thomas Thrainer
  return dict(zip(node_uuids, flags))
756 319322a7 Bernardo Dal Seno
757 319322a7 Bernardo Dal Seno
758 da803ff1 Helga Velroyen
def PrepareStorageUnitsForNodes(cfg, storage_units, node_uuids):
759 da803ff1 Helga Velroyen
  """Return the lvm storage unit for all the given nodes.
760 da803ff1 Helga Velroyen

761 da803ff1 Helga Velroyen
  Main purpose of this function is to map the exclusive storage flag, which
762 da803ff1 Helga Velroyen
  can be different for each node, to the default LVM storage unit.
763 da803ff1 Helga Velroyen

764 da803ff1 Helga Velroyen
  @type cfg: L{config.ConfigWriter}
765 da803ff1 Helga Velroyen
  @param cfg: cluster configuration
766 da803ff1 Helga Velroyen
  @type storage_units: list of pairs (string, string)
767 da803ff1 Helga Velroyen
  @param storage_units: list of 'raw' storage units, e.g. pairs of
768 da803ff1 Helga Velroyen
    (storage_type, storage_key)
769 da803ff1 Helga Velroyen
  @type node_uuids: list or tuple
770 da803ff1 Helga Velroyen
  @param node_uuids: node UUIDs for which to read the flag
771 da803ff1 Helga Velroyen
  @rtype: dict
772 da803ff1 Helga Velroyen
  @return: mapping from node uuids to a list of storage units which include
773 da803ff1 Helga Velroyen
    the exclusive storage flag for lvm storage
774 da803ff1 Helga Velroyen
  @raise errors.OpPrereqError: if any given node name has no corresponding
775 da803ff1 Helga Velroyen
  node
776 da803ff1 Helga Velroyen

777 da803ff1 Helga Velroyen
  """
778 da803ff1 Helga Velroyen
  getunit = lambda n: _AddExclusiveStorageFlagToLvmStorageUnits(
779 da803ff1 Helga Velroyen
      storage_units, _GetExclusiveStorageFlag(cfg, n))
780 da803ff1 Helga Velroyen
  flags = map(getunit, node_uuids)
781 da803ff1 Helga Velroyen
  return dict(zip(node_uuids, flags))
782 da803ff1 Helga Velroyen
783 da803ff1 Helga Velroyen
784 cd40dc53 Michael Hanselmann
#: Generic encoders
785 cd40dc53 Michael Hanselmann
_ENCODERS = {
786 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
787 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
788 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
789 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
790 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
791 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
792 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
793 cd40dc53 Michael Hanselmann
  }
794 cd40dc53 Michael Hanselmann
795 cd40dc53 Michael Hanselmann
796 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
797 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
798 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
799 bd6d1202 René Nussbaumer
                _generated_rpc.RpcClientDnsOnly,
800 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
801 87b3cb26 Michael Hanselmann
  """RPC runner class.
802 a8083063 Iustin Pop

803 87b3cb26 Michael Hanselmann
  """
804 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
805 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
806 a8083063 Iustin Pop

807 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
808 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
809 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
810 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
811 a8083063 Iustin Pop

812 72737a7f Iustin Pop
    """
813 d5ea30e8 Michael Hanselmann
    self._cfg = cfg
814 cd40dc53 Michael Hanselmann
815 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
816 cd40dc53 Michael Hanselmann
817 cd40dc53 Michael Hanselmann
    encoders.update({
818 601dfcbb Michael Hanselmann
      # Encoders requiring configuration object
819 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
820 5fce6a89 Constantinos Venetsanopoulos
      rpc_defs.ED_INST_DICT_HVP_BEP_DP: self._InstDictHvpBepDp,
821 b8291e00 René Nussbaumer
      rpc_defs.ED_INST_DICT_OSP_DP: self._InstDictOspDp,
822 cbe4a0a5 Dimitris Aragiorgis
      rpc_defs.ED_NIC_DICT: self._NicDict,
823 601dfcbb Michael Hanselmann
824 aedf5fd7 René Nussbaumer
      # Encoders annotating disk parameters
825 aedf5fd7 René Nussbaumer
      rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP,
826 235a6b29 Thomas Thrainer
      rpc_defs.ED_MULTI_DISKS_DICT_DP: self._MultiDiskDictDP,
827 aedf5fd7 René Nussbaumer
      rpc_defs.ED_SINGLE_DISK_DICT_DP: self._SingleDiskDictDP,
828 aedf5fd7 René Nussbaumer
829 601dfcbb Michael Hanselmann
      # Encoders with special requirements
830 601dfcbb Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
831 cd40dc53 Michael Hanselmann
      })
832 cd40dc53 Michael Hanselmann
833 cd40dc53 Michael Hanselmann
    # Resolver using configuration
834 d5ea30e8 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, cfg.GetNodeInfo,
835 d5ea30e8 Michael Hanselmann
                              cfg.GetAllNodesInfo)
836 cd40dc53 Michael Hanselmann
837 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
838 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
839 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
840 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
841 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
842 d5ea30e8 Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
843 d5ea30e8 Michael Hanselmann
                            _req_process_fn=_req_process_fn)
844 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
845 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
846 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
847 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
848 200de241 Michael Hanselmann
849 cbe4a0a5 Dimitris Aragiorgis
  def _NicDict(self, nic):
850 cbe4a0a5 Dimitris Aragiorgis
    """Convert the given nic to a dict and encapsulate netinfo
851 cbe4a0a5 Dimitris Aragiorgis

852 cbe4a0a5 Dimitris Aragiorgis
    """
853 cbe4a0a5 Dimitris Aragiorgis
    n = copy.deepcopy(nic)
854 cbe4a0a5 Dimitris Aragiorgis
    if n.network:
855 cbe4a0a5 Dimitris Aragiorgis
      net_uuid = self._cfg.LookupNetwork(n.network)
856 cbe4a0a5 Dimitris Aragiorgis
      if net_uuid:
857 cbe4a0a5 Dimitris Aragiorgis
        nobj = self._cfg.GetNetwork(net_uuid)
858 cbe4a0a5 Dimitris Aragiorgis
        n.netinfo = objects.Network.ToDict(nobj)
859 cbe4a0a5 Dimitris Aragiorgis
    return n.ToDict()
860 cbe4a0a5 Dimitris Aragiorgis
861 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
862 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
863 26ba2bd8 Iustin Pop

864 26ba2bd8 Iustin Pop
    This is done via the instance's ToDict() method and additionally
865 26ba2bd8 Iustin Pop
    we fill the hvparams with the cluster defaults.
866 26ba2bd8 Iustin Pop

867 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
868 26ba2bd8 Iustin Pop
    @param instance: an Instance object
869 0eca8e0c Iustin Pop
    @type hvp: dict or None
870 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
871 0eca8e0c Iustin Pop
    @type bep: dict or None
872 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
873 1bdcbbab Iustin Pop
    @type osp: dict or None
874 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
875 26ba2bd8 Iustin Pop
    @rtype: dict
876 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
877 26ba2bd8 Iustin Pop
        cluster defaults
878 26ba2bd8 Iustin Pop

879 26ba2bd8 Iustin Pop
    """
880 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
881 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
882 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
883 0eca8e0c Iustin Pop
    if hvp is not None:
884 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
885 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
886 0eca8e0c Iustin Pop
    if bep is not None:
887 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
888 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
889 1bdcbbab Iustin Pop
    if osp is not None:
890 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
891 cbe4a0a5 Dimitris Aragiorgis
    idict["disks"] = self._DisksDictDP((instance.disks, instance))
892 b848ce79 Guido Trotter
    for nic in idict["nics"]:
893 3ccb3a64 Michael Hanselmann
      nic["nicparams"] = objects.FillDict(
894 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
895 3ccb3a64 Michael Hanselmann
        nic["nicparams"])
896 cbe4a0a5 Dimitris Aragiorgis
      network = nic.get("network", None)
897 cbe4a0a5 Dimitris Aragiorgis
      if network:
898 cbe4a0a5 Dimitris Aragiorgis
        net_uuid = self._cfg.LookupNetwork(network)
899 cbe4a0a5 Dimitris Aragiorgis
        if net_uuid:
900 cbe4a0a5 Dimitris Aragiorgis
          nobj = self._cfg.GetNetwork(net_uuid)
901 cbe4a0a5 Dimitris Aragiorgis
          nic["netinfo"] = objects.Network.ToDict(nobj)
902 26ba2bd8 Iustin Pop
    return idict
903 26ba2bd8 Iustin Pop
904 5fce6a89 Constantinos Venetsanopoulos
  def _InstDictHvpBepDp(self, (instance, hvp, bep)):
905 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
906 c4de9b7a Michael Hanselmann

907 c4de9b7a Michael Hanselmann
    """
908 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
909 c4de9b7a Michael Hanselmann
910 b8291e00 René Nussbaumer
  def _InstDictOspDp(self, (instance, osparams)):
911 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
912 c4de9b7a Michael Hanselmann

913 c4de9b7a Michael Hanselmann
    """
914 0e2b7c58 Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
915 c4de9b7a Michael Hanselmann
916 aedf5fd7 René Nussbaumer
  def _DisksDictDP(self, (disks, instance)):
917 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
918 aedf5fd7 René Nussbaumer

919 aedf5fd7 René Nussbaumer
    """
920 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
921 aedf5fd7 René Nussbaumer
    return [disk.ToDict()
922 aedf5fd7 René Nussbaumer
            for disk in AnnotateDiskParams(instance.disk_template,
923 aedf5fd7 René Nussbaumer
                                           disks, diskparams)]
924 aedf5fd7 René Nussbaumer
925 235a6b29 Thomas Thrainer
  def _MultiDiskDictDP(self, disks_insts):
926 235a6b29 Thomas Thrainer
    """Wrapper for L{AnnotateDiskParams}.
927 235a6b29 Thomas Thrainer

928 235a6b29 Thomas Thrainer
    Supports a list of (disk, instance) tuples.
929 235a6b29 Thomas Thrainer
    """
930 235a6b29 Thomas Thrainer
    return [disk for disk_inst in disks_insts
931 235a6b29 Thomas Thrainer
            for disk in self._DisksDictDP(disk_inst)]
932 235a6b29 Thomas Thrainer
933 aedf5fd7 René Nussbaumer
  def _SingleDiskDictDP(self, (disk, instance)):
934 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
935 aedf5fd7 René Nussbaumer

936 aedf5fd7 René Nussbaumer
    """
937 aedf5fd7 René Nussbaumer
    (anno_disk,) = self._DisksDictDP(([disk], instance))
938 aedf5fd7 René Nussbaumer
    return anno_disk
939 aedf5fd7 René Nussbaumer
940 fb1ffbca Michael Hanselmann
941 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
942 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
943 fb1ffbca Michael Hanselmann

944 fb1ffbca Michael Hanselmann
  """
945 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
946 fb1ffbca Michael Hanselmann
    """Initializes this class.
947 fb1ffbca Michael Hanselmann

948 fb1ffbca Michael Hanselmann
    """
949 fb1ffbca Michael Hanselmann
    if address_list is None:
950 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
951 fb1ffbca Michael Hanselmann
    else:
952 fb1ffbca Michael Hanselmann
      # Caller provided an address list
953 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
954 fb1ffbca Michael Hanselmann
955 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
956 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
957 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
958 db04ce5d Michael Hanselmann
959 db04ce5d Michael Hanselmann
960 bd6d1202 René Nussbaumer
class BootstrapRunner(_RpcClientBase,
961 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientBootstrap,
962 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientDnsOnly):
963 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
964 db04ce5d Michael Hanselmann

965 db04ce5d Michael Hanselmann
  """
966 db04ce5d Michael Hanselmann
  def __init__(self):
967 db04ce5d Michael Hanselmann
    """Initializes this class.
968 db04ce5d Michael Hanselmann

969 db04ce5d Michael Hanselmann
    """
970 bd6d1202 René Nussbaumer
    # Pylint doesn't recognize multiple inheritance properly, see
971 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/36586> and
972 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/35642>
973 bd6d1202 René Nussbaumer
    # pylint: disable=W0233
974 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, True),
975 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
976 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
977 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
978 bd6d1202 René Nussbaumer
979 bd6d1202 René Nussbaumer
980 bd6d1202 René Nussbaumer
class DnsOnlyRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly):
981 bd6d1202 René Nussbaumer
  """RPC wrappers for calls using only DNS.
982 bd6d1202 René Nussbaumer

983 bd6d1202 René Nussbaumer
  """
984 bd6d1202 René Nussbaumer
  def __init__(self):
985 bd6d1202 René Nussbaumer
    """Initialize this class.
986 bd6d1202 René Nussbaumer

987 bd6d1202 René Nussbaumer
    """
988 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, False),
989 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
990 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
991 db04ce5d Michael Hanselmann
992 415a7304 Michael Hanselmann
993 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
994 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
995 415a7304 Michael Hanselmann

996 415a7304 Michael Hanselmann
  """
997 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
998 c2dc025a Michael Hanselmann
               _getents=None):
999 415a7304 Michael Hanselmann
    """Initializes this class.
1000 415a7304 Michael Hanselmann

1001 415a7304 Michael Hanselmann
    """
1002 b2acdbdc Michael Hanselmann
    if context:
1003 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
1004 b2acdbdc Michael Hanselmann
    else:
1005 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
1006 b2acdbdc Michael Hanselmann
1007 415a7304 Michael Hanselmann
    if address_list is None:
1008 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
1009 415a7304 Michael Hanselmann
    else:
1010 415a7304 Michael Hanselmann
      # Caller provided an address list
1011 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
1012 415a7304 Michael Hanselmann
1013 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
1014 c2dc025a Michael Hanselmann
1015 c2dc025a Michael Hanselmann
    encoders.update({
1016 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
1017 c2dc025a Michael Hanselmann
      })
1018 c2dc025a Michael Hanselmann
1019 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
1020 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
1021 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
1022 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)