Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 42c067b7

History | View | Annotate | Download (33.2 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 72737a7f Iustin Pop
# pylint: disable-msg=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 a8083063 Iustin Pop
import os
34 58b311ca Iustin Pop
import logging
35 12bce260 Michael Hanselmann
import zlib
36 12bce260 Michael Hanselmann
import base64
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
from ganeti import utils
39 a8083063 Iustin Pop
from ganeti import objects
40 ecfe9491 Michael Hanselmann
from ganeti import http
41 7c28c575 Michael Hanselmann
from ganeti import serializer
42 eafd8762 Michael Hanselmann
from ganeti import constants
43 781de953 Iustin Pop
from ganeti import errors
44 a8083063 Iustin Pop
45 ae88ef45 Michael Hanselmann
import ganeti.http.client
46 ae88ef45 Michael Hanselmann
47 a8083063 Iustin Pop
48 4331f6cd Michael Hanselmann
# Module level variable
49 4331f6cd Michael Hanselmann
_http_manager = None
50 4331f6cd Michael Hanselmann
51 4331f6cd Michael Hanselmann
52 4331f6cd Michael Hanselmann
def Init():
53 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
54 4331f6cd Michael Hanselmann

55 4331f6cd Michael Hanselmann
  Must be called before using any RPC function.
56 4331f6cd Michael Hanselmann

57 4331f6cd Michael Hanselmann
  """
58 4331f6cd Michael Hanselmann
  global _http_manager
59 4331f6cd Michael Hanselmann
60 4331f6cd Michael Hanselmann
  assert not _http_manager, "RPC module initialized more than once"
61 4331f6cd Michael Hanselmann
62 ae88ef45 Michael Hanselmann
  _http_manager = http.client.HttpClientManager()
63 4331f6cd Michael Hanselmann
64 4331f6cd Michael Hanselmann
65 4331f6cd Michael Hanselmann
def Shutdown():
66 4331f6cd Michael Hanselmann
  """Stops the module-global HTTP client manager.
67 4331f6cd Michael Hanselmann

68 4331f6cd Michael Hanselmann
  Must be called before quitting the program.
69 4331f6cd Michael Hanselmann

70 4331f6cd Michael Hanselmann
  """
71 4331f6cd Michael Hanselmann
  global _http_manager
72 4331f6cd Michael Hanselmann
73 4331f6cd Michael Hanselmann
  if _http_manager:
74 4331f6cd Michael Hanselmann
    _http_manager.Shutdown()
75 4331f6cd Michael Hanselmann
    _http_manager = None
76 4331f6cd Michael Hanselmann
77 4331f6cd Michael Hanselmann
78 781de953 Iustin Pop
class RpcResult(object):
79 781de953 Iustin Pop
  """RPC Result class.
80 781de953 Iustin Pop

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

85 5bbd3f7f Michael Hanselmann
  @ivar data: the data payload, for successful results, or None
86 ed83f5cc Iustin Pop
  @type failed: boolean
87 d3c8b360 Iustin Pop
  @ivar failed: whether the operation failed at transport level (not
88 ed83f5cc Iustin Pop
      application level on the remote node)
89 ed83f5cc Iustin Pop
  @ivar call: the name of the RPC call
90 ed83f5cc Iustin Pop
  @ivar node: the name of the node to which we made the call
91 ed83f5cc Iustin Pop
  @ivar offline: whether the operation failed because the node was
92 ed83f5cc Iustin Pop
      offline, as opposed to actual failure; offline=True will always
93 ed83f5cc Iustin Pop
      imply failed=True, in order to allow simpler checking if
94 ed83f5cc Iustin Pop
      the user doesn't care about the exact failure mode
95 4c4e4e1e Iustin Pop
  @ivar fail_msg: the error message if the call failed
96 ed83f5cc Iustin Pop

97 781de953 Iustin Pop
  """
98 ed83f5cc Iustin Pop
  def __init__(self, data=None, failed=False, offline=False,
99 ed83f5cc Iustin Pop
               call=None, node=None):
100 781de953 Iustin Pop
    self.failed = failed
101 ed83f5cc Iustin Pop
    self.offline = offline
102 ed83f5cc Iustin Pop
    self.call = call
103 ed83f5cc Iustin Pop
    self.node = node
104 ed83f5cc Iustin Pop
    if offline:
105 ed83f5cc Iustin Pop
      self.failed = True
106 4c4e4e1e Iustin Pop
      self.fail_msg = "Node is marked offline"
107 f2def43a Iustin Pop
      self.data = self.payload = None
108 ed83f5cc Iustin Pop
    elif failed:
109 4c4e4e1e Iustin Pop
      self.fail_msg = self._EnsureErr(data)
110 f2def43a Iustin Pop
      self.data = self.payload = None
111 781de953 Iustin Pop
    else:
112 781de953 Iustin Pop
      self.data = data
113 d3c8b360 Iustin Pop
      if not isinstance(self.data, (tuple, list)):
114 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result type (%s)" %
115 4c4e4e1e Iustin Pop
                         type(self.data))
116 d3c8b360 Iustin Pop
      elif len(data) != 2:
117 4c4e4e1e Iustin Pop
        self.fail_msg = ("RPC layer error: invalid result length (%d), "
118 4c4e4e1e Iustin Pop
                         "expected 2" % len(self.data))
119 d3c8b360 Iustin Pop
      elif not self.data[0]:
120 4c4e4e1e Iustin Pop
        self.fail_msg = self._EnsureErr(self.data[1])
121 f2def43a Iustin Pop
      else:
122 d3c8b360 Iustin Pop
        # finally success
123 4c4e4e1e Iustin Pop
        self.fail_msg = None
124 d3c8b360 Iustin Pop
        self.payload = data[1]
125 d3c8b360 Iustin Pop
126 d3c8b360 Iustin Pop
  @staticmethod
127 d3c8b360 Iustin Pop
  def _EnsureErr(val):
128 d3c8b360 Iustin Pop
    """Helper to ensure we return a 'True' value for error."""
129 d3c8b360 Iustin Pop
    if val:
130 d3c8b360 Iustin Pop
      return val
131 d3c8b360 Iustin Pop
    else:
132 d3c8b360 Iustin Pop
      return "No error information"
133 781de953 Iustin Pop
134 4c4e4e1e Iustin Pop
  def Raise(self, msg, prereq=False):
135 781de953 Iustin Pop
    """If the result has failed, raise an OpExecError.
136 781de953 Iustin Pop

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

140 781de953 Iustin Pop
    """
141 4c4e4e1e Iustin Pop
    if not self.fail_msg:
142 4c4e4e1e Iustin Pop
      return
143 4c4e4e1e Iustin Pop
144 4c4e4e1e Iustin Pop
    if not msg: # one could pass None for default message
145 4c4e4e1e Iustin Pop
      msg = ("Call '%s' to node '%s' has failed: %s" %
146 4c4e4e1e Iustin Pop
             (self.call, self.node, self.fail_msg))
147 4c4e4e1e Iustin Pop
    else:
148 4c4e4e1e Iustin Pop
      msg = "%s: %s" % (msg, self.fail_msg)
149 4c4e4e1e Iustin Pop
    if prereq:
150 4c4e4e1e Iustin Pop
      ec = errors.OpPrereqError
151 4c4e4e1e Iustin Pop
    else:
152 4c4e4e1e Iustin Pop
      ec = errors.OpExecError
153 4c4e4e1e Iustin Pop
    raise ec(msg)
154 781de953 Iustin Pop
155 3247bbac Iustin Pop
  def RemoteFailMsg(self):
156 3247bbac Iustin Pop
    """Check if the remote procedure failed.
157 3247bbac Iustin Pop

158 d3c8b360 Iustin Pop
    @return: the fail_msg attribute
159 3247bbac Iustin Pop

160 3247bbac Iustin Pop
    """
161 4c4e4e1e Iustin Pop
    return self.fail_msg
162 3247bbac Iustin Pop
163 781de953 Iustin Pop
164 a8083063 Iustin Pop
class Client:
165 a8083063 Iustin Pop
  """RPC Client class.
166 a8083063 Iustin Pop

167 2f8598a5 Alexander Schreiber
  This class, given a (remote) method name, a list of parameters and a
168 a8083063 Iustin Pop
  list of nodes, will contact (in parallel) all nodes, and return a
169 a8083063 Iustin Pop
  dict of results (key: node name, value: result).
170 a8083063 Iustin Pop

171 5bbd3f7f Michael Hanselmann
  One current bug is that generic failure is still signaled by
172 a8083063 Iustin Pop
  'False' result, which is not good. This overloading of values can
173 a8083063 Iustin Pop
  cause bugs.
174 a8083063 Iustin Pop

175 a8083063 Iustin Pop
  """
176 160e2921 Iustin Pop
  def __init__(self, procedure, body, port):
177 a8083063 Iustin Pop
    self.procedure = procedure
178 160e2921 Iustin Pop
    self.body = body
179 160e2921 Iustin Pop
    self.port = port
180 ecfe9491 Michael Hanselmann
    self.nc = {}
181 a8083063 Iustin Pop
182 d57ae7f7 Michael Hanselmann
    self._ssl_params = \
183 d57ae7f7 Michael Hanselmann
      http.HttpSslParams(ssl_key_path=constants.SSL_CERT_FILE,
184 d57ae7f7 Michael Hanselmann
                         ssl_cert_path=constants.SSL_CERT_FILE)
185 d57ae7f7 Michael Hanselmann
186 bdf7d8c0 Iustin Pop
  def ConnectList(self, node_list, address_list=None):
187 a8083063 Iustin Pop
    """Add a list of nodes to the target nodes.
188 a8083063 Iustin Pop

189 3ef3c771 Iustin Pop
    @type node_list: list
190 3ef3c771 Iustin Pop
    @param node_list: the list of node names to connect
191 bdf7d8c0 Iustin Pop
    @type address_list: list or None
192 bdf7d8c0 Iustin Pop
    @keyword address_list: either None or a list with node addresses,
193 bdf7d8c0 Iustin Pop
        which must have the same length as the node list
194 3ef3c771 Iustin Pop

195 a8083063 Iustin Pop
    """
196 bdf7d8c0 Iustin Pop
    if address_list is None:
197 bdf7d8c0 Iustin Pop
      address_list = [None for _ in node_list]
198 bdf7d8c0 Iustin Pop
    else:
199 bdf7d8c0 Iustin Pop
      assert len(node_list) == len(address_list), \
200 bdf7d8c0 Iustin Pop
             "Name and address lists should have the same length"
201 bdf7d8c0 Iustin Pop
    for node, address in zip(node_list, address_list):
202 bdf7d8c0 Iustin Pop
      self.ConnectNode(node, address)
203 bdf7d8c0 Iustin Pop
204 bdf7d8c0 Iustin Pop
  def ConnectNode(self, name, address=None):
205 a8083063 Iustin Pop
    """Add a node to the target list.
206 a8083063 Iustin Pop

207 bdf7d8c0 Iustin Pop
    @type name: str
208 bdf7d8c0 Iustin Pop
    @param name: the node name
209 bdf7d8c0 Iustin Pop
    @type address: str
210 bdf7d8c0 Iustin Pop
    @keyword address: the node address, if known
211 bdf7d8c0 Iustin Pop

212 a8083063 Iustin Pop
    """
213 ecfe9491 Michael Hanselmann
    if address is None:
214 ecfe9491 Michael Hanselmann
      address = name
215 ecfe9491 Michael Hanselmann
216 ae88ef45 Michael Hanselmann
    self.nc[name] = \
217 ae88ef45 Michael Hanselmann
      http.client.HttpClientRequest(address, self.port, http.HTTP_PUT,
218 ae88ef45 Michael Hanselmann
                                    "/%s" % self.procedure,
219 ae88ef45 Michael Hanselmann
                                    post_data=self.body,
220 ae88ef45 Michael Hanselmann
                                    ssl_params=self._ssl_params,
221 ae88ef45 Michael Hanselmann
                                    ssl_verify_peer=True)
222 a8083063 Iustin Pop
223 3ef3c771 Iustin Pop
  def GetResults(self):
224 ecfe9491 Michael Hanselmann
    """Call nodes and return results.
225 ecfe9491 Michael Hanselmann

226 ecfe9491 Michael Hanselmann
    @rtype: list
227 5fcc718f Iustin Pop
    @return: List of RPC results
228 a8083063 Iustin Pop

229 a8083063 Iustin Pop
    """
230 5bbd3f7f Michael Hanselmann
    assert _http_manager, "RPC module not initialized"
231 4331f6cd Michael Hanselmann
232 4331f6cd Michael Hanselmann
    _http_manager.ExecRequests(self.nc.values())
233 a8083063 Iustin Pop
234 ecfe9491 Michael Hanselmann
    results = {}
235 a8083063 Iustin Pop
236 ecfe9491 Michael Hanselmann
    for name, req in self.nc.iteritems():
237 ae88ef45 Michael Hanselmann
      if req.success and req.resp_status_code == http.HTTP_OK:
238 781de953 Iustin Pop
        results[name] = RpcResult(data=serializer.LoadJson(req.resp_body),
239 781de953 Iustin Pop
                                  node=name, call=self.procedure)
240 ecfe9491 Michael Hanselmann
        continue
241 a8083063 Iustin Pop
242 d57ae7f7 Michael Hanselmann
      # TODO: Better error reporting
243 ecfe9491 Michael Hanselmann
      if req.error:
244 ecfe9491 Michael Hanselmann
        msg = req.error
245 ecfe9491 Michael Hanselmann
      else:
246 ecfe9491 Michael Hanselmann
        msg = req.resp_body
247 ecfe9491 Michael Hanselmann
248 1b8acf70 Iustin Pop
      logging.error("RPC error in %s from node %s: %s",
249 1b8acf70 Iustin Pop
                    self.procedure, name, msg)
250 781de953 Iustin Pop
      results[name] = RpcResult(data=msg, failed=True, node=name,
251 781de953 Iustin Pop
                                call=self.procedure)
252 ecfe9491 Michael Hanselmann
253 ecfe9491 Michael Hanselmann
    return results
254 a8083063 Iustin Pop
255 a8083063 Iustin Pop
256 72737a7f Iustin Pop
class RpcRunner(object):
257 72737a7f Iustin Pop
  """RPC runner class"""
258 a8083063 Iustin Pop
259 72737a7f Iustin Pop
  def __init__(self, cfg):
260 72737a7f Iustin Pop
    """Initialized the rpc runner.
261 a8083063 Iustin Pop

262 72737a7f Iustin Pop
    @type cfg:  C{config.ConfigWriter}
263 72737a7f Iustin Pop
    @param cfg: the configuration object that will be used to get data
264 72737a7f Iustin Pop
                about the cluster
265 a8083063 Iustin Pop

266 72737a7f Iustin Pop
    """
267 72737a7f Iustin Pop
    self._cfg = cfg
268 cd50653c Guido Trotter
    self.port = utils.GetDaemonPort(constants.NODED)
269 a8083063 Iustin Pop
270 0eca8e0c Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None):
271 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
272 26ba2bd8 Iustin Pop

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

276 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
277 26ba2bd8 Iustin Pop
    @param instance: an Instance object
278 0eca8e0c Iustin Pop
    @type hvp: dict or None
279 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
280 0eca8e0c Iustin Pop
    @type bep: dict or None
281 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
282 26ba2bd8 Iustin Pop
    @rtype: dict
283 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
284 26ba2bd8 Iustin Pop
        cluster defaults
285 26ba2bd8 Iustin Pop

286 26ba2bd8 Iustin Pop
    """
287 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
288 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
289 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
290 0eca8e0c Iustin Pop
    if hvp is not None:
291 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
292 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
293 0eca8e0c Iustin Pop
    if bep is not None:
294 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
295 b848ce79 Guido Trotter
    for nic in idict["nics"]:
296 b848ce79 Guido Trotter
      nic['nicparams'] = objects.FillDict(
297 b848ce79 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT],
298 b848ce79 Guido Trotter
        nic['nicparams'])
