Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ cd40dc53

History | View | Annotate | Download (20.7 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 a8083063 Iustin Pop
import os
34 58b311ca Iustin Pop
import logging
35 12bce260 Michael Hanselmann
import zlib
36 12bce260 Michael Hanselmann
import base64
37 33231500 Michael Hanselmann
import pycurl
38 33231500 Michael Hanselmann
import threading
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 a8083063 Iustin Pop
52 200de241 Michael Hanselmann
# Special module generated at build time
53 200de241 Michael Hanselmann
from ganeti import _generated_rpc
54 200de241 Michael Hanselmann
55 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
56 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
57 ae88ef45 Michael Hanselmann
58 a8083063 Iustin Pop
59 33231500 Michael Hanselmann
# Timeout for connecting to nodes (seconds)
60 33231500 Michael Hanselmann
_RPC_CONNECT_TIMEOUT = 5
61 33231500 Michael Hanselmann
62 33231500 Michael Hanselmann
_RPC_CLIENT_HEADERS = [
63 33231500 Michael Hanselmann
  "Content-type: %s" % http.HTTP_APP_JSON,
64 8e29563f Iustin Pop
  "Expect:",
65 33231500 Michael Hanselmann
  ]
66 4331f6cd Michael Hanselmann
67 92fd2250 Iustin Pop
# Various time constants for the timeout table
68 92fd2250 Iustin Pop
_TMO_URGENT = 60 # one minute
69 92fd2250 Iustin Pop
_TMO_FAST = 5 * 60 # five minutes
70 92fd2250 Iustin Pop
_TMO_NORMAL = 15 * 60 # 15 minutes
71 92fd2250 Iustin Pop
_TMO_SLOW = 3600 # one hour
72 92fd2250 Iustin Pop
_TMO_4HRS = 4 * 3600
73 92fd2250 Iustin Pop
_TMO_1DAY = 86400
74 92fd2250 Iustin Pop
75 00267bfe Michael Hanselmann
#: Special value to describe an offline host
76 00267bfe Michael Hanselmann
_OFFLINE = object()
77 00267bfe Michael Hanselmann
78 4331f6cd Michael Hanselmann
79 4331f6cd Michael Hanselmann
def Init():
80 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
81 4331f6cd Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

341 00267bfe Michael Hanselmann
    """
342 00267bfe Michael Hanselmann
    results = {}
343 00267bfe Michael Hanselmann
    requests = {}
344 bdf7d8c0 Iustin Pop
345 00267bfe Michael Hanselmann
    for (name, ip) in hosts:
346 00267bfe Michael Hanselmann
      if ip is _OFFLINE:
347 00267bfe Michael Hanselmann
        # Node is marked as offline
348 00267bfe Michael Hanselmann
        results[name] = RpcResult(node=name, offline=True, call=procedure)
349 00267bfe Michael Hanselmann
      else:
350 00267bfe Michael Hanselmann
        requests[name] = \
351 00267bfe Michael Hanselmann
          http.client.HttpClientRequest(str(ip), port,
352 00267bfe Michael Hanselmann
                                        http.HTTP_PUT, str("/%s" % procedure),
353 00267bfe Michael Hanselmann
                                        headers=_RPC_CLIENT_HEADERS,
354 00267bfe Michael Hanselmann
                                        post_data=body,
355 7cb2d205 Michael Hanselmann
                                        read_timeout=read_timeout,
356 abbf2cd9 Michael Hanselmann
                                        nicename="%s/%s" % (name, procedure),
357 abbf2cd9 Michael Hanselmann
                                        curl_config_fn=_ConfigRpcCurl)
358 a8083063 Iustin Pop
359 00267bfe Michael Hanselmann
    return (results, requests)
360 00267bfe Michael Hanselmann
361 00267bfe Michael Hanselmann
  @staticmethod
362 00267bfe Michael Hanselmann
  def _CombineResults(results, requests, procedure):
363 00267bfe Michael Hanselmann
    """Combines pre-computed results for offline hosts with actual call results.
364 bdf7d8c0 Iustin Pop

365 a8083063 Iustin Pop
    """
366 00267bfe Michael Hanselmann
    for name, req in requests.items():
367 00267bfe Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
368 00267bfe Michael Hanselmann
        host_result = RpcResult(data=serializer.LoadJson(req.resp_body),
369 00267bfe Michael Hanselmann
                                node=name, call=procedure)
370 00267bfe Michael Hanselmann
      else:
371 00267bfe Michael Hanselmann
        # TODO: Better error reporting
372 00267bfe Michael Hanselmann
        if req.error:
373 00267bfe Michael Hanselmann
          msg = req.error
374 00267bfe Michael Hanselmann
        else:
375 00267bfe Michael Hanselmann
          msg = req.resp_body
376 eb202c13 Manuel Franceschini
377 00267bfe Michael Hanselmann
        logging.error("RPC error in %s on node %s: %s", procedure, name, msg)
378 00267bfe Michael Hanselmann
        host_result = RpcResult(data=msg, failed=True, node=name,
379 00267bfe Michael Hanselmann
                                call=procedure)
380 ecfe9491 Michael Hanselmann
381 00267bfe Michael Hanselmann
      results[name] = host_result
382 92fd2250 Iustin Pop
383 00267bfe Michael Hanselmann
    return results
384 a8083063 Iustin Pop
385 abbf2cd9 Michael Hanselmann
  def __call__(self, hosts, procedure, body, read_timeout=None,
386 abbf2cd9 Michael Hanselmann
               _req_process_fn=http.client.ProcessRequests):
387 00267bfe Michael Hanselmann
    """Makes an RPC request to a number of nodes.
388 ecfe9491 Michael Hanselmann

389 00267bfe Michael Hanselmann
    @type hosts: sequence
390 00267bfe Michael Hanselmann
    @param hosts: Hostnames
391 00267bfe Michael Hanselmann
    @type procedure: string
392 00267bfe Michael Hanselmann
    @param procedure: Request path
393 00267bfe Michael Hanselmann
    @type body: string
394 00267bfe Michael Hanselmann
    @param body: Request body
395 00267bfe Michael Hanselmann
    @type read_timeout: int or None
396 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
397 a8083063 Iustin Pop

398 a8083063 Iustin Pop
    """
399 83e7af18 Michael Hanselmann
    assert read_timeout is not None, \
400 83e7af18 Michael Hanselmann
      "Missing RPC read timeout for procedure '%s'" % procedure
401 a8083063 Iustin Pop
402 00267bfe Michael Hanselmann
    (results, requests) = \
403 00267bfe Michael Hanselmann
      self._PrepareRequests(self._resolver(hosts), self._port, procedure,
404 00267bfe Michael Hanselmann
                            str(body), read_timeout)
405 a8083063 Iustin Pop
406 abbf2cd9 Michael Hanselmann
    _req_process_fn(requests.values(), lock_monitor_cb=self._lock_monitor_cb)
407 a8083063 Iustin Pop
408 00267bfe Michael Hanselmann
    assert not frozenset(results).intersection(requests)
409 ecfe9491 Michael Hanselmann
410 00267bfe Michael Hanselmann
    return self._CombineResults(results, requests, procedure)
411 a8083063 Iustin Pop
412 a8083063 Iustin Pop
413 cd40dc53 Michael Hanselmann
class _RpcClientBase:
414 cd40dc53 Michael Hanselmann
  def __init__(self, resolver, encoder_fn, lock_monitor_cb=None):
415 cd40dc53 Michael Hanselmann
    """Initializes this class.
416 cd40dc53 Michael Hanselmann

417 cd40dc53 Michael Hanselmann
    """
418 cd40dc53 Michael Hanselmann
    self._proc = _RpcProcessor(resolver,
419 cd40dc53 Michael Hanselmann
                               netutils.GetDaemonPort(constants.NODED),
420 cd40dc53 Michael Hanselmann
                               lock_monitor_cb=lock_monitor_cb)
421 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
422 cd40dc53 Michael Hanselmann
423 cd40dc53 Michael Hanselmann
  @staticmethod
424 cd40dc53 Michael Hanselmann
  def _EncodeArg(encoder_fn, (argkind, value)):
425 cd40dc53 Michael Hanselmann
    """Encode argument.
426 cd40dc53 Michael Hanselmann

427 cd40dc53 Michael Hanselmann
    """
428 cd40dc53 Michael Hanselmann
    if argkind is None:
429 cd40dc53 Michael Hanselmann
      return value
430 cd40dc53 Michael Hanselmann
    else:
431 cd40dc53 Michael Hanselmann
      return encoder_fn(argkind)(value)
432 cd40dc53 Michael Hanselmann
433 cd40dc53 Michael Hanselmann
  def _Call(self, node_list, procedure, timeout, argdefs, args):
434 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
435 cd40dc53 Michael Hanselmann

436 cd40dc53 Michael Hanselmann
    """
437 cd40dc53 Michael Hanselmann
    assert len(args) == len(argdefs), "Wrong number of arguments"
438 cd40dc53 Michael Hanselmann
439 cd40dc53 Michael Hanselmann
    body = serializer.DumpJson(map(self._encoder, zip(argdefs, args)),
440 cd40dc53 Michael Hanselmann
                               indent=False)
441 cd40dc53 Michael Hanselmann
442 cd40dc53 Michael Hanselmann
    return self._proc(node_list, procedure, body, read_timeout=timeout)
443 cd40dc53 Michael Hanselmann
444 cd40dc53 Michael Hanselmann
445 cd40dc53 Michael Hanselmann
def _ObjectToDict(value):
446 cd40dc53 Michael Hanselmann
  """Converts an object to a dictionary.
447 cd40dc53 Michael Hanselmann

448 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
449 cd40dc53 Michael Hanselmann

450 cd40dc53 Michael Hanselmann
  """
451 cd40dc53 Michael Hanselmann
  return value.ToDict()
452 cd40dc53 Michael Hanselmann
453 cd40dc53 Michael Hanselmann
454 cd40dc53 Michael Hanselmann
def _ObjectListToDict(value):
455 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
456 cd40dc53 Michael Hanselmann

457 cd40dc53 Michael Hanselmann
  """
458 cd40dc53 Michael Hanselmann
  return map(_ObjectToDict, value)
459 cd40dc53 Michael Hanselmann
460 cd40dc53 Michael Hanselmann
461 cd40dc53 Michael Hanselmann
def _EncodeNodeToDiskDict(value):
462 cd40dc53 Michael Hanselmann
  """Encodes a dictionary with node name as key and disk objects as values.
463 cd40dc53 Michael Hanselmann

464 cd40dc53 Michael Hanselmann
  """
465 cd40dc53 Michael Hanselmann
  return dict((name, _ObjectListToDict(disks))
466 cd40dc53 Michael Hanselmann
              for name, disks in value.items())
467 cd40dc53 Michael Hanselmann
468 cd40dc53 Michael Hanselmann
469 cd40dc53 Michael Hanselmann
def _PrepareFileUpload(filename):
470 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
471 cd40dc53 Michael Hanselmann

472 cd40dc53 Michael Hanselmann
  """
473 cd40dc53 Michael Hanselmann
  data = _Compress(utils.ReadFile(filename))
474 cd40dc53 Michael Hanselmann
  st = os.stat(filename)
475 cd40dc53 Michael Hanselmann
  getents = runtime.GetEnts()
476 cd40dc53 Michael Hanselmann
  return [filename, data, st.st_mode, getents.LookupUid(st.st_uid),
477 cd40dc53 Michael Hanselmann
          getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
478 cd40dc53 Michael Hanselmann
479 cd40dc53 Michael Hanselmann
480 cd40dc53 Michael Hanselmann
def _PrepareFinalizeExportDisks(snap_disks):
481 cd40dc53 Michael Hanselmann
  """Encodes disks for finalizing export.
482 cd40dc53 Michael Hanselmann

483 cd40dc53 Michael Hanselmann
  """
484 cd40dc53 Michael Hanselmann
  flat_disks = []
485 cd40dc53 Michael Hanselmann
486 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
487 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
488 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
489 cd40dc53 Michael Hanselmann
    else:
490 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
491 cd40dc53 Michael Hanselmann
492 cd40dc53 Michael Hanselmann
  return flat_disks
493 cd40dc53 Michael Hanselmann
494 cd40dc53 Michael Hanselmann
495 cd40dc53 Michael Hanselmann
def _EncodeImportExportIO((ieio, ieioargs)):
496 cd40dc53 Michael Hanselmann
  """Encodes import/export I/O information.
497 cd40dc53 Michael Hanselmann

498 cd40dc53 Michael Hanselmann
  """
499 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_RAW_DISK:
500 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 1
501 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ))
502 cd40dc53 Michael Hanselmann
503 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_SCRIPT:
504 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 2
505 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ieioargs[1]))
506 cd40dc53 Michael Hanselmann
507 cd40dc53 Michael Hanselmann
  return (ieio, ieioargs)
