Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 3a6a89d7

History | View | Annotate | Download (24.4 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 80ec9f96 Michael Hanselmann
from ganeti import pathutils
51 cffbbae7 Michael Hanselmann
from ganeti import vcluster
52 a8083063 Iustin Pop
53 200de241 Michael Hanselmann
# Special module generated at build time
54 200de241 Michael Hanselmann
from ganeti import _generated_rpc
55 200de241 Michael Hanselmann
56 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
57 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
58 ae88ef45 Michael Hanselmann
59 a8083063 Iustin Pop
60 33231500 Michael Hanselmann
_RPC_CLIENT_HEADERS = [
61 33231500 Michael Hanselmann
  "Content-type: %s" % http.HTTP_APP_JSON,
62 8e29563f Iustin Pop
  "Expect:",
63 33231500 Michael Hanselmann
  ]
64 4331f6cd Michael Hanselmann
65 00267bfe Michael Hanselmann
#: Special value to describe an offline host
66 00267bfe Michael Hanselmann
_OFFLINE = object()
67 00267bfe Michael Hanselmann
68 4331f6cd Michael Hanselmann
69 4331f6cd Michael Hanselmann
def Init():
70 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
71 4331f6cd Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

213 781de953 Iustin Pop
    """
214 4c4e4e1e Iustin Pop
    if not self.fail_msg:
215 4c4e4e1e Iustin Pop
      return
216 4c4e4e1e Iustin Pop
217 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
218 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
219 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
220 4c4e4e1e Iustin Pop
    else:
221 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
222 4c4e4e1e Iustin Pop
    if prereq:
223 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
224 4c4e4e1e Iustin Pop
    else:
225 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
226 045dd6d9 Iustin Pop
    if ecode is not None:
227 27137e55 Iustin Pop
      args = (msg, ecode)
228 045dd6d9 Iustin Pop
    else:
229 045dd6d9 Iustin Pop
      args = (msg, )
230 b459a848 Andrea Spadaccini
    raise ec(*args) # pylint: disable=W0142
231 781de953 Iustin Pop
232 781de953 Iustin Pop
233 bd6d1202 René Nussbaumer
def _SsconfResolver(ssconf_ips, node_list, _,
234 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
235 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
236 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
237 eb202c13 Manuel Franceschini

238 bd6d1202 René Nussbaumer
  @type ssconf_ips: bool
239 bd6d1202 René Nussbaumer
  @param ssconf_ips: Use the ssconf IPs
240 eb202c13 Manuel Franceschini
  @type node_list: list
241 eb202c13 Manuel Franceschini
  @param node_list: List of node names
242 eb202c13 Manuel Franceschini
  @type ssc: class
243 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
244 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
245 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
246 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
247 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
248 eb202c13 Manuel Franceschini

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

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

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

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

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

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

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

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

342 d9de612c Iustin Pop
    @type body: dict
343 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
344 d9de612c Iustin Pop

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

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

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

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

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

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

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

494 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
495 cd40dc53 Michael Hanselmann

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

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

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

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

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

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

567 cd40dc53 Michael Hanselmann
  """
568 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
569 cd40dc53 Michael Hanselmann
570 cd40dc53 Michael Hanselmann
571 b112bfc4 René Nussbaumer
def MakeLegacyNodeInfo(data):
572 b112bfc4 René Nussbaumer
  """Formats the data returned by L{rpc.RpcRunner.call_node_info}.
573 b112bfc4 René Nussbaumer

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

577 b112bfc4 René Nussbaumer
  """
578 b112bfc4 René Nussbaumer
  (bootid, (vg_info, ), (hv_info, )) = data
579 b112bfc4 René Nussbaumer
580 b112bfc4 René Nussbaumer
  return utils.JoinDisjointDicts(utils.JoinDisjointDicts(vg_info, hv_info), {
581 b112bfc4 René Nussbaumer
    "bootid": bootid,
582 b112bfc4 René Nussbaumer
    })
583 b112bfc4 René Nussbaumer
584 b112bfc4 René Nussbaumer
585 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
586 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
587 cd46491f René Nussbaumer

588 cd46491f René Nussbaumer
  """
589 cd46491f René Nussbaumer
  assert disk.dev_type == constants.LD_DRBD8
590 cd46491f René Nussbaumer
591 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
592 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
593 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
594 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
595 cd46491f René Nussbaumer
596 cd46491f René Nussbaumer
  return disk
597 cd46491f René Nussbaumer
598 cd46491f René Nussbaumer
599 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
600 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
601 cd46491f René Nussbaumer

602 cd46491f René Nussbaumer
  """
603 cd46491f René Nussbaumer
  assert disk.dev_type != constants.LD_DRBD8
604 cd46491f René Nussbaumer
605 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
606 cd46491f René Nussbaumer
607 cd46491f René Nussbaumer
  return disk
608 cd46491f René Nussbaumer
609 cd46491f René Nussbaumer
610 cd46491f René Nussbaumer
def AnnotateDiskParams(template, disks, disk_params):
611 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
612 cd46491f René Nussbaumer

613 cd46491f René Nussbaumer
  @param template: The disk template used
614 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
615 cd46491f René Nussbaumer
  @param disk_params: The disk paramaters for annotation
616 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
617 cd46491f René Nussbaumer

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

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

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

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

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

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

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

733 c4de9b7a Michael Hanselmann
    """
734 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
735 c4de9b7a Michael Hanselmann
736 b8291e00 René Nussbaumer
  def _InstDictOspDp(self, (instance, osparams)):
737 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
738 c4de9b7a Michael Hanselmann

739 c4de9b7a Michael Hanselmann
    """
740 b8291e00 René Nussbaumer
    updated_inst = self._InstDict(instance, osp=osparams)
741 b8291e00 René Nussbaumer
    updated_inst["disks"] = self._DisksDictDP((instance.disks, instance))
742 b8291e00 René Nussbaumer
    return updated_inst
743 c4de9b7a Michael Hanselmann
744 aedf5fd7 René Nussbaumer
  def _DisksDictDP(self, (disks, instance)):
745 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
746 aedf5fd7 René Nussbaumer

747 aedf5fd7 René Nussbaumer
    """
748 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
749 aedf5fd7 René Nussbaumer
    return [disk.ToDict()
750 aedf5fd7 René Nussbaumer
            for disk in AnnotateDiskParams(instance.disk_template,
751 aedf5fd7 René Nussbaumer
                                           disks, diskparams)]
752 aedf5fd7 René Nussbaumer
753 aedf5fd7 René Nussbaumer
  def _SingleDiskDictDP(self, (disk, instance)):
754 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
755 aedf5fd7 René Nussbaumer

756 aedf5fd7 René Nussbaumer
    """
757 aedf5fd7 René Nussbaumer
    (anno_disk,) = self._DisksDictDP(([disk], instance))
758 aedf5fd7 René Nussbaumer
    return anno_disk
759 aedf5fd7 René Nussbaumer
760 fb1ffbca Michael Hanselmann
761 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
762 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
763 fb1ffbca Michael Hanselmann

764 fb1ffbca Michael Hanselmann
  """
765 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
766 fb1ffbca Michael Hanselmann
    """Initializes this class.
767 fb1ffbca Michael Hanselmann

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

785 db04ce5d Michael Hanselmann
  """
786 db04ce5d Michael Hanselmann
  def __init__(self):
787 db04ce5d Michael Hanselmann
    """Initializes this class.
788 db04ce5d Michael Hanselmann

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

803 bd6d1202 René Nussbaumer
  """
804 bd6d1202 René Nussbaumer
  def __init__(self):
805 bd6d1202 René Nussbaumer
    """Initialize this class.
806 bd6d1202 René Nussbaumer

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

816 415a7304 Michael Hanselmann
  """
817 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
818 c2dc025a Michael Hanselmann
               _getents=None):
819 415a7304 Michael Hanselmann
    """Initializes this class.
820 415a7304 Michael Hanselmann

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