299 26ba2bd8 Iustin Pop
    return idict
300 26ba2bd8 Iustin Pop
301 84b45587 Iustin Pop
  def _ConnectList(self, client, node_list, call):
302 25348212 Iustin Pop
    """Helper for computing node addresses.
303 25348212 Iustin Pop

304 6af6270a Iustin Pop
    @type client: L{ganeti.rpc.Client}
305 25348212 Iustin Pop
    @param client: a C{Client} instance
306 25348212 Iustin Pop
    @type node_list: list
307 25348212 Iustin Pop
    @param node_list: the node list we should connect
308 84b45587 Iustin Pop
    @type call: string
309 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
310 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
311 25348212 Iustin Pop

312 25348212 Iustin Pop
    """
313 25348212 Iustin Pop
    all_nodes = self._cfg.GetAllNodesInfo()
314 ed83f5cc Iustin Pop
    name_list = []
315 25348212 Iustin Pop
    addr_list = []
316 ed83f5cc Iustin Pop
    skip_dict = {}
317 25348212 Iustin Pop
    for node in node_list:
318 25348212 Iustin Pop
      if node in all_nodes:
319 ed83f5cc Iustin Pop
        if all_nodes[node].offline:
320 84b45587 Iustin Pop
          skip_dict[node] = RpcResult(node=node, offline=True, call=call)
