Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 3bd0f3d8

History | View | Annotate | Download (21.2 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 d2cd6944 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 a8083063 Iustin Pop
39 a8083063 Iustin Pop
from ganeti import utils
40 a8083063 Iustin Pop
from ganeti import objects
41 ecfe9491 Michael Hanselmann
from ganeti import http
42 7c28c575 Michael Hanselmann
from ganeti import serializer
43 eafd8762 Michael Hanselmann
from ganeti import constants
44 781de953 Iustin Pop
from ganeti import errors
45 a744b676 Manuel Franceschini
from ganeti import netutils
46 eb202c13 Manuel Franceschini
from ganeti import ssconf
47 9a914f7a René Nussbaumer
from ganeti import runtime
48 00267bfe Michael Hanselmann
from ganeti import compat
49 cd40dc53 Michael Hanselmann
from ganeti import rpc_defs
50 a8083063 Iustin Pop
51 200de241 Michael Hanselmann
# Special module generated at build time
52 200de241 Michael Hanselmann
from ganeti import _generated_rpc
53 200de241 Michael Hanselmann
54 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
55 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
56 ae88ef45 Michael Hanselmann
57 a8083063 Iustin Pop
58 33231500 Michael Hanselmann
# Timeout for connecting to nodes (seconds)
59 33231500 Michael Hanselmann
_RPC_CONNECT_TIMEOUT = 5
60 33231500 Michael Hanselmann
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 92fd2250 Iustin Pop
# Various time constants for the timeout table
67 92fd2250 Iustin Pop
_TMO_URGENT = 60 # one minute
68 92fd2250 Iustin Pop
_TMO_FAST = 5 * 60 # five minutes
69 92fd2250 Iustin Pop
_TMO_NORMAL = 15 * 60 # 15 minutes
70 92fd2250 Iustin Pop
_TMO_SLOW = 3600 # one hour
71 92fd2250 Iustin Pop
_TMO_4HRS = 4 * 3600
72 92fd2250 Iustin Pop
_TMO_1DAY = 86400
73 92fd2250 Iustin Pop
74 00267bfe Michael Hanselmann
#: Special value to describe an offline host
75 00267bfe Michael Hanselmann
_OFFLINE = object()
76 00267bfe Michael Hanselmann
77 4331f6cd Michael Hanselmann
78 4331f6cd Michael Hanselmann
def Init():
79 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
80 4331f6cd Michael Hanselmann

81 33231500 Michael Hanselmann
  Must be called before using any RPC function and while exactly one thread is
82 33231500 Michael Hanselmann
  running.
83 4331f6cd Michael Hanselmann

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

99 33231500 Michael Hanselmann
  Must be called before quitting the program and while exactly one thread is
100 33231500 Michael Hanselmann
  running.
101 4331f6cd Michael Hanselmann

102 4331f6cd Michael Hanselmann
  """
103 33231500 Michael Hanselmann
  pycurl.global_cleanup()
104 33231500 Michael Hanselmann
105 33231500 Michael Hanselmann
106 33231500 Michael Hanselmann
def _ConfigRpcCurl(curl):
107 33231500 Michael Hanselmann
  noded_cert = str(constants.NODED_CERT_FILE)
108 4331f6cd Michael Hanselmann
109 33231500 Michael Hanselmann
  curl.setopt(pycurl.FOLLOWLOCATION, False)
110 33231500 Michael Hanselmann
  curl.setopt(pycurl.CAINFO, noded_cert)
111 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYHOST, 0)
112 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYPEER, True)
113 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERTTYPE, "PEM")
114 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERT, noded_cert)
115 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEYTYPE, "PEM")
116 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEY, noded_cert)
117 33231500 Michael Hanselmann
  curl.setopt(pycurl.CONNECTTIMEOUT, _RPC_CONNECT_TIMEOUT)
118 33231500 Michael Hanselmann
119 33231500 Michael Hanselmann
120 e0e916fe Iustin Pop
def RunWithRPC(fn):
121 e0e916fe Iustin Pop
  """RPC-wrapper decorator.
122 e0e916fe Iustin Pop

123 e0e916fe Iustin Pop
  When applied to a function, it runs it with the RPC system
124 e0e916fe Iustin Pop
  initialized, and it shutsdown the system afterwards. This means the
125 e0e916fe Iustin Pop
  function must be called without RPC being initialized.
126 e0e916fe Iustin Pop

127 e0e916fe Iustin Pop
  """
128 e0e916fe Iustin Pop
  def wrapper(*args, **kwargs):
129 e0e916fe Iustin Pop
    Init()
130 e0e916fe Iustin Pop
    try:
131 e0e916fe Iustin Pop
      return fn(*args, **kwargs)
132 e0e916fe Iustin Pop
    finally:
133 e0e916fe Iustin Pop
      Shutdown()
134 e0e916fe Iustin Pop
  return wrapper
135 e0e916fe Iustin Pop
136 e0e916fe Iustin Pop
137 30474135 Michael Hanselmann
def _Compress(data):
138 30474135 Michael Hanselmann
  """Compresses a string for transport over RPC.
139 30474135 Michael Hanselmann

140 30474135 Michael Hanselmann
  Small amounts of data are not compressed.
141 30474135 Michael Hanselmann

142 30474135 Michael Hanselmann
  @type data: str
143 30474135 Michael Hanselmann
  @param data: Data
144 30474135 Michael Hanselmann
  @rtype: tuple
145 30474135 Michael Hanselmann
  @return: Encoded data to send
146 30474135 Michael Hanselmann

147 30474135 Michael Hanselmann
  """
148 30474135 Michael Hanselmann
  # Small amounts of data are not compressed
149 30474135 Michael Hanselmann
  if len(data) < 512:
150 30474135 Michael Hanselmann
    return (constants.RPC_ENCODING_NONE, data)
151 30474135 Michael Hanselmann
152 30474135 Michael Hanselmann
  # Compress with zlib and encode in base64
153 30474135 Michael Hanselmann
  return (constants.RPC_ENCODING_ZLIB_BASE64,
154 30474135 Michael Hanselmann
          base64.b64encode(zlib.compress(data, 3)))
155 30474135 Michael Hanselmann
156 30474135 Michael Hanselmann
157 781de953 Iustin Pop
class RpcResult(object):
158 781de953 Iustin Pop
  """RPC Result class.
159 781de953 Iustin Pop

160 781de953 Iustin Pop
  This class holds an RPC result. It is needed since in multi-node
161 781de953 Iustin Pop
  calls we can't raise an exception just because one one out of many
162 781de953 Iustin Pop
  failed, and therefore we use this class to encapsulate the result.
163 781de953 Iustin Pop

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

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

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

222 781de953 Iustin Pop
    """
223 4c4e4e1e Iustin Pop
    if not self.fail_msg:
224 4c4e4e1e Iustin Pop
      return
225 4c4e4e1e Iustin Pop
226 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
227 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
228 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
229 4c4e4e1e Iustin Pop
    else:
230 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
231 4c4e4e1e Iustin Pop
    if prereq:
232 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
233 4c4e4e1e Iustin Pop
    else:
234 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
235 045dd6d9 Iustin Pop
    if ecode is not None:
236 27137e55 Iustin Pop
      args = (msg, ecode)
237 045dd6d9 Iustin Pop
    else:
238 045dd6d9 Iustin Pop
      args = (msg, )
239 b459a848 Andrea Spadaccini
    raise ec(*args) # pylint: disable=W0142
240 781de953 Iustin Pop
241 781de953 Iustin Pop
242 fce5efd1 Michael Hanselmann
def _SsconfResolver(node_list, _,
243 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
244 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
245 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
246 eb202c13 Manuel Franceschini

247 eb202c13 Manuel Franceschini
  @type node_list: list
248 eb202c13 Manuel Franceschini
  @param node_list: List of node names
249 eb202c13 Manuel Franceschini
  @type ssc: class
250 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
251 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
252 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
253 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
254 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
255 eb202c13 Manuel Franceschini

256 eb202c13 Manuel Franceschini
  """
257 b43dcc5a Manuel Franceschini
  ss = ssc()
258 b43dcc5a Manuel Franceschini
  iplist = ss.GetNodePrimaryIPList()
259 b43dcc5a Manuel Franceschini
  family = ss.GetPrimaryIPFamily()
260 b705c7a6 Manuel Franceschini
  ipmap = dict(entry.split() for entry in iplist)
261 00267bfe Michael Hanselmann
262 00267bfe Michael Hanselmann
  result = []
263 b705c7a6 Manuel Franceschini
  for node in node_list:
264 00267bfe Michael Hanselmann
    ip = ipmap.get(node)
265 00267bfe Michael Hanselmann
    if ip is None:
266 00267bfe Michael Hanselmann
      ip = nslookup_fn(node, family=family)
267 00267bfe Michael Hanselmann
    result.append((node, ip))
268 00267bfe Michael Hanselmann
269 00267bfe Michael Hanselmann
  return result
270 00267bfe Michael Hanselmann
271 00267bfe Michael Hanselmann
272 00267bfe Michael Hanselmann
class _StaticResolver:
273 00267bfe Michael Hanselmann
  def __init__(self, addresses):
274 00267bfe Michael Hanselmann
    """Initializes this class.
275 00267bfe Michael Hanselmann

276 00267bfe Michael Hanselmann
    """
277 00267bfe Michael Hanselmann
    self._addresses = addresses
278 00267bfe Michael Hanselmann
279 fce5efd1 Michael Hanselmann
  def __call__(self, hosts, _):
280 00267bfe Michael Hanselmann
    """Returns static addresses for hosts.
281 00267bfe Michael Hanselmann

282 00267bfe Michael Hanselmann
    """
283 00267bfe Michael Hanselmann
    assert len(hosts) == len(self._addresses)
284 00267bfe Michael Hanselmann
    return zip(hosts, self._addresses)
285 00267bfe Michael Hanselmann
286 eb202c13 Manuel Franceschini
287 890ea4ce Michael Hanselmann
def _CheckConfigNode(name, node, accept_offline_node):
288 00267bfe Michael Hanselmann
  """Checks if a node is online.
289 eb202c13 Manuel Franceschini

290 00267bfe Michael Hanselmann
  @type name: string
291 00267bfe Michael Hanselmann
  @param name: Node name
292 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
293 00267bfe Michael Hanselmann
  @param node: Node object
294 eb202c13 Manuel Franceschini

295 00267bfe Michael Hanselmann
  """
296 00267bfe Michael Hanselmann
  if node is None:
297 00267bfe Michael Hanselmann
    # Depend on DNS for name resolution
298 00267bfe Michael Hanselmann
    ip = name
299 890ea4ce Michael Hanselmann
  elif node.offline and not accept_offline_node:
300 00267bfe Michael Hanselmann
    ip = _OFFLINE
301 00267bfe Michael Hanselmann
  else:
302 00267bfe Michael Hanselmann
    ip = node.primary_ip
303 00267bfe Michael Hanselmann
  return (name, ip)
304 a8083063 Iustin Pop
305 a8083063 Iustin Pop
306 890ea4ce Michael Hanselmann
def _NodeConfigResolver(single_node_fn, all_nodes_fn, hosts, opts):
307 00267bfe Michael Hanselmann
  """Calculate node addresses using configuration.
308 a8083063 Iustin Pop

309 a8083063 Iustin Pop
  """
310 890ea4ce Michael Hanselmann
  accept_offline_node = (opts is rpc_defs.ACCEPT_OFFLINE_NODE)
311 890ea4ce Michael Hanselmann
312 890ea4ce Michael Hanselmann
  assert accept_offline_node or opts is None, "Unknown option"
313 890ea4ce Michael Hanselmann
314 00267bfe Michael Hanselmann
  # Special case for single-host lookups
315 00267bfe Michael Hanselmann
  if len(hosts) == 1:
316 00267bfe Michael Hanselmann
    (name, ) = hosts
317 890ea4ce Michael Hanselmann
    return [_CheckConfigNode(name, single_node_fn(name), accept_offline_node)]
318 00267bfe Michael Hanselmann
  else:
319 00267bfe Michael Hanselmann
    all_nodes = all_nodes_fn()
320 890ea4ce Michael Hanselmann
    return [_CheckConfigNode(name, all_nodes.get(name, None),
321 890ea4ce Michael Hanselmann
                             accept_offline_node)
322 00267bfe Michael Hanselmann
            for name in hosts]
323 00267bfe Michael Hanselmann
324 00267bfe Michael Hanselmann
325 00267bfe Michael Hanselmann
class _RpcProcessor:
326 aea5caef Michael Hanselmann
  def __init__(self, resolver, port, lock_monitor_cb=None):
327 00267bfe Michael Hanselmann
    """Initializes this class.
328 00267bfe Michael Hanselmann

329 00267bfe Michael Hanselmann
    @param resolver: callable accepting a list of hostnames, returning a list
330 00267bfe Michael Hanselmann
      of tuples containing name and IP address (IP address can be the name or
331 00267bfe Michael Hanselmann
      the special value L{_OFFLINE} to mark offline machines)
332 00267bfe Michael Hanselmann
    @type port: int
333 00267bfe Michael Hanselmann
    @param port: TCP port
334 aea5caef Michael Hanselmann
    @param lock_monitor_cb: Callable for registering with lock monitor
335 3ef3c771 Iustin Pop

336 a8083063 Iustin Pop
    """
337 00267bfe Michael Hanselmann
    self._resolver = resolver
338 00267bfe Michael Hanselmann
    self._port = port
339 aea5caef Michael Hanselmann
    self._lock_monitor_cb = lock_monitor_cb
340 eb202c13 Manuel Franceschini
341 00267bfe Michael Hanselmann
  @staticmethod
342 00267bfe Michael Hanselmann
  def _PrepareRequests(hosts, port, procedure, body, read_timeout):
343 00267bfe Michael Hanselmann
    """Prepares requests by sorting offline hosts into separate list.
344 eb202c13 Manuel Franceschini

345 d9de612c Iustin Pop
    @type body: dict
346 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
347 d9de612c Iustin Pop

348 00267bfe Michael Hanselmann
    """
349 00267bfe Michael Hanselmann
    results = {}
350 00267bfe Michael Hanselmann
    requests = {}
351 bdf7d8c0 Iustin Pop
352 d9de612c Iustin Pop
    assert isinstance(body, dict)
353 d9de612c Iustin Pop
    assert len(body) == len(hosts)
354 d9de612c Iustin Pop
    assert compat.all(isinstance(v, str) for v in body.values())
355 d9de612c Iustin Pop
    assert frozenset(map(compat.fst, hosts)) == frozenset(body.keys()), \
356 d9de612c Iustin Pop
        "%s != %s" % (hosts, body.keys())
357 d9de612c Iustin Pop
358 00267bfe Michael Hanselmann
    for (name, ip) in hosts:
359 00267bfe Michael Hanselmann
      if ip is _OFFLINE:
360 00267bfe Michael Hanselmann
        # Node is marked as offline
361 00267bfe Michael Hanselmann
        results[name] = RpcResult(node=name, offline=True, call=procedure)
362 00267bfe Michael Hanselmann
      else:
363 00267bfe Michael Hanselmann
        requests[name] = \
364 00267bfe Michael Hanselmann
          http.client.HttpClientRequest(str(ip), port,
365 7530364d Iustin Pop
                                        http.HTTP_POST, str("/%s" % procedure),
366 00267bfe Michael Hanselmann
                                        headers=_RPC_CLIENT_HEADERS,
367 d9de612c Iustin Pop
                                        post_data=body[name],
368 7cb2d205 Michael Hanselmann
                                        read_timeout=read_timeout,
369 abbf2cd9 Michael Hanselmann
                                        nicename="%s/%s" % (name, procedure),
370 abbf2cd9 Michael Hanselmann
                                        curl_config_fn=_ConfigRpcCurl)
371 a8083063 Iustin Pop
372 00267bfe Michael Hanselmann
    return (results, requests)
373 00267bfe Michael Hanselmann
374 00267bfe Michael Hanselmann
  @staticmethod
375 00267bfe Michael Hanselmann
  def _CombineResults(results, requests, procedure):
376 00267bfe Michael Hanselmann
    """Combines pre-computed results for offline hosts with actual call results.
377 bdf7d8c0 Iustin Pop

378 a8083063 Iustin Pop
    """
379 00267bfe Michael Hanselmann
    for name, req in requests.items():
380 00267bfe Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
381 00267bfe Michael Hanselmann
        host_result = RpcResult(data=serializer.LoadJson(req.resp_body),
382 00267bfe Michael Hanselmann
                                node=name, call=procedure)
383 00267bfe Michael Hanselmann
      else:
384 00267bfe Michael Hanselmann
        # TODO: Better error reporting
385 00267bfe Michael Hanselmann
        if req.error:
386 00267bfe Michael Hanselmann
          msg = req.error
387 00267bfe Michael Hanselmann
        else:
388 00267bfe Michael Hanselmann
          msg = req.resp_body
389 eb202c13 Manuel Franceschini
390 00267bfe Michael Hanselmann
        logging.error("RPC error in %s on node %s: %s", procedure, name, msg)
391 00267bfe Michael Hanselmann
        host_result = RpcResult(data=msg, failed=True, node=name,
392 00267bfe Michael Hanselmann
                                call=procedure)
393 ecfe9491 Michael Hanselmann
394 00267bfe Michael Hanselmann
      results[name] = host_result
395 92fd2250 Iustin Pop
396 00267bfe Michael Hanselmann
    return results
397 a8083063 Iustin Pop
398 fce5efd1 Michael Hanselmann
  def __call__(self, hosts, procedure, body, read_timeout, resolver_opts,
399 065be3f0 Michael Hanselmann
               _req_process_fn=None):
400 00267bfe Michael Hanselmann
    """Makes an RPC request to a number of nodes.
401 ecfe9491 Michael Hanselmann

402 00267bfe Michael Hanselmann
    @type hosts: sequence
403 00267bfe Michael Hanselmann
    @param hosts: Hostnames
404 00267bfe Michael Hanselmann
    @type procedure: string
405 00267bfe Michael Hanselmann
    @param procedure: Request path
406 d9de612c Iustin Pop
    @type body: dictionary
407 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
408 00267bfe Michael Hanselmann
    @type read_timeout: int or None
409 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
410 a8083063 Iustin Pop

411 a8083063 Iustin Pop
    """
412 83e7af18 Michael Hanselmann
    assert read_timeout is not None, \
413 83e7af18 Michael Hanselmann
      "Missing RPC read timeout for procedure '%s'" % procedure
414 a8083063 Iustin Pop
415 065be3f0 Michael Hanselmann
    if _req_process_fn is None:
416 065be3f0 Michael Hanselmann
      _req_process_fn = http.client.ProcessRequests
417 065be3f0 Michael Hanselmann
418 00267bfe Michael Hanselmann
    (results, requests) = \
419 fce5efd1 Michael Hanselmann
      self._PrepareRequests(self._resolver(hosts, resolver_opts), self._port,
420 fce5efd1 Michael Hanselmann
                            procedure, body, read_timeout)
421 a8083063 Iustin Pop
422 abbf2cd9 Michael Hanselmann
    _req_process_fn(requests.values(), lock_monitor_cb=self._lock_monitor_cb)
423 a8083063 Iustin Pop
424 00267bfe Michael Hanselmann
    assert not frozenset(results).intersection(requests)
425 ecfe9491 Michael Hanselmann
426 00267bfe Michael Hanselmann
    return self._CombineResults(results, requests, procedure)
427 a8083063 Iustin Pop
428 a8083063 Iustin Pop
429 cd40dc53 Michael Hanselmann
class _RpcClientBase:
430 065be3f0 Michael Hanselmann
  def __init__(self, resolver, encoder_fn, lock_monitor_cb=None,
431 065be3f0 Michael Hanselmann
               _req_process_fn=None):
432 cd40dc53 Michael Hanselmann
    """Initializes this class.
433 cd40dc53 Michael Hanselmann

434 cd40dc53 Michael Hanselmann
    """
435 065be3f0 Michael Hanselmann
    proc = _RpcProcessor(resolver,
436 065be3f0 Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED),
437 065be3f0 Michael Hanselmann
                         lock_monitor_cb=lock_monitor_cb)