508 cd40dc53 Michael Hanselmann
509 cd40dc53 Michael Hanselmann
510 cd40dc53 Michael Hanselmann
def _EncodeBlockdevRename(value):
511 cd40dc53 Michael Hanselmann
  """Encodes information for renaming block devices.
512 cd40dc53 Michael Hanselmann

513 cd40dc53 Michael Hanselmann
  """
514 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
515 cd40dc53 Michael Hanselmann
516 cd40dc53 Michael Hanselmann
517 cd40dc53 Michael Hanselmann
#: Generic encoders
518 cd40dc53 Michael Hanselmann
_ENCODERS = {
519 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
520 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
521 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
522 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FILE_DETAILS: _PrepareFileUpload,
523 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
524 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
525 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
526 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
527 cd40dc53 Michael Hanselmann
  }
528 cd40dc53 Michael Hanselmann
529 cd40dc53 Michael Hanselmann
530 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
531 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
532 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
533 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
534 87b3cb26 Michael Hanselmann
  """RPC runner class.
535 a8083063 Iustin Pop

536 87b3cb26 Michael Hanselmann
  """
537 87b3cb26 Michael Hanselmann
  def __init__(self, context):
538 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
539 a8083063 Iustin Pop

540 87b3cb26 Michael Hanselmann
    @type context: C{masterd.GanetiContext}
