Statistics
| Branch: | Tag: | Revision:

root / lib / rpc / node.py @ 8e8cf324

History | View | Annotate | Download (32 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 d5104ca4 Helga Velroyen
import os
40 a8083063 Iustin Pop
41 a8083063 Iustin Pop
from ganeti import utils
42 a8083063 Iustin Pop
from ganeti import objects
43 ecfe9491 Michael Hanselmann
from ganeti import http
44 7c28c575 Michael Hanselmann
from ganeti import serializer
45 eafd8762 Michael Hanselmann
from ganeti import constants
46 781de953 Iustin Pop
from ganeti import errors
47 a744b676 Manuel Franceschini
from ganeti import netutils
48 eb202c13 Manuel Franceschini
from ganeti import ssconf
49 9a914f7a René Nussbaumer
from ganeti import runtime
50 00267bfe Michael Hanselmann
from ganeti import compat
51 cd40dc53 Michael Hanselmann
from ganeti import rpc_defs
52 80ec9f96 Michael Hanselmann
from ganeti import pathutils
53 cffbbae7 Michael Hanselmann
from ganeti import vcluster
54 a8083063 Iustin Pop
55 200de241 Michael Hanselmann
# Special module generated at build time
56 200de241 Michael Hanselmann
from ganeti import _generated_rpc
57 200de241 Michael Hanselmann
58 fe267188 Iustin Pop
# pylint has a bug here, doesn't see this import
59 b459a848 Andrea Spadaccini
import ganeti.http.client  # pylint: disable=W0611
60 ae88ef45 Michael Hanselmann
61 a8083063 Iustin Pop
62 33231500 Michael Hanselmann
_RPC_CLIENT_HEADERS = [
63 33231500 Michael Hanselmann
  "Content-type: %s" % http.HTTP_APP_JSON,
64 8e29563f Iustin Pop
  "Expect:",
65 33231500 Michael Hanselmann
  ]
66 4331f6cd Michael Hanselmann
67 00267bfe Michael Hanselmann
#: Special value to describe an offline host
68 00267bfe Michael Hanselmann
_OFFLINE = object()
69 00267bfe Michael Hanselmann
70 4331f6cd Michael Hanselmann
71 4331f6cd Michael Hanselmann
def Init():
72 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
73 4331f6cd Michael Hanselmann

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

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

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

95 4331f6cd Michael Hanselmann
  """
96 33231500 Michael Hanselmann
  pycurl.global_cleanup()
97 33231500 Michael Hanselmann
98 33231500 Michael Hanselmann
99 33231500 Michael Hanselmann
def _ConfigRpcCurl(curl):
100 80ec9f96 Michael Hanselmann
  noded_cert = str(pathutils.NODED_CERT_FILE)
101 d5104ca4 Helga Velroyen
  noded_client_cert = str(pathutils.NODED_CLIENT_CERT_FILE)
102 d5104ca4 Helga Velroyen
103 d5104ca4 Helga Velroyen
  # FIXME: The next two lines are necessary to ensure upgradability from
104 d5104ca4 Helga Velroyen
  # 2.10 to 2.11. Remove in 2.12, because this slows down RPC calls.
105 d5104ca4 Helga Velroyen
  if not os.path.exists(noded_client_cert):
106 d5104ca4 Helga Velroyen
    logging.info("Using server certificate as client certificate for RPC"
107 d5104ca4 Helga Velroyen
                 "call.")
108 d5104ca4 Helga Velroyen
    noded_client_cert = noded_cert
109 4331f6cd Michael Hanselmann
110 33231500 Michael Hanselmann
  curl.setopt(pycurl.FOLLOWLOCATION, False)
111 33231500 Michael Hanselmann
  curl.setopt(pycurl.CAINFO, noded_cert)
112 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYHOST, 0)
113 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSL_VERIFYPEER, True)
114 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLCERTTYPE, "PEM")
115 d5104ca4 Helga Velroyen
  curl.setopt(pycurl.SSLCERT, noded_client_cert)
116 33231500 Michael Hanselmann
  curl.setopt(pycurl.SSLKEYTYPE, "PEM")
117 d5104ca4 Helga Velroyen
  curl.setopt(pycurl.SSLKEY, noded_client_cert)
118 2ff587d4 Agata Murawska
  curl.setopt(pycurl.CONNECTTIMEOUT, constants.RPC_CONNECT_TIMEOUT)
119 33231500 Michael Hanselmann
120 33231500 Michael Hanselmann
121 e0e916fe Iustin Pop
def RunWithRPC(fn):
122 e0e916fe Iustin Pop
  """RPC-wrapper decorator.
123 e0e916fe Iustin Pop

124 e0e916fe Iustin Pop
  When applied to a function, it runs it with the RPC system
125 e0e916fe Iustin Pop
  initialized, and it shutsdown the system afterwards. This means the
126 e0e916fe Iustin Pop
  function must be called without RPC being initialized.
127 e0e916fe Iustin Pop

128 e0e916fe Iustin Pop
  """
129 e0e916fe Iustin Pop
  def wrapper(*args, **kwargs):
130 e0e916fe Iustin Pop
    Init()
131 e0e916fe Iustin Pop
    try:
132 e0e916fe Iustin Pop
      return fn(*args, **kwargs)
133 e0e916fe Iustin Pop
    finally:
134 e0e916fe Iustin Pop
      Shutdown()
135 e0e916fe Iustin Pop
  return wrapper
136 e0e916fe Iustin Pop
137 e0e916fe Iustin Pop
138 0c3d9c7c Thomas Thrainer
def _Compress(_, data):
139 30474135 Michael Hanselmann
  """Compresses a string for transport over RPC.
140 30474135 Michael Hanselmann

141 30474135 Michael Hanselmann
  Small amounts of data are not compressed.
142 30474135 Michael Hanselmann

143 30474135 Michael Hanselmann
  @type data: str
144 30474135 Michael Hanselmann
  @param data: Data
145 30474135 Michael Hanselmann
  @rtype: tuple
146 30474135 Michael Hanselmann
  @return: Encoded data to send
147 30474135 Michael Hanselmann

148 30474135 Michael Hanselmann
  """
149 30474135 Michael Hanselmann
  # Small amounts of data are not compressed
150 30474135 Michael Hanselmann
  if len(data) < 512:
151 30474135 Michael Hanselmann
    return (constants.RPC_ENCODING_NONE, data)
152 30474135 Michael Hanselmann
153 30474135 Michael Hanselmann
  # Compress with zlib and encode in base64
154 30474135 Michael Hanselmann
  return (constants.RPC_ENCODING_ZLIB_BASE64,
155 30474135 Michael Hanselmann
          base64.b64encode(zlib.compress(data, 3)))
156 30474135 Michael Hanselmann
157 30474135 Michael Hanselmann
158 781de953 Iustin Pop
class RpcResult(object):
159 781de953 Iustin Pop
  """RPC Result class.
160 781de953 Iustin Pop

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

165 5bbd3f7f Michael Hanselmann
  @ivar data: the data payload, for successful results, or None
166 ed83f5cc Iustin Pop
  @ivar call: the name of the RPC call
167 ed83f5cc Iustin Pop
  @ivar node: the name of the node to which we made the call
168 ed83f5cc Iustin Pop
  @ivar offline: whether the operation failed because the node was
169 ed83f5cc Iustin Pop
      offline, as opposed to actual failure; offline=True will always
170 ed83f5cc Iustin Pop
      imply failed=True, in order to allow simpler checking if
171 ed83f5cc Iustin Pop
      the user doesn't care about the exact failure mode
172 4c4e4e1e Iustin Pop
  @ivar fail_msg: the error message if the call failed
173 ed83f5cc Iustin Pop

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

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

227 781de953 Iustin Pop
    """
228 4c4e4e1e Iustin Pop
    if not self.fail_msg:
229 4c4e4e1e Iustin Pop
      return
230 4c4e4e1e Iustin Pop
231 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
232 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
233 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
234 4c4e4e1e Iustin Pop
    else:
235 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
236 4c4e4e1e Iustin Pop
    if prereq:
237 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
238 4c4e4e1e Iustin Pop
    else:
239 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
240 045dd6d9 Iustin Pop
    if ecode is not None:
241 27137e55 Iustin Pop
      args = (msg, ecode)
242 045dd6d9 Iustin Pop
    else:
243 045dd6d9 Iustin Pop
      args = (msg, )
244 b459a848 Andrea Spadaccini
    raise ec(*args) # pylint: disable=W0142
245 781de953 Iustin Pop
246 95e7e85e Klaus Aehlig
  def Warn(self, msg, feedback_fn):
247 95e7e85e Klaus Aehlig
    """If the result has failed, call the feedback_fn.
248 95e7e85e Klaus Aehlig

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

252 95e7e85e Klaus Aehlig
    """
253 95e7e85e Klaus Aehlig
    if not self.fail_msg:
254 95e7e85e Klaus Aehlig
      return
255 95e7e85e Klaus Aehlig
256 95e7e85e Klaus Aehlig
    msg = "%s: %s" % (msg, self.fail_msg)
257 95e7e85e Klaus Aehlig
    feedback_fn(msg)
258 95e7e85e Klaus Aehlig
259 781de953 Iustin Pop
260 bd6d1202 René Nussbaumer
def _SsconfResolver(ssconf_ips, node_list, _,
261 00267bfe Michael Hanselmann
                    ssc=ssconf.SimpleStore,
262 00267bfe Michael Hanselmann
                    nslookup_fn=netutils.Hostname.GetIP):
263 eb202c13 Manuel Franceschini
  """Return addresses for given node names.
264 eb202c13 Manuel Franceschini

265 bd6d1202 René Nussbaumer
  @type ssconf_ips: bool
266 bd6d1202 René Nussbaumer
  @param ssconf_ips: Use the ssconf IPs
267 eb202c13 Manuel Franceschini
  @type node_list: list
268 eb202c13 Manuel Franceschini
  @param node_list: List of node names
269 eb202c13 Manuel Franceschini
  @type ssc: class
270 eb202c13 Manuel Franceschini
  @param ssc: SimpleStore class that is used to obtain node->ip mappings
271 17f7fd27 Manuel Franceschini
  @type nslookup_fn: callable
272 17f7fd27 Manuel Franceschini
  @param nslookup_fn: function use to do NS lookup
273 00267bfe Michael Hanselmann
  @rtype: list of tuple; (string, string)
274 00267bfe Michael Hanselmann
  @return: List of tuples containing node name and IP address
275 eb202c13 Manuel Franceschini

276 eb202c13 Manuel Franceschini
  """
277 b43dcc5a Manuel Franceschini
  ss = ssc()
278 b43dcc5a Manuel Franceschini
  family = ss.GetPrimaryIPFamily()
279 bd6d1202 René Nussbaumer
280 bd6d1202 René Nussbaumer
  if ssconf_ips:
281 bd6d1202 René Nussbaumer
    iplist = ss.GetNodePrimaryIPList()
282 bd6d1202 René Nussbaumer
    ipmap = dict(entry.split() for entry in iplist)
283 bd6d1202 René Nussbaumer
  else:
284 bd6d1202 René Nussbaumer
    ipmap = {}
285 00267bfe Michael Hanselmann
286 00267bfe Michael Hanselmann
  result = []
287 b705c7a6 Manuel Franceschini
  for node in node_list:
288 00267bfe Michael Hanselmann
    ip = ipmap.get(node)
289 00267bfe Michael Hanselmann
    if ip is None:
290 00267bfe Michael Hanselmann
      ip = nslookup_fn(node, family=family)
291 1c3231aa Thomas Thrainer
    result.append((node, ip, node))
292 00267bfe Michael Hanselmann
293 00267bfe Michael Hanselmann
  return result
294 00267bfe Michael Hanselmann
295 00267bfe Michael Hanselmann
296 00267bfe Michael Hanselmann
class _StaticResolver:
297 00267bfe Michael Hanselmann
  def __init__(self, addresses):
298 00267bfe Michael Hanselmann
    """Initializes this class.
299 00267bfe Michael Hanselmann

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

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

314 1c3231aa Thomas Thrainer
  @type node_uuid_or_name: string
315 1c3231aa Thomas Thrainer
  @param node_uuid_or_name: Node UUID
316 00267bfe Michael Hanselmann
  @type node: L{objects.Node} or None
317 00267bfe Michael Hanselmann
  @param node: Node object
318 eb202c13 Manuel Franceschini

319 00267bfe Michael Hanselmann
  """
320 00267bfe Michael Hanselmann
  if node is None:
321 1c3231aa Thomas Thrainer
    # Assume that the passed parameter was actually a node name, so depend on
322 1c3231aa Thomas Thrainer
    # DNS for name resolution
323 1c3231aa Thomas Thrainer
    return (node_uuid_or_name, node_uuid_or_name, node_uuid_or_name)
324 00267bfe Michael Hanselmann
  else:
325 1c3231aa Thomas Thrainer
    if node.offline and not accept_offline_node:
326 1c3231aa Thomas Thrainer
      ip = _OFFLINE
327 1c3231aa Thomas Thrainer
    else:
328 1c3231aa Thomas Thrainer
      ip = node.primary_ip
329 1c3231aa Thomas Thrainer
    return (node.name, ip, node_uuid_or_name)
330 a8083063 Iustin Pop
331 a8083063 Iustin Pop
332 1c3231aa Thomas Thrainer
def _NodeConfigResolver(single_node_fn, all_nodes_fn, node_uuids, opts):
333 00267bfe Michael Hanselmann
  """Calculate node addresses using configuration.
334 a8083063 Iustin Pop

335 1c3231aa Thomas Thrainer
  Note that strings in node_uuids are treated as node names if the UUID is not
336 1c3231aa Thomas Thrainer
  found in the configuration.
337 1c3231aa Thomas Thrainer

338 a8083063 Iustin Pop
  """
339 890ea4ce Michael Hanselmann
  accept_offline_node = (opts is rpc_defs.ACCEPT_OFFLINE_NODE)
340 890ea4ce Michael Hanselmann
341 890ea4ce Michael Hanselmann
  assert accept_offline_node or opts is None, "Unknown option"
342 890ea4ce Michael Hanselmann
343 00267bfe Michael Hanselmann
  # Special case for single-host lookups
344 1c3231aa Thomas Thrainer
  if len(node_uuids) == 1:
345 1c3231aa Thomas Thrainer
    (uuid, ) = node_uuids
346 1c3231aa Thomas Thrainer
    return [_CheckConfigNode(uuid, single_node_fn(uuid), accept_offline_node)]
347 00267bfe Michael Hanselmann
  else:
348 00267bfe Michael Hanselmann
    all_nodes = all_nodes_fn()
349 1c3231aa Thomas Thrainer
    return [_CheckConfigNode(uuid, all_nodes.get(uuid, None),
350 890ea4ce Michael Hanselmann
                             accept_offline_node)
351 1c3231aa Thomas Thrainer
            for uuid in node_uuids]
352 00267bfe Michael Hanselmann
353 00267bfe Michael Hanselmann
354 00267bfe Michael Hanselmann
class _RpcProcessor:
355 aea5caef Michael Hanselmann
  def __init__(self, resolver, port, lock_monitor_cb=None):
356 00267bfe Michael Hanselmann
    """Initializes this class.
357 00267bfe Michael Hanselmann

358 1c3231aa Thomas Thrainer
    @param resolver: callable accepting a list of node UUIDs or hostnames,
359 1c3231aa Thomas Thrainer
      returning a list of tuples containing name, IP address and original name
360 1c3231aa Thomas Thrainer
      of the resolved node. IP address can be the name or the special value
361 1c3231aa Thomas Thrainer
      L{_OFFLINE} to mark offline machines.
362 00267bfe Michael Hanselmann
    @type port: int
363 00267bfe Michael Hanselmann
    @param port: TCP port
364 aea5caef Michael Hanselmann
    @param lock_monitor_cb: Callable for registering with lock monitor
365 3ef3c771 Iustin Pop

366 a8083063 Iustin Pop
    """
367 00267bfe Michael Hanselmann
    self._resolver = resolver
368 00267bfe Michael Hanselmann
    self._port = port
369 aea5caef Michael Hanselmann
    self._lock_monitor_cb = lock_monitor_cb
370 eb202c13 Manuel Franceschini
371 00267bfe Michael Hanselmann
  @staticmethod
372 00267bfe Michael Hanselmann
  def _PrepareRequests(hosts, port, procedure, body, read_timeout):
373 00267bfe Michael Hanselmann
    """Prepares requests by sorting offline hosts into separate list.
374 eb202c13 Manuel Franceschini

375 d9de612c Iustin Pop
    @type body: dict
376 d9de612c Iustin Pop
    @param body: a dictionary with per-host body data
377 d9de612c Iustin Pop

378 00267bfe Michael Hanselmann
    """
379 00267bfe Michael Hanselmann
    results = {}
380 00267bfe Michael Hanselmann
    requests = {}
381 bdf7d8c0 Iustin Pop
382 d9de612c Iustin Pop
    assert isinstance(body, dict)
383 d9de612c Iustin Pop
    assert len(body) == len(hosts)
384 d9de612c Iustin Pop
    assert compat.all(isinstance(v, str) for v in body.values())
385 1c3231aa Thomas Thrainer
    assert frozenset(map(lambda x: x[2], hosts)) == frozenset(body.keys()), \
386 d9de612c Iustin Pop
        "%s != %s" % (hosts, body.keys())
387 d9de612c Iustin Pop
388 1c3231aa Thomas Thrainer
    for (name, ip, original_name) in hosts:
389 00267bfe Michael Hanselmann
      if ip is _OFFLINE:
390 00267bfe Michael Hanselmann
        # Node is marked as offline
391 1c3231aa Thomas Thrainer
        results[original_name] = RpcResult(node=name,
392 1c3231aa Thomas Thrainer
                                           offline=True,
393 1c3231aa Thomas Thrainer
                                           call=procedure)
394 00267bfe Michael Hanselmann
      else:
395 1c3231aa Thomas Thrainer
        requests[original_name] = \
396 00267bfe Michael Hanselmann
          http.client.HttpClientRequest(str(ip), port,
397 7530364d Iustin Pop
                                        http.HTTP_POST, str("/%s" % procedure),
398 00267bfe Michael Hanselmann
                                        headers=_RPC_CLIENT_HEADERS,
399 1c3231aa Thomas Thrainer
                                        post_data=body[original_name],
400 7cb2d205 Michael Hanselmann
                                        read_timeout=read_timeout,
401 abbf2cd9 Michael Hanselmann
                                        nicename="%s/%s" % (name, procedure),
402 abbf2cd9 Michael Hanselmann
                                        curl_config_fn=_ConfigRpcCurl)
403 a8083063 Iustin Pop
404 00267bfe Michael Hanselmann
    return (results, requests)
405 00267bfe Michael Hanselmann
406 00267bfe Michael Hanselmann
  @staticmethod
407 00267bfe Michael Hanselmann
  def _CombineResults(results, requests, procedure):
408 00267bfe Michael Hanselmann
    """Combines pre-computed results for offline hosts with actual call results.
409 bdf7d8c0 Iustin Pop

410 a8083063 Iustin Pop
    """
411 00267bfe Michael Hanselmann
    for name, req in requests.items():
412 00267bfe Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
413 00267bfe Michael Hanselmann
        host_result = RpcResult(data=serializer.LoadJson(req.resp_body),
414 00267bfe Michael Hanselmann
                                node=name, call=procedure)
415 00267bfe Michael Hanselmann
      else:
416 00267bfe Michael Hanselmann
        # TODO: Better error reporting
417 00267bfe Michael Hanselmann
        if req.error:
418 00267bfe Michael Hanselmann
          msg = req.error
419 00267bfe Michael Hanselmann
        else:
420 00267bfe Michael Hanselmann
          msg = req.resp_body
421 eb202c13 Manuel Franceschini
422 00267bfe Michael Hanselmann
        logging.error("RPC error in %s on node %s: %s", procedure, name, msg)
423 00267bfe Michael Hanselmann
        host_result = RpcResult(data=msg, failed=True, node=name,
424 00267bfe Michael Hanselmann
                                call=procedure)
425 ecfe9491 Michael Hanselmann
426 00267bfe Michael Hanselmann
      results[name] = host_result
427 92fd2250 Iustin Pop
428 00267bfe Michael Hanselmann
    return results
429 a8083063 Iustin Pop
430 1c3231aa Thomas Thrainer
  def __call__(self, nodes, procedure, body, read_timeout, resolver_opts,
431 065be3f0 Michael Hanselmann
               _req_process_fn=None):
432 00267bfe Michael Hanselmann
    """Makes an RPC request to a number of nodes.
433 ecfe9491 Michael Hanselmann

434 1c3231aa Thomas Thrainer
    @type nodes: sequence
435 1c3231aa Thomas Thrainer
    @param nodes: node UUIDs or Hostnames
436 00267bfe Michael Hanselmann
    @type procedure: string
437 00267bfe Michael Hanselmann
    @param procedure: Request path
438 d9de612c Iustin Pop
    @type body: dictionary
439 d9de612c Iustin Pop
    @param body: dictionary with request bodies per host
440 00267bfe Michael Hanselmann
    @type read_timeout: int or None
441 00267bfe Michael Hanselmann
    @param read_timeout: Read timeout for request
442 05325a35 Bernardo Dal Seno
    @rtype: dictionary
443 05325a35 Bernardo Dal Seno
    @return: a dictionary mapping host names to rpc.RpcResult objects
444 a8083063 Iustin Pop

445 a8083063 Iustin Pop
    """
446 83e7af18 Michael Hanselmann
    assert read_timeout is not None, \
447 83e7af18 Michael Hanselmann
      "Missing RPC read timeout for procedure '%s'" % procedure
448 a8083063 Iustin Pop
449 065be3f0 Michael Hanselmann
    if _req_process_fn is None:
450 065be3f0 Michael Hanselmann
      _req_process_fn = http.client.ProcessRequests
451 065be3f0 Michael Hanselmann
452 00267bfe Michael Hanselmann
    (results, requests) = \
453 1c3231aa Thomas Thrainer
      self._PrepareRequests(self._resolver(nodes, resolver_opts), self._port,
454 fce5efd1 Michael Hanselmann
                            procedure, body, read_timeout)
455 a8083063 Iustin Pop
456 abbf2cd9 Michael Hanselmann
    _req_process_fn(requests.values(), lock_monitor_cb=self._lock_monitor_cb)
457 a8083063 Iustin Pop
458 00267bfe Michael Hanselmann
    assert not frozenset(results).intersection(requests)
459 ecfe9491 Michael Hanselmann
460 00267bfe Michael Hanselmann
    return self._CombineResults(results, requests, procedure)
461 a8083063 Iustin Pop
462 a8083063 Iustin Pop
463 cd40dc53 Michael Hanselmann
class _RpcClientBase:
464 065be3f0 Michael Hanselmann
  def __init__(self, resolver, encoder_fn, lock_monitor_cb=None,
465 065be3f0 Michael Hanselmann
               _req_process_fn=None):
466 cd40dc53 Michael Hanselmann
    """Initializes this class.
467 cd40dc53 Michael Hanselmann

468 cd40dc53 Michael Hanselmann
    """
469 065be3f0 Michael Hanselmann
    proc = _RpcProcessor(resolver,
470 065be3f0 Michael Hanselmann
                         netutils.GetDaemonPort(constants.NODED),
471 065be3f0 Michael Hanselmann
                         lock_monitor_cb=lock_monitor_cb)
472 065be3f0 Michael Hanselmann
    self._proc = compat.partial(proc, _req_process_fn=_req_process_fn)
473 cd40dc53 Michael Hanselmann
    self._encoder = compat.partial(self._EncodeArg, encoder_fn)
474 cd40dc53 Michael Hanselmann
475 cd40dc53 Michael Hanselmann
  @staticmethod
476 0c3d9c7c Thomas Thrainer
  def _EncodeArg(encoder_fn, node, (argkind, value)):
477 cd40dc53 Michael Hanselmann
    """Encode argument.
478 cd40dc53 Michael Hanselmann

479 cd40dc53 Michael Hanselmann
    """
480 cd40dc53 Michael Hanselmann
    if argkind is None:
481 cd40dc53 Michael Hanselmann
      return value
482 cd40dc53 Michael Hanselmann
    else:
483 0c3d9c7c Thomas Thrainer
      return encoder_fn(argkind)(node, value)
484 cd40dc53 Michael Hanselmann
485 f7d9b3aa Michael Hanselmann
  def _Call(self, cdef, node_list, args):
486 cd40dc53 Michael Hanselmann
    """Entry point for automatically generated RPC wrappers.
487 cd40dc53 Michael Hanselmann

488 cd40dc53 Michael Hanselmann
    """
489 dd6d2d09 Michael Hanselmann
    (procedure, _, resolver_opts, timeout, argdefs,
490 dd6d2d09 Michael Hanselmann
     prep_fn, postproc_fn, _) = cdef
491 f7d9b3aa Michael Hanselmann
492 f7d9b3aa Michael Hanselmann
    if callable(timeout):
493 f7d9b3aa Michael Hanselmann
      read_timeout = timeout(args)
494 f7d9b3aa Michael Hanselmann
    else:
495 f7d9b3aa Michael Hanselmann
      read_timeout = timeout
496 cd40dc53 Michael Hanselmann
497 dd6d2d09 Michael Hanselmann
    if callable(resolver_opts):
498 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts(args)
499 dd6d2d09 Michael Hanselmann
    else:
500 dd6d2d09 Michael Hanselmann
      req_resolver_opts = resolver_opts
501 dd6d2d09 Michael Hanselmann
502 e78667fe Michael Hanselmann
    if len(args) != len(argdefs):
503 e78667fe Michael Hanselmann
      raise errors.ProgrammerError("Number of passed arguments doesn't match")
504 e78667fe Michael Hanselmann
505 d9de612c Iustin Pop
    if prep_fn is None:
506 0c3d9c7c Thomas Thrainer
      prep_fn = lambda _, args: args
507 0c3d9c7c Thomas Thrainer
    assert callable(prep_fn)
508 0c3d9c7c Thomas Thrainer
509 0c3d9c7c Thomas Thrainer
    # encode the arguments for each node individually, pass them and the node
510 0c3d9c7c Thomas Thrainer
    # name to the prep_fn, and serialise its return value
511 0c3d9c7c Thomas Thrainer
    encode_args_fn = lambda node: map(compat.partial(self._encoder, node),
512 0c3d9c7c Thomas Thrainer
                                      zip(map(compat.snd, argdefs), args))
513 1a182390 Santi Raffa
    pnbody = dict(
514 1a182390 Santi Raffa
      (n,
515 1a182390 Santi Raffa
       serializer.DumpJson(prep_fn(n, encode_args_fn(n)),
516 1a182390 Santi Raffa
                           private_encoder=serializer.EncodeWithPrivateFields))
517 1a182390 Santi Raffa
      for n in node_list
518 1a182390 Santi Raffa
    )
519 d9de612c Iustin Pop
520 fce5efd1 Michael Hanselmann
    result = self._proc(node_list, procedure, pnbody, read_timeout,
521 fce5efd1 Michael Hanselmann
                        req_resolver_opts)
522 26d502d0 Michael Hanselmann
523 26d502d0 Michael Hanselmann
    if postproc_fn:
524 d9da5065 Michael Hanselmann
      return dict(map(lambda (key, value): (key, postproc_fn(value)),
525 d9da5065 Michael Hanselmann
                      result.items()))
526 26d502d0 Michael Hanselmann
    else:
527 26d502d0 Michael Hanselmann
      return result
528 cd40dc53 Michael Hanselmann
529 cd40dc53 Michael Hanselmann
530 0c3d9c7c Thomas Thrainer
def _ObjectToDict(_, value):
531 cd40dc53 Michael Hanselmann
  """Converts an object to a dictionary.
532 cd40dc53 Michael Hanselmann

533 cd40dc53 Michael Hanselmann
  @note: See L{objects}.
534 cd40dc53 Michael Hanselmann

535 cd40dc53 Michael Hanselmann
  """
536 cd40dc53 Michael Hanselmann
  return value.ToDict()
537 cd40dc53 Michael Hanselmann
538 cd40dc53 Michael Hanselmann
539 0c3d9c7c Thomas Thrainer
def _ObjectListToDict(node, value):
540 cd40dc53 Michael Hanselmann
  """Converts a list of L{objects} to dictionaries.
541 cd40dc53 Michael Hanselmann

542 cd40dc53 Michael Hanselmann
  """
543 0c3d9c7c Thomas Thrainer
  return map(compat.partial(_ObjectToDict, node), value)
544 cd40dc53 Michael Hanselmann
545 cd40dc53 Michael Hanselmann
546 0c3d9c7c Thomas Thrainer
def _PrepareFileUpload(getents_fn, node, filename):
547 cd40dc53 Michael Hanselmann
  """Loads a file and prepares it for an upload to nodes.
548 cd40dc53 Michael Hanselmann

549 cd40dc53 Michael Hanselmann
  """
550 2ce40421 Michael Hanselmann
  statcb = utils.FileStatHelper()
551 0c3d9c7c Thomas Thrainer
  data = _Compress(node, utils.ReadFile(filename, preread=statcb))
552 2ce40421 Michael Hanselmann
  st = statcb.st
553 601dfcbb Michael Hanselmann
554 601dfcbb Michael Hanselmann
  if getents_fn is None:
555 601dfcbb Michael Hanselmann
    getents_fn = runtime.GetEnts
556 601dfcbb Michael Hanselmann
557 601dfcbb Michael Hanselmann
  getents = getents_fn()
558 601dfcbb Michael Hanselmann
559 cffbbae7 Michael Hanselmann
  virt_filename = vcluster.MakeVirtualPath(filename)
560 cffbbae7 Michael Hanselmann
561 cffbbae7 Michael Hanselmann
  return [virt_filename, data, st.st_mode, getents.LookupUid(st.st_uid),
562 cd40dc53 Michael Hanselmann
          getents.LookupGid(st.st_gid), st.st_atime, st.st_mtime]
563 cd40dc53 Michael Hanselmann
564 cd40dc53 Michael Hanselmann
565 0c3d9c7c Thomas Thrainer
def _PrepareFinalizeExportDisks(_, snap_disks):
566 cd40dc53 Michael Hanselmann
  """Encodes disks for finalizing export.
567 cd40dc53 Michael Hanselmann

568 cd40dc53 Michael Hanselmann
  """
569 cd40dc53 Michael Hanselmann
  flat_disks = []
570 cd40dc53 Michael Hanselmann
571 cd40dc53 Michael Hanselmann
  for disk in snap_disks:
572 cd40dc53 Michael Hanselmann
    if isinstance(disk, bool):
573 cd40dc53 Michael Hanselmann
      flat_disks.append(disk)
574 cd40dc53 Michael Hanselmann
    else:
575 cd40dc53 Michael Hanselmann
      flat_disks.append(disk.ToDict())
576 cd40dc53 Michael Hanselmann
577 cd40dc53 Michael Hanselmann
  return flat_disks
578 cd40dc53 Michael Hanselmann
579 cd40dc53 Michael Hanselmann
580 0c3d9c7c Thomas Thrainer
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 32389d91 Helga Velroyen
def _AddSpindlesToLegacyNodeInfo(result, space_info):
588 32389d91 Helga Velroyen
  """Extracts the spindle information from the space info and adds
589 32389d91 Helga Velroyen
  it to the result dictionary.
590 32389d91 Helga Velroyen

591 32389d91 Helga Velroyen
  @type result: dict of strings
592 32389d91 Helga Velroyen
  @param result: dictionary holding the result of the legacy node info
593 32389d91 Helga Velroyen
  @type space_info: list of dicts of strings
594 32389d91 Helga Velroyen
  @param space_info: list, each row holding space information of one storage
595 32389d91 Helga Velroyen
    unit
596 32389d91 Helga Velroyen
  @rtype: None
597 32389d91 Helga Velroyen
  @return: does not return anything, manipulates the C{result} variable
598 32389d91 Helga Velroyen

599 32389d91 Helga Velroyen
  """
600 32389d91 Helga Velroyen
  lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
601 32389d91 Helga Velroyen
      space_info, constants.ST_LVM_PV)
602 32389d91 Helga Velroyen
  if lvm_pv_info:
603 32389d91 Helga Velroyen
    result["spindles_free"] = lvm_pv_info["storage_free"]
604 32389d91 Helga Velroyen
    result["spindles_total"] = lvm_pv_info["storage_size"]
605 20faaa74 Helga Velroyen
  else:
606 6c00b2c7 Helga Velroyen
    result["spindles_free"] = 0
607 6c00b2c7 Helga Velroyen
    result["spindles_total"] = 0
608 06fb92cf Bernardo Dal Seno
609 06fb92cf Bernardo Dal Seno
610 6c00b2c7 Helga Velroyen
def _AddStorageInfoToLegacyNodeInfoByTemplate(
611 6c00b2c7 Helga Velroyen
    result, space_info, disk_template):
612 6c00b2c7 Helga Velroyen
  """Extracts the storage space information of the disk template from
613 32389d91 Helga Velroyen
  the space info and adds it to the result dictionary.
614 32389d91 Helga Velroyen

615 32389d91 Helga Velroyen
  @see: C{_AddSpindlesToLegacyNodeInfo} for parameter information.
616 06fb92cf Bernardo Dal Seno

617 06fb92cf Bernardo Dal Seno
  """
618 6c00b2c7 Helga Velroyen
  if utils.storage.DiskTemplateSupportsSpaceReporting(disk_template):
619 6c00b2c7 Helga Velroyen
    disk_info = utils.storage.LookupSpaceInfoByDiskTemplate(
620 6c00b2c7 Helga Velroyen
        space_info, disk_template)
621 6c00b2c7 Helga Velroyen
    result["name"] = disk_info["name"]
622 6c00b2c7 Helga Velroyen
    result["storage_free"] = disk_info["storage_free"]
623 6c00b2c7 Helga Velroyen
    result["storage_size"] = disk_info["storage_size"]
624 06fb92cf Bernardo Dal Seno
  else:
625 6c00b2c7 Helga Velroyen
    # FIXME: consider displaying '-' in this case
626 6c00b2c7 Helga Velroyen
    result["storage_free"] = 0
627 6c00b2c7 Helga Velroyen
    result["storage_size"] = 0
628 06fb92cf Bernardo Dal Seno
629 06fb92cf Bernardo Dal Seno
630 6c00b2c7 Helga Velroyen
def MakeLegacyNodeInfo(data, disk_template):
631 4e745e62 Santi Raffa
  """Formats the data returned by call_node_info.
632 b112bfc4 René Nussbaumer

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

636 b112bfc4 René Nussbaumer
  """
637 32389d91 Helga Velroyen
  (bootid, space_info, (hv_info, )) = data
638 91c17910 Iustin Pop
639 91c17910 Iustin Pop
  ret = utils.JoinDisjointDicts(hv_info, {"bootid": bootid})
640 91c17910 Iustin Pop
641 6c00b2c7 Helga Velroyen
  _AddSpindlesToLegacyNodeInfo(ret, space_info)
642 6c00b2c7 Helga Velroyen
  _AddStorageInfoToLegacyNodeInfoByTemplate(ret, space_info, disk_template)
643 b112bfc4 René Nussbaumer
644 91c17910 Iustin Pop
  return ret
645 b112bfc4 René Nussbaumer
646 b112bfc4 René Nussbaumer
647 cd46491f René Nussbaumer
def _AnnotateDParamsDRBD(disk, (drbd_params, data_params, meta_params)):
648 cd46491f René Nussbaumer
  """Annotates just DRBD disks layouts.
649 cd46491f René Nussbaumer

650 cd46491f René Nussbaumer
  """
651 cd3b4ff4 Helga Velroyen
  assert disk.dev_type == constants.DT_DRBD8
652 cd46491f René Nussbaumer
653 cd46491f René Nussbaumer
  disk.params = objects.FillDict(drbd_params, disk.params)
654 cd46491f René Nussbaumer
  (dev_data, dev_meta) = disk.children
655 cd46491f René Nussbaumer
  dev_data.params = objects.FillDict(data_params, dev_data.params)
656 cd46491f René Nussbaumer
  dev_meta.params = objects.FillDict(meta_params, dev_meta.params)
657 cd46491f René Nussbaumer
658 cd46491f René Nussbaumer
  return disk
659 cd46491f René Nussbaumer
660 cd46491f René Nussbaumer
661 cd46491f René Nussbaumer
def _AnnotateDParamsGeneric(disk, (params, )):
662 cd46491f René Nussbaumer
  """Generic disk parameter annotation routine.
663 cd46491f René Nussbaumer

664 cd46491f René Nussbaumer
  """
665 cd3b4ff4 Helga Velroyen
  assert disk.dev_type != constants.DT_DRBD8
666 cd46491f René Nussbaumer
667 cd46491f René Nussbaumer
  disk.params = objects.FillDict(params, disk.params)
668 cd46491f René Nussbaumer
669 cd46491f René Nussbaumer
  return disk
670 cd46491f René Nussbaumer
671 cd46491f René Nussbaumer
672 0c3d9c7c Thomas Thrainer
def AnnotateDiskParams(disks, disk_params):
673 cd46491f René Nussbaumer
  """Annotates the disk objects with the disk parameters.
674 cd46491f René Nussbaumer

675 cd46491f René Nussbaumer
  @param disks: The list of disks objects to annotate
676 0c3d9c7c Thomas Thrainer
  @param disk_params: The disk parameters for annotation
677 cd46491f René Nussbaumer
  @returns: A list of disk objects annotated
678 cd46491f René Nussbaumer

679 cd46491f René Nussbaumer
  """
680 0c3d9c7c Thomas Thrainer
  def AnnotateDisk(disk):
681 0c3d9c7c Thomas Thrainer
    if disk.dev_type == constants.DT_DISKLESS:
682 0c3d9c7c Thomas Thrainer
      return disk
683 cd46491f René Nussbaumer
684 0c3d9c7c Thomas Thrainer
    ld_params = objects.Disk.ComputeLDParams(disk.dev_type, disk_params)
685 cd46491f René Nussbaumer
686 0c3d9c7c Thomas Thrainer
    if disk.dev_type == constants.DT_DRBD8:
687 0c3d9c7c Thomas Thrainer
      return _AnnotateDParamsDRBD(disk, ld_params)
688 0c3d9c7c Thomas Thrainer
    else:
689 0c3d9c7c Thomas Thrainer
      return _AnnotateDParamsGeneric(disk, ld_params)
690 0c3d9c7c Thomas Thrainer
691 0c3d9c7c Thomas Thrainer
  return [AnnotateDisk(disk.Copy()) for disk in disks]
692 cd46491f René Nussbaumer
693 cd46491f René Nussbaumer
694 da803ff1 Helga Velroyen
def _GetExclusiveStorageFlag(cfg, node_uuid):
695 1c3231aa Thomas Thrainer
  ni = cfg.GetNodeInfo(node_uuid)
696 319322a7 Bernardo Dal Seno
  if ni is None:
697 1c3231aa Thomas Thrainer
    raise errors.OpPrereqError("Invalid node name %s" % node_uuid,
698 319322a7 Bernardo Dal Seno
                               errors.ECODE_NOENT)
699 319322a7 Bernardo Dal Seno
  return cfg.GetNdParams(ni)[constants.ND_EXCLUSIVE_STORAGE]
700 319322a7 Bernardo Dal Seno
701 319322a7 Bernardo Dal Seno
702 da803ff1 Helga Velroyen
def _AddExclusiveStorageFlagToLvmStorageUnits(storage_units, es_flag):
703 da803ff1 Helga Velroyen
  """Adds the exclusive storage flag to lvm units.
704 da803ff1 Helga Velroyen

705 da803ff1 Helga Velroyen
  This function creates a copy of the storage_units lists, with the
706 da803ff1 Helga Velroyen
  es_flag being added to all lvm storage units.
707 da803ff1 Helga Velroyen

708 da803ff1 Helga Velroyen
  @type storage_units: list of pairs (string, string)
709 da803ff1 Helga Velroyen
  @param storage_units: list of 'raw' storage units, consisting only of
710 da803ff1 Helga Velroyen
    (storage_type, storage_key)
711 da803ff1 Helga Velroyen
  @type es_flag: boolean
712 da803ff1 Helga Velroyen
  @param es_flag: exclusive storage flag
713 da803ff1 Helga Velroyen
  @rtype: list of tuples (string, string, list)
714 da803ff1 Helga Velroyen
  @return: list of storage units (storage_type, storage_key, params) with
715 da803ff1 Helga Velroyen
    the params containing the es_flag for lvm-vg storage units
716 da803ff1 Helga Velroyen

717 da803ff1 Helga Velroyen
  """
718 da803ff1 Helga Velroyen
  result = []
719 da803ff1 Helga Velroyen
  for (storage_type, storage_key) in storage_units:
720 e7098533 Helga Velroyen
    if storage_type in [constants.ST_LVM_VG]:
721 52a8a6ae Helga Velroyen
      result.append((storage_type, storage_key, [es_flag]))
722 e7098533 Helga Velroyen
      if es_flag:
723 e7098533 Helga Velroyen
        result.append((constants.ST_LVM_PV, storage_key, [es_flag]))
724 da803ff1 Helga Velroyen
    else:
725 da803ff1 Helga Velroyen
      result.append((storage_type, storage_key, []))
726 da803ff1 Helga Velroyen
  return result
727 da803ff1 Helga Velroyen
728 da803ff1 Helga Velroyen
729 1c3231aa Thomas Thrainer
def GetExclusiveStorageForNodes(cfg, node_uuids):
730 319322a7 Bernardo Dal Seno
  """Return the exclusive storage flag for all the given nodes.
731 319322a7 Bernardo Dal Seno

732 319322a7 Bernardo Dal Seno
  @type cfg: L{config.ConfigWriter}
733 319322a7 Bernardo Dal Seno
  @param cfg: cluster configuration
734 1c3231aa Thomas Thrainer
  @type node_uuids: list or tuple
735 1c3231aa Thomas Thrainer
  @param node_uuids: node UUIDs for which to read the flag
736 319322a7 Bernardo Dal Seno
  @rtype: dict
737 da803ff1 Helga Velroyen
  @return: mapping from node uuids to exclusive storage flags
738 1c3231aa Thomas Thrainer
  @raise errors.OpPrereqError: if any given node name has no corresponding
739 1c3231aa Thomas Thrainer
  node
740 319322a7 Bernardo Dal Seno

741 319322a7 Bernardo Dal Seno
  """
742 da803ff1 Helga Velroyen
  getflag = lambda n: _GetExclusiveStorageFlag(cfg, n)
743 1c3231aa Thomas Thrainer
  flags = map(getflag, node_uuids)
744 1c3231aa Thomas Thrainer
  return dict(zip(node_uuids, flags))
745 319322a7 Bernardo Dal Seno
746 319322a7 Bernardo Dal Seno
747 da803ff1 Helga Velroyen
def PrepareStorageUnitsForNodes(cfg, storage_units, node_uuids):
748 da803ff1 Helga Velroyen
  """Return the lvm storage unit for all the given nodes.
749 da803ff1 Helga Velroyen

750 da803ff1 Helga Velroyen
  Main purpose of this function is to map the exclusive storage flag, which
751 da803ff1 Helga Velroyen
  can be different for each node, to the default LVM storage unit.
752 da803ff1 Helga Velroyen

753 da803ff1 Helga Velroyen
  @type cfg: L{config.ConfigWriter}
754 da803ff1 Helga Velroyen
  @param cfg: cluster configuration
755 da803ff1 Helga Velroyen
  @type storage_units: list of pairs (string, string)
756 da803ff1 Helga Velroyen
  @param storage_units: list of 'raw' storage units, e.g. pairs of
757 da803ff1 Helga Velroyen
    (storage_type, storage_key)
758 da803ff1 Helga Velroyen
  @type node_uuids: list or tuple
759 da803ff1 Helga Velroyen
  @param node_uuids: node UUIDs for which to read the flag
760 da803ff1 Helga Velroyen
  @rtype: dict
761 da803ff1 Helga Velroyen
  @return: mapping from node uuids to a list of storage units which include
762 da803ff1 Helga Velroyen
    the exclusive storage flag for lvm storage
763 da803ff1 Helga Velroyen
  @raise errors.OpPrereqError: if any given node name has no corresponding
764 da803ff1 Helga Velroyen
  node
765 da803ff1 Helga Velroyen

766 da803ff1 Helga Velroyen
  """
767 da803ff1 Helga Velroyen
  getunit = lambda n: _AddExclusiveStorageFlagToLvmStorageUnits(
768 da803ff1 Helga Velroyen
      storage_units, _GetExclusiveStorageFlag(cfg, n))
769 da803ff1 Helga Velroyen
  flags = map(getunit, node_uuids)
770 da803ff1 Helga Velroyen
  return dict(zip(node_uuids, flags))
771 da803ff1 Helga Velroyen
772 da803ff1 Helga Velroyen
773 cd40dc53 Michael Hanselmann
#: Generic encoders
774 cd40dc53 Michael Hanselmann
_ENCODERS = {
775 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT: _ObjectToDict,
776 cd40dc53 Michael Hanselmann
  rpc_defs.ED_OBJECT_DICT_LIST: _ObjectListToDict,
777 cd40dc53 Michael Hanselmann
  rpc_defs.ED_COMPRESS: _Compress,
778 cd40dc53 Michael Hanselmann
  rpc_defs.ED_FINALIZE_EXPORT_DISKS: _PrepareFinalizeExportDisks,
779 cd40dc53 Michael Hanselmann
  rpc_defs.ED_BLOCKDEV_RENAME: _EncodeBlockdevRename,
780 cd40dc53 Michael Hanselmann
  }
781 cd40dc53 Michael Hanselmann
782 cd40dc53 Michael Hanselmann
783 cd40dc53 Michael Hanselmann
class RpcRunner(_RpcClientBase,
784 cd40dc53 Michael Hanselmann
                _generated_rpc.RpcClientDefault,
785 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientBootstrap,
786 bd6d1202 René Nussbaumer
                _generated_rpc.RpcClientDnsOnly,
787 415a7304 Michael Hanselmann
                _generated_rpc.RpcClientConfig):
788 87b3cb26 Michael Hanselmann
  """RPC runner class.
789 a8083063 Iustin Pop

790 87b3cb26 Michael Hanselmann
  """
791 d5ea30e8 Michael Hanselmann
  def __init__(self, cfg, lock_monitor_cb, _req_process_fn=None, _getents=None):
792 87b3cb26 Michael Hanselmann
    """Initialized the RPC runner.
793 a8083063 Iustin Pop

794 d5ea30e8 Michael Hanselmann
    @type cfg: L{config.ConfigWriter}
795 d5ea30e8 Michael Hanselmann
    @param cfg: Configuration
796 d5ea30e8 Michael Hanselmann
    @type lock_monitor_cb: callable
797 d5ea30e8 Michael Hanselmann
    @param lock_monitor_cb: Lock monitor callback
798 a8083063 Iustin Pop

799 72737a7f Iustin Pop
    """
800 d5ea30e8 Michael Hanselmann
    self._cfg = cfg
801 cd40dc53 Michael Hanselmann
802 cd40dc53 Michael Hanselmann
    encoders = _ENCODERS.copy()
803 cd40dc53 Michael Hanselmann
804 cd40dc53 Michael Hanselmann
    encoders.update({
805 601dfcbb Michael Hanselmann
      # Encoders requiring configuration object
806 cd40dc53 Michael Hanselmann
      rpc_defs.ED_INST_DICT: self._InstDict,
807 5fce6a89 Constantinos Venetsanopoulos
      rpc_defs.ED_INST_DICT_HVP_BEP_DP: self._InstDictHvpBepDp,
808 b8291e00 René Nussbaumer
      rpc_defs.ED_INST_DICT_OSP_DP: self._InstDictOspDp,
809 cbe4a0a5 Dimitris Aragiorgis
      rpc_defs.ED_NIC_DICT: self._NicDict,
810 c5708931 Dimitris Aragiorgis
      rpc_defs.ED_DEVICE_DICT: self._DeviceDict,
811 601dfcbb Michael Hanselmann
812 aedf5fd7 René Nussbaumer
      # Encoders annotating disk parameters
813 aedf5fd7 René Nussbaumer
      rpc_defs.ED_DISKS_DICT_DP: self._DisksDictDP,
814 235a6b29 Thomas Thrainer
      rpc_defs.ED_MULTI_DISKS_DICT_DP: self._MultiDiskDictDP,
815 aedf5fd7 René Nussbaumer
      rpc_defs.ED_SINGLE_DISK_DICT_DP: self._SingleDiskDictDP,
816 0c3d9c7c Thomas Thrainer
      rpc_defs.ED_NODE_TO_DISK_DICT_DP: self._EncodeNodeToDiskDictDP,
817 aedf5fd7 René Nussbaumer
818 601dfcbb Michael Hanselmann
      # Encoders with special requirements
819 601dfcbb Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
820 0c3d9c7c Thomas Thrainer
821 0c3d9c7c Thomas Thrainer
      rpc_defs.ED_IMPEXP_IO: self._EncodeImportExportIO,
822 cd40dc53 Michael Hanselmann
      })
823 cd40dc53 Michael Hanselmann
824 cd40dc53 Michael Hanselmann
    # Resolver using configuration
825 d5ea30e8 Michael Hanselmann
    resolver = compat.partial(_NodeConfigResolver, cfg.GetNodeInfo,
826 d5ea30e8 Michael Hanselmann
                              cfg.GetAllNodesInfo)
827 cd40dc53 Michael Hanselmann
828 db04ce5d Michael Hanselmann
    # Pylint doesn't recognize multiple inheritance properly, see
829 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/36586> and
830 db04ce5d Michael Hanselmann
    # <http://www.logilab.org/ticket/35642>
831 db04ce5d Michael Hanselmann
    # pylint: disable=W0233
832 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
833 d5ea30e8 Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
834 d5ea30e8 Michael Hanselmann
                            _req_process_fn=_req_process_fn)
835 415a7304 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)
836 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
837 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
838 200de241 Michael Hanselmann
    _generated_rpc.RpcClientDefault.__init__(self)
839 200de241 Michael Hanselmann
840 0c3d9c7c Thomas Thrainer
  def _NicDict(self, _, nic):
841 cbe4a0a5 Dimitris Aragiorgis
    """Convert the given nic to a dict and encapsulate netinfo
842 cbe4a0a5 Dimitris Aragiorgis

843 cbe4a0a5 Dimitris Aragiorgis
    """
844 cbe4a0a5 Dimitris Aragiorgis
    n = copy.deepcopy(nic)
845 cbe4a0a5 Dimitris Aragiorgis
    if n.network:
846 cbe4a0a5 Dimitris Aragiorgis
      net_uuid = self._cfg.LookupNetwork(n.network)
847 cbe4a0a5 Dimitris Aragiorgis
      if net_uuid:
848 cbe4a0a5 Dimitris Aragiorgis
        nobj = self._cfg.GetNetwork(net_uuid)
849 cbe4a0a5 Dimitris Aragiorgis
        n.netinfo = objects.Network.ToDict(nobj)
850 cbe4a0a5 Dimitris Aragiorgis
    return n.ToDict()
851 cbe4a0a5 Dimitris Aragiorgis
852 51951d38 Dimitris Aragiorgis
  def _DeviceDict(self, _, (device, instance)):
853 c5708931 Dimitris Aragiorgis
    if isinstance(device, objects.NIC):
854 c5708931 Dimitris Aragiorgis
      return self._NicDict(None, device)
855 c5708931 Dimitris Aragiorgis
    elif isinstance(device, objects.Disk):
856 51951d38 Dimitris Aragiorgis
      return self._SingleDiskDictDP(None, (device, instance))
857 c5708931 Dimitris Aragiorgis
858 0c3d9c7c Thomas Thrainer
  def _InstDict(self, node, instance, hvp=None, bep=None, osp=None):
859 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
860 26ba2bd8 Iustin Pop

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

864 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
865 26ba2bd8 Iustin Pop
    @param instance: an Instance object
866 0eca8e0c Iustin Pop
    @type hvp: dict or None
867 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
868 0eca8e0c Iustin Pop
    @type bep: dict or None
869 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
870 1bdcbbab Iustin Pop
    @type osp: dict or None
871 8d8c4eff Michael Hanselmann
    @param osp: a dictionary with overridden os parameters
872 26ba2bd8 Iustin Pop
    @rtype: dict
873 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
874 26ba2bd8 Iustin Pop
        cluster defaults
875 26ba2bd8 Iustin Pop

876 26ba2bd8 Iustin Pop
    """
877 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
878 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
879 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
880 6ccce5d4 Ilias Tsitsimpis
    idict["secondary_nodes"] = self._cfg.GetInstanceSecondaryNodes(instance)
881 0eca8e0c Iustin Pop
    if hvp is not None:
882 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
883 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
884 0eca8e0c Iustin Pop
    if bep is not None:
885 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
886 1bdcbbab Iustin Pop
    idict["osparams"] = cluster.SimpleFillOS(instance.os, instance.osparams)
887 1bdcbbab Iustin Pop
    if osp is not None:
888 1bdcbbab Iustin Pop
      idict["osparams"].update(osp)
889 8e8cf324 Ilias Tsitsimpis
    idict["disks_info"] = self._DisksDictDP(node, (instance.disks, instance))
890 b848ce79 Guido Trotter
    for nic in idict["nics"]:
891 3ccb3a64 Michael Hanselmann
      nic["nicparams"] = objects.FillDict(
892 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
893 3ccb3a64 Michael Hanselmann
        nic["nicparams"])
894 cbe4a0a5 Dimitris Aragiorgis
      network = nic.get("network", None)
895 cbe4a0a5 Dimitris Aragiorgis
      if network:
896 cbe4a0a5 Dimitris Aragiorgis
        net_uuid = self._cfg.LookupNetwork(network)
897 cbe4a0a5 Dimitris Aragiorgis
        if net_uuid:
898 cbe4a0a5 Dimitris Aragiorgis
          nobj = self._cfg.GetNetwork(net_uuid)
899 cbe4a0a5 Dimitris Aragiorgis
          nic["netinfo"] = objects.Network.ToDict(nobj)
900 26ba2bd8 Iustin Pop
    return idict
901 26ba2bd8 Iustin Pop
902 0c3d9c7c Thomas Thrainer
  def _InstDictHvpBepDp(self, node, (instance, hvp, bep)):
903 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
904 c4de9b7a Michael Hanselmann

905 c4de9b7a Michael Hanselmann
    """
906 0c3d9c7c Thomas Thrainer
    return self._InstDict(node, instance, hvp=hvp, bep=bep)
907 c4de9b7a Michael Hanselmann
908 0c3d9c7c Thomas Thrainer
  def _InstDictOspDp(self, node, (instance, osparams)):
909 c4de9b7a Michael Hanselmann
    """Wrapper for L{_InstDict}.
910 c4de9b7a Michael Hanselmann

911 c4de9b7a Michael Hanselmann
    """
912 0c3d9c7c Thomas Thrainer
    return self._InstDict(node, instance, osp=osparams)
913 c4de9b7a Michael Hanselmann
914 0c3d9c7c Thomas Thrainer
  def _DisksDictDP(self, node, (disks, instance)):
915 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
916 aedf5fd7 René Nussbaumer

917 aedf5fd7 René Nussbaumer
    """
918 aedf5fd7 René Nussbaumer
    diskparams = self._cfg.GetInstanceDiskParams(instance)
919 0c3d9c7c Thomas Thrainer
    ret = []
920 0c3d9c7c Thomas Thrainer
    for disk in AnnotateDiskParams(disks, diskparams):
921 0c3d9c7c Thomas Thrainer
      disk_node_uuids = disk.GetNodes(instance.primary_node)
922 0c3d9c7c Thomas Thrainer
      node_ips = dict((uuid, node.secondary_ip) for (uuid, node)
923 0c3d9c7c Thomas Thrainer
                      in self._cfg.GetMultiNodeInfo(disk_node_uuids))
924 0c3d9c7c Thomas Thrainer
925 0c3d9c7c Thomas Thrainer
      disk.UpdateDynamicDiskParams(node, node_ips)
926 0c3d9c7c Thomas Thrainer
927 a0d2a91e Thomas Thrainer
      ret.append(disk.ToDict(include_dynamic_params=True))
928 aedf5fd7 René Nussbaumer
929 0c3d9c7c Thomas Thrainer
    return ret
930 0c3d9c7c Thomas Thrainer
931 0c3d9c7c Thomas Thrainer
  def _MultiDiskDictDP(self, node, disks_insts):
932 235a6b29 Thomas Thrainer
    """Wrapper for L{AnnotateDiskParams}.
933 235a6b29 Thomas Thrainer

934 235a6b29 Thomas Thrainer
    Supports a list of (disk, instance) tuples.
935 235a6b29 Thomas Thrainer
    """
936 235a6b29 Thomas Thrainer
    return [disk for disk_inst in disks_insts
937 0c3d9c7c Thomas Thrainer
            for disk in self._DisksDictDP(node, disk_inst)]
938 235a6b29 Thomas Thrainer
939 0c3d9c7c Thomas Thrainer
  def _SingleDiskDictDP(self, node, (disk, instance)):
940 aedf5fd7 René Nussbaumer
    """Wrapper for L{AnnotateDiskParams}.
941 aedf5fd7 René Nussbaumer

942 aedf5fd7 René Nussbaumer
    """
943 0c3d9c7c Thomas Thrainer
    (anno_disk,) = self._DisksDictDP(node, ([disk], instance))
944 aedf5fd7 René Nussbaumer
    return anno_disk
945 aedf5fd7 René Nussbaumer
946 0c3d9c7c Thomas Thrainer
  def _EncodeNodeToDiskDictDP(self, node, value):
947 0c3d9c7c Thomas Thrainer
    """Encode dict of node name -> list of (disk, instance) tuples as values.
948 0c3d9c7c Thomas Thrainer

949 0c3d9c7c Thomas Thrainer
    """
950 0c3d9c7c Thomas Thrainer
    return dict((name, [self._SingleDiskDictDP(node, disk) for disk in disks])
951 0c3d9c7c Thomas Thrainer
                for name, disks in value.items())
952 0c3d9c7c Thomas Thrainer
953 0c3d9c7c Thomas Thrainer
  def _EncodeImportExportIO(self, node, (ieio, ieioargs)):
954 0c3d9c7c Thomas Thrainer
    """Encodes import/export I/O information.
955 0c3d9c7c Thomas Thrainer

956 0c3d9c7c Thomas Thrainer
    """
957 0c3d9c7c Thomas Thrainer
    if ieio == constants.IEIO_RAW_DISK:
958 063613aa Thomas Thrainer
      assert len(ieioargs) == 2
959 063613aa Thomas Thrainer
      return (ieio, (self._SingleDiskDictDP(node, ieioargs), ))
960 0c3d9c7c Thomas Thrainer
961 0c3d9c7c Thomas Thrainer
    if ieio == constants.IEIO_SCRIPT:
962 0c3d9c7c Thomas Thrainer
      assert len(ieioargs) == 2
963 0c3d9c7c Thomas Thrainer
      return (ieio, (self._SingleDiskDictDP(node, ieioargs[0]), ieioargs[1]))
964 0c3d9c7c Thomas Thrainer
965 0c3d9c7c Thomas Thrainer
    return (ieio, ieioargs)
966 0c3d9c7c Thomas Thrainer
967 fb1ffbca Michael Hanselmann
968 cd40dc53 Michael Hanselmann
class JobQueueRunner(_RpcClientBase, _generated_rpc.RpcClientJobQueue):
969 fb1ffbca Michael Hanselmann
  """RPC wrappers for job queue.
970 fb1ffbca Michael Hanselmann

971 fb1ffbca Michael Hanselmann
  """
972 fb1ffbca Michael Hanselmann
  def __init__(self, context, address_list):
973 fb1ffbca Michael Hanselmann
    """Initializes this class.
974 fb1ffbca Michael Hanselmann

975 fb1ffbca Michael Hanselmann
    """
976 fb1ffbca Michael Hanselmann
    if address_list is None:
977 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
978 fb1ffbca Michael Hanselmann
    else:
979 fb1ffbca Michael Hanselmann
      # Caller provided an address list
980 fb1ffbca Michael Hanselmann
      resolver = _StaticResolver(address_list)
981 fb1ffbca Michael Hanselmann
982 cd40dc53 Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, _ENCODERS.get,
983 cd40dc53 Michael Hanselmann
                            lock_monitor_cb=context.glm.AddToLockMonitor)