321 ed83f5cc Iustin Pop
          continue
322 25348212 Iustin Pop
        val = all_nodes[node].primary_ip
323 25348212 Iustin Pop
      else:
324 25348212 Iustin Pop
        val = None
325 25348212 Iustin Pop
      addr_list.append(val)
326 ed83f5cc Iustin Pop
      name_list.append(node)
327 ed83f5cc Iustin Pop
    if name_list:
328 ed83f5cc Iustin Pop
      client.ConnectList(name_list, address_list=addr_list)
329 ed83f5cc Iustin Pop
    return skip_dict
330 25348212 Iustin Pop
331 84b45587 Iustin Pop
  def _ConnectNode(self, client, node, call):
332 25348212 Iustin Pop
    """Helper for computing one node's address.
333 25348212 Iustin Pop

334 6af6270a Iustin Pop
    @type client: L{ganeti.rpc.Client}
335 25348212 Iustin Pop
    @param client: a C{Client} instance
336 25348212 Iustin Pop
    @type node: str
337 25348212 Iustin Pop
    @param node: the node we should connect
338 84b45587 Iustin Pop
    @type call: string
339 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
340 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
341 25348212 Iustin Pop

342 25348212 Iustin Pop
    """
343 25348212 Iustin Pop
    node_info = self._cfg.GetNodeInfo(node)
344 25348212 Iustin Pop
    if node_info is not None:
345 ed83f5cc Iustin Pop
      if node_info.offline:
346 84b45587 Iustin Pop
        return RpcResult(node=node, offline=True, call=call)
347 25348212 Iustin Pop
      addr = node_info.primary_ip
348 25348212 Iustin Pop
    else:
349 25348212 Iustin Pop
      addr = None
350 25348212 Iustin Pop
    client.ConnectNode(node, address=addr)
351 25348212 Iustin Pop
352 ed83f5cc Iustin Pop
  def _MultiNodeCall(self, node_list, procedure, args):
353 160e2921 Iustin Pop
    """Helper for making a multi-node call
354 160e2921 Iustin Pop

355 160e2921 Iustin Pop
    """
356 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
357 160e2921 Iustin Pop
    c = Client(procedure, body, self.port)
358 84b45587 Iustin Pop
    skip_dict = self._ConnectList(c, node_list, procedure)
359 ed83f5cc Iustin Pop
    skip_dict.update(c.GetResults())
360 ed83f5cc Iustin Pop
    return skip_dict
361 9a525d83 Michael Hanselmann
362 9a525d83 Michael Hanselmann
  @classmethod
363 9a525d83 Michael Hanselmann
  def _StaticMultiNodeCall(cls, node_list, procedure, args,
364 9a525d83 Michael Hanselmann
                           address_list=None):
365 160e2921 Iustin Pop
    """Helper for making a multi-node static call
366 160e2921 Iustin Pop

367 160e2921 Iustin Pop
    """
368 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
369 cd50653c Guido Trotter
    c = Client(procedure, body, utils.GetDaemonPort(constants.NODED))
370 9a525d83 Michael Hanselmann
    c.ConnectList(node_list, address_list=address_list)
371 9a525d83 Michael Hanselmann
    return c.GetResults()
372 9a525d83 Michael Hanselmann
373 9a525d83 Michael Hanselmann
  def _SingleNodeCall(self, node, procedure, args):
374 160e2921 Iustin Pop
    """Helper for making a single-node call
375 9a525d83 Michael Hanselmann

376 9a525d83 Michael Hanselmann
    """
377 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
378 160e2921 Iustin Pop
    c = Client(procedure, body, self.port)
379 84b45587 Iustin Pop
    result = self._ConnectNode(c, node, procedure)
380 ed83f5cc Iustin Pop
    if result is None:
381 ed83f5cc Iustin Pop
      # we did connect, node is not offline
382 ed83f5cc Iustin Pop
      result = c.GetResults()[node]
383 ed83f5cc Iustin Pop
    return result
384 9a525d83 Michael Hanselmann
385 9a525d83 Michael Hanselmann
  @classmethod
386 9a525d83 Michael Hanselmann
  def _StaticSingleNodeCall(cls, node, procedure, args):
387 160e2921 Iustin Pop
    """Helper for making a single-node static call
388 9a525d83 Michael Hanselmann

389 9a525d83 Michael Hanselmann
    """
390 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
391 cd50653c Guido Trotter
    c = Client(procedure, body, utils.GetDaemonPort(constants.NODED))
392 3097c858 Michael Hanselmann
    c.ConnectNode(node)
393 ed83f5cc Iustin Pop
    return c.GetResults()[node]
394 9a525d83 Michael Hanselmann
395 12bce260 Michael Hanselmann
  @staticmethod
396 12bce260 Michael Hanselmann
  def _Compress(data):
397 12bce260 Michael Hanselmann
    """Compresses a string for transport over RPC.
398 12bce260 Michael Hanselmann

399 12bce260 Michael Hanselmann
    Small amounts of data are not compressed.
400 12bce260 Michael Hanselmann

401 12bce260 Michael Hanselmann
    @type data: str
402 12bce260 Michael Hanselmann
    @param data: Data
403 12bce260 Michael Hanselmann
    @rtype: tuple
404 12bce260 Michael Hanselmann
    @return: Encoded data to send
405 12bce260 Michael Hanselmann

406 12bce260 Michael Hanselmann
    """
407 12bce260 Michael Hanselmann
    # Small amounts of data are not compressed
408 12bce260 Michael Hanselmann
    if len(data) < 512:
409 12bce260 Michael Hanselmann
      return (constants.RPC_ENCODING_NONE, data)
410 12bce260 Michael Hanselmann
411 12bce260 Michael Hanselmann
    # Compress with zlib and encode in base64
412 12bce260 Michael Hanselmann
    return (constants.RPC_ENCODING_ZLIB_BASE64,
413 12bce260 Michael Hanselmann
            base64.b64encode(zlib.compress(data, 3)))
414 12bce260 Michael Hanselmann
415 781de953 Iustin Pop
  #
416 781de953 Iustin Pop
  # Begin RPC calls
417 781de953 Iustin Pop
  #
418 781de953 Iustin Pop
419 b2a6ccd4 Iustin Pop
  def call_lv_list(self, node_list, vg_name):
420 72737a7f Iustin Pop
    """Gets the logical volumes present in a given volume group.
421 a8083063 Iustin Pop

422 72737a7f Iustin Pop
    This is a multi-node call.
423 a8083063 Iustin Pop

424 72737a7f Iustin Pop
    """
425 b2a6ccd4 Iustin Pop
    return self._MultiNodeCall(node_list, "lv_list", [vg_name])
426 a8083063 Iustin Pop
427 72737a7f Iustin Pop
  def call_vg_list(self, node_list):
428 72737a7f Iustin Pop
    """Gets the volume group list.
429 a8083063 Iustin Pop

430 72737a7f Iustin Pop
    This is a multi-node call.
431 a8083063 Iustin Pop

432 72737a7f Iustin Pop
    """
433 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "vg_list", [])
434 a8083063 Iustin Pop
435 e337de97 Michael Hanselmann
  def call_storage_list(self, node_list, su_name, su_args, name, fields):
436 e337de97 Michael Hanselmann
    """Get list of storage units..
437 e337de97 Michael Hanselmann

438 e337de97 Michael Hanselmann
    This is a multi-node call.
439 e337de97 Michael Hanselmann

440 e337de97 Michael Hanselmann
    """