541 87b3cb26 Michael Hanselmann
    @param context: Ganeti context
542 a8083063 Iustin Pop

543 72737a7f Iustin Pop
    """
544 cd40dc53 Michael Hanselmann
    self._cfg = context.cfg
545 cd40dc53 Michael Hanselmann
546 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
547 cd40dc53 Michael Hanselmann
548 cd40dc53 Michael Hanselmann
    # Add encoders requiring configuration object
549 cd40dc53 Michael Hanselmann
    encoders.update({
550 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
551 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_HVP_BEP: self._InstDictHvpBep,
552 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_OSP: self._InstDictOsp,
553 cd40dc53 Michael Hanselmann
      })
554 cd40dc53 Michael Hanselmann
555 cd40dc53 Michael Hanselmann
    # Resolver using configuration
556 cd40dc53 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, self._cfg.GetNodeInfo,
557 cd40dc53 Michael Hanselmann
                              self._cfg.GetAllNodesInfo)
558 cd40dc53 Michael Hanselmann
559 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
560 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
561 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
562 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
563 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
564 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
565 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
566 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
567 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
568 200de241 Michael Hanselmann
569 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
570 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
571 26ba2bd8 Iustin Pop

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

575 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
576 26ba2bd8 Iustin Pop
    @param instance: an Instance object
577 0eca8e0c Iustin Pop
    @type hvp: dict or None
578 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
579 0eca8e0c Iustin Pop
    @type bep: dict or None
580 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
581 1bdcbbab Iustin Pop
    @type osp: dict or None
582 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
583 26ba2bd8 Iustin Pop
    @rtype: dict
584 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
585 26ba2bd8 Iustin Pop
        cluster defaults
586 26ba2bd8 Iustin Pop

587 26ba2bd8 Iustin Pop
    """