438 065be3f0 Michael Hanselmann
    self._proc = compat.partial(proc, _req_process_fn=_req_process_fn)
439 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
440 cd40dc53 Michael Hanselmann
441 cd40dc53 Michael Hanselmann
  @staticmethod
442 cd40dc53 Michael Hanselmann
  def _EncodeArg(encoder_fn, (argkind, value)):
443 cd40dc53 Michael Hanselmann
    """Encode argument.
444 cd40dc53 Michael Hanselmann

445 cd40dc53 Michael Hanselmann
    """
446 cd40dc53 Michael Hanselmann
    if argkind is None:
447 cd40dc53 Michael Hanselmann
      return value
448 cd40dc53 Michael Hanselmann
    else:
449 cd40dc53 Michael Hanselmann
      return encoder_fn(argkind)(value)
450 cd40dc53 Michael Hanselmann
451 f7d9b3aa Michael Hanselmann
  def _Call(self, cdef, node_list, args):
452 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
453 cd40dc53 Michael Hanselmann

454 cd40dc53 Michael Hanselmann
    """
455 dd6d2d09 Michael Hanselmann
    (procedure, _, resolver_opts, timeout, argdefs,
456 dd6d2d09 Michael Hanselmann
     prep_fn, postproc_fn, _) = cdef
457 f7d9b3aa Michael Hanselmann
458 f7d9b3aa Michael Hanselmann
    if callable(timeout):
459 f7d9b3aa Michael Hanselmann
      read_timeout = timeout(args)
460 f7d9b3aa Michael Hanselmann
    else:
461 f7d9b3aa Michael Hanselmann
      read_timeout = timeout
462 cd40dc53 Michael Hanselmann
463 dd6d2d09 Michael Hanselmann
    if callable(resolver_opts):
464 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts(args)
465 dd6d2d09 Michael Hanselmann
    else:
466 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts
467 dd6d2d09 Michael Hanselmann
468 e78667fe Michael Hanselmann
    if len(args) != len(argdefs):
469 e78667fe Michael Hanselmann
      raise errors.ProgrammerError("Number of passed arguments doesn't match")
470 e78667fe Michael Hanselmann
471 d9de612c Iustin Pop
    enc_args = map(self._encoder, zip(map(compat.snd, argdefs), args))
472 d9de612c Iustin Pop
    if prep_fn is None:
473 d9de612c Iustin Pop
      # for a no-op prep_fn, we serialise the body once, and then we
474 d9de612c Iustin Pop
      # reuse it in the dictionary values
475 d9de612c Iustin Pop
      body = serializer.DumpJson(enc_args)
476 d9de612c Iustin Pop
      pnbody = dict((n, body) for n in node_list)
477 d9de612c Iustin Pop
    else:
478 d9de612c Iustin Pop
      # for a custom prep_fn, we pass the encoded arguments and the
479 d9de612c Iustin Pop
      # node name to the prep_fn, and we serialise its return value
480 764ff2eb Michael Hanselmann
      assert callable(prep_fn)
481 d9de612c Iustin Pop
      pnbody = dict((n, serializer.DumpJson(prep_fn(n, enc_args)))
482 d9de612c Iustin Pop
                    for n in node_list)
483 d9de612c Iustin Pop
484 fce5efd1 Michael Hanselmann
    result = self._proc(node_list, procedure, pnbody, read_timeout,
485 fce5efd1 Michael Hanselmann
                        req_resolver_opts)
486 26d502d0 Michael Hanselmann
487 26d502d0 Michael Hanselmann
    if postproc_fn:
488 d9da5065 Michael Hanselmann
      return dict(map(lambda (key, value): (key, postproc_fn(value)),
489 d9da5065 Michael Hanselmann
                      result.items()))
490 26d502d0 Michael Hanselmann
    else:
491 26d502d0 Michael Hanselmann
      return result
492 cd40dc53 Michael Hanselmann
493 cd40dc53 Michael Hanselmann
494 cd40dc53 Michael Hanselmann
def _ObjectToDict(value):
495 cd40dc53 Michael Hanselmann
  """Converts an object to a dictionary.
