Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 95e7e85e

History | View | Annotate | Download (26.4 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 95e7e85e Klaus Aehlig
  def Warn(self, msg, feedback_fn):
234 95e7e85e Klaus Aehlig
    """If the result has failed, call the feedback_fn.
235 95e7e85e Klaus Aehlig

236 95e7e85e Klaus Aehlig
    This is used to in cases were LU wants to warn the
237 95e7e85e Klaus Aehlig
    user about a failure, but continue anyway.
238 95e7e85e Klaus Aehlig

239 95e7e85e Klaus Aehlig
    """
240 95e7e85e Klaus Aehlig
    if not self.fail_msg:
241 95e7e85e Klaus Aehlig
      return
242 95e7e85e Klaus Aehlig
243 95e7e85e Klaus Aehlig
    msg = "%s: %s" % (msg, self.fail_msg)
244 95e7e85e Klaus Aehlig
    feedback_fn(msg)
245 95e7e85e Klaus Aehlig
246 781de953 Iustin Pop
247 bd6d1202 René Nussbaumer
def _SsconfResolver(ssconf_ips, node_list, _,
248 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
249 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
250 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
251 eb202c13 Manuel Franceschini

252 bd6d1202 René Nussbaumer
  @type ssconf_ips: bool
253 bd6d1202 René Nussbaumer
  @param ssconf_ips: Use the ssconf IPs
254 eb202c13 Manuel Franceschini
  @type node_list: list
255 eb202c13 Manuel Franceschini
  @param node_list: List of node names
256 eb202c13 Manuel Franceschini
  @type ssc: class
257 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
258 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
259 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
260 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
261 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
262 eb202c13 Manuel Franceschini

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

287 00267bfe Michael Hanselmann
    """
288 00267bfe Michael Hanselmann
    self._addresses = addresses
289 00267bfe Michael Hanselmann
290 fce5efd1 Michael Hanselmann
  def __call__(self, hosts, _):
291 00267bfe Michael Hanselmann
    """Returns static addresses for hosts.
292 00267bfe Michael Hanselmann

293 00267bfe Michael Hanselmann
    """
294 00267bfe Michael Hanselmann
    assert len(hosts) == len(self._addresses)
295 00267bfe Michael Hanselmann
    return zip(hosts, self._addresses)
296 00267bfe Michael Hanselmann
297 eb202c13 Manuel Franceschini
298 890ea4ce Michael Hanselmann
def _CheckConfigNode(name, node, accept_offline_node):
299 00267bfe Michael Hanselmann
  """Checks if a node is online.
300 eb202c13 Manuel Franceschini

301 00267bfe Michael Hanselmann
  @type name: string
302 00267bfe Michael Hanselmann
  @param name: Node name
303 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
304 00267bfe Michael Hanselmann
  @param node: Node object
305 eb202c13 Manuel Franceschini

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

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

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

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

356 d9de612c Iustin Pop
    @type body: dict
357 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
358 d9de612c Iustin Pop

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

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

413 00267bfe Michael Hanselmann
    @type hosts: sequence
414 00267bfe Michael Hanselmann
    @param hosts: Hostnames
415 00267bfe Michael Hanselmann
    @type procedure: string
416 00267bfe Michael Hanselmann
    @param procedure: Request path
417 d9de612c Iustin Pop
    @type body: dictionary
418 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
419 00267bfe Michael Hanselmann
    @type read_timeout: int or None
420 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
421 05325a35 Bernardo Dal Seno
    @rtype: dictionary
422 05325a35 Bernardo Dal Seno
    @return: a dictionary mapping host names to rpc.RpcResult objects
423 a8083063 Iustin Pop

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

447 cd40dc53 Michael Hanselmann
    """
448 065be3f0 Michael Hanselmann
    proc = _RpcProcessor(resolver,
449 065be3f0 Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED),
450 065be3f0 Michael Hanselmann
                         lock_monitor_cb=lock_monitor_cb)
451 065be3f0 Michael Hanselmann
    self._proc = compat.partial(proc, _req_process_fn=_req_process_fn)
452 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
453 cd40dc53 Michael Hanselmann
454 cd40dc53 Michael Hanselmann
  @staticmethod
455 cd40dc53 Michael Hanselmann
  def _EncodeArg(encoder_fn, (argkind, value)):
456 cd40dc53 Michael Hanselmann
    """Encode argument.
457 cd40dc53 Michael Hanselmann

458 cd40dc53 Michael Hanselmann
    """
459 cd40dc53 Michael Hanselmann
    if argkind is None:
460 cd40dc53 Michael Hanselmann
      return value
461 cd40dc53 Michael Hanselmann
    else:
462 cd40dc53 Michael Hanselmann
      return encoder_fn(argkind)(value)
463 cd40dc53 Michael Hanselmann
464 f7d9b3aa Michael Hanselmann
  def _Call(self, cdef, node_list, args):
465 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
466 cd40dc53 Michael Hanselmann

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

510 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
511 cd40dc53 Michael Hanselmann

512 cd40dc53 Michael Hanselmann
  """
513 cd40dc53 Michael Hanselmann
  return value.ToDict()
514 cd40dc53 Michael Hanselmann
515 cd40dc53 Michael Hanselmann
516 cd40dc53 Michael Hanselmann
def _ObjectListToDict(value):
517 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
518 cd40dc53 Michael Hanselmann

519 cd40dc53 Michael Hanselmann
  """
520 cd40dc53 Michael Hanselmann
  return map(_ObjectToDict, value)
521 cd40dc53 Michael Hanselmann
522 cd40dc53 Michael Hanselmann
523 cd40dc53 Michael Hanselmann
def _EncodeNodeToDiskDict(value):
524 cd40dc53 Michael Hanselmann
  """Encodes a dictionary with node name as key and disk objects as values.
525 cd40dc53 Michael Hanselmann

526 cd40dc53 Michael Hanselmann
  """
527 cd40dc53 Michael Hanselmann
  return dict((name, _ObjectListToDict(disks))
528 cd40dc53 Michael Hanselmann
              for name, disks in value.items())
529 cd40dc53 Michael Hanselmann
530 cd40dc53 Michael Hanselmann
531 601dfcbb Michael Hanselmann
def _PrepareFileUpload(getents_fn, filename):
532 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
533 cd40dc53 Michael Hanselmann

534 cd40dc53 Michael Hanselmann
  """
535 2ce40421 Michael Hanselmann
  statcb = utils.FileStatHelper()
536 2ce40421 Michael Hanselmann
  data = _Compress(utils.ReadFile(filename, preread=statcb))
537 2ce40421 Michael Hanselmann
  st = statcb.st
538 601dfcbb Michael Hanselmann
539 601dfcbb Michael Hanselmann
  if getents_fn is None:
540 601dfcbb Michael Hanselmann
    getents_fn = runtime.GetEnts
541 601dfcbb Michael Hanselmann
542 601dfcbb Michael Hanselmann
  getents = getents_fn()
543 601dfcbb Michael Hanselmann
544 cffbbae7 Michael Hanselmann
  virt_filename = vcluster.MakeVirtualPath(filename)
545 cffbbae7 Michael Hanselmann
546 cffbbae7 Michael Hanselmann
  return [virt_filename, data, st.st_mode, getents.LookupUid(st.st_uid),
547 cd40dc53 Michael Hanselmann
          getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
548 cd40dc53 Michael Hanselmann
549 cd40dc53 Michael Hanselmann
550 cd40dc53 Michael Hanselmann
def _PrepareFinalizeExportDisks(snap_disks):
551 cd40dc53 Michael Hanselmann
  """Encodes disks for finalizing export.
552 cd40dc53 Michael Hanselmann

553 cd40dc53 Michael Hanselmann
  """
554 cd40dc53 Michael Hanselmann
  flat_disks = []
555 cd40dc53 Michael Hanselmann
556 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
557 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
558 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
559 cd40dc53 Michael Hanselmann
    else:
560 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
561 cd40dc53 Michael Hanselmann
562 cd40dc53 Michael Hanselmann
  return flat_disks
563 cd40dc53 Michael Hanselmann
564 cd40dc53 Michael Hanselmann
565 cd40dc53 Michael Hanselmann
def _EncodeImportExportIO((ieio, ieioargs)):
566 cd40dc53 Michael Hanselmann
  """Encodes import/export I/O information.
567 cd40dc53 Michael Hanselmann

568 cd40dc53 Michael Hanselmann
  """
569 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_RAW_DISK:
570 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 1
571 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ))
572 cd40dc53 Michael Hanselmann
573 cd40dc53 Michael Hanselmann
  if ieio == constants.IEIO_SCRIPT:
574 cd40dc53 Michael Hanselmann
    assert len(ieioargs) == 2
575 cd40dc53 Michael Hanselmann
    return (ieio, (ieioargs[0].ToDict(), ieioargs[1]))
576 cd40dc53 Michael Hanselmann
577 cd40dc53 Michael Hanselmann
  return (ieio, ieioargs)
578 cd40dc53 Michael Hanselmann
579 cd40dc53 Michael Hanselmann
580 cd40dc53 Michael Hanselmann
def _EncodeBlockdevRename(value):
581 cd40dc53 Michael Hanselmann
  """Encodes information for renaming block devices.
582 cd40dc53 Michael Hanselmann

583 cd40dc53 Michael Hanselmann
  """
584 cd40dc53 Michael Hanselmann
  return [(d.ToDict(), uid) for d, uid in value]
585 cd40dc53 Michael Hanselmann
586 cd40dc53 Michael Hanselmann
587 91c17910 Iustin Pop
def MakeLegacyNodeInfo(data, require_vg_info=True):
588 b112bfc4 René Nussbaumer
  """Formats the data returned by L{rpc.RpcRunner.call_node_info}.
589 b112bfc4 René Nussbaumer

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

593 91c17910 Iustin Pop
  @param require_vg_info: raise an error if the returnd vg_info
594 91c17910 Iustin Pop
      doesn't have any values
595 91c17910 Iustin Pop

596 b112bfc4 René Nussbaumer
  """
597 91c17910 Iustin Pop
  (bootid, vgs_info, (hv_info, )) = data
598 91c17910 Iustin Pop
599 91c17910 Iustin Pop
  ret = utils.JoinDisjointDicts(hv_info, {"bootid": bootid})
600 91c17910 Iustin Pop
601 91c17910 Iustin Pop
  if require_vg_info or vgs_info:
602 91c17910 Iustin Pop
    (vg0_info, ) = vgs_info
603 91c17910 Iustin Pop
    ret = utils.JoinDisjointDicts(vg0_info, ret)
604 b112bfc4 René Nussbaumer
605 91c17910 Iustin Pop
  return ret
606 b112bfc4 René Nussbaumer
607 b112bfc4 René Nussbaumer
608 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
609 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
610 cd46491f René Nussbaumer

611 cd46491f René Nussbaumer
  """
612 cd46491f René Nussbaumer
  assert disk.dev_type == constants.LD_DRBD8
613 cd46491f René Nussbaumer
614 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
615 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
616 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
617 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
618 cd46491f René Nussbaumer
619 cd46491f René Nussbaumer
  return disk
620 cd46491f René Nussbaumer
621 cd46491f René Nussbaumer
622 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
623 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
624 cd46491f René Nussbaumer

625 cd46491f René Nussbaumer
  """
626 cd46491f René Nussbaumer
  assert disk.dev_type != constants.LD_DRBD8
627 cd46491f René Nussbaumer
628 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
629 cd46491f René Nussbaumer
630 cd46491f René Nussbaumer
  return disk
631 cd46491f René Nussbaumer
632 cd46491f René Nussbaumer
633 cd46491f René Nussbaumer
def AnnotateDiskParams(template, disks, disk_params):
634 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
635 cd46491f René Nussbaumer

636 cd46491f René Nussbaumer
  @param template: The disk template used
637 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
638 cd46491f René Nussbaumer
  @param disk_params: The disk paramaters for annotation
639 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
640 cd46491f René Nussbaumer

641 cd46491f René Nussbaumer
  """
642 cd46491f René Nussbaumer
  ld_params = objects.Disk.ComputeLDParams(template, disk_params)
643 cd46491f René Nussbaumer
644 cd46491f René Nussbaumer
  if template == constants.DT_DRBD8:
645 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsDRBD
646 cd46491f René Nussbaumer
  elif template == constants.DT_DISKLESS:
647 cd46491f René Nussbaumer
    annotation_fn = lambda disk, _: disk
648 cd46491f René Nussbaumer
  else:
649 cd46491f René Nussbaumer
    annotation_fn = _AnnotateDParamsGeneric
650 cd46491f René Nussbaumer
651 52f93ffd Michael Hanselmann
  return [annotation_fn(disk.Copy(), ld_params) for disk in disks]
652 cd46491f René Nussbaumer
653 cd46491f René Nussbaumer
654 319322a7 Bernardo Dal Seno
def _GetESFlag(cfg, nodename):
655 319322a7 Bernardo Dal Seno
  ni = cfg.GetNodeInfo(nodename)
656 319322a7 Bernardo Dal Seno
  if ni is None:
657 319322a7 Bernardo Dal Seno
    raise errors.OpPrereqError("Invalid node name %s" % nodename,
658 319322a7 Bernardo Dal Seno
                               errors.ECODE_NOENT)
659 319322a7 Bernardo Dal Seno
  return cfg.GetNdParams(ni)[constants.ND_EXCLUSIVE_STORAGE]
660 319322a7 Bernardo Dal Seno
661 319322a7 Bernardo Dal Seno
662 319322a7 Bernardo Dal Seno
def GetExclusiveStorageForNodeNames(cfg, nodelist):
663 319322a7 Bernardo Dal Seno
  """Return the exclusive storage flag for all the given nodes.
664 319322a7 Bernardo Dal Seno

665 319322a7 Bernardo Dal Seno
  @type cfg: L{config.ConfigWriter}
666 319322a7 Bernardo Dal Seno
  @param cfg: cluster configuration
667 319322a7 Bernardo Dal Seno
  @type nodelist: list or tuple
668 319322a7 Bernardo Dal Seno
  @param nodelist: node names for which to read the flag
669 319322a7 Bernardo Dal Seno
  @rtype: dict
670 319322a7 Bernardo Dal Seno
  @return: mapping from node names to exclusive storage flags
671 319322a7 Bernardo Dal Seno
  @raise errors.OpPrereqError: if any given node name has no corresponding node
672 319322a7 Bernardo Dal Seno

673 319322a7 Bernardo Dal Seno
  """
674 319322a7 Bernardo Dal Seno
  getflag = lambda n: _GetESFlag(cfg, n)
675 319322a7 Bernardo Dal Seno
  flags = map(getflag, nodelist)
676 319322a7 Bernardo Dal Seno
  return dict(zip(nodelist, flags))
677 319322a7 Bernardo Dal Seno
678 319322a7 Bernardo Dal Seno
679 cd40dc53 Michael Hanselmann
#: Generic encoders
680 cd40dc53 Michael Hanselmann
_ENCODERS = {
681 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
682 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
683 cd40dc53 Michael Hanselmann
  rpc_defs.ED_NODE_TO_DISK_DICT: _EncodeNodeToDiskDict,
684 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
685 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
686 cd40dc53 Michael Hanselmann
  rpc_defs.ED_IMPEXP_IO: _EncodeImportExportIO,
687 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
688 cd40dc53 Michael Hanselmann
  }
689 cd40dc53 Michael Hanselmann
690 cd40dc53 Michael Hanselmann
691 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
692 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
693 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
694 bd6d1202 René Nussbaumer
                _generated_rpc.RpcClientDnsOnly,
695 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
696 87b3cb26 Michael Hanselmann
  """RPC runner class.
697 a8083063 Iustin Pop

698 87b3cb26 Michael Hanselmann
  """
699 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
700 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
701 a8083063 Iustin Pop

702 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
703 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
704 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
705 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
706 a8083063 Iustin Pop

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

746 cbe4a0a5 Dimitris Aragiorgis
    """
747 cbe4a0a5 Dimitris Aragiorgis
    n = copy.deepcopy(nic)
748 cbe4a0a5 Dimitris Aragiorgis
    if n.network:
749 cbe4a0a5 Dimitris Aragiorgis
      net_uuid = self._cfg.LookupNetwork(n.network)
750 cbe4a0a5 Dimitris Aragiorgis
      if net_uuid:
751 cbe4a0a5 Dimitris Aragiorgis
        nobj = self._cfg.GetNetwork(net_uuid)
752 cbe4a0a5 Dimitris Aragiorgis
        n.netinfo = objects.Network.ToDict(nobj)
753 cbe4a0a5 Dimitris Aragiorgis
    return n.ToDict()
754 cbe4a0a5 Dimitris Aragiorgis
755 1bdcbbab Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None, osp=None):
756 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
757 26ba2bd8 Iustin Pop

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