588 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
589 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
590 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
591 0eca8e0c Iustin Pop
    if hvp is not None:
592 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
593 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
594 0eca8e0c Iustin Pop
    if bep is not None:
595 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
596 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
597 1bdcbbab Iustin Pop
    if osp is not None:
598 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
599 b848ce79 Guido Trotter
    for nic in idict["nics"]:
600 b848ce79 Guido Trotter
      nic['nicparams'] = objects.FillDict(
601 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
602 b848ce79 Guido Trotter
        nic['nicparams'])
603 26ba2bd8 Iustin Pop
    return idict
604 26ba2bd8 Iustin Pop
605 c4de9b7a Michael Hanselmann
  def _InstDictHvpBep(self, (instance, hvp, bep)):
606 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
607 c4de9b7a Michael Hanselmann

608 c4de9b7a Michael Hanselmann
    """
609 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
610 c4de9b7a Michael Hanselmann
611 c4de9b7a Michael Hanselmann
  def _InstDictOsp(self, (instance, osparams)):
612 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
613 c4de9b7a Michael Hanselmann

614 c4de9b7a Michael Hanselmann
    """
615 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
616 c4de9b7a Michael Hanselmann
617 efc71a02 Michael Hanselmann
  @staticmethod
618 e3ac8406 Andrea Spadaccini
  def _MigrationStatusPostProc(result):