496 cd40dc53 Michael Hanselmann

497 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
498 cd40dc53 Michael Hanselmann

499 cd40dc53 Michael Hanselmann
  """
500 cd40dc53 Michael Hanselmann
  return value.ToDict()
501 cd40dc53 Michael Hanselmann
502 cd40dc53 Michael Hanselmann
503 cd40dc53 Michael Hanselmann
def _ObjectListToDict(value):
504 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
505 cd40dc53 Michael Hanselmann

506 cd40dc53 Michael Hanselmann
  """
507 cd40dc53 Michael Hanselmann
  return map(_ObjectToDict, value)
508 cd40dc53 Michael Hanselmann
509 cd40dc53 Michael Hanselmann
510 cd40dc53 Michael Hanselmann
def _EncodeNodeToDiskDict(value):
511 cd40dc53 Michael Hanselmann
  """Encodes a dictionary with node name as key and disk objects as values.
512 cd40dc53 Michael Hanselmann

513 cd40dc53 Michael Hanselmann
  """
514 cd40dc53 Michael Hanselmann
  return dict((name, _ObjectListToDict(disks))
515 cd40dc53 Michael Hanselmann
              for name, disks in value.items())
516 cd40dc53 Michael Hanselmann
517 cd40dc53 Michael Hanselmann
518 601dfcbb Michael Hanselmann
def _PrepareFileUpload(getents_fn, filename):
519 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
520 cd40dc53 Michael Hanselmann