984 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientJobQueue.__init__(self)
985 db04ce5d Michael Hanselmann
986 db04ce5d Michael Hanselmann
987 bd6d1202 René Nussbaumer
class BootstrapRunner(_RpcClientBase,
988 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientBootstrap,
989 bd6d1202 René Nussbaumer
                      _generated_rpc.RpcClientDnsOnly):
990 db04ce5d Michael Hanselmann
  """RPC wrappers for bootstrapping.
991 db04ce5d Michael Hanselmann

992 db04ce5d Michael Hanselmann
  """
993 db04ce5d Michael Hanselmann
  def __init__(self):
994 db04ce5d Michael Hanselmann
    """Initializes this class.
995 db04ce5d Michael Hanselmann

996 db04ce5d Michael Hanselmann
    """
997 bd6d1202 René Nussbaumer
    # Pylint doesn't recognize multiple inheritance properly, see
998 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/36586> and
999 bd6d1202 René Nussbaumer
    # <http://www.logilab.org/ticket/35642>
1000 bd6d1202 René Nussbaumer
    # pylint: disable=W0233
1001 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, True),
1002 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
1003 db04ce5d Michael Hanselmann
    _generated_rpc.RpcClientBootstrap.__init__(self)
1004 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
1005 bd6d1202 René Nussbaumer
1006 bd6d1202 René Nussbaumer
1007 bd6d1202 René Nussbaumer
class DnsOnlyRunner(_RpcClientBase, _generated_rpc.RpcClientDnsOnly):
1008 bd6d1202 René Nussbaumer
  """RPC wrappers for calls using only DNS.
1009 bd6d1202 René Nussbaumer

1010 bd6d1202 René Nussbaumer
  """