619 e3ac8406 Andrea Spadaccini
    if not result.fail_msg and result.payload is not None:
620 e3ac8406 Andrea Spadaccini
      result.payload = objects.MigrationStatus.FromDict(result.payload)
621 e3ac8406 Andrea Spadaccini
    return result
622 e3ac8406 Andrea Spadaccini
623 e3ac8406 Andrea Spadaccini
  @staticmethod
624 efc71a02 Michael Hanselmann
  def _BlockdevFindPostProc(result):
625 efc71a02 Michael Hanselmann
    if not result.fail_msg and result.payload is not None:
626 efc71a02 Michael Hanselmann
      result.payload = objects.BlockDevStatus.FromDict(result.payload)
627 efc71a02 Michael Hanselmann
    return result
628 efc71a02 Michael Hanselmann
629 efc71a02 Michael Hanselmann
  @staticmethod
630 efc71a02 Michael Hanselmann
  def _BlockdevGetMirrorStatusPostProc(result):
631 efc71a02 Michael Hanselmann
    if not result.fail_msg:
632 efc71a02 Michael Hanselmann
      result.payload = [objects.BlockDevStatus.FromDict(i)
633 efc71a02 Michael Hanselmann
                        for i in result.payload]
634 efc71a02 Michael Hanselmann
    return result
635 efc71a02 Michael Hanselmann
636 efc71a02 Michael Hanselmann
  @staticmethod
637 efc71a02 Michael Hanselmann
  def _BlockdevGetMirrorStatusMultiPostProc(result):
638 efc71a02 Michael Hanselmann
    for nres in result.values():
639 efc71a02 Michael Hanselmann
      if nres.fail_msg:
640 efc71a02 Michael Hanselmann
        continue
641 efc71a02 Michael Hanselmann
642 efc71a02 Michael Hanselmann
      for idx, (success, status) in enumerate(nres.payload):
643 efc71a02 Michael Hanselmann
        if success:
644 efc71a02 Michael Hanselmann
          nres.payload[idx] = (success, objects.BlockDevStatus.FromDict(status))
645 efc71a02 Michael Hanselmann
646 efc71a02 Michael Hanselmann
    return result
647 efc71a02 Michael Hanselmann
648 efc71a02 Michael Hanselmann
  @staticmethod
649 efc71a02 Michael Hanselmann
  def _OsGetPostProc(result):
650 efc71a02 Michael Hanselmann
    if not result.fail_msg and isinstance(result.payload, dict):
651 efc71a02 Michael Hanselmann
      result.payload = objects.OS.FromDict(result.payload)
652 efc71a02 Michael Hanselmann
    return result
653 efc71a02 Michael Hanselmann
654 efc71a02 Michael Hanselmann
  @staticmethod
655 efc71a02 Michael Hanselmann
  def _ImpExpStatusPostProc(result):
656 efc71a02 Michael Hanselmann
    """Post-processor for import/export status.
657 efc71a02 Michael Hanselmann

658 efc71a02 Michael Hanselmann
    @rtype: Payload containing list of L{objects.ImportExportStatus} instances
659 efc71a02 Michael Hanselmann
    @return: Returns a list of the state of each named import/export or None if
660 efc71a02 Michael Hanselmann
             a status couldn't be retrieved
661 efc71a02 Michael Hanselmann

662 efc71a02 Michael Hanselmann
    """