521 cd40dc53 Michael Hanselmann
  """
522 2ce40421 Michael Hanselmann
  statcb = utils.FileStatHelper()
523 2ce40421 Michael Hanselmann
  data = _Compress(utils.ReadFile(filename, preread=statcb))
524 2ce40421 Michael Hanselmann
  st = statcb.st
525 601dfcbb Michael Hanselmann
526 601dfcbb Michael Hanselmann
  if getents_fn is None:
527 601dfcbb Michael Hanselmann
    getents_fn = runtime.GetEnts
528 601dfcbb Michael Hanselmann
529 601dfcbb Michael Hanselmann
  getents = getents_fn()
530 601dfcbb Michael Hanselmann
531 cd40dc53 Michael Hanselmann
  return [filename, data, st.st_mode, getents.LookupUid(st.st_uid),
532 cd40dc53 Michael Hanselmann
          getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
533 cd40dc53 Michael Hanselmann
534 cd40dc53 Michael Hanselmann
535 cd40dc53 Michael Hanselmann
def _PrepareFinalizeExportDisks(snap_disks):
536 cd40dc53 Michael Hanselmann
  """Encodes disks for finalizing export.
537 cd40dc53 Michael Hanselmann

538 cd40dc53 Michael Hanselmann
  """
539 cd40dc53 Michael Hanselmann
  flat_disks = []
540 cd40dc53 Michael Hanselmann
541 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
542 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
543 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
544 cd40dc53 Michael Hanselmann
    else:
545 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
546 cd40dc53 Michael Hanselmann
547 cd40dc53 Michael Hanselmann
  return flat_disks
548 cd40dc53 Michael Hanselmann
549 cd40dc53 Michael Hanselmann
550 cd40dc53 Michael Hanselmann
def _EncodeImportExportIO((ieio, ieioargs)):
551 cd40dc53 Michael Hanselmann
  """Encodes import/export I/O information.
