Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ f7f03738

History | View | Annotate | Download (26.1 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 91c17910 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 cbe4a0a5 Dimitris Aragiorgis
import copy
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
from ganeti import utils
41 a8083063 Iustin Pop
from ganeti import objects
42 ecfe9491 Michael Hanselmann
from ganeti import http
43 7c28c575 Michael Hanselmann
from ganeti import serializer
44 eafd8762 Michael Hanselmann
from ganeti import constants
45 781de953 Iustin Pop
from ganeti import errors
46 a744b676 Manuel Franceschini
from ganeti import netutils
47 eb202c13 Manuel Franceschini
from ganeti import ssconf
48 9a914f7a René Nussbaumer
from ganeti import runtime
49 00267bfe Michael Hanselmann
from ganeti import compat
50 cd40dc53 Michael Hanselmann
from ganeti import rpc_defs
51 80ec9f96 Michael Hanselmann
from ganeti import pathutils
52 cffbbae7 Michael Hanselmann
from ganeti import vcluster
53 a8083063 Iustin Pop
54 200de241 Michael Hanselmann
# Special module generated at build time
55 200de241 Michael Hanselmann
from ganeti import _generated_rpc
56 200de241 Michael Hanselmann
57 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
58 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
59 ae88ef45 Michael Hanselmann
60 a8083063 Iustin Pop
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 00267bfe Michael Hanselmann
#: Special value to describe an offline host
67 00267bfe Michael Hanselmann
_OFFLINE = object()
68 00267bfe Michael Hanselmann
69 4331f6cd Michael Hanselmann
70 4331f6cd Michael Hanselmann
def Init():
71 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
72 4331f6cd Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

400 00267bfe Michael Hanselmann
    @type hosts: sequence
401 00267bfe Michael Hanselmann
    @param hosts: Hostnames
402 00267bfe Michael Hanselmann
    @type procedure: string
403 00267bfe Michael Hanselmann
    @param procedure: Request path
404 d9de612c Iustin Pop
    @type body: dictionary
405 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
406 00267bfe Michael Hanselmann
    @type read_timeout: int or None
407 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
408 05325a35 Bernardo Dal Seno
    @rtype: dictionary
409 05325a35 Bernardo Dal Seno
    @return: a dictionary mapping host names to rpc.RpcResult objects
410 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

570 cd40dc53 Michael Hanselmann
  """
571 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
572 cd40dc53 Michael Hanselmann
573 cd40dc53 Michael Hanselmann
574 91c17910 Iustin Pop
def MakeLegacyNodeInfo(data, require_vg_info=True):
575 b112bfc4 René Nussbaumer
  """Formats the data returned by L{rpc.RpcRunner.call_node_info}.
576 b112bfc4 René Nussbaumer

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

580 91c17910 Iustin Pop
  @param require_vg_info: raise an error if the returnd vg_info
581 91c17910 Iustin Pop
      doesn't have any values
582 91c17910 Iustin Pop

583 b112bfc4 René Nussbaumer
  """
584 91c17910 Iustin Pop
  (bootid, vgs_info, (hv_info, )) = data
585 91c17910 Iustin Pop
586 91c17910 Iustin Pop
  ret = utils.JoinDisjointDicts(hv_info, {"bootid": bootid})
587 91c17910 Iustin Pop
588 91c17910 Iustin Pop
  if require_vg_info or vgs_info:
589 91c17910 Iustin Pop
    (vg0_info, ) = vgs_info
590 91c17910 Iustin Pop
    ret = utils.JoinDisjointDicts(vg0_info, ret)
591 b112bfc4 René Nussbaumer
592 91c17910 Iustin Pop
  return ret
593 b112bfc4 René Nussbaumer
594 b112bfc4 René Nussbaumer
595 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
596 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
597 cd46491f René Nussbaumer

598 cd46491f René Nussbaumer
  """
599 cd46491f René Nussbaumer
  assert disk.dev_type == constants.LD_DRBD8
600 cd46491f René Nussbaumer
601 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
602 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
603 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
604 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
605 cd46491f René Nussbaumer
606 cd46491f René Nussbaumer
  return disk
607 cd46491f René Nussbaumer
608 cd46491f René Nussbaumer
609 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
610 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
611 cd46491f René Nussbaumer

612 cd46491f René Nussbaumer
  """
613 cd46491f René Nussbaumer
  assert disk.dev_type != constants.LD_DRBD8
614 cd46491f René Nussbaumer
615 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
616 cd46491f René Nussbaumer
617 cd46491f René Nussbaumer
  return disk
618 cd46491f René Nussbaumer
619 cd46491f René Nussbaumer
620 cd46491f René Nussbaumer
def AnnotateDiskParams(template, disks, disk_params):
621 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
622 cd46491f René Nussbaumer

623 cd46491f René Nussbaumer
  @param template: The disk template used
624 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
625 cd46491f René Nussbaumer
  @param disk_params: The disk paramaters for annotation
626 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
627 cd46491f René Nussbaumer

628 cd46491f René Nussbaumer
  """
629 cd46491f René Nussbaumer
  ld_params = objects.Disk.ComputeLDParams(template, disk_params)
630 cd46491f René Nussbaumer
631 cd46491f René Nussbaumer
  if template == constants.DT_DRBD8:
632 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsDRBD
633 cd46491f René Nussbaumer
  elif template == constants.DT_DISKLESS:
634 cd46491f René Nussbaumer
    annotation_fn = lambda disk, _: disk
635 cd46491f René Nussbaumer
  else:
636 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsGeneric
637 cd46491f René Nussbaumer
638 52f93ffd Michael Hanselmann
  return [annotation_fn(disk.Copy(), ld_params) for disk in disks]
639 cd46491f René Nussbaumer
640 cd46491f René Nussbaumer
641 319322a7 Bernardo Dal Seno
def _GetESFlag(cfg, nodename):
642 319322a7 Bernardo Dal Seno
  ni = cfg.GetNodeInfo(nodename)
643 319322a7 Bernardo Dal Seno
  if ni is None:
644 319322a7 Bernardo Dal Seno
    raise errors.OpPrereqError("Invalid node name %s" % nodename,
645 319322a7 Bernardo Dal Seno
                               errors.ECODE_NOENT)
646 319322a7 Bernardo Dal Seno
  return cfg.GetNdParams(ni)[constants.ND_EXCLUSIVE_STORAGE]
647 319322a7 Bernardo Dal Seno
648 319322a7 Bernardo Dal Seno
649 319322a7 Bernardo Dal Seno
def GetExclusiveStorageForNodeNames(cfg, nodelist):
650 319322a7 Bernardo Dal Seno
  """Return the exclusive storage flag for all the given nodes.
651 319322a7 Bernardo Dal Seno

652 319322a7 Bernardo Dal Seno
  @type cfg: L{config.ConfigWriter}
653 319322a7 Bernardo Dal Seno
  @param cfg: cluster configuration
654 319322a7 Bernardo Dal Seno
  @type nodelist: list or tuple
655 319322a7 Bernardo Dal Seno
  @param nodelist: node names for which to read the flag
656 319322a7 Bernardo Dal Seno
  @rtype: dict
657 319322a7 Bernardo Dal Seno
  @return: mapping from node names to exclusive storage flags
658 319322a7 Bernardo Dal Seno
  @raise errors.OpPrereqError: if any given node name has no corresponding node
659 319322a7 Bernardo Dal Seno

660 319322a7 Bernardo Dal Seno
  """
661 319322a7 Bernardo Dal Seno
  getflag = lambda n: _GetESFlag(cfg, n)
662 319322a7 Bernardo Dal Seno
  flags = map(getflag, nodelist)
663 319322a7 Bernardo Dal Seno
  return dict(zip(nodelist, flags))
664 319322a7 Bernardo Dal Seno
665 319322a7 Bernardo Dal Seno
666 cd40dc53 Michael Hanselmann
#: Generic encoders
667 cd40dc53 Michael Hanselmann
_ENCODERS = {
668 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
669 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
670 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
671 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
672 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
673 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
674 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
675 cd40dc53 Michael Hanselmann
  }
676 cd40dc53 Michael Hanselmann
677 cd40dc53 Michael Hanselmann
678 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
679 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
680 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
681 bd6d1202 René Nussbaumer
                _generated_rpc.RpcClientDnsOnly,
682 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
683 87b3cb26 Michael Hanselmann
  """RPC runner class.
684 a8083063 Iustin Pop

685 87b3cb26 Michael Hanselmann
  """
686 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
687 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
688 a8083063 Iustin Pop

689 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
690 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
691 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
692 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
693 a8083063 Iustin Pop

694 72737a7f Iustin Pop
    """
695 d5ea30e8 Michael Hanselmann
    self._cfg = cfg
696 cd40dc53 Michael Hanselmann
697 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
698 cd40dc53 Michael Hanselmann
699 cd40dc53 Michael Hanselmann
    encoders.update({
700 601dfcbb Michael Hanselmann
      # Encoders requiring configuration object
701 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
702 5fce6a89 Constantinos Venetsanopoulos
      rpc_defs.ED_INST_DICT_HVP_BEP_DP: self._InstDictHvpBepDp,
703 b8291e00 René Nussbaumer
      rpc_defs.ED_INST_DICT_OSP_DP: self._InstDictOspDp,
704 cbe4a0a5 Dimitris Aragiorgis
      rpc_defs.ED_NIC_DICT: self._NicDict,
705 601dfcbb Michael Hanselmann
706 aedf5fd7 René Nussbaumer
      # Encoders annotating disk parameters
707 aedf5fd7 René Nussbaumer
      rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP,
708 aedf5fd7 René Nussbaumer
      rpc_defs.ED_SINGLE_DISK_DICT_DP: self._SingleDiskDictDP,
709 aedf5fd7 René Nussbaumer
710 601dfcbb Michael Hanselmann
      # Encoders with special requirements
711 601dfcbb Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
712 cd40dc53 Michael Hanselmann
      })
713 cd40dc53 Michael Hanselmann
714 cd40dc53 Michael Hanselmann
    # Resolver using configuration
715 d5ea30e8 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, cfg.GetNodeInfo,
716 d5ea30e8 Michael Hanselmann
                              cfg.GetAllNodesInfo)
717 cd40dc53 Michael Hanselmann
718 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
719 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
720 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
721 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
722 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
723 d5ea30e8 Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
724 d5ea30e8 Michael Hanselmann
                            _req_process_fn=_req_process_fn)
725 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
726 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
727 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
728 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
729 200de241 Michael Hanselmann
730 cbe4a0a5 Dimitris Aragiorgis
  def _NicDict(self, nic):
731 cbe4a0a5 Dimitris Aragiorgis
    """Convert the given nic to a dict and encapsulate netinfo
732 cbe4a0a5 Dimitris Aragiorgis

733 cbe4a0a5 Dimitris Aragiorgis
    """
734 cbe4a0a5 Dimitris Aragiorgis
    n = copy.deepcopy(nic)
735 cbe4a0a5 Dimitris Aragiorgis
    if n.network:
736 cbe4a0a5 Dimitris Aragiorgis
      net_uuid = self._cfg.LookupNetwork(n.network)
737 cbe4a0a5 Dimitris Aragiorgis
      if net_uuid:
738 cbe4a0a5 Dimitris Aragiorgis
        nobj = self._cfg.GetNetwork(net_uuid)
739 cbe4a0a5 Dimitris Aragiorgis
        n.netinfo = objects.Network.ToDict(nobj)
740 cbe4a0a5 Dimitris Aragiorgis
    return n.ToDict()
741 cbe4a0a5 Dimitris Aragiorgis
742 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
743 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
744 26ba2bd8 Iustin Pop

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

748 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
749 26ba2bd8 Iustin Pop
    @param instance: an Instance object
750 0eca8e0c Iustin Pop
    @type hvp: dict or None
751 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
752 0eca8e0c Iustin Pop
    @type bep: dict or None
753 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
754 1bdcbbab Iustin Pop
    @type osp: dict or None
755 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
756 26ba2bd8 Iustin Pop
    @rtype: dict
757 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
758 26ba2bd8 Iustin Pop
        cluster defaults
759 26ba2bd8 Iustin Pop

760 26ba2bd8 Iustin Pop
    """
761 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
762 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
763 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
764 0eca8e0c Iustin Pop
    if hvp is not None:
765 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
766 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
767 0eca8e0c Iustin Pop
    if bep is not None:
768 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
769 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
770 1bdcbbab Iustin Pop
    if osp is not None:
771 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
772 cbe4a0a5 Dimitris Aragiorgis
    idict["disks"] = self._DisksDictDP((instance.disks, instance))
773 b848ce79 Guido Trotter
    for nic in idict["nics"]:
774 3ccb3a64 Michael Hanselmann
      nic["nicparams"] = objects.FillDict(
775 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
776 3ccb3a64 Michael Hanselmann
        nic["nicparams"])
777 cbe4a0a5 Dimitris Aragiorgis
      network = nic.get("network", None)
778 cbe4a0a5 Dimitris Aragiorgis
      if network:
779 cbe4a0a5 Dimitris Aragiorgis
        net_uuid = self._cfg.LookupNetwork(network)
780 cbe4a0a5 Dimitris Aragiorgis
        if net_uuid:
781 cbe4a0a5 Dimitris Aragiorgis
          nobj = self._cfg.GetNetwork(net_uuid)
782 cbe4a0a5 Dimitris Aragiorgis
          nic["netinfo"] = objects.Network.ToDict(nobj)
783 26ba2bd8 Iustin Pop
    return idict
784 26ba2bd8 Iustin Pop
785 5fce6a89 Constantinos Venetsanopoulos
  def _InstDictHvpBepDp(self, (instance, hvp, bep)):
786 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
787 c4de9b7a Michael Hanselmann

788 c4de9b7a Michael Hanselmann
    """
789 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
790 c4de9b7a Michael Hanselmann
791 b8291e00 René Nussbaumer
  def _InstDictOspDp(self, (instance, osparams)):
792 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
793 c4de9b7a Michael Hanselmann

794 c4de9b7a Michael Hanselmann
    """
795 0e2b7c58 Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
796 c4de9b7a Michael Hanselmann
797 aedf5fd7 René Nussbaumer
  def _DisksDictDP(self, (disks, instance)):
798 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
799 aedf5fd7 René Nussbaumer

800 aedf5fd7 René Nussbaumer
    """
801 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
802 aedf5fd7 René Nussbaumer
    return [disk.ToDict()
803 aedf5fd7 René Nussbaumer
            for disk in AnnotateDiskParams(instance.disk_template,
804 aedf5fd7 René Nussbaumer
                                           disks, diskparams)]
805 aedf5fd7 René Nussbaumer
806 aedf5fd7 René Nussbaumer
  def _SingleDiskDictDP(self, (disk, instance)):
807 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
808 aedf5fd7 René Nussbaumer

809 aedf5fd7 René Nussbaumer
    """
810 aedf5fd7 René Nussbaumer
    (anno_disk,) = self._DisksDictDP(([disk], instance))
811 aedf5fd7 René Nussbaumer
    return anno_disk
812 aedf5fd7 René Nussbaumer
813 fb1ffbca Michael Hanselmann
814 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
815 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
816 fb1ffbca Michael Hanselmann

817 fb1ffbca Michael Hanselmann
  """
818 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
819 fb1ffbca Michael Hanselmann
    """Initializes this class.
820 fb1ffbca Michael Hanselmann

821 fb1ffbca Michael Hanselmann
    """
822 fb1ffbca Michael Hanselmann
    if address_list is None:
823 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
824 fb1ffbca Michael Hanselmann
    else:
825 fb1ffbca Michael Hanselmann
      # Caller provided an address list
826 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
827 fb1ffbca Michael Hanselmann
828 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
829 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
830 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
831 db04ce5d Michael Hanselmann
832 db04ce5d Michael Hanselmann
833 bd6d1202 René Nussbaumer
class BootstrapRunner(_RpcClientBase,
834 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientBootstrap,
835 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientDnsOnly):
836 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
837 db04ce5d Michael Hanselmann

838 db04ce5d Michael Hanselmann
  """
839 db04ce5d Michael Hanselmann
  def __init__(self):
840 db04ce5d Michael Hanselmann
    """Initializes this class.
841 db04ce5d Michael Hanselmann

842 db04ce5d Michael Hanselmann
    """
843 bd6d1202 René Nussbaumer
    # Pylint doesn't recognize multiple inheritance properly, see
844 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/36586> and
845 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/35642>
846 bd6d1202 René Nussbaumer
    # pylint: disable=W0233
847 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, True),
848 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
849 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
850 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
851 bd6d1202 René Nussbaumer
852 bd6d1202 René Nussbaumer
853 bd6d1202 René Nussbaumer
class DnsOnlyRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly):
854 bd6d1202 René Nussbaumer
  """RPC wrappers for calls using only DNS.
855 bd6d1202 René Nussbaumer

856 bd6d1202 René Nussbaumer
  """