663 efc71a02 Michael Hanselmann
    if not result.fail_msg:
664 efc71a02 Michael Hanselmann
      decoded = []
665 efc71a02 Michael Hanselmann
666 efc71a02 Michael Hanselmann
      for i in result.payload:
667 efc71a02 Michael Hanselmann
        if i is None:
668 efc71a02 Michael Hanselmann
          decoded.append(None)
669 efc71a02 Michael Hanselmann
          continue
670 efc71a02 Michael Hanselmann
        decoded.append(objects.ImportExportStatus.FromDict(i))
671 efc71a02 Michael Hanselmann
672 efc71a02 Michael Hanselmann
      result.payload = decoded
673 efc71a02 Michael Hanselmann
674 efc71a02 Michael Hanselmann
    return result
675 efc71a02 Michael Hanselmann
676 415a7304 Michael Hanselmann
  #
677 415a7304 Michael Hanselmann
  # Begin RPC calls
678 415a7304 Michael Hanselmann
  #
679 6ddc95ec Michael Hanselmann
680 0436da49 Michael Hanselmann
  def call_test_delay(self, node_list, duration, read_timeout=None):
681 72737a7f Iustin Pop
    """Sleep for a fixed time on given node(s).
682 06009e27 Iustin Pop

683 72737a7f Iustin Pop
    This is a multi-node call.
684 06009e27 Iustin Pop

685 72737a7f Iustin Pop
    """
686 0436da49 Michael Hanselmann
    assert read_timeout is None
687 0436da49 Michael Hanselmann
    return self.call_test_delay(node_list, duration,
688 0436da49 Michael Hanselmann
                                read_timeout=int(duration + 5))
689 5e04ed8b Manuel Franceschini
690 fb1ffbca Michael Hanselmann
691 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
692 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
693 fb1ffbca Michael Hanselmann

694 fb1ffbca Michael Hanselmann
  """
695 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
696 fb1ffbca Michael Hanselmann
    """Initializes this class.
697 fb1ffbca Michael Hanselmann

698 fb1ffbca Michael Hanselmann
    """
699 fb1ffbca Michael Hanselmann
    if address_list is None:
700 fb1ffbca Michael Hanselmann
      resolver = _SsconfResolver
701 fb1ffbca Michael Hanselmann
    else:
702 fb1ffbca Michael Hanselmann
      # Caller provided an address list
703 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
704 fb1ffbca Michael Hanselmann
705 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
706 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
707 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
708 db04ce5d Michael Hanselmann
709 db04ce5d Michael Hanselmann
710 cd40dc53 Michael Hanselmann
class BootstrapRunner(_RpcClientBase, _generated_rpc.RpcClientBootstrap):
711 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
712 db04ce5d Michael Hanselmann

713 db04ce5d Michael Hanselmann
  """
714 db04ce5d Michael Hanselmann
  def __init__(self):
715 db04ce5d Michael Hanselmann
    """Initializes this class.
716 db04ce5d Michael Hanselmann

717 db04ce5d Michael Hanselmann
    """
718 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, _SsconfResolver, _ENCODERS.get)
719 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
720 db04ce5d Michael Hanselmann
721 415a7304 Michael Hanselmann
722 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
723 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
724 415a7304 Michael Hanselmann

725 415a7304 Michael Hanselmann
  """
726 415a7304 Michael Hanselmann
  def __init__(self, address_list):
727 415a7304 Michael Hanselmann
    """Initializes this class.
728 415a7304 Michael Hanselmann

729 415a7304 Michael Hanselmann
    """
730 415a7304 Michael Hanselmann
    if address_list is None:
731 415a7304 Michael Hanselmann
      resolver = _SsconfResolver
732 415a7304 Michael Hanselmann
    else:
733 415a7304 Michael Hanselmann
      # Caller provided an address list
734 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
735 415a7304 Michael Hanselmann
736 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get)
737 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)