Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ db04ce5d

History | View | Annotate | Download (22.6 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 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 92fd2250 Iustin Pop
# Timeout table that will be built later by decorators
75 92fd2250 Iustin Pop
# Guidelines for choosing timeouts:
76 92fd2250 Iustin Pop
# - call used during watcher: timeout -> 1min, _TMO_URGENT
77 92fd2250 Iustin Pop
# - trivial (but be sure it is trivial) (e.g. reading a file): 5min, _TMO_FAST
78 92fd2250 Iustin Pop
# - other calls: 15 min, _TMO_NORMAL
79 92fd2250 Iustin Pop
# - special calls (instance add, etc.): either _TMO_SLOW (1h) or huge timeouts
80 92fd2250 Iustin Pop
81 92fd2250 Iustin Pop
_TIMEOUTS = {
82 92fd2250 Iustin Pop
}
83 92fd2250 Iustin Pop
84 00267bfe Michael Hanselmann
#: Special value to describe an offline host
85 00267bfe Michael Hanselmann
_OFFLINE = object()
86 00267bfe Michael Hanselmann
87 4331f6cd Michael Hanselmann
88 4331f6cd Michael Hanselmann
def Init():
89 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
90 4331f6cd Michael Hanselmann

91 33231500 Michael Hanselmann
  Must be called before using any RPC function and while exactly one thread is
92 33231500 Michael Hanselmann
  running.
93 4331f6cd Michael Hanselmann

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

109 33231500 Michael Hanselmann
  Must be called before quitting the program and while exactly one thread is
110 33231500 Michael Hanselmann
  running.
111 4331f6cd Michael Hanselmann

112 4331f6cd Michael Hanselmann
  """
113 33231500 Michael Hanselmann
  pycurl.global_cleanup()
114 33231500 Michael Hanselmann
115 33231500 Michael Hanselmann
116 33231500 Michael Hanselmann
def _ConfigRpcCurl(curl):
117 33231500 Michael Hanselmann
  noded_cert = str(constants.NODED_CERT_FILE)
118 4331f6cd Michael Hanselmann
119 33231500 Michael Hanselmann
  curl.setopt(pycurl.FOLLOWLOCATION, False)
120 33231500 Michael Hanselmann
  curl.setopt(pycurl.CAINFO, noded_cert)
121 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYHOST, 0)
122 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYPEER, True)
123 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERTTYPE, "PEM")
124 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERT, noded_cert)
125 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEYTYPE, "PEM")
126 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEY, noded_cert)
127 33231500 Michael Hanselmann
  curl.setopt(pycurl.CONNECTTIMEOUT, _RPC_CONNECT_TIMEOUT)
128 33231500 Michael Hanselmann
129 33231500 Michael Hanselmann
130 92fd2250 Iustin Pop
def _RpcTimeout(secs):
131 92fd2250 Iustin Pop
  """Timeout decorator.
132 92fd2250 Iustin Pop

133 92fd2250 Iustin Pop
  When applied to a rpc call_* function, it updates the global timeout
134 92fd2250 Iustin Pop
  table with the given function/timeout.
135 92fd2250 Iustin Pop

136 92fd2250 Iustin Pop
  """
137 92fd2250 Iustin Pop
  def decorator(f):
138 92fd2250 Iustin Pop
    name = f.__name__
139 92fd2250 Iustin Pop
    assert name.startswith("call_")
140 92fd2250 Iustin Pop
    _TIMEOUTS[name[len("call_"):]] = secs
141 92fd2250 Iustin Pop
    return f
142 92fd2250 Iustin Pop
  return decorator
143 92fd2250 Iustin Pop
144 92fd2250 Iustin Pop
145 e0e916fe Iustin Pop
def RunWithRPC(fn):
146 e0e916fe Iustin Pop
  """RPC-wrapper decorator.
147 e0e916fe Iustin Pop

148 e0e916fe Iustin Pop
  When applied to a function, it runs it with the RPC system
149 e0e916fe Iustin Pop
  initialized, and it shutsdown the system afterwards. This means the
150 e0e916fe Iustin Pop
  function must be called without RPC being initialized.
151 e0e916fe Iustin Pop

152 e0e916fe Iustin Pop
  """
153 e0e916fe Iustin Pop
  def wrapper(*args, **kwargs):
154 e0e916fe Iustin Pop
    Init()
155 e0e916fe Iustin Pop
    try:
156 e0e916fe Iustin Pop
      return fn(*args, **kwargs)
157 e0e916fe Iustin Pop
    finally:
158 e0e916fe Iustin Pop
      Shutdown()
159 e0e916fe Iustin Pop
  return wrapper
160 e0e916fe Iustin Pop
161 e0e916fe Iustin Pop
162 30474135 Michael Hanselmann
def _Compress(data):
163 30474135 Michael Hanselmann
  """Compresses a string for transport over RPC.
164 30474135 Michael Hanselmann

165 30474135 Michael Hanselmann
  Small amounts of data are not compressed.
166 30474135 Michael Hanselmann

167 30474135 Michael Hanselmann
  @type data: str
168 30474135 Michael Hanselmann
  @param data: Data
169 30474135 Michael Hanselmann
  @rtype: tuple
170 30474135 Michael Hanselmann
  @return: Encoded data to send
171 30474135 Michael Hanselmann

172 30474135 Michael Hanselmann
  """
173 30474135 Michael Hanselmann
  # Small amounts of data are not compressed
174 30474135 Michael Hanselmann
  if len(data) < 512:
175 30474135 Michael Hanselmann
    return (constants.RPC_ENCODING_NONE, data)
176 30474135 Michael Hanselmann
177 30474135 Michael Hanselmann
  # Compress with zlib and encode in base64
178 30474135 Michael Hanselmann
  return (constants.RPC_ENCODING_ZLIB_BASE64,
179 30474135 Michael Hanselmann
          base64.b64encode(zlib.compress(data, 3)))
180 30474135 Michael Hanselmann
181 30474135 Michael Hanselmann
182 781de953 Iustin Pop
class RpcResult(object):
183 781de953 Iustin Pop
  """RPC Result class.
184 781de953 Iustin Pop

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

189 5bbd3f7f Michael Hanselmann
  @ivar data: the data payload, for successful results, or None
190 ed83f5cc Iustin Pop
  @ivar call: the name of the RPC call
191 ed83f5cc Iustin Pop
  @ivar node: the name of the node to which we made the call
192 ed83f5cc Iustin Pop
  @ivar offline: whether the operation failed because the node was
193 ed83f5cc Iustin Pop
      offline, as opposed to actual failure; offline=True will always
194 ed83f5cc Iustin Pop
      imply failed=True, in order to allow simpler checking if
195 ed83f5cc Iustin Pop
      the user doesn't care about the exact failure mode
196 4c4e4e1e Iustin Pop
  @ivar fail_msg: the error message if the call failed
197 ed83f5cc Iustin Pop

198 781de953 Iustin Pop
  """
199 ed83f5cc Iustin Pop
  def __init__(self, data=None, failed=False, offline=False,
200 ed83f5cc Iustin Pop
               call=None, node=None):
201 ed83f5cc Iustin Pop
    self.offline = offline
202 ed83f5cc Iustin Pop
    self.call = call
203 ed83f5cc Iustin Pop
    self.node = node
204 1645d22d Michael Hanselmann
205 ed83f5cc Iustin Pop
    if offline:
206 4c4e4e1e Iustin Pop
      self.fail_msg = "Node is marked offline"
207 f2def43a Iustin Pop
      self.data = self.payload = None
208 ed83f5cc Iustin Pop
    elif failed:
209 4c4e4e1e Iustin Pop
      self.fail_msg = self._EnsureErr(data)
210 f2def43a Iustin Pop
      self.data = self.payload = None
211 781de953 Iustin Pop
    else:
212 781de953 Iustin Pop
      self.data = data
213 d3c8b360 Iustin Pop
      if not isinstance(self.data, (tuple, list)):
214 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result type (%s)" %
215 4c4e4e1e Iustin Pop
                         type(self.data))
216 1645d22d Michael Hanselmann
        self.payload = None
217 d3c8b360 Iustin Pop
      elif len(data) != 2:
218 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result length (%d), "
219 4c4e4e1e Iustin Pop
                         "expected 2" % len(self.data))
220 1645d22d Michael Hanselmann
        self.payload = None
221 d3c8b360 Iustin Pop
      elif not self.data[0]:
222 4c4e4e1e Iustin Pop
        self.fail_msg = self._EnsureErr(self.data[1])
223 1645d22d Michael Hanselmann
        self.payload = None
224 f2def43a Iustin Pop
      else:
225 d3c8b360 Iustin Pop
        # finally success
226 4c4e4e1e Iustin Pop
        self.fail_msg = None
227 d3c8b360 Iustin Pop
        self.payload = data[1]
228 d3c8b360 Iustin Pop
229 2c0f74f2 Iustin Pop
    for attr_name in ["call", "data", "fail_msg",
230 2c0f74f2 Iustin Pop
                      "node", "offline", "payload"]:
231 2c0f74f2 Iustin Pop
      assert hasattr(self, attr_name), "Missing attribute %s" % attr_name
232 1645d22d Michael Hanselmann
233 d3c8b360 Iustin Pop
  @staticmethod
234 d3c8b360 Iustin Pop
  def _EnsureErr(val):
235 d3c8b360 Iustin Pop
    """Helper to ensure we return a 'True' value for error."""
236 d3c8b360 Iustin Pop
    if val:
237 d3c8b360 Iustin Pop
      return val
238 d3c8b360 Iustin Pop
    else:
239 d3c8b360 Iustin Pop
      return "No error information"
240 781de953 Iustin Pop
241 045dd6d9 Iustin Pop
  def Raise(self, msg, prereq=False, ecode=None):
242 781de953 Iustin Pop
    """If the result has failed, raise an OpExecError.
243 781de953 Iustin Pop

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

247 781de953 Iustin Pop
    """
248 4c4e4e1e Iustin Pop
    if not self.fail_msg:
249 4c4e4e1e Iustin Pop
      return
250 4c4e4e1e Iustin Pop
251 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
252 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
253 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
254 4c4e4e1e Iustin Pop
    else:
255 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
256 4c4e4e1e Iustin Pop
    if prereq:
257 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
258 4c4e4e1e Iustin Pop
    else:
259 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
260 045dd6d9 Iustin Pop
    if ecode is not None:
261 27137e55 Iustin Pop
      args = (msg, ecode)
262 045dd6d9 Iustin Pop
    else:
263 045dd6d9 Iustin Pop
      args = (msg, )
264 b459a848 Andrea Spadaccini
    raise ec(*args) # pylint: disable=W0142
265 781de953 Iustin Pop
266 781de953 Iustin Pop
267 00267bfe Michael Hanselmann
def _SsconfResolver(node_list,
268 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
269 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
270 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
271 eb202c13 Manuel Franceschini

272 eb202c13 Manuel Franceschini
  @type node_list: list
273 eb202c13 Manuel Franceschini
  @param node_list: List of node names
274 eb202c13 Manuel Franceschini
  @type ssc: class
275 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
276 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
277 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
278 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
279 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
280 eb202c13 Manuel Franceschini

281 eb202c13 Manuel Franceschini
  """
282 b43dcc5a Manuel Franceschini
  ss = ssc()
283 b43dcc5a Manuel Franceschini
  iplist = ss.GetNodePrimaryIPList()
284 b43dcc5a Manuel Franceschini
  family = ss.GetPrimaryIPFamily()
285 b705c7a6 Manuel Franceschini
  ipmap = dict(entry.split() for entry in iplist)
286 00267bfe Michael Hanselmann
287 00267bfe Michael Hanselmann
  result = []
288 b705c7a6 Manuel Franceschini
  for node in node_list:
289 00267bfe Michael Hanselmann
    ip = ipmap.get(node)
290 00267bfe Michael Hanselmann
    if ip is None:
291 00267bfe Michael Hanselmann
      ip = nslookup_fn(node, family=family)
292 00267bfe Michael Hanselmann
    result.append((node, ip))
293 00267bfe Michael Hanselmann
294 00267bfe Michael Hanselmann
  return result
295 00267bfe Michael Hanselmann
296 00267bfe Michael Hanselmann
297 00267bfe Michael Hanselmann
class _StaticResolver:
298 00267bfe Michael Hanselmann
  def __init__(self, addresses):
299 00267bfe Michael Hanselmann
    """Initializes this class.
300 00267bfe Michael Hanselmann

301 00267bfe Michael Hanselmann
    """
302 00267bfe Michael Hanselmann
    self._addresses = addresses
303 00267bfe Michael Hanselmann
304 00267bfe Michael Hanselmann
  def __call__(self, hosts):
305 00267bfe Michael Hanselmann
    """Returns static addresses for hosts.
306 00267bfe Michael Hanselmann

307 00267bfe Michael Hanselmann
    """
308 00267bfe Michael Hanselmann
    assert len(hosts) == len(self._addresses)
309 00267bfe Michael Hanselmann
    return zip(hosts, self._addresses)
310 00267bfe Michael Hanselmann
311 eb202c13 Manuel Franceschini
312 00267bfe Michael Hanselmann
def _CheckConfigNode(name, node):
313 00267bfe Michael Hanselmann
  """Checks if a node is online.
314 eb202c13 Manuel Franceschini

315 00267bfe Michael Hanselmann
  @type name: string
316 00267bfe Michael Hanselmann
  @param name: Node name
317 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
318 00267bfe Michael Hanselmann
  @param node: Node object
319 eb202c13 Manuel Franceschini

320 00267bfe Michael Hanselmann
  """
321 00267bfe Michael Hanselmann
  if node is None:
322 00267bfe Michael Hanselmann
    # Depend on DNS for name resolution
323 00267bfe Michael Hanselmann
    ip = name
324 00267bfe Michael Hanselmann
  elif node.offline:
325 00267bfe Michael Hanselmann
    ip = _OFFLINE
326 00267bfe Michael Hanselmann
  else:
327 00267bfe Michael Hanselmann
    ip = node.primary_ip
328 00267bfe Michael Hanselmann
  return (name, ip)
329 a8083063 Iustin Pop
330 a8083063 Iustin Pop
331 00267bfe Michael Hanselmann
def _NodeConfigResolver(single_node_fn, all_nodes_fn, hosts):
332 00267bfe Michael Hanselmann
  """Calculate node addresses using configuration.
333 a8083063 Iustin Pop

334 a8083063 Iustin Pop
  """
335 00267bfe Michael Hanselmann
  # Special case for single-host lookups
336 00267bfe Michael Hanselmann
  if len(hosts) == 1:
337 00267bfe Michael Hanselmann
    (name, ) = hosts
338 00267bfe Michael Hanselmann
    return [_CheckConfigNode(name, single_node_fn(name))]
339 00267bfe Michael Hanselmann
  else:
340 00267bfe Michael Hanselmann
    all_nodes = all_nodes_fn()
341 00267bfe Michael Hanselmann
    return [_CheckConfigNode(name, all_nodes.get(name, None))
342 00267bfe Michael Hanselmann
            for name in hosts]
343 00267bfe Michael Hanselmann
344 00267bfe Michael Hanselmann
345 00267bfe Michael Hanselmann
class _RpcProcessor:
346 aea5caef Michael Hanselmann
  def __init__(self, resolver, port, lock_monitor_cb=None):
347 00267bfe Michael Hanselmann
    """Initializes this class.
348 00267bfe Michael Hanselmann

349 00267bfe Michael Hanselmann
    @param resolver: callable accepting a list of hostnames, returning a list
350 00267bfe Michael Hanselmann
      of tuples containing name and IP address (IP address can be the name or
351 00267bfe Michael Hanselmann
      the special value L{_OFFLINE} to mark offline machines)
352 00267bfe Michael Hanselmann
    @type port: int
353 00267bfe Michael Hanselmann
    @param port: TCP port
354 aea5caef Michael Hanselmann
    @param lock_monitor_cb: Callable for registering with lock monitor
355 3ef3c771 Iustin Pop

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

365 00267bfe Michael Hanselmann
    """
366 00267bfe Michael Hanselmann
    results = {}
367 00267bfe Michael Hanselmann
    requests = {}
368 bdf7d8c0 Iustin Pop
369 00267bfe Michael Hanselmann
    for (name, ip) in hosts:
370 00267bfe Michael Hanselmann
      if ip is _OFFLINE:
371 00267bfe Michael Hanselmann
        # Node is marked as offline
372 00267bfe Michael Hanselmann
        results[name] = RpcResult(node=name, offline=True, call=procedure)
373 00267bfe Michael Hanselmann
      else:
374 00267bfe Michael Hanselmann
        requests[name] = \
375 00267bfe Michael Hanselmann
          http.client.HttpClientRequest(str(ip), port,
376 00267bfe Michael Hanselmann
                                        http.HTTP_PUT, str("/%s" % procedure),
377 00267bfe Michael Hanselmann
                                        headers=_RPC_CLIENT_HEADERS,
378 00267bfe Michael Hanselmann
                                        post_data=body,
379 7cb2d205 Michael Hanselmann
                                        read_timeout=read_timeout,
380 abbf2cd9 Michael Hanselmann
                                        nicename="%s/%s" % (name, procedure),
381 abbf2cd9 Michael Hanselmann
                                        curl_config_fn=_ConfigRpcCurl)
382 a8083063 Iustin Pop
383 00267bfe Michael Hanselmann
    return (results, requests)
384 00267bfe Michael Hanselmann
385 00267bfe Michael Hanselmann
  @staticmethod
386 00267bfe Michael Hanselmann
  def _CombineResults(results, requests, procedure):
387 00267bfe Michael Hanselmann
    """Combines pre-computed results for offline hosts with actual call results.
388 bdf7d8c0 Iustin Pop

389 a8083063 Iustin Pop
    """
390 00267bfe Michael Hanselmann
    for name, req in requests.items():
391 00267bfe Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
392 00267bfe Michael Hanselmann
        host_result = RpcResult(data=serializer.LoadJson(req.resp_body),
393 00267bfe Michael Hanselmann
                                node=name, call=procedure)
394 00267bfe Michael Hanselmann
      else:
395 00267bfe Michael Hanselmann
        # TODO: Better error reporting
396 00267bfe Michael Hanselmann
        if req.error:
397 00267bfe Michael Hanselmann
          msg = req.error
398 00267bfe Michael Hanselmann
        else:
399 00267bfe Michael Hanselmann
          msg = req.resp_body
400 eb202c13 Manuel Franceschini
401 00267bfe Michael Hanselmann
        logging.error("RPC error in %s on node %s: %s", procedure, name, msg)
402 00267bfe Michael Hanselmann
        host_result = RpcResult(data=msg, failed=True, node=name,
403 00267bfe Michael Hanselmann
                                call=procedure)
404 ecfe9491 Michael Hanselmann
405 00267bfe Michael Hanselmann
      results[name] = host_result
406 92fd2250 Iustin Pop
407 00267bfe Michael Hanselmann
    return results
408 a8083063 Iustin Pop
409 abbf2cd9 Michael Hanselmann
  def __call__(self, hosts, procedure, body, read_timeout=None,
410 abbf2cd9 Michael Hanselmann
               _req_process_fn=http.client.ProcessRequests):
411 00267bfe Michael Hanselmann
    """Makes an RPC request to a number of nodes.
412 ecfe9491 Michael Hanselmann

413 00267bfe Michael Hanselmann
    @type hosts: sequence
414 00267bfe Michael Hanselmann
    @param hosts: Hostnames
415 00267bfe Michael Hanselmann
    @type procedure: string
416 00267bfe Michael Hanselmann
    @param procedure: Request path
417 00267bfe Michael Hanselmann
    @type body: string
418 00267bfe Michael Hanselmann
    @param body: Request body
419 00267bfe Michael Hanselmann
    @type read_timeout: int or None
420 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
421 a8083063 Iustin Pop

422 a8083063 Iustin Pop
    """
423 00267bfe Michael Hanselmann
    if read_timeout is None:
424 83e7af18 Michael Hanselmann
      read_timeout = _TIMEOUTS.get(procedure, None)
425 83e7af18 Michael Hanselmann
426 83e7af18 Michael Hanselmann
    assert read_timeout is not None, \
427 83e7af18 Michael Hanselmann
      "Missing RPC read timeout for procedure '%s'" % procedure
428 a8083063 Iustin Pop
429 00267bfe Michael Hanselmann
    (results, requests) = \
430 00267bfe Michael Hanselmann
      self._PrepareRequests(self._resolver(hosts), self._port, procedure,
431 00267bfe Michael Hanselmann
                            str(body), read_timeout)
432 a8083063 Iustin Pop
433 abbf2cd9 Michael Hanselmann
    _req_process_fn(requests.values(), lock_monitor_cb=self._lock_monitor_cb)
434 a8083063 Iustin Pop
435 00267bfe Michael Hanselmann
    assert not frozenset(results).intersection(requests)
436 ecfe9491 Michael Hanselmann
437 00267bfe Michael Hanselmann
    return self._CombineResults(results, requests, procedure)
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
440 db04ce5d Michael Hanselmann
class RpcRunner(_generated_rpc.RpcClientDefault,
441 db04ce5d Michael Hanselmann
                _generated_rpc.RpcClientBootstrap):
442 87b3cb26 Michael Hanselmann
  """RPC runner class.
443 a8083063 Iustin Pop

444 87b3cb26 Michael Hanselmann
  """
445 87b3cb26 Michael Hanselmann
  def __init__(self, context):
446 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
447 a8083063 Iustin Pop

448 87b3cb26 Michael Hanselmann
    @type context: C{masterd.GanetiContext}
449 87b3cb26 Michael Hanselmann
    @param context: Ganeti context
450 a8083063 Iustin Pop

451 72737a7f Iustin Pop
    """
452 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
453 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
454 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
455 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
456 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
457 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
458 200de241 Michael Hanselmann
459 87b3cb26 Michael Hanselmann
    self._cfg = context.cfg
460 00267bfe Michael Hanselmann
    self._proc = _RpcProcessor(compat.partial(_NodeConfigResolver,
461 00267bfe Michael Hanselmann
                                              self._cfg.GetNodeInfo,
462 00267bfe Michael Hanselmann
                                              self._cfg.GetAllNodesInfo),
463 aea5caef Michael Hanselmann
                               netutils.GetDaemonPort(constants.NODED),
464 aea5caef Michael Hanselmann
                               lock_monitor_cb=context.glm.AddToLockMonitor)
465 a8083063 Iustin Pop
466 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
467 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
468 26ba2bd8 Iustin Pop

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

472 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
473 26ba2bd8 Iustin Pop
    @param instance: an Instance object
474 0eca8e0c Iustin Pop
    @type hvp: dict or None
475 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
476 0eca8e0c Iustin Pop
    @type bep: dict or None
477 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
478 1bdcbbab Iustin Pop
    @type osp: dict or None
479 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
480 26ba2bd8 Iustin Pop
    @rtype: dict
481 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
482 26ba2bd8 Iustin Pop
        cluster defaults
483 26ba2bd8 Iustin Pop

484 26ba2bd8 Iustin Pop
    """
485 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
486 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
487 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
488 0eca8e0c Iustin Pop
    if hvp is not None:
489 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
490 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
491 0eca8e0c Iustin Pop
    if bep is not None:
492 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
493 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
494 1bdcbbab Iustin Pop
    if osp is not None:
495 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
496 b848ce79 Guido Trotter
    for nic in idict["nics"]:
497 b848ce79 Guido Trotter
      nic['nicparams'] = objects.FillDict(
498 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
499 b848ce79 Guido Trotter
        nic['nicparams'])
500 26ba2bd8 Iustin Pop
    return idict
501 26ba2bd8 Iustin Pop
502 e0036155 Iustin Pop
  def _MultiNodeCall(self, node_list, procedure, args, read_timeout=None):
503 160e2921 Iustin Pop
    """Helper for making a multi-node call
504 160e2921 Iustin Pop

505 160e2921 Iustin Pop
    """
506 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
507 00267bfe Michael Hanselmann
    return self._proc(node_list, procedure, body, read_timeout=read_timeout)
508 9a525d83 Michael Hanselmann
509 200de241 Michael Hanselmann
  def _Call(self, node_list, procedure, timeout, args):
510 200de241 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
511 200de241 Michael Hanselmann

512 200de241 Michael Hanselmann
    """
513 200de241 Michael Hanselmann
    return self._MultiNodeCall(node_list, procedure, args, read_timeout=timeout)
514 200de241 Michael Hanselmann
515 00267bfe Michael Hanselmann
  @staticmethod
516 00267bfe Michael Hanselmann
  def _StaticMultiNodeCall(node_list, procedure, args,
517 e0036155 Iustin Pop
                           address_list=None, read_timeout=None):
518 160e2921 Iustin Pop
    """Helper for making a multi-node static call
519 160e2921 Iustin Pop

520 160e2921 Iustin Pop
    """
521 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
522 00267bfe Michael Hanselmann
523 00267bfe Michael Hanselmann
    if address_list is None:
524 00267bfe Michael Hanselmann
      resolver = _SsconfResolver
525 00267bfe Michael Hanselmann
    else:
526 00267bfe Michael Hanselmann
      # Caller provided an address list
527 00267bfe Michael Hanselmann
      resolver = _StaticResolver(address_list)
528 00267bfe Michael Hanselmann
529 00267bfe Michael Hanselmann
    proc = _RpcProcessor(resolver,
530 00267bfe Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED))
531 00267bfe Michael Hanselmann
    return proc(node_list, procedure, body, read_timeout=read_timeout)
532 9a525d83 Michael Hanselmann
533 e0036155 Iustin Pop
  def _SingleNodeCall(self, node, procedure, args, read_timeout=None):
534 160e2921 Iustin Pop
    """Helper for making a single-node call
535 9a525d83 Michael Hanselmann

536 9a525d83 Michael Hanselmann
    """
537 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
538 00267bfe Michael Hanselmann
    return self._proc([node], procedure, body, read_timeout=read_timeout)[node]
539 9a525d83 Michael Hanselmann
540 9a525d83 Michael Hanselmann
  @classmethod
541 e0036155 Iustin Pop
  def _StaticSingleNodeCall(cls, node, procedure, args, read_timeout=None):
542 160e2921 Iustin Pop
    """Helper for making a single-node static call
543 9a525d83 Michael Hanselmann

544 9a525d83 Michael Hanselmann
    """
545 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
546 00267bfe Michael Hanselmann
    proc = _RpcProcessor(_SsconfResolver,
547 00267bfe Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED))
548 00267bfe Michael Hanselmann
    return proc([node], procedure, body, read_timeout=read_timeout)[node]
549 9a525d83 Michael Hanselmann
550 efc71a02 Michael Hanselmann
  @staticmethod
551 efc71a02 Michael Hanselmann
  def _BlockdevFindPostProc(result):
552 efc71a02 Michael Hanselmann
    if not result.fail_msg and result.payload is not None:
553 efc71a02 Michael Hanselmann
      result.payload = objects.BlockDevStatus.FromDict(result.payload)
554 efc71a02 Michael Hanselmann
    return result
555 efc71a02 Michael Hanselmann
556 efc71a02 Michael Hanselmann
  @staticmethod
557 efc71a02 Michael Hanselmann
  def _BlockdevGetMirrorStatusPostProc(result):
558 efc71a02 Michael Hanselmann
    if not result.fail_msg:
559 efc71a02 Michael Hanselmann
      result.payload = [objects.BlockDevStatus.FromDict(i)
560 efc71a02 Michael Hanselmann
                        for i in result.payload]
561 efc71a02 Michael Hanselmann
    return result
562 efc71a02 Michael Hanselmann
563 efc71a02 Michael Hanselmann
  @staticmethod
564 efc71a02 Michael Hanselmann
  def _BlockdevGetMirrorStatusMultiPostProc(result):
565 efc71a02 Michael Hanselmann
    for nres in result.values():
566 efc71a02 Michael Hanselmann
      if nres.fail_msg:
567 efc71a02 Michael Hanselmann
        continue
568 efc71a02 Michael Hanselmann
569 efc71a02 Michael Hanselmann
      for idx, (success, status) in enumerate(nres.payload):
570 efc71a02 Michael Hanselmann
        if success:
571 efc71a02 Michael Hanselmann
          nres.payload[idx] = (success, objects.BlockDevStatus.FromDict(status))
572 efc71a02 Michael Hanselmann
573 efc71a02 Michael Hanselmann
    return result
574 efc71a02 Michael Hanselmann
575 efc71a02 Michael Hanselmann
  @staticmethod
576 efc71a02 Michael Hanselmann
  def _OsGetPostProc(result):
577 efc71a02 Michael Hanselmann
    if not result.fail_msg and isinstance(result.payload, dict):
578 efc71a02 Michael Hanselmann
      result.payload = objects.OS.FromDict(result.payload)
579 efc71a02 Michael Hanselmann
    return result
580 efc71a02 Michael Hanselmann
581 efc71a02 Michael Hanselmann
  @staticmethod
582 efc71a02 Michael Hanselmann
  def _PrepareFinalizeExportDisks(snap_disks):
583 efc71a02 Michael Hanselmann
    flat_disks = []
584 efc71a02 Michael Hanselmann
585 efc71a02 Michael Hanselmann
    for disk in snap_disks:
586 efc71a02 Michael Hanselmann
      if isinstance(disk, bool):
587 efc71a02 Michael Hanselmann
        flat_disks.append(disk)
588 efc71a02 Michael Hanselmann
      else:
589 efc71a02 Michael Hanselmann
        flat_disks.append(disk.ToDict())
590 efc71a02 Michael Hanselmann
591 efc71a02 Michael Hanselmann
    return flat_disks
592 efc71a02 Michael Hanselmann
593 efc71a02 Michael Hanselmann
  @staticmethod
594 efc71a02 Michael Hanselmann
  def _ImpExpStatusPostProc(result):
595 efc71a02 Michael Hanselmann
    """Post-processor for import/export status.
596 efc71a02 Michael Hanselmann

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

601 efc71a02 Michael Hanselmann
    """
602 efc71a02 Michael Hanselmann
    if not result.fail_msg:
603 efc71a02 Michael Hanselmann
      decoded = []
604 efc71a02 Michael Hanselmann
605 efc71a02 Michael Hanselmann
      for i in result.payload:
606 efc71a02 Michael Hanselmann
        if i is None:
607 efc71a02 Michael Hanselmann
          decoded.append(None)
608 efc71a02 Michael Hanselmann
          continue
609 efc71a02 Michael Hanselmann
        decoded.append(objects.ImportExportStatus.FromDict(i))
610 efc71a02 Michael Hanselmann
611 efc71a02 Michael Hanselmann
      result.payload = decoded
612 efc71a02 Michael Hanselmann
613 efc71a02 Michael Hanselmann
    return result
614 efc71a02 Michael Hanselmann
615 46c293f0 Michael Hanselmann
  @staticmethod
616 46c293f0 Michael Hanselmann
  def _EncodeImportExportIO(ieio, ieioargs):
617 46c293f0 Michael Hanselmann
    """Encodes import/export I/O information.
618 46c293f0 Michael Hanselmann

619 46c293f0 Michael Hanselmann
    """
620 46c293f0 Michael Hanselmann
    if ieio == constants.IEIO_RAW_DISK:
621 46c293f0 Michael Hanselmann
      assert len(ieioargs) == 1
622 46c293f0 Michael Hanselmann
      return (ieioargs[0].ToDict(), )
623 46c293f0 Michael Hanselmann
624 46c293f0 Michael Hanselmann
    if ieio == constants.IEIO_SCRIPT:
625 46c293f0 Michael Hanselmann
      assert len(ieioargs) == 2
626 46c293f0 Michael Hanselmann
      return (ieioargs[0].ToDict(), ieioargs[1])
627 46c293f0 Michael Hanselmann
628 46c293f0 Michael Hanselmann
    return ieioargs
629 46c293f0 Michael Hanselmann
630 781de953 Iustin Pop
  #
631 781de953 Iustin Pop
  # Begin RPC calls
632 781de953 Iustin Pop
  #
633 781de953 Iustin Pop
634 92fd2250 Iustin Pop
  @_RpcTimeout(_TMO_NORMAL)
635 323f9095 Stephen Shirley
  def call_instance_start(self, node, instance, hvp, bep, startup_paused):
636 72737a7f Iustin Pop
    """Starts an instance.
637 a8083063 Iustin Pop

638 72737a7f Iustin Pop
    This is a single-node call.
639 a8083063 Iustin Pop

640 72737a7f Iustin Pop
    """
641 0eca8e0c Iustin Pop
    idict = self._InstDict(instance, hvp=hvp, bep=bep)
642 323f9095 Stephen Shirley
    return self._SingleNodeCall(node, "instance_start", [idict, startup_paused])
643 a8083063 Iustin Pop
644 92fd2250 Iustin Pop
  @_RpcTimeout(_TMO_1DAY)
645 8d8c4eff Michael Hanselmann
  def call_instance_os_add(self, node, inst, reinstall, debug, osparams=None):
646 72737a7f Iustin Pop
    """Installs an OS on the given instance.
647 a8083063 Iustin Pop

648 72737a7f Iustin Pop
    This is a single-node call.
649 decd5f45 Iustin Pop

650 72737a7f Iustin Pop
    """
651 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_add",
652 8d8c4eff Michael Hanselmann
                                [self._InstDict(inst, osp=osparams),
653 8d8c4eff Michael Hanselmann
                                 reinstall, debug])
654 decd5f45 Iustin Pop
655 9a525d83 Michael Hanselmann
  @classmethod
656 92fd2250 Iustin Pop
  @_RpcTimeout(_TMO_NORMAL)
657 9a525d83 Michael Hanselmann
  def call_upload_file(cls, node_list, file_name, address_list=None):
658 72737a7f Iustin Pop
    """Upload a file.
659 72737a7f Iustin Pop

660 72737a7f Iustin Pop
    The node will refuse the operation in case the file is not on the
661 72737a7f Iustin Pop
    approved file list.
662 72737a7f Iustin Pop

663 72737a7f Iustin Pop
    This is a multi-node call.
664 a8083063 Iustin Pop

665 6b294c53 Iustin Pop
    @type node_list: list
666 6b294c53 Iustin Pop
    @param node_list: the list of node names to upload to
667 6b294c53 Iustin Pop
    @type file_name: str
668 6b294c53 Iustin Pop
    @param file_name: the filename to upload
669 6b294c53 Iustin Pop
    @type address_list: list or None
670 6b294c53 Iustin Pop
    @keyword address_list: an optional list of node addresses, in order
671 6b294c53 Iustin Pop
        to optimize the RPC speed
672 6b294c53 Iustin Pop

673 72737a7f Iustin Pop
    """
674 12bce260 Michael Hanselmann
    file_contents = utils.ReadFile(file_name)
675 30474135 Michael Hanselmann
    data = _Compress(file_contents)
676 72737a7f Iustin Pop
    st = os.stat(file_name)
677 9a914f7a René Nussbaumer
    getents = runtime.GetEnts()
678 9a914f7a René Nussbaumer
    params = [file_name, data, st.st_mode, getents.LookupUid(st.st_uid),
679 9a914f7a René Nussbaumer
              getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
680 9a525d83 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "upload_file", params,
681 9a525d83 Michael Hanselmann
                                    address_list=address_list)
682 72737a7f Iustin Pop
683 6ddc95ec Michael Hanselmann
  @classmethod
684 92fd2250 Iustin Pop
  @_RpcTimeout(_TMO_NORMAL)
685 03d1dba2 Michael Hanselmann
  def call_write_ssconf_files(cls, node_list, values):
686 6ddc95ec Michael Hanselmann
    """Write ssconf files.
687 6ddc95ec Michael Hanselmann

688 6ddc95ec Michael Hanselmann
    This is a multi-node call.
689 6ddc95ec Michael Hanselmann

690 6ddc95ec Michael Hanselmann
    """
691 03d1dba2 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "write_ssconf_files", [values])
692 6ddc95ec Michael Hanselmann
693 0436da49 Michael Hanselmann
  def call_test_delay(self, node_list, duration, read_timeout=None):
694 72737a7f Iustin Pop
    """Sleep for a fixed time on given node(s).
695 06009e27 Iustin Pop

696 72737a7f Iustin Pop
    This is a multi-node call.
697 06009e27 Iustin Pop

698 72737a7f Iustin Pop
    """
699 0436da49 Michael Hanselmann
    assert read_timeout is None
700 0436da49 Michael Hanselmann
    return self.call_test_delay(node_list, duration,
701 0436da49 Michael Hanselmann
                                read_timeout=int(duration + 5))
702 5e04ed8b Manuel Franceschini
703 92fd2250 Iustin Pop
  @_RpcTimeout(_TMO_NORMAL)
704 6217e295 Iustin Pop
  def call_hypervisor_validate_params(self, node_list, hvname, hvparams):
705 6217e295 Iustin Pop
    """Validate the hypervisor params.
706 6217e295 Iustin Pop

707 6217e295 Iustin Pop
    This is a multi-node call.
708 6217e295 Iustin Pop

709 6217e295 Iustin Pop
    @type node_list: list
710 6217e295 Iustin Pop
    @param node_list: the list of nodes to query
711 6217e295 Iustin Pop
    @type hvname: string
712 6217e295 Iustin Pop
    @param hvname: the hypervisor name
713 6217e295 Iustin Pop
    @type hvparams: dict
714 6217e295 Iustin Pop
    @param hvparams: the hypervisor parameters to be validated
715 6217e295 Iustin Pop

716 6217e295 Iustin Pop
    """
717 6217e295 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
718 abe609b2 Guido Trotter
    hv_full = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
719 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "hypervisor_validate_params",
720 9a525d83 Michael Hanselmann
                               [hvname, hv_full])
721 fb1ffbca Michael Hanselmann
722 fb1ffbca Michael Hanselmann
723 fb1ffbca Michael Hanselmann
class JobQueueRunner(_generated_rpc.RpcClientJobQueue):
724 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
725 fb1ffbca Michael Hanselmann

726 fb1ffbca Michael Hanselmann
  """
727 fb1ffbca Michael Hanselmann
  _Compress = staticmethod(_Compress)
728 fb1ffbca Michael Hanselmann
729 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
730 fb1ffbca Michael Hanselmann
    """Initializes this class.
731 fb1ffbca Michael Hanselmann

732 fb1ffbca Michael Hanselmann
    """
733 fb1ffbca Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
734 fb1ffbca Michael Hanselmann
735 fb1ffbca Michael Hanselmann
    if address_list is None:
736 fb1ffbca Michael Hanselmann
      resolver = _SsconfResolver
737 fb1ffbca Michael Hanselmann
    else:
738 fb1ffbca Michael Hanselmann
      # Caller provided an address list
739 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
740 fb1ffbca Michael Hanselmann
741 fb1ffbca Michael Hanselmann
    self._proc = _RpcProcessor(resolver,
742 fb1ffbca Michael Hanselmann
                               netutils.GetDaemonPort(constants.NODED),
743 fb1ffbca Michael Hanselmann
                               lock_monitor_cb=context.glm.AddToLockMonitor)
744 fb1ffbca Michael Hanselmann
745 fb1ffbca Michael Hanselmann
  def _Call(self, node_list, procedure, timeout, args):
746 fb1ffbca Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
747 fb1ffbca Michael Hanselmann

748 fb1ffbca Michael Hanselmann
    """
749 fb1ffbca Michael Hanselmann
    body = serializer.DumpJson(args, indent=False)
750 fb1ffbca Michael Hanselmann
751 fb1ffbca Michael Hanselmann
    return self._proc(node_list, procedure, body, read_timeout=timeout)
752 db04ce5d Michael Hanselmann
753 db04ce5d Michael Hanselmann
754 db04ce5d Michael Hanselmann
class BootstrapRunner(_generated_rpc.RpcClientBootstrap):
755 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
756 db04ce5d Michael Hanselmann

757 db04ce5d Michael Hanselmann
  """
758 db04ce5d Michael Hanselmann
  def __init__(self):
759 db04ce5d Michael Hanselmann
    """Initializes this class.
760 db04ce5d Michael Hanselmann

761 db04ce5d Michael Hanselmann
    """
762 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
763 db04ce5d Michael Hanselmann
764 db04ce5d Michael Hanselmann
    self._proc = _RpcProcessor(_SsconfResolver,
765 db04ce5d Michael Hanselmann
                               netutils.GetDaemonPort(constants.NODED))
766 db04ce5d Michael Hanselmann
767 db04ce5d Michael Hanselmann
  def _Call(self, node_list, procedure, timeout, args):
768 db04ce5d Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
769 db04ce5d Michael Hanselmann

770 db04ce5d Michael Hanselmann
    """
771 db04ce5d Michael Hanselmann
    body = serializer.DumpJson(args, indent=False)
772 db04ce5d Michael Hanselmann
773 db04ce5d Michael Hanselmann
    return self._proc(node_list, procedure, body, read_timeout=timeout)