Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ aedf5fd7

History | View | Annotate | Download (24.1 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 bd6d1202 René Nussbaumer
def _SsconfResolver(ssconf_ips, 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 bd6d1202 René Nussbaumer
  @type ssconf_ips: bool
248 bd6d1202 René Nussbaumer
  @param ssconf_ips: Use the ssconf IPs
249 eb202c13 Manuel Franceschini
  @type node_list: list
250 eb202c13 Manuel Franceschini
  @param node_list: List of node names
251 eb202c13 Manuel Franceschini
  @type ssc: class
252 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
253 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
254 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
255 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
256 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
257 eb202c13 Manuel Franceschini

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

282 00267bfe Michael Hanselmann
    """
283 00267bfe Michael Hanselmann
    self._addresses = addresses
284 00267bfe Michael Hanselmann
285 fce5efd1 Michael Hanselmann
  def __call__(self, hosts, _):
286 00267bfe Michael Hanselmann
    """Returns static addresses for hosts.
287 00267bfe Michael Hanselmann

288 00267bfe Michael Hanselmann
    """
289 00267bfe Michael Hanselmann
    assert len(hosts) == len(self._addresses)
290 00267bfe Michael Hanselmann
    return zip(hosts, self._addresses)
291 00267bfe Michael Hanselmann
292 eb202c13 Manuel Franceschini
293 890ea4ce Michael Hanselmann
def _CheckConfigNode(name, node, accept_offline_node):
294 00267bfe Michael Hanselmann
  """Checks if a node is online.
295 eb202c13 Manuel Franceschini

296 00267bfe Michael Hanselmann
  @type name: string
297 00267bfe Michael Hanselmann
  @param name: Node name
298 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
299 00267bfe Michael Hanselmann
  @param node: Node object
300 eb202c13 Manuel Franceschini

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

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

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

342 a8083063 Iustin Pop
    """
343 00267bfe Michael Hanselmann
    self._resolver = resolver
344 00267bfe Michael Hanselmann
    self._port = port
345 aea5caef Michael Hanselmann
    self._lock_monitor_cb = lock_monitor_cb
346 eb202c13 Manuel Franceschini
347 00267bfe Michael Hanselmann
  @staticmethod
348 00267bfe Michael Hanselmann
  def _PrepareRequests(hosts, port, procedure, body, read_timeout):
349 00267bfe Michael Hanselmann
    """Prepares requests by sorting offline hosts into separate list.
350 eb202c13 Manuel Franceschini

351 d9de612c Iustin Pop
    @type body: dict
352 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
353 d9de612c Iustin Pop

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

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

408 00267bfe Michael Hanselmann
    @type hosts: sequence
409 00267bfe Michael Hanselmann
    @param hosts: Hostnames
410 00267bfe Michael Hanselmann
    @type procedure: string
411 00267bfe Michael Hanselmann
    @param procedure: Request path
412 d9de612c Iustin Pop
    @type body: dictionary
413 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
414 00267bfe Michael Hanselmann
    @type read_timeout: int or None
415 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
416 a8083063 Iustin Pop

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

440 cd40dc53 Michael Hanselmann
    """
441 065be3f0 Michael Hanselmann
    proc = _RpcProcessor(resolver,
442 065be3f0 Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED),
443 065be3f0 Michael Hanselmann
                         lock_monitor_cb=lock_monitor_cb)
444 065be3f0 Michael Hanselmann
    self._proc = compat.partial(proc, _req_process_fn=_req_process_fn)
445 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
446 cd40dc53 Michael Hanselmann
447 cd40dc53 Michael Hanselmann
  @staticmethod
448 cd40dc53 Michael Hanselmann
  def _EncodeArg(encoder_fn, (argkind, value)):
449 cd40dc53 Michael Hanselmann
    """Encode argument.
450 cd40dc53 Michael Hanselmann

451 cd40dc53 Michael Hanselmann
    """
452 cd40dc53 Michael Hanselmann
    if argkind is None:
453 cd40dc53 Michael Hanselmann
      return value
454 cd40dc53 Michael Hanselmann
    else:
455 cd40dc53 Michael Hanselmann
      return encoder_fn(argkind)(value)
456 cd40dc53 Michael Hanselmann
457 f7d9b3aa Michael Hanselmann
  def _Call(self, cdef, node_list, args):
458 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
459 cd40dc53 Michael Hanselmann

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

503 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
504 cd40dc53 Michael Hanselmann

505 cd40dc53 Michael Hanselmann
  """
506 cd40dc53 Michael Hanselmann
  return value.ToDict()
507 cd40dc53 Michael Hanselmann
508 cd40dc53 Michael Hanselmann
509 cd40dc53 Michael Hanselmann
def _ObjectListToDict(value):
510 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
511 cd40dc53 Michael Hanselmann

512 cd40dc53 Michael Hanselmann
  """
513 cd40dc53 Michael Hanselmann
  return map(_ObjectToDict, value)
514 cd40dc53 Michael Hanselmann
515 cd40dc53 Michael Hanselmann
516 cd40dc53 Michael Hanselmann
def _EncodeNodeToDiskDict(value):
517 cd40dc53 Michael Hanselmann
  """Encodes a dictionary with node name as key and disk objects as values.
518 cd40dc53 Michael Hanselmann

519 cd40dc53 Michael Hanselmann
  """
520 cd40dc53 Michael Hanselmann
  return dict((name, _ObjectListToDict(disks))
521 cd40dc53 Michael Hanselmann
              for name, disks in value.items())
522 cd40dc53 Michael Hanselmann
523 cd40dc53 Michael Hanselmann
524 601dfcbb Michael Hanselmann
def _PrepareFileUpload(getents_fn, filename):
525 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
526 cd40dc53 Michael Hanselmann

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

544 cd40dc53 Michael Hanselmann
  """
545 cd40dc53 Michael Hanselmann
  flat_disks = []
546 cd40dc53 Michael Hanselmann
547 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
548 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
549 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
550 cd40dc53 Michael Hanselmann
    else:
551 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
552 cd40dc53 Michael Hanselmann
553 cd40dc53 Michael Hanselmann
  return flat_disks
554 cd40dc53 Michael Hanselmann
555 cd40dc53 Michael Hanselmann
556 cd40dc53 Michael Hanselmann
def _EncodeImportExportIO((ieio, ieioargs)):
557 cd40dc53 Michael Hanselmann
  """Encodes import/export I/O information.
558 cd40dc53 Michael Hanselmann

559 cd40dc53 Michael Hanselmann
  """
560 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_RAW_DISK:
561 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 1
562 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ))
563 cd40dc53 Michael Hanselmann
564 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_SCRIPT:
565 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 2
566 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ieioargs[1]))
567 cd40dc53 Michael Hanselmann
568 cd40dc53 Michael Hanselmann
  return (ieio, ieioargs)