441 e337de97 Michael Hanselmann
    return self._MultiNodeCall(node_list, "storage_list",
442 e337de97 Michael Hanselmann
                               [su_name, su_args, name, fields])
443 e337de97 Michael Hanselmann
444 72737a7f Iustin Pop
  def call_bridges_exist(self, node, bridges_list):
445 72737a7f Iustin Pop
    """Checks if a node has all the bridges given.
446 a8083063 Iustin Pop

447 72737a7f Iustin Pop
    This method checks if all bridges given in the bridges_list are
448 72737a7f Iustin Pop
    present on the remote node, so that an instance that uses interfaces
449 72737a7f Iustin Pop
    on those bridges can be started.
450 a8083063 Iustin Pop

451 72737a7f Iustin Pop
    This is a single-node call.
452 a8083063 Iustin Pop

453 72737a7f Iustin Pop
    """
454 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "bridges_exist", [bridges_list])
455 a8083063 Iustin Pop
456 0eca8e0c Iustin Pop
  def call_instance_start(self, node, instance, hvp, bep):
457 72737a7f Iustin Pop
    """Starts an instance.
458 a8083063 Iustin Pop

459 72737a7f Iustin Pop
    This is a single-node call.
460 a8083063 Iustin Pop

461 72737a7f Iustin Pop
    """
462 0eca8e0c Iustin Pop
    idict = self._InstDict(instance, hvp=hvp, bep=bep)
463 0eca8e0c Iustin Pop
    return self._SingleNodeCall(node, "instance_start", [idict])
464 a8083063 Iustin Pop
465 72737a7f Iustin Pop
  def call_instance_shutdown(self, node, instance):
466 72737a7f Iustin Pop
    """Stops an instance.
467 a8083063 Iustin Pop

468 72737a7f Iustin Pop
    This is a single-node call.
469 2a10865c Iustin Pop

470 72737a7f Iustin Pop
    """
471 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_shutdown",
472 9a525d83 Michael Hanselmann
                                [self._InstDict(instance)])
473 2a10865c Iustin Pop
474 6906a9d8 Guido Trotter
  def call_migration_info(self, node, instance):
475 6906a9d8 Guido Trotter
    """Gather the information necessary to prepare an instance migration.
476 6906a9d8 Guido Trotter

477 6906a9d8 Guido Trotter
    This is a single-node call.
478 6906a9d8 Guido Trotter

479 6906a9d8 Guido Trotter
    @type node: string
480 6906a9d8 Guido Trotter
    @param node: the node on which the instance is currently running
481 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
482 6906a9d8 Guido Trotter
    @param instance: the instance definition
483 6906a9d8 Guido Trotter

484 6906a9d8 Guido Trotter
    """
485 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "migration_info",
486 6906a9d8 Guido Trotter
                                [self._InstDict(instance)])
487 6906a9d8 Guido Trotter
488 6906a9d8 Guido Trotter
  def call_accept_instance(self, node, instance, info, target):
489 6906a9d8 Guido Trotter
    """Prepare a node to accept an instance.
490 6906a9d8 Guido Trotter

491 6906a9d8 Guido Trotter
    This is a single-node call.
492 6906a9d8 Guido Trotter

493 6906a9d8 Guido Trotter
    @type node: string
494 6906a9d8 Guido Trotter
    @param node: the target node for the migration
495 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
496 6906a9d8 Guido Trotter
    @param instance: the instance definition
497 6906a9d8 Guido Trotter
    @type info: opaque/hypervisor specific (string/data)
498 6906a9d8 Guido Trotter
    @param info: result for the call_migration_info call
499 6906a9d8 Guido Trotter
    @type target: string
500 6906a9d8 Guido Trotter
    @param target: target hostname (usually ip address) (on the node itself)
501 6906a9d8 Guido Trotter

502 6906a9d8 Guido Trotter
    """
503 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "accept_instance",
504 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, target])
505 6906a9d8 Guido Trotter
506 6906a9d8 Guido Trotter
  def call_finalize_migration(self, node, instance, info, success):
507 6906a9d8 Guido Trotter
    """Finalize any target-node migration specific operation.
508 6906a9d8 Guido Trotter

509 6906a9d8 Guido Trotter
    This is called both in case of a successful migration and in case of error
510 6906a9d8 Guido Trotter
    (in which case it should abort the migration).
511 6906a9d8 Guido Trotter

512 6906a9d8 Guido Trotter
    This is a single-node call.
513 6906a9d8 Guido Trotter

514 6906a9d8 Guido Trotter
    @type node: string
515 6906a9d8 Guido Trotter
    @param node: the target node for the migration
516 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
517 6906a9d8 Guido Trotter
    @param instance: the instance definition
518 6906a9d8 Guido Trotter
    @type info: opaque/hypervisor specific (string/data)
519 6906a9d8 Guido Trotter
    @param info: result for the call_migration_info call
520 6906a9d8 Guido Trotter
    @type success: boolean
521 6906a9d8 Guido Trotter
    @param success: whether the migration was a success or a failure
522 6906a9d8 Guido Trotter

523 6906a9d8 Guido Trotter
    """
524 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "finalize_migration",
525 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, success])
526 6906a9d8 Guido Trotter
527 72737a7f Iustin Pop
  def call_instance_migrate(self, node, instance, target, live):
528 72737a7f Iustin Pop
    """Migrate an instance.
529 2a10865c Iustin Pop

530 72737a7f Iustin Pop
    This is a single-node call.
531 2a10865c Iustin Pop

532 72737a7f Iustin Pop
    @type node: string
533 72737a7f Iustin Pop
    @param node: the node on which the instance is currently running
534 72737a7f Iustin Pop
    @type instance: C{objects.Instance}
535 72737a7f Iustin Pop
    @param instance: the instance definition
536 72737a7f Iustin Pop
    @type target: string
537 72737a7f Iustin Pop
    @param target: the target node name
538 72737a7f Iustin Pop
    @type live: boolean
539 72737a7f Iustin Pop
    @param live: whether the migration should be done live or not (the
540 72737a7f Iustin Pop
        interpretation of this parameter is left to the hypervisor)
541 007a2f3e Alexander Schreiber

542 72737a7f Iustin Pop
    """
543 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_migrate",
544 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), target, live])
545 007a2f3e Alexander Schreiber
546 07813a9e Iustin Pop
  def call_instance_reboot(self, node, instance, reboot_type):
547 72737a7f Iustin Pop
    """Reboots an instance.
548 007a2f3e Alexander Schreiber

549 72737a7f Iustin Pop
    This is a single-node call.
550 a8083063 Iustin Pop

551 72737a7f Iustin Pop
    """
552 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_reboot",
553 07813a9e Iustin Pop
                                [self._InstDict(instance), reboot_type])
554 a8083063 Iustin Pop
555 e557bae9 Guido Trotter
  def call_instance_os_add(self, node, inst, reinstall):
556 72737a7f Iustin Pop
    """Installs an OS on the given instance.
557 a8083063 Iustin Pop

558 72737a7f Iustin Pop
    This is a single-node call.
559 decd5f45 Iustin Pop

560 72737a7f Iustin Pop
    """
561 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_add",
562 e557bae9 Guido Trotter
                                [self._InstDict(inst), reinstall])
563 decd5f45 Iustin Pop
564 d15a9ad3 Guido Trotter
  def call_instance_run_rename(self, node, inst, old_name):
565 72737a7f Iustin Pop
    """Run the OS rename script for an instance.
566 decd5f45 Iustin Pop

567 72737a7f Iustin Pop
    This is a single-node call.
568 a8083063 Iustin Pop

569 72737a7f Iustin Pop
    """
570 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_run_rename",
571 9a525d83 Michael Hanselmann
                                [self._InstDict(inst), old_name])
572 a8083063 Iustin Pop
573 72737a7f Iustin Pop
  def call_instance_info(self, node, instance, hname):
574 72737a7f Iustin Pop
    """Returns information about a single instance.
575 a8083063 Iustin Pop

576 72737a7f Iustin Pop
    This is a single-node call.
577 a8083063 Iustin Pop

578 9a525d83 Michael Hanselmann
    @type node: list
579 9a525d83 Michael Hanselmann
    @param node: the list of nodes to query
580 72737a7f Iustin Pop
    @type instance: string
581 72737a7f Iustin Pop
    @param instance: the instance name
582 72737a7f Iustin Pop
    @type hname: string
583 72737a7f Iustin Pop
    @param hname: the hypervisor type of the instance
584 a8083063 Iustin Pop

585 72737a7f Iustin Pop
    """