761 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
762 26ba2bd8 Iustin Pop
    @param instance: an Instance object
763 0eca8e0c Iustin Pop
    @type hvp: dict or None
764 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
765 0eca8e0c Iustin Pop
    @type bep: dict or None
766 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
767 1bdcbbab Iustin Pop
    @type osp: dict or None
768 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
769 26ba2bd8 Iustin Pop
    @rtype: dict
770 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
771 26ba2bd8 Iustin Pop
        cluster defaults
772 26ba2bd8 Iustin Pop

773 26ba2bd8 Iustin Pop
    """
774 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
775 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
776 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
777 0eca8e0c Iustin Pop
    if hvp is not None:
778 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
779 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
780 0eca8e0c Iustin Pop
    if bep is not None:
781 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
782 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
783 1bdcbbab Iustin Pop
    if osp is not None:
784 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
785 cbe4a0a5 Dimitris Aragiorgis
    idict["disks"] = self._DisksDictDP((instance.disks, instance))
786 b848ce79 Guido Trotter
    for nic in idict["nics"]:
787 3ccb3a64 Michael Hanselmann
      nic["nicparams"] = objects.FillDict(
788 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
789 3ccb3a64 Michael Hanselmann
        nic["nicparams"])
790 cbe4a0a5 Dimitris Aragiorgis
      network = nic.get("network", None)
791 cbe4a0a5 Dimitris Aragiorgis
      if network:
792 cbe4a0a5 Dimitris Aragiorgis
        net_uuid = self._cfg.LookupNetwork(network)
793 cbe4a0a5 Dimitris Aragiorgis
        if net_uuid:
794 cbe4a0a5 Dimitris Aragiorgis
          nobj = self._cfg.GetNetwork(net_uuid)
795 cbe4a0a5 Dimitris Aragiorgis
          nic["netinfo"] = objects.Network.ToDict(nobj)
796 26ba2bd8 Iustin Pop
    return idict
797 26ba2bd8 Iustin Pop
798 5fce6a89 Constantinos Venetsanopoulos
  def _InstDictHvpBepDp(self, (instance, hvp, bep)):
799 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
800 c4de9b7a Michael Hanselmann

801 c4de9b7a Michael Hanselmann
    """