1011 bd6d1202 René Nussbaumer
  def __init__(self):
1012 bd6d1202 René Nussbaumer
    """Initialize this class.
1013 bd6d1202 René Nussbaumer

1014 bd6d1202 René Nussbaumer
    """
1015 bd6d1202 René Nussbaumer
    _RpcClientBase.__init__(self, compat.partial(_SsconfResolver, False),
1016 bd6d1202 René Nussbaumer
                            _ENCODERS.get)
1017 bd6d1202 René Nussbaumer
    _generated_rpc.RpcClientDnsOnly.__init__(self)
1018 db04ce5d Michael Hanselmann
1019 415a7304 Michael Hanselmann
1020 cd40dc53 Michael Hanselmann
class ConfigRunner(_RpcClientBase, _generated_rpc.RpcClientConfig):
1021 415a7304 Michael Hanselmann
  """RPC wrappers for L{config}.
1022 415a7304 Michael Hanselmann

1023 415a7304 Michael Hanselmann
  """
1024 c2dc025a Michael Hanselmann
  def __init__(self, context, address_list, _req_process_fn=None,
1025 c2dc025a Michael Hanselmann
               _getents=None):
1026 415a7304 Michael Hanselmann
    """Initializes this class.
1027 415a7304 Michael Hanselmann

1028 415a7304 Michael Hanselmann
    """