569 cd40dc53 Michael Hanselmann
570 cd40dc53 Michael Hanselmann
571 cd40dc53 Michael Hanselmann
def _EncodeBlockdevRename(value):
572 cd40dc53 Michael Hanselmann
  """Encodes information for renaming block devices.
573 cd40dc53 Michael Hanselmann

574 cd40dc53 Michael Hanselmann
  """
575 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
576 cd40dc53 Michael Hanselmann
577 cd40dc53 Michael Hanselmann
578 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
579 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
580 cd46491f René Nussbaumer

581 cd46491f René Nussbaumer
  """
582 cd46491f René Nussbaumer
  assert disk.dev_type == constants.LD_DRBD8
583 cd46491f René Nussbaumer
584 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
585 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
586 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
587 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
588 cd46491f René Nussbaumer
589 cd46491f René Nussbaumer
  return disk
590 cd46491f René Nussbaumer
591 cd46491f René Nussbaumer
592 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
593 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
594 cd46491f René Nussbaumer

595 cd46491f René Nussbaumer
  """
596 cd46491f René Nussbaumer
  assert disk.dev_type != constants.LD_DRBD8
597 cd46491f René Nussbaumer
598 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
599 cd46491f René Nussbaumer
600 cd46491f René Nussbaumer
  return disk
601 cd46491f René Nussbaumer
602 cd46491f René Nussbaumer
603 cd46491f René Nussbaumer
def AnnotateDiskParams(template, disks, disk_params):
604 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
605 cd46491f René Nussbaumer

606 cd46491f René Nussbaumer
  @param template: The disk template used
607 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
608 cd46491f René Nussbaumer
  @param disk_params: The disk paramaters for annotation
609 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
610 cd46491f René Nussbaumer