802 c4de9b7a Michael Hanselmann
    return self._InstDict(instance, hvp=hvp, bep=bep)
803 c4de9b7a Michael Hanselmann
804 b8291e00 René Nussbaumer
  def _InstDictOspDp(self, (instance, osparams)):
805 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
806 c4de9b7a Michael Hanselmann

807 c4de9b7a Michael Hanselmann
    """
808 0e2b7c58 Michael Hanselmann
    return self._InstDict(instance, osp=osparams)
809 c4de9b7a Michael Hanselmann
810 aedf5fd7 René Nussbaumer
  def _DisksDictDP(self, (disks, instance)):
811 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
812 aedf5fd7 René Nussbaumer

813 aedf5fd7 René Nussbaumer
    """
814 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
815 aedf5fd7 René Nussbaumer
    return [disk.ToDict()
816 aedf5fd7 René Nussbaumer
            for disk in AnnotateDiskParams(instance.disk_template,
817 aedf5fd7 René Nussbaumer
                                           disks, diskparams)]
818 aedf5fd7 René Nussbaumer
819 aedf5fd7 René Nussbaumer
  def _SingleDiskDictDP(self, (disk, instance)):
820 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
821 aedf5fd7 René Nussbaumer

822 aedf5fd7 René Nussbaumer
    """
823 aedf5fd7 René Nussbaumer
    (anno_disk,) = self._DisksDictDP(([disk], instance))
824 aedf5fd7 René Nussbaumer
    return anno_disk
825 aedf5fd7 René Nussbaumer
826 fb1ffbca Michael Hanselmann
827 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
828 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
829 fb1ffbca Michael Hanselmann

830 fb1ffbca Michael Hanselmann
  """