1029 b2acdbdc Michael Hanselmann
    if context:
1030 b2acdbdc Michael Hanselmann
      lock_monitor_cb = context.glm.AddToLockMonitor
1031 b2acdbdc Michael Hanselmann
    else:
1032 b2acdbdc Michael Hanselmann
      lock_monitor_cb = None
1033 b2acdbdc Michael Hanselmann
1034 415a7304 Michael Hanselmann
    if address_list is None:
1035 bd6d1202 René Nussbaumer
      resolver = compat.partial(_SsconfResolver, True)
1036 415a7304 Michael Hanselmann
    else:
1037 415a7304 Michael Hanselmann
      # Caller provided an address list
1038 415a7304 Michael Hanselmann
      resolver = _StaticResolver(address_list)
1039 415a7304 Michael Hanselmann
1040 c2dc025a Michael Hanselmann
    encoders = _ENCODERS.copy()
1041 c2dc025a Michael Hanselmann
1042 c2dc025a Michael Hanselmann
    encoders.update({
1043 c2dc025a Michael Hanselmann
      rpc_defs.ED_FILE_DETAILS: compat.partial(_PrepareFileUpload, _getents),
1044 c2dc025a Michael Hanselmann
      })
1045 c2dc025a Michael Hanselmann
1046 c2dc025a Michael Hanselmann
    _RpcClientBase.__init__(self, resolver, encoders.get,
1047 c2dc025a Michael Hanselmann
                            lock_monitor_cb=lock_monitor_cb,
1048 c2dc025a Michael Hanselmann
                            _req_process_fn=_req_process_fn)
1049 cd40dc53 Michael Hanselmann
    _generated_rpc.RpcClientConfig.__init__(self)