552 cd40dc53 Michael Hanselmann

553 cd40dc53 Michael Hanselmann
  """
554 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_RAW_DISK:
555 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 1
556 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ))
557 cd40dc53 Michael Hanselmann
558 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_SCRIPT:
559 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 2
560 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ieioargs[1]))
561 cd40dc53 Michael Hanselmann
562 cd40dc53 Michael Hanselmann
  return (ieio, ieioargs)
563 cd40dc53 Michael Hanselmann
564 cd40dc53 Michael Hanselmann
565 cd40dc53 Michael Hanselmann
def _EncodeBlockdevRename(value):
566 cd40dc53 Michael Hanselmann
  """Encodes information for renaming block devices.
567 cd40dc53 Michael Hanselmann

568 cd40dc53 Michael Hanselmann
  """
569 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
570 cd40dc53 Michael Hanselmann
571 cd40dc53 Michael Hanselmann
572 cd40dc53 Michael Hanselmann
#: Generic encoders
573 cd40dc53 Michael Hanselmann
_ENCODERS = {
574 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
575 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
576 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
577 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
578 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
579 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
580 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
581 cd40dc53 Michael Hanselmann
  }
582 cd40dc53 Michael Hanselmann
583 cd40dc53 Michael Hanselmann
584 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
585 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
586 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
587 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
588 87b3cb26 Michael Hanselmann
  """RPC runner class.