831 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
832 fb1ffbca Michael Hanselmann
    """Initializes this class.
833 fb1ffbca Michael Hanselmann

834 fb1ffbca Michael Hanselmann
    """
835 fb1ffbca Michael Hanselmann
    if address_list is None:
836 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
837 fb1ffbca Michael Hanselmann
    else:
838 fb1ffbca Michael Hanselmann
      # Caller provided an address list
839 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
840 fb1ffbca Michael Hanselmann
841 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
842 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
843 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
844 db04ce5d Michael Hanselmann
845 db04ce5d Michael Hanselmann
846 bd6d1202 René Nussbaumer
class BootstrapRunner(_RpcClientBase,
847 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientBootstrap,
848 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientDnsOnly):
849 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
850 db04ce5d Michael Hanselmann

851 db04ce5d Michael Hanselmann
  """
852 db04ce5d Michael Hanselmann
  def __init__(self):
853 db04ce5d Michael Hanselmann
    """Initializes this class.
854 db04ce5d Michael Hanselmann

855 db04ce5d Michael Hanselmann
    """
856 bd6d1202 René Nussbaumer
    # Pylint doesn't recognize multiple inheritance properly, see
857 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/36586> and
858 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/35642>
859 bd6d1202 René Nussbaumer
    # pylint: disable=W0233
860 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, True),
861 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
862 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
863 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
864 bd6d1202 René Nussbaumer
865 bd6d1202 René Nussbaumer
866 bd6d1202 René Nussbaumer
class DnsOnlyRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly):
867 bd6d1202 René Nussbaumer
  """RPC wrappers for calls using only DNS.