586 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_info", [instance, hname])
587 e69d05fd Iustin Pop
588 56e7640c Iustin Pop
  def call_instance_migratable(self, node, instance):
589 56e7640c Iustin Pop
    """Checks whether the given instance can be migrated.
590 56e7640c Iustin Pop

591 56e7640c Iustin Pop
    This is a single-node call.
592 56e7640c Iustin Pop

593 56e7640c Iustin Pop
    @param node: the node to query
594 56e7640c Iustin Pop
    @type instance: L{objects.Instance}
595 56e7640c Iustin Pop
    @param instance: the instance to check
596 56e7640c Iustin Pop

597 56e7640c Iustin Pop

598 56e7640c Iustin Pop
    """
599 56e7640c Iustin Pop
    return self._SingleNodeCall(node, "instance_migratable",
600 56e7640c Iustin Pop
                                [self._InstDict(instance)])
601 56e7640c Iustin Pop
602 72737a7f Iustin Pop
  def call_all_instances_info(self, node_list, hypervisor_list):
603 72737a7f Iustin Pop
    """Returns information about all instances on the given nodes.
604 a8083063 Iustin Pop

605 72737a7f Iustin Pop
    This is a multi-node call.
606 a8083063 Iustin Pop

607 72737a7f Iustin Pop
    @type node_list: list
608 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
609 72737a7f Iustin Pop
    @type hypervisor_list: list
610 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
611 a8083063 Iustin Pop

612 72737a7f Iustin Pop
    """
613 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "all_instances_info",
614 9a525d83 Michael Hanselmann
                               [hypervisor_list])
615 e69d05fd Iustin Pop
616 72737a7f Iustin Pop
  def call_instance_list(self, node_list, hypervisor_list):
617 72737a7f Iustin Pop
    """Returns the list of running instances on a given node.
618 a8083063 Iustin Pop

619 72737a7f Iustin Pop
    This is a multi-node call.
620 a8083063 Iustin Pop

621 72737a7f Iustin Pop
    @type node_list: list
622 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
623 72737a7f Iustin Pop
    @type hypervisor_list: list
624 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
625 16abfbc2 Alexander Schreiber

626 72737a7f Iustin Pop
    """
627 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "instance_list", [hypervisor_list])
628 16abfbc2 Alexander Schreiber
629 72737a7f Iustin Pop
  def call_node_tcp_ping(self, node, source, target, port, timeout,
630 72737a7f Iustin Pop
                         live_port_needed):
631 72737a7f Iustin Pop
    """Do a TcpPing on the remote node
632 a8083063 Iustin Pop

633 72737a7f Iustin Pop
    This is a single-node call.
634 caad16e2 Iustin Pop

635 72737a7f Iustin Pop
    """
636 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_tcp_ping",
637 9a525d83 Michael Hanselmann
                                [source, target, port, timeout,
638 72737a7f Iustin Pop
                                 live_port_needed])
639 a8083063 Iustin Pop
640 caad16e2 Iustin Pop
  def call_node_has_ip_address(self, node, address):
641 caad16e2 Iustin Pop
    """Checks if a node has the given IP address.
642 caad16e2 Iustin Pop

643 caad16e2 Iustin Pop
    This is a single-node call.
644 caad16e2 Iustin Pop

645 caad16e2 Iustin Pop
    """
646 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_has_ip_address", [address])
647 a8083063 Iustin Pop
648 72737a7f Iustin Pop
  def call_node_info(self, node_list, vg_name, hypervisor_type):
649 72737a7f Iustin Pop
    """Return node information.
650 e69d05fd Iustin Pop

651 72737a7f Iustin Pop
    This will return memory information and volume group size and free
652 72737a7f Iustin Pop
    space.
653 a8083063 Iustin Pop

654 72737a7f Iustin Pop
    This is a multi-node call.
655 a8083063 Iustin Pop

656 72737a7f Iustin Pop
    @type node_list: list
657 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
658 c41eea6e Iustin Pop
    @type vg_name: C{string}
659 c41eea6e Iustin Pop
    @param vg_name: the name of the volume group to ask for disk space
660 72737a7f Iustin Pop
        information
661 72737a7f Iustin Pop
    @type hypervisor_type: C{str}
662 72737a7f Iustin Pop
    @param hypervisor_type: the name of the hypervisor to ask for
663 72737a7f Iustin Pop
        memory information
664 a8083063 Iustin Pop

665 72737a7f Iustin Pop
    """
666 070e998b Iustin Pop
    return self._MultiNodeCall(node_list, "node_info",
667 070e998b Iustin Pop
                               [vg_name, hypervisor_type])
668 a8083063 Iustin Pop
669 72737a7f Iustin Pop
  def call_node_add(self, node, dsa, dsapub, rsa, rsapub, ssh, sshpub):
670 72737a7f Iustin Pop
    """Add a node to the cluster.
671 a8083063 Iustin Pop

672 72737a7f Iustin Pop
    This is a single-node call.
673 a8083063 Iustin Pop

674 72737a7f Iustin Pop
    """
675 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_add",
676 9a525d83 Michael Hanselmann
                                [dsa, dsapub, rsa, rsapub, ssh, sshpub])
677 a8083063 Iustin Pop
678 72737a7f Iustin Pop
  def call_node_verify(self, node_list, checkdict, cluster_name):
679 72737a7f Iustin Pop
    """Request verification of given parameters.
680 a8083063 Iustin Pop

681 72737a7f Iustin Pop
    This is a multi-node call.
682 a8083063 Iustin Pop

683 72737a7f Iustin Pop
    """
684 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "node_verify",
685 9a525d83 Michael Hanselmann
                               [checkdict, cluster_name])
686 a8083063 Iustin Pop
687 9a525d83 Michael Hanselmann
  @classmethod
688 3583908a Guido Trotter
  def call_node_start_master(cls, node, start_daemons, no_voting):
689 72737a7f Iustin Pop
    """Tells a node to activate itself as a master.
690 a8083063 Iustin Pop

691 72737a7f Iustin Pop
    This is a single-node call.
692 a8083063 Iustin Pop

693 72737a7f Iustin Pop
    """
694 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "node_start_master",
695 3583908a Guido Trotter
                                     [start_daemons, no_voting])
696 a8083063 Iustin Pop
697 9a525d83 Michael Hanselmann
  @classmethod
698 9a525d83 Michael Hanselmann
  def call_node_stop_master(cls, node, stop_daemons):
699 72737a7f Iustin Pop
    """Tells a node to demote itself from master status.
700 a8083063 Iustin Pop

701 72737a7f Iustin Pop
    This is a single-node call.
702 4e071d3b Iustin Pop

703 72737a7f Iustin Pop
    """
704 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "node_stop_master", [stop_daemons])
705 4e071d3b Iustin Pop
706 9a525d83 Michael Hanselmann
  @classmethod
707 9a525d83 Michael Hanselmann
  def call_master_info(cls, node_list):
708 72737a7f Iustin Pop
    """Query master info.
709 4e071d3b Iustin Pop

710 72737a7f Iustin Pop
    This is a multi-node call.
711 a8083063 Iustin Pop

712 72737a7f Iustin Pop
    """
713 72737a7f Iustin Pop
    # TODO: should this method query down nodes?
714 9a525d83 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "master_info", [])
715 a8083063 Iustin Pop
716 72737a7f Iustin Pop
  def call_version(self, node_list):
717 72737a7f Iustin Pop
    """Query node version.
718 a8083063 Iustin Pop

719 72737a7f Iustin Pop
    This is a multi-node call.
720 a8083063 Iustin Pop

721 72737a7f Iustin Pop
    """
722 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "version", [])
723 a8083063 Iustin Pop
724 72737a7f Iustin Pop
  def call_blockdev_create(self, node, bdev, size, owner, on_primary, info):
725 72737a7f Iustin Pop
    """Request creation of a given block device.
726 a8083063 Iustin Pop

727 72737a7f Iustin Pop
    This is a single-node call.
728 a8083063 Iustin Pop

729 72737a7f Iustin Pop
    """
730 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_create",
731 9a525d83 Michael Hanselmann
                                [bdev.ToDict(), size, owner, on_primary, info])