857 bd6d1202 René Nussbaumer
  def __init__(self):
858 bd6d1202 René Nussbaumer
    """Initialize this class.
859 bd6d1202 René Nussbaumer

860 bd6d1202 René Nussbaumer
    """
861 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, False),
862 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
863 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
864 db04ce5d Michael Hanselmann
865 415a7304 Michael Hanselmann
866 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
867 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
868 415a7304 Michael Hanselmann

869 415a7304 Michael Hanselmann
  """
870 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
871 c2dc025a Michael Hanselmann
               _getents=None):
872 415a7304 Michael Hanselmann
    """Initializes this class.
873 415a7304 Michael Hanselmann

874 415a7304 Michael Hanselmann
    """
875 b2acdbdc Michael Hanselmann
    if context:
876 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
877 b2acdbdc Michael Hanselmann
    else:
878 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
879 b2acdbdc Michael Hanselmann
880 415a7304 Michael Hanselmann
    if address_list is None:
881 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
882 415a7304 Michael Hanselmann
    else:
883 415a7304 Michael Hanselmann
      # Caller provided an address list
884 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
885 415a7304 Michael Hanselmann
886 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
887 c2dc025a Michael Hanselmann
888 c2dc025a Michael Hanselmann
    encoders.update({
889 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
890 c2dc025a Michael Hanselmann
      })
891 c2dc025a Michael Hanselmann
892 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
893 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
894 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
895 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)