611 cd46491f René Nussbaumer
  """
612 cd46491f René Nussbaumer
  ld_params = objects.Disk.ComputeLDParams(template, disk_params)
613 cd46491f René Nussbaumer
614 cd46491f René Nussbaumer
  if template == constants.DT_DRBD8:
615 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsDRBD
616 cd46491f René Nussbaumer
  elif template == constants.DT_DISKLESS:
617 cd46491f René Nussbaumer
    annotation_fn = lambda disk, _: disk
618 cd46491f René Nussbaumer
  else:
619 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsGeneric
620 cd46491f René Nussbaumer
621 cd46491f René Nussbaumer
  new_disks = []
622 cd46491f René Nussbaumer
  for disk in disks:
623 cd46491f René Nussbaumer
    new_disks.append(annotation_fn(disk.Copy(), ld_params))
624 cd46491f René Nussbaumer
625 cd46491f René Nussbaumer
  return new_disks
626 cd46491f René Nussbaumer
627 cd46491f René Nussbaumer
628 cd40dc53 Michael Hanselmann
#: Generic encoders
629 cd40dc53 Michael Hanselmann
_ENCODERS = {
630 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
631 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
632 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
633 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
634 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
635 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
636 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
637 cd40dc53 Michael Hanselmann
  }
638 cd40dc53 Michael Hanselmann
639 cd40dc53 Michael Hanselmann
640 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
641 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
642 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
643 bd6d1202 René Nussbaumer
                _generated_rpc.RpcClientDnsOnly,
644 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
645 87b3cb26 Michael Hanselmann
  """RPC runner class.
646 a8083063 Iustin Pop

647 87b3cb26 Michael Hanselmann
  """
648 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
649 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
650 a8083063 Iustin Pop

651 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
652 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
653 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
654 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
655 a8083063 Iustin Pop

656 72737a7f Iustin Pop
    """
657 d5ea30e8 Michael Hanselmann
    self._cfg = cfg
658 cd40dc53 Michael Hanselmann
659 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
660 cd40dc53 Michael Hanselmann
661 cd40dc53 Michael Hanselmann
    encoders.update({
662 601dfcbb Michael Hanselmann
      # Encoders requiring configuration object
663 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
664 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_HVP_BEP: self._InstDictHvpBep,
665 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT_OSP: self._InstDictOsp,
666 601dfcbb Michael Hanselmann
667 aedf5fd7 René Nussbaumer
      # Encoders annotating disk parameters
668 aedf5fd7 René Nussbaumer
      rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP,
669 aedf5fd7 René Nussbaumer
      rpc_defs.ED_SINGLE_DISK_DICT_DP: self._SingleDiskDictDP,
670 aedf5fd7 René Nussbaumer
671 601dfcbb Michael Hanselmann
      # Encoders with special requirements
672 601dfcbb Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
673 cd40dc53 Michael Hanselmann
      })
674 cd40dc53 Michael Hanselmann
675 cd40dc53 Michael Hanselmann
    # Resolver using configuration
676 d5ea30e8 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, cfg.GetNodeInfo,
677 d5ea30e8 Michael Hanselmann
                              cfg.GetAllNodesInfo)
678 cd40dc53 Michael Hanselmann
679 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
680 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
681 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
682 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
683 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
684 d5ea30e8 Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
685 d5ea30e8 Michael Hanselmann
                            _req_process_fn=_req_process_fn)
686 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
687 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
688 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
689 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
690 200de241 Michael Hanselmann
691 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
692 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
693 26ba2bd8 Iustin Pop

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

697 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
698 26ba2bd8 Iustin Pop
    @param instance: an Instance object
699 0eca8e0c Iustin Pop
    @type hvp: dict or None
700 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
701 0eca8e0c Iustin Pop
    @type bep: dict or None
702 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
703 1bdcbbab Iustin Pop
    @type osp: dict or None
704 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
705 26ba2bd8 Iustin Pop
    @rtype: dict
706 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
707 26ba2bd8 Iustin Pop
        cluster defaults
708 26ba2bd8 Iustin Pop

709 26ba2bd8 Iustin Pop
    """
710 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
711 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
712 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
713 0eca8e0c Iustin Pop
    if hvp is not None:
714 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
715 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
716 0eca8e0c Iustin Pop
    if bep is not None:
717 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
718 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
719 1bdcbbab Iustin Pop
    if osp is not None:
720 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
721 b848ce79 Guido Trotter
    for nic in idict["nics"]:
722 3ccb3a64 Michael Hanselmann
      nic["nicparams"] = objects.FillDict(
723 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
724 3ccb3a64 Michael Hanselmann
        nic["nicparams"])
725 26ba2bd8 Iustin Pop
    return idict
726 26ba2bd8 Iustin Pop
727 c4de9b7a Michael Hanselmann
  def _InstDictHvpBep(self, (instance, hvp, bep)):
728 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
729 c4de9b7a Michael Hanselmann

730 c4de9b7a Michael Hanselmann
    """
731 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
732 c4de9b7a Michael Hanselmann
733 c4de9b7a Michael Hanselmann
  def _InstDictOsp(self, (instance, osparams)):