732 a8083063 Iustin Pop
733 72737a7f Iustin Pop
  def call_blockdev_remove(self, node, bdev):
734 72737a7f Iustin Pop
    """Request removal of a given block device.
735 a8083063 Iustin Pop

736 72737a7f Iustin Pop
    This is a single-node call.
737 f3e513ad Iustin Pop

738 72737a7f Iustin Pop
    """
739 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_remove", [bdev.ToDict()])
740 f3e513ad Iustin Pop
741 72737a7f Iustin Pop
  def call_blockdev_rename(self, node, devlist):
742 72737a7f Iustin Pop
    """Request rename of the given block devices.
743 f3e513ad Iustin Pop

744 72737a7f Iustin Pop
    This is a single-node call.
745 a8083063 Iustin Pop

746 72737a7f Iustin Pop
    """
747 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_rename",
748 9a525d83 Michael Hanselmann
                                [(d.ToDict(), uid) for d, uid in devlist])
749 a8083063 Iustin Pop
750 72737a7f Iustin Pop
  def call_blockdev_assemble(self, node, disk, owner, on_primary):
751 72737a7f Iustin Pop
    """Request assembling of a given block device.
752 a8083063 Iustin Pop

753 72737a7f Iustin Pop
    This is a single-node call.
754 a8083063 Iustin Pop

755 72737a7f Iustin Pop
    """
756 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_assemble",
757 9a525d83 Michael Hanselmann
                                [disk.ToDict(), owner, on_primary])
758 a8083063 Iustin Pop
759 72737a7f Iustin Pop
  def call_blockdev_shutdown(self, node, disk):
760 72737a7f Iustin Pop
    """Request shutdown of a given block device.
761 a8083063 Iustin Pop

762 72737a7f Iustin Pop
    This is a single-node call.
763 a8083063 Iustin Pop

764 72737a7f Iustin Pop
    """
765 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_shutdown", [disk.ToDict()])
766 a8083063 Iustin Pop
767 72737a7f Iustin Pop
  def call_blockdev_addchildren(self, node, bdev, ndevs):
768 72737a7f Iustin Pop
    """Request adding a list of children to a (mirroring) device.
769 a8083063 Iustin Pop

770 72737a7f Iustin Pop
    This is a single-node call.
771 a8083063 Iustin Pop

772 72737a7f Iustin Pop
    """
773 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_addchildren",
774 9a525d83 Michael Hanselmann
                                [bdev.ToDict(),
775 9a525d83 Michael Hanselmann
                                 [disk.ToDict() for disk in ndevs]])
776 a8083063 Iustin Pop
777 72737a7f Iustin Pop
  def call_blockdev_removechildren(self, node, bdev, ndevs):
778 72737a7f Iustin Pop
    """Request removing a list of children from a (mirroring) device.
779 a8083063 Iustin Pop

780 72737a7f Iustin Pop
    This is a single-node call.
781 a8083063 Iustin Pop

782 72737a7f Iustin Pop
    """
783 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_removechildren",
784 9a525d83 Michael Hanselmann
                                [bdev.ToDict(),
785 9a525d83 Michael Hanselmann
                                 [disk.ToDict() for disk in ndevs]])
786 a8083063 Iustin Pop
787 72737a7f Iustin Pop
  def call_blockdev_getmirrorstatus(self, node, disks):
788 72737a7f Iustin Pop
    """Request status of a (mirroring) device.
789 a8083063 Iustin Pop

790 72737a7f Iustin Pop
    This is a single-node call.
791 a8083063 Iustin Pop

792 72737a7f Iustin Pop
    """
793 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_getmirrorstatus",
794 9a525d83 Michael Hanselmann
                                [dsk.ToDict() for dsk in disks])
795 a8083063 Iustin Pop
796 72737a7f Iustin Pop
  def call_blockdev_find(self, node, disk):
797 72737a7f Iustin Pop
    """Request identification of a given block device.
798 72737a7f Iustin Pop

799 72737a7f Iustin Pop
    This is a single-node call.
800 a8083063 Iustin Pop

801 72737a7f Iustin Pop
    """
802 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_find", [disk.ToDict()])
803 d61cbe76 Iustin Pop
804 b2e7666a Iustin Pop
  def call_blockdev_close(self, node, instance_name, disks):
805 72737a7f Iustin Pop
    """Closes the given block devices.
806 d61cbe76 Iustin Pop

807 72737a7f Iustin Pop
    This is a single-node call.
808 d61cbe76 Iustin Pop

809 72737a7f Iustin Pop
    """
810 b2e7666a Iustin Pop
    params = [instance_name, [cf.ToDict() for cf in disks]]
811 b2e7666a Iustin Pop
    return self._SingleNodeCall(node, "blockdev_close", params)
812 a8083063 Iustin Pop
813 6b93ec9d Iustin Pop
  def call_drbd_disconnect_net(self, node_list, nodes_ip, disks):
814 6b93ec9d Iustin Pop
    """Disconnects the network of the given drbd devices.
815 6b93ec9d Iustin Pop

816 6b93ec9d Iustin Pop
    This is a multi-node call.
817 6b93ec9d Iustin Pop

818 6b93ec9d Iustin Pop
    """
819 6b93ec9d Iustin Pop
    return self._MultiNodeCall(node_list, "drbd_disconnect_net",
820 6b93ec9d Iustin Pop
                               [nodes_ip, [cf.ToDict() for cf in disks]])
821 6b93ec9d Iustin Pop
822 6b93ec9d Iustin Pop
  def call_drbd_attach_net(self, node_list, nodes_ip,
823 6b93ec9d Iustin Pop
                           disks, instance_name, multimaster):
824 6b93ec9d Iustin Pop
    """Disconnects the given drbd devices.
825 6b93ec9d Iustin Pop

826 6b93ec9d Iustin Pop
    This is a multi-node call.
827 6b93ec9d Iustin Pop

828 6b93ec9d Iustin Pop
    """
829 6b93ec9d Iustin Pop
    return self._MultiNodeCall(node_list, "drbd_attach_net",
830 6b93ec9d Iustin Pop
                               [nodes_ip, [cf.ToDict() for cf in disks],
831 6b93ec9d Iustin Pop
                                instance_name, multimaster])
832 6b93ec9d Iustin Pop
833 6b93ec9d Iustin Pop
  def call_drbd_wait_sync(self, node_list, nodes_ip, disks):
834 6b93ec9d Iustin Pop
    """Waits for the synchronization of drbd devices is complete.
835 6b93ec9d Iustin Pop

836 6b93ec9d Iustin Pop
    This is a multi-node call.
837 6b93ec9d Iustin Pop

838 6b93ec9d Iustin Pop
    """
839 6b93ec9d Iustin Pop
    return self._MultiNodeCall(node_list, "drbd_wait_sync",
840 6b93ec9d Iustin Pop
                               [nodes_ip, [cf.ToDict() for cf in disks]])
841 6b93ec9d Iustin Pop
842 9a525d83 Michael Hanselmann
  @classmethod
843 9a525d83 Michael Hanselmann
  def call_upload_file(cls, node_list, file_name, address_list=None):
844 72737a7f Iustin Pop
    """Upload a file.
845 72737a7f Iustin Pop

846 72737a7f Iustin Pop
    The node will refuse the operation in case the file is not on the
847 72737a7f Iustin Pop
    approved file list.
848 72737a7f Iustin Pop

849 72737a7f Iustin Pop
    This is a multi-node call.
850 a8083063 Iustin Pop

851 6b294c53 Iustin Pop
    @type node_list: list
852 6b294c53 Iustin Pop
    @param node_list: the list of node names to upload to
853 6b294c53 Iustin Pop
    @type file_name: str
854 6b294c53 Iustin Pop
    @param file_name: the filename to upload
855 6b294c53 Iustin Pop
    @type address_list: list or None
856 6b294c53 Iustin Pop
    @keyword address_list: an optional list of node addresses, in order
857 6b294c53 Iustin Pop
        to optimize the RPC speed
858 6b294c53 Iustin Pop

859 72737a7f Iustin Pop
    """
860 12bce260 Michael Hanselmann
    file_contents = utils.ReadFile(file_name)
861 12bce260 Michael Hanselmann
    data = cls._Compress(file_contents)
862 72737a7f Iustin Pop
    st = os.stat(file_name)