589 a8083063 Iustin Pop

590 87b3cb26 Michael Hanselmann
  """
591 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
592 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
593 a8083063 Iustin Pop

594 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
595 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
596 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
597 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
598 a8083063 Iustin Pop

599 72737a7f Iustin Pop
    """
600 d5ea30e8 Michael Hanselmann
    self._cfg = cfg
601 cd40dc53 Michael Hanselmann
602 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
603 cd40dc53 Michael Hanselmann
604 cd40dc53 Michael Hanselmann
    encoders.update({
605 601dfcbb Michael Hanselmann
      # Encoders requiring configuration object
606 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
607 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_HVP_BEP: self._InstDictHvpBep,
608 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_OSP: self._InstDictOsp,
609 601dfcbb Michael Hanselmann
610 601dfcbb Michael Hanselmann
      # Encoders with special requirements
611 601dfcbb Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
612 cd40dc53 Michael Hanselmann
      })
613 cd40dc53 Michael Hanselmann
614 cd40dc53 Michael Hanselmann
    # Resolver using configuration
615 d5ea30e8 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, cfg.GetNodeInfo,
616 d5ea30e8 Michael Hanselmann
                              cfg.GetAllNodesInfo)
617 cd40dc53 Michael Hanselmann
618 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
619 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
620 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
621 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
622 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
623 d5ea30e8 Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
624 d5ea30e8 Michael Hanselmann
                            _req_process_fn=_req_process_fn)