734 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
735 c4de9b7a Michael Hanselmann

736 c4de9b7a Michael Hanselmann
    """
737 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
738 c4de9b7a Michael Hanselmann
739 aedf5fd7 René Nussbaumer
  def _DisksDictDP(self, (disks, instance)):
740 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
741 aedf5fd7 René Nussbaumer

742 aedf5fd7 René Nussbaumer
    """
743 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
744 aedf5fd7 René Nussbaumer
    return [disk.ToDict()
745 aedf5fd7 René Nussbaumer
            for disk in AnnotateDiskParams(instance.disk_template,
746 aedf5fd7 René Nussbaumer
                                           disks, diskparams)]
747 aedf5fd7 René Nussbaumer
748 aedf5fd7 René Nussbaumer
  def _SingleDiskDictDP(self, (disk, instance)):
749 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
750 aedf5fd7 René Nussbaumer

751 aedf5fd7 René Nussbaumer
    """
752 aedf5fd7 René Nussbaumer
    (anno_disk,) = self._DisksDictDP(([disk], instance))
753 aedf5fd7 René Nussbaumer
    return anno_disk
754 aedf5fd7 René Nussbaumer
755 fb1ffbca Michael Hanselmann
756 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
757 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
758 fb1ffbca Michael Hanselmann

759 fb1ffbca Michael Hanselmann
  """
760 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
761 fb1ffbca Michael Hanselmann
    """Initializes this class.
762 fb1ffbca Michael Hanselmann

763 fb1ffbca Michael Hanselmann
    """
764 fb1ffbca Michael Hanselmann
    if address_list is None:
765 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
766 fb1ffbca Michael Hanselmann
    else:
767 fb1ffbca Michael Hanselmann
      # Caller provided an address list
768 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
769 fb1ffbca Michael Hanselmann
770 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
771 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
772 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
773 db04ce5d Michael Hanselmann
774 db04ce5d Michael Hanselmann
775 bd6d1202 René Nussbaumer
class BootstrapRunner(_RpcClientBase,
776 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientBootstrap,
777 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientDnsOnly):
778 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
779 db04ce5d Michael Hanselmann

780 db04ce5d Michael Hanselmann
  """
781 db04ce5d Michael Hanselmann
  def __init__(self):
782 db04ce5d Michael Hanselmann
    """Initializes this class.
783 db04ce5d Michael Hanselmann

784 db04ce5d Michael Hanselmann
    """
785 bd6d1202 René Nussbaumer
    # Pylint doesn't recognize multiple inheritance properly, see
786 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/36586> and
787 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/35642>
788 bd6d1202 René Nussbaumer
    # pylint: disable=W0233
789 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, True),
790 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
791 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
792 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
793 bd6d1202 René Nussbaumer
794 bd6d1202 René Nussbaumer
795 bd6d1202 René Nussbaumer
class DnsOnlyRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly):
796 bd6d1202 René Nussbaumer
  """RPC wrappers for calls using only DNS.
797 bd6d1202 René Nussbaumer

798 bd6d1202 René Nussbaumer
  """
799 bd6d1202 René Nussbaumer
  def __init__(self):
800 bd6d1202 René Nussbaumer
    """Initialize this class.
801 bd6d1202 René Nussbaumer

802 bd6d1202 René Nussbaumer
    """
803 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, False),
804 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
805 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
806 db04ce5d Michael Hanselmann
807 415a7304 Michael Hanselmann
808 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
809 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
810 415a7304 Michael Hanselmann

811 415a7304 Michael Hanselmann
  """
812 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
813 c2dc025a Michael Hanselmann
               _getents=None):
814 415a7304 Michael Hanselmann
    """Initializes this class.
815 415a7304 Michael Hanselmann

816 415a7304 Michael Hanselmann
    """
817 b2acdbdc Michael Hanselmann
    if context:
818 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
819 b2acdbdc Michael Hanselmann
    else:
820 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
821 b2acdbdc Michael Hanselmann
822 415a7304 Michael Hanselmann
    if address_list is None:
823 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
824 415a7304 Michael Hanselmann
    else:
825 415a7304 Michael Hanselmann
      # Caller provided an address list
826 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
827 415a7304 Michael Hanselmann
828 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
829 c2dc025a Michael Hanselmann
830 c2dc025a Michael Hanselmann
    encoders.update({
831 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
832 c2dc025a Michael Hanselmann
      })
833 c2dc025a Michael Hanselmann
834 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
835 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
836 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
837 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)