863 72737a7f Iustin Pop
    params = [file_name, data, st.st_mode, st.st_uid, st.st_gid,
864 72737a7f Iustin Pop
              st.st_atime, st.st_mtime]
865 9a525d83 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "upload_file", params,
866 9a525d83 Michael Hanselmann
                                    address_list=address_list)
867 72737a7f Iustin Pop
868 6ddc95ec Michael Hanselmann
  @classmethod
869 03d1dba2 Michael Hanselmann
  def call_write_ssconf_files(cls, node_list, values):
870 6ddc95ec Michael Hanselmann
    """Write ssconf files.
871 6ddc95ec Michael Hanselmann

872 6ddc95ec Michael Hanselmann
    This is a multi-node call.
873 6ddc95ec Michael Hanselmann

874 6ddc95ec Michael Hanselmann
    """
875 03d1dba2 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "write_ssconf_files", [values])
876 6ddc95ec Michael Hanselmann
877 72737a7f Iustin Pop
  def call_os_diagnose(self, node_list):
878 72737a7f Iustin Pop
    """Request a diagnose of OS definitions.
879 72737a7f Iustin Pop

880 72737a7f Iustin Pop
    This is a multi-node call.
881 a8083063 Iustin Pop

882 72737a7f Iustin Pop
    """
883 83d92ad8 Iustin Pop
    return self._MultiNodeCall(node_list, "os_diagnose", [])
884 a8083063 Iustin Pop
885 72737a7f Iustin Pop
  def call_os_get(self, node, name):
886 72737a7f Iustin Pop
    """Returns an OS definition.
887 a8083063 Iustin Pop

888 72737a7f Iustin Pop
    This is a single-node call.
889 a8083063 Iustin Pop

890 72737a7f Iustin Pop
    """
891 9a525d83 Michael Hanselmann
    result = self._SingleNodeCall(node, "os_get", [name])
892 781de953 Iustin Pop
    if not result.failed and isinstance(result.data, dict):
893 781de953 Iustin Pop
      result.data = objects.OS.FromDict(result.data)
894 781de953 Iustin Pop
    return result
895 a8083063 Iustin Pop
896 72737a7f Iustin Pop
  def call_hooks_runner(self, node_list, hpath, phase, env):
897 72737a7f Iustin Pop
    """Call the hooks runner.
898 a8083063 Iustin Pop

899 72737a7f Iustin Pop
    Args:
900 72737a7f Iustin Pop
      - op: the OpCode instance
901 72737a7f Iustin Pop
      - env: a dictionary with the environment
902 a8083063 Iustin Pop

903 72737a7f Iustin Pop
    This is a multi-node call.
904 a8083063 Iustin Pop

905 72737a7f Iustin Pop
    """
906 72737a7f Iustin Pop
    params = [hpath, phase, env]
907 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "hooks_runner", params)
908 a8083063 Iustin Pop
909 72737a7f Iustin Pop
  def call_iallocator_runner(self, node, name, idata):
910 72737a7f Iustin Pop
    """Call an iallocator on a remote node
911 8d528b7c Iustin Pop

912 72737a7f Iustin Pop
    Args:
913 72737a7f Iustin Pop
      - name: the iallocator name
914 72737a7f Iustin Pop
      - input: the json-encoded input string
915 8d528b7c Iustin Pop

916 72737a7f Iustin Pop
    This is a single-node call.
917 8d528b7c Iustin Pop

918 72737a7f Iustin Pop
    """
919 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "iallocator_runner", [name, idata])
920 8d528b7c Iustin Pop
921 72737a7f Iustin Pop
  def call_blockdev_grow(self, node, cf_bdev, amount):
922 72737a7f Iustin Pop
    """Request a snapshot of the given block device.
923 4c8ba8b3 Iustin Pop

924 72737a7f Iustin Pop
    This is a single-node call.
925 4c8ba8b3 Iustin Pop

926 72737a7f Iustin Pop
    """
927 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_grow",
928 9a525d83 Michael Hanselmann
                                [cf_bdev.ToDict(), amount])
929 4c8ba8b3 Iustin Pop
930 72737a7f Iustin Pop
  def call_blockdev_snapshot(self, node, cf_bdev):
931 72737a7f Iustin Pop
    """Request a snapshot of the given block device.
932 a8083063 Iustin Pop

933 72737a7f Iustin Pop
    This is a single-node call.
934 a8083063 Iustin Pop

935 72737a7f Iustin Pop
    """
936 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_snapshot", [cf_bdev.ToDict()])
937 a8083063 Iustin Pop
938 72737a7f Iustin Pop
  def call_snapshot_export(self, node, snap_bdev, dest_node, instance,
939 74c47259 Iustin Pop
                           cluster_name, idx):
940 72737a7f Iustin Pop
    """Request the export of a given snapshot.
941 a8083063 Iustin Pop

942 72737a7f Iustin Pop
    This is a single-node call.
943 a8083063 Iustin Pop

944 72737a7f Iustin Pop
    """
945 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "snapshot_export",
946 9a525d83 Michael Hanselmann
                                [snap_bdev.ToDict(), dest_node,
947 9a525d83 Michael Hanselmann
                                 self._InstDict(instance), cluster_name, idx])
948 a8083063 Iustin Pop
949 72737a7f Iustin Pop
  def call_finalize_export(self, node, instance, snap_disks):
950 72737a7f Iustin Pop
    """Request the completion of an export operation.
951 a8083063 Iustin Pop

952 72737a7f Iustin Pop
    This writes the export config file, etc.
953 a8083063 Iustin Pop

954 72737a7f Iustin Pop
    This is a single-node call.
955 a8083063 Iustin Pop

956 72737a7f Iustin Pop
    """
957 72737a7f Iustin Pop
    flat_disks = []
958 72737a7f Iustin Pop
    for disk in snap_disks:
959 a97da6b7 Iustin Pop
      if isinstance(disk, bool):
960 a97da6b7 Iustin Pop
        flat_disks.append(disk)
961 a97da6b7 Iustin Pop
      else:
962 a97da6b7 Iustin Pop
        flat_disks.append(disk.ToDict())
963 9a525d83 Michael Hanselmann
964 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "finalize_export",
965 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), flat_disks])
966 a8083063 Iustin Pop
967 72737a7f Iustin Pop
  def call_export_info(self, node, path):
968 72737a7f Iustin Pop
    """Queries the export information in a given path.
969 a8083063 Iustin Pop

970 72737a7f Iustin Pop
    This is a single-node call.
971 a8083063 Iustin Pop

972 72737a7f Iustin Pop
    """
973 3eccac06 Iustin Pop
    return self._SingleNodeCall(node, "export_info", [path])
974 a8083063 Iustin Pop
975 6c0af70e Guido Trotter
  def call_instance_os_import(self, node, inst, src_node, src_images,
976 6c0af70e Guido Trotter
                              cluster_name):
977 72737a7f Iustin Pop
    """Request the import of a backup into an instance.
978 a8083063 Iustin Pop

979 72737a7f Iustin Pop
    This is a single-node call.
980 a8083063 Iustin Pop

981 72737a7f Iustin Pop
    """
982 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_import",
983 9a525d83 Michael Hanselmann
                                [self._InstDict(inst), src_node, src_images,
984 9a525d83 Michael Hanselmann
                                 cluster_name])
985 a8083063 Iustin Pop
986 72737a7f Iustin Pop
  def call_export_list(self, node_list):
987 72737a7f Iustin Pop
    """Gets the stored exports list.
988 a8083063 Iustin Pop

989 72737a7f Iustin Pop
    This is a multi-node call.
990 a8083063 Iustin Pop

991 72737a7f Iustin Pop
    """
992 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "export_list", [])
993 a8083063 Iustin Pop
994 72737a7f Iustin Pop
  def call_export_remove(self, node, export):
995 72737a7f Iustin Pop
    """Requests removal of a given export.
996 a8083063 Iustin Pop

997 72737a7f Iustin Pop
    This is a single-node call.
998 a8083063 Iustin Pop

999 72737a7f Iustin Pop
    """
1000 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "export_remove", [export])
1001 a8083063 Iustin Pop
1002 9a525d83 Michael Hanselmann
  @classmethod
1003 9a525d83 Michael Hanselmann
  def call_node_leave_cluster(cls, node):