625 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
626 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
627 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
628 200de241 Michael Hanselmann
629 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
630 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
631 26ba2bd8 Iustin Pop

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

635 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
636 26ba2bd8 Iustin Pop
    @param instance: an Instance object
637 0eca8e0c Iustin Pop
    @type hvp: dict or None
638 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
639 0eca8e0c Iustin Pop
    @type bep: dict or None
640 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
641 1bdcbbab Iustin Pop
    @type osp: dict or None
642 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
643 26ba2bd8 Iustin Pop
    @rtype: dict
644 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
645 26ba2bd8 Iustin Pop
        cluster defaults
646 26ba2bd8 Iustin Pop

647 26ba2bd8 Iustin Pop
    """
648 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
649 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
650 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
651 0eca8e0c Iustin Pop
    if hvp is not None:
652 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
653 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
654 0eca8e0c Iustin Pop
    if bep is not None:
655 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
656 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
657 1bdcbbab Iustin Pop
    if osp is not None:
658 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
659 b848ce79 Guido Trotter
    for nic in idict["nics"]:
660 b848ce79 Guido Trotter
      nic['nicparams'] = objects.FillDict(
661 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
662 b848ce79 Guido Trotter
        nic['nicparams'])
663 26ba2bd8 Iustin Pop
    return idict
664 26ba2bd8 Iustin Pop
665 c4de9b7a Michael Hanselmann
  def _InstDictHvpBep(self, (instance, hvp, bep)):
666 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
667 c4de9b7a Michael Hanselmann

668 c4de9b7a Michael Hanselmann
    """