868 bd6d1202 René Nussbaumer

869 bd6d1202 René Nussbaumer
  """
870 bd6d1202 René Nussbaumer
  def __init__(self):
871 bd6d1202 René Nussbaumer
    """Initialize this class.
872 bd6d1202 René Nussbaumer

873 bd6d1202 René Nussbaumer
    """
874 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, False),
875 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
876 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
877 db04ce5d Michael Hanselmann
878 415a7304 Michael Hanselmann
879 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
880 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
881 415a7304 Michael Hanselmann

882 415a7304 Michael Hanselmann
  """
883 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
884 c2dc025a Michael Hanselmann
               _getents=None):
885 415a7304 Michael Hanselmann
    """Initializes this class.
886 415a7304 Michael Hanselmann

887 415a7304 Michael Hanselmann
    """
888 b2acdbdc Michael Hanselmann
    if context:
889 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
890 b2acdbdc Michael Hanselmann
    else:
891 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
892 b2acdbdc Michael Hanselmann
893 415a7304 Michael Hanselmann
    if address_list is None:
894 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
895 415a7304 Michael Hanselmann
    else:
896 415a7304 Michael Hanselmann
      # Caller provided an address list
897 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
898 415a7304 Michael Hanselmann
899 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
900 c2dc025a Michael Hanselmann
901 c2dc025a Michael Hanselmann
    encoders.update({
902 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
903 c2dc025a Michael Hanselmann
      })
904 c2dc025a Michael Hanselmann
905 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
906 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
907 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
908 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)