1004 72737a7f Iustin Pop
    """Requests a node to clean the cluster information it has.
1005 a8083063 Iustin Pop

1006 72737a7f Iustin Pop
    This will remove the configuration information from the ganeti data
1007 72737a7f Iustin Pop
    dir.
1008 a8083063 Iustin Pop

1009 72737a7f Iustin Pop
    This is a single-node call.
1010 a8083063 Iustin Pop

1011 72737a7f Iustin Pop
    """
1012 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "node_leave_cluster", [])
1013 dcb93971 Michael Hanselmann
1014 72737a7f Iustin Pop
  def call_node_volumes(self, node_list):
1015 72737a7f Iustin Pop
    """Gets all volumes on node(s).
1016 dcb93971 Michael Hanselmann

1017 72737a7f Iustin Pop
    This is a multi-node call.
1018 dcb93971 Michael Hanselmann

1019 72737a7f Iustin Pop
    """
1020 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "node_volumes", [])
1021 06009e27 Iustin Pop
1022 56aa9fd5 Iustin Pop
  def call_node_demote_from_mc(self, node):
1023 56aa9fd5 Iustin Pop
    """Demote a node from the master candidate role.
1024 56aa9fd5 Iustin Pop

1025 56aa9fd5 Iustin Pop
    This is a single-node call.
1026 56aa9fd5 Iustin Pop

1027 56aa9fd5 Iustin Pop
    """
1028 56aa9fd5 Iustin Pop
    return self._SingleNodeCall(node, "node_demote_from_mc", [])
1029 56aa9fd5 Iustin Pop
1030 f5118ade Iustin Pop
1031 f5118ade Iustin Pop
  def call_node_powercycle(self, node, hypervisor):
1032 f5118ade Iustin Pop
    """Tries to powercycle a node.
1033 f5118ade Iustin Pop

1034 f5118ade Iustin Pop
    This is a single-node call.
1035 f5118ade Iustin Pop

1036 f5118ade Iustin Pop
    """
1037 f5118ade Iustin Pop
    return self._SingleNodeCall(node, "node_powercycle", [hypervisor])
1038 f5118ade Iustin Pop
1039 f5118ade Iustin Pop
1040 72737a7f Iustin Pop
  def call_test_delay(self, node_list, duration):
1041 72737a7f Iustin Pop
    """Sleep for a fixed time on given node(s).
1042 06009e27 Iustin Pop

1043 72737a7f Iustin Pop
    This is a multi-node call.
1044 06009e27 Iustin Pop

1045 72737a7f Iustin Pop
    """
1046 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "test_delay", [duration])
1047 5e04ed8b Manuel Franceschini
1048 72737a7f Iustin Pop
  def call_file_storage_dir_create(self, node, file_storage_dir):
1049 72737a7f Iustin Pop
    """Create the given file storage directory.
1050 5e04ed8b Manuel Franceschini

1051 72737a7f Iustin Pop
    This is a single-node call.
1052 5e04ed8b Manuel Franceschini

1053 72737a7f Iustin Pop
    """
1054 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "file_storage_dir_create",
1055 9a525d83 Michael Hanselmann
                                [file_storage_dir])
1056 5e04ed8b Manuel Franceschini
1057 72737a7f Iustin Pop
  def call_file_storage_dir_remove(self, node, file_storage_dir):
1058 72737a7f Iustin Pop
    """Remove the given file storage directory.
1059 5e04ed8b Manuel Franceschini

1060 72737a7f Iustin Pop
    This is a single-node call.
1061 5e04ed8b Manuel Franceschini

1062 72737a7f Iustin Pop
    """
1063 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "file_storage_dir_remove",
1064 9a525d83 Michael Hanselmann
                                [file_storage_dir])
1065 5e04ed8b Manuel Franceschini
1066 72737a7f Iustin Pop
  def call_file_storage_dir_rename(self, node, old_file_storage_dir,
1067 72737a7f Iustin Pop
                                   new_file_storage_dir):
1068 72737a7f Iustin Pop
    """Rename file storage directory.
1069 5e04ed8b Manuel Franceschini

1070 72737a7f Iustin Pop
    This is a single-node call.
1071 5e04ed8b Manuel Franceschini

1072 72737a7f Iustin Pop
    """
1073 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "file_storage_dir_rename",
1074 9a525d83 Michael Hanselmann
                                [old_file_storage_dir, new_file_storage_dir])
1075 ca52cdeb Michael Hanselmann
1076 9a525d83 Michael Hanselmann
  @classmethod
1077 9a525d83 Michael Hanselmann
  def call_jobqueue_update(cls, node_list, address_list, file_name, content):
1078 72737a7f Iustin Pop
    """Update job queue.
1079 ca52cdeb Michael Hanselmann

1080 72737a7f Iustin Pop
    This is a multi-node call.
1081 ca52cdeb Michael Hanselmann

1082 72737a7f Iustin Pop
    """
1083 9a525d83 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "jobqueue_update",
1084 12bce260 Michael Hanselmann
                                    [file_name, cls._Compress(content)],
1085 9a525d83 Michael Hanselmann
                                    address_list=address_list)
1086 ca52cdeb Michael Hanselmann
1087 9a525d83 Michael Hanselmann
  @classmethod
1088 9a525d83 Michael Hanselmann
  def call_jobqueue_purge(cls, node):
1089 72737a7f Iustin Pop
    """Purge job queue.
1090 ca52cdeb Michael Hanselmann

1091 72737a7f Iustin Pop
    This is a single-node call.
1092 ca52cdeb Michael Hanselmann

1093 72737a7f Iustin Pop
    """
1094 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "jobqueue_purge", [])
1095 af5ebcb1 Michael Hanselmann
1096 9a525d83 Michael Hanselmann
  @classmethod
1097 dd875d32 Michael Hanselmann
  def call_jobqueue_rename(cls, node_list, address_list, rename):
1098 72737a7f Iustin Pop
    """Rename a job queue file.
1099 af5ebcb1 Michael Hanselmann

1100 72737a7f Iustin Pop
    This is a multi-node call.
1101 af5ebcb1 Michael Hanselmann

1102 72737a7f Iustin Pop
    """
1103 dd875d32 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "jobqueue_rename", rename,
1104 9a525d83 Michael Hanselmann
                                    address_list=address_list)
1105 6217e295 Iustin Pop
1106 9a525d83 Michael Hanselmann
  @classmethod
1107 9a525d83 Michael Hanselmann
  def call_jobqueue_set_drain(cls, node_list, drain_flag):
1108 5d672980 Iustin Pop
    """Set the drain flag on the queue.
1109 5d672980 Iustin Pop

1110 5d672980 Iustin Pop
    This is a multi-node call.
1111 5d672980 Iustin Pop

1112 5d672980 Iustin Pop
    @type node_list: list
1113 5d672980 Iustin Pop
    @param node_list: the list of nodes to query
1114 5d672980 Iustin Pop
    @type drain_flag: bool
1115 5d672980 Iustin Pop
    @param drain_flag: if True, will set the drain flag, otherwise reset it.
1116 5d672980 Iustin Pop

1117 5d672980 Iustin Pop
    """
1118 9a525d83 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "jobqueue_set_drain",
1119 9a525d83 Michael Hanselmann
                                    [drain_flag])
1120 5d672980 Iustin Pop
1121 6217e295 Iustin Pop
  def call_hypervisor_validate_params(self, node_list, hvname, hvparams):
1122 6217e295 Iustin Pop
    """Validate the hypervisor params.
1123 6217e295 Iustin Pop

1124 6217e295 Iustin Pop
    This is a multi-node call.
1125 6217e295 Iustin Pop

1126 6217e295 Iustin Pop
    @type node_list: list
1127 6217e295 Iustin Pop
    @param node_list: the list of nodes to query
1128 6217e295 Iustin Pop
    @type hvname: string
1129 6217e295 Iustin Pop
    @param hvname: the hypervisor name
1130 6217e295 Iustin Pop
    @type hvparams: dict
1131 6217e295 Iustin Pop
    @param hvparams: the hypervisor parameters to be validated
1132 6217e295 Iustin Pop

1133 6217e295 Iustin Pop
    """
1134 6217e295 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
1135 abe609b2 Guido Trotter
    hv_full = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
1136 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "hypervisor_validate_params",
1137 9a525d83 Michael Hanselmann
                               [hvname, hv_full])