669 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
670 c4de9b7a Michael Hanselmann
671 c4de9b7a Michael Hanselmann
  def _InstDictOsp(self, (instance, osparams)):
672 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
673 c4de9b7a Michael Hanselmann

674 c4de9b7a Michael Hanselmann
    """
675 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
676 c4de9b7a Michael Hanselmann
677 fb1ffbca Michael Hanselmann
678 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
679 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
680 fb1ffbca Michael Hanselmann

681 fb1ffbca Michael Hanselmann
  """
682 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
683 fb1ffbca Michael Hanselmann
    """Initializes this class.
684 fb1ffbca Michael Hanselmann

685 fb1ffbca Michael Hanselmann
    """
686 fb1ffbca Michael Hanselmann
    if address_list is None:
687 fb1ffbca Michael Hanselmann
      resolver = _SsconfResolver
688 fb1ffbca Michael Hanselmann
    else:
689 fb1ffbca Michael Hanselmann
      # Caller provided an address list
690 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
691 fb1ffbca Michael Hanselmann
692 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
693 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
694 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
695 db04ce5d Michael Hanselmann
696 db04ce5d Michael Hanselmann
697 cd40dc53 Michael Hanselmann
class BootstrapRunner(_RpcClientBase, _generated_rpc.RpcClientBootstrap):
698 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
699 db04ce5d Michael Hanselmann

700 db04ce5d Michael Hanselmann
  """
701 db04ce5d Michael Hanselmann
  def __init__(self):
702 db04ce5d Michael Hanselmann
    """Initializes this class.
703 db04ce5d Michael Hanselmann

704 db04ce5d Michael Hanselmann
    """
705 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, _SsconfResolver, _ENCODERS.get)
706 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
707 db04ce5d Michael Hanselmann
708 415a7304 Michael Hanselmann
709 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
710 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
711 415a7304 Michael Hanselmann

712 415a7304 Michael Hanselmann
  """
713 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
714 c2dc025a Michael Hanselmann
               _getents=None):
715 415a7304 Michael Hanselmann
    """Initializes this class.
716 415a7304 Michael Hanselmann

717 415a7304 Michael Hanselmann
    """
718 b2acdbdc Michael Hanselmann
    if context:
719 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
720 b2acdbdc Michael Hanselmann
    else:
721 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
722 b2acdbdc Michael Hanselmann
723 415a7304 Michael Hanselmann
    if address_list is None:
724 415a7304 Michael Hanselmann
      resolver = _SsconfResolver
725 415a7304 Michael Hanselmann
    else:
726 415a7304 Michael Hanselmann
      # Caller provided an address list
727 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
728 415a7304 Michael Hanselmann
729 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
730 c2dc025a Michael Hanselmann
731 c2dc025a Michael Hanselmann
    encoders.update({
732 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
733 c2dc025a Michael Hanselmann
      })
734 c2dc025a Michael Hanselmann
735 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
736 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
737 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
738 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)