Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ f95c81bf

History | View | Annotate | Download (33.4 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 ed83f5cc Iustin Pop
  @ivar failed: whether the operation failed at RPC 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 ed83f5cc Iustin Pop

96 781de953 Iustin Pop
  """
97 ed83f5cc Iustin Pop
  def __init__(self, data=None, failed=False, offline=False,
98 ed83f5cc Iustin Pop
               call=None, node=None):
99 781de953 Iustin Pop
    self.failed = failed
100 ed83f5cc Iustin Pop
    self.offline = offline
101 ed83f5cc Iustin Pop
    self.call = call
102 ed83f5cc Iustin Pop
    self.node = node
103 ed83f5cc Iustin Pop
    if offline:
104 ed83f5cc Iustin Pop
      self.failed = True
105 ed83f5cc Iustin Pop
      self.error = "Node is marked offline"
106 f2def43a Iustin Pop
      self.data = self.payload = None
107 ed83f5cc Iustin Pop
    elif failed:
108 781de953 Iustin Pop
      self.error = data
109 f2def43a Iustin Pop
      self.data = self.payload = None
110 781de953 Iustin Pop
    else:
111 781de953 Iustin Pop
      self.data = data
112 781de953 Iustin Pop
      self.error = None
113 f2def43a Iustin Pop
      if isinstance(data, (tuple, list)) and len(data) == 2:
114 f2def43a Iustin Pop
        self.payload = data[1]
115 f2def43a Iustin Pop
      else:
116 f2def43a Iustin Pop
        self.payload = None
117 781de953 Iustin Pop
118 781de953 Iustin Pop
  def Raise(self):
119 781de953 Iustin Pop
    """If the result has failed, raise an OpExecError.
120 781de953 Iustin Pop

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

124 781de953 Iustin Pop
    """
125 781de953 Iustin Pop
    if self.failed:
126 781de953 Iustin Pop
      raise errors.OpExecError("Call '%s' to node '%s' has failed: %s" %
127 781de953 Iustin Pop
                               (self.call, self.node, self.error))
128 781de953 Iustin Pop
129 3247bbac Iustin Pop
  def RemoteFailMsg(self):
130 3247bbac Iustin Pop
    """Check if the remote procedure failed.
131 3247bbac Iustin Pop

132 3247bbac Iustin Pop
    This is valid only for RPC calls which return result of the form
133 3247bbac Iustin Pop
    (status, data | error_msg).
134 3247bbac Iustin Pop

135 3247bbac Iustin Pop
    @return: empty string for succcess, otherwise an error message
136 3247bbac Iustin Pop

137 3247bbac Iustin Pop
    """
138 3247bbac Iustin Pop
    def _EnsureErr(val):
139 3247bbac Iustin Pop
      """Helper to ensure we return a 'True' value for error."""
140 3247bbac Iustin Pop
      if val:
141 3247bbac Iustin Pop
        return val
142 3247bbac Iustin Pop
      else:
143 3247bbac Iustin Pop
        return "No error information"
144 3247bbac Iustin Pop
145 3247bbac Iustin Pop
    if self.failed:
146 3247bbac Iustin Pop
      return _EnsureErr(self.error)
147 3247bbac Iustin Pop
    if not isinstance(self.data, (tuple, list)):
148 3247bbac Iustin Pop
      return "Invalid result type (%s)" % type(self.data)
149 3247bbac Iustin Pop
    if len(self.data) != 2:
150 3247bbac Iustin Pop
      return "Invalid result length (%d), expected 2" % len(self.data)
151 3247bbac Iustin Pop
    if not self.data[0]:
152 3247bbac Iustin Pop
      return _EnsureErr(self.data[1])
153 3247bbac Iustin Pop
    return ""
154 3247bbac Iustin Pop
155 781de953 Iustin Pop
156 a8083063 Iustin Pop
class Client:
157 a8083063 Iustin Pop
  """RPC Client class.
158 a8083063 Iustin Pop

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

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

167 a8083063 Iustin Pop
  """
168 160e2921 Iustin Pop
  def __init__(self, procedure, body, port):
169 a8083063 Iustin Pop
    self.procedure = procedure
170 160e2921 Iustin Pop
    self.body = body
171 160e2921 Iustin Pop
    self.port = port
172 ecfe9491 Michael Hanselmann
    self.nc = {}
173 a8083063 Iustin Pop
174 d57ae7f7 Michael Hanselmann
    self._ssl_params = \
175 d57ae7f7 Michael Hanselmann
      http.HttpSslParams(ssl_key_path=constants.SSL_CERT_FILE,
176 d57ae7f7 Michael Hanselmann
                         ssl_cert_path=constants.SSL_CERT_FILE)
177 d57ae7f7 Michael Hanselmann
178 bdf7d8c0 Iustin Pop
  def ConnectList(self, node_list, address_list=None):
179 a8083063 Iustin Pop
    """Add a list of nodes to the target nodes.
180 a8083063 Iustin Pop

181 3ef3c771 Iustin Pop
    @type node_list: list
182 3ef3c771 Iustin Pop
    @param node_list: the list of node names to connect
183 bdf7d8c0 Iustin Pop
    @type address_list: list or None
184 bdf7d8c0 Iustin Pop
    @keyword address_list: either None or a list with node addresses,
185 bdf7d8c0 Iustin Pop
        which must have the same length as the node list
186 3ef3c771 Iustin Pop

187 a8083063 Iustin Pop
    """
188 bdf7d8c0 Iustin Pop
    if address_list is None:
189 bdf7d8c0 Iustin Pop
      address_list = [None for _ in node_list]
190 bdf7d8c0 Iustin Pop
    else:
191 bdf7d8c0 Iustin Pop
      assert len(node_list) == len(address_list), \
192 bdf7d8c0 Iustin Pop
             "Name and address lists should have the same length"
193 bdf7d8c0 Iustin Pop
    for node, address in zip(node_list, address_list):
194 bdf7d8c0 Iustin Pop
      self.ConnectNode(node, address)
195 bdf7d8c0 Iustin Pop
196 bdf7d8c0 Iustin Pop
  def ConnectNode(self, name, address=None):
197 a8083063 Iustin Pop
    """Add a node to the target list.
198 a8083063 Iustin Pop

199 bdf7d8c0 Iustin Pop
    @type name: str
200 bdf7d8c0 Iustin Pop
    @param name: the node name
201 bdf7d8c0 Iustin Pop
    @type address: str
202 bdf7d8c0 Iustin Pop
    @keyword address: the node address, if known
203 bdf7d8c0 Iustin Pop

204 a8083063 Iustin Pop
    """
205 ecfe9491 Michael Hanselmann
    if address is None:
206 ecfe9491 Michael Hanselmann
      address = name
207 ecfe9491 Michael Hanselmann
208 ae88ef45 Michael Hanselmann
    self.nc[name] = \
209 ae88ef45 Michael Hanselmann
      http.client.HttpClientRequest(address, self.port, http.HTTP_PUT,
210 ae88ef45 Michael Hanselmann
                                    "/%s" % self.procedure,
211 ae88ef45 Michael Hanselmann
                                    post_data=self.body,
212 ae88ef45 Michael Hanselmann
                                    ssl_params=self._ssl_params,
213 ae88ef45 Michael Hanselmann
                                    ssl_verify_peer=True)
214 a8083063 Iustin Pop
215 3ef3c771 Iustin Pop
  def GetResults(self):
216 ecfe9491 Michael Hanselmann
    """Call nodes and return results.
217 ecfe9491 Michael Hanselmann

218 ecfe9491 Michael Hanselmann
    @rtype: list
219 5fcc718f Iustin Pop
    @return: List of RPC results
220 a8083063 Iustin Pop

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

254 72737a7f Iustin Pop
    @type cfg:  C{config.ConfigWriter}
255 72737a7f Iustin Pop
    @param cfg: the configuration object that will be used to get data
256 72737a7f Iustin Pop
                about the cluster
257 a8083063 Iustin Pop

258 72737a7f Iustin Pop
    """
259 72737a7f Iustin Pop
    self._cfg = cfg
260 160e2921 Iustin Pop
    self.port = utils.GetNodeDaemonPort()
261 a8083063 Iustin Pop
262 0eca8e0c Iustin Pop
  def _InstDict(self, instance, hvp=None, bep=None):
263 26ba2bd8 Iustin Pop
    """Convert the given instance to a dict.
264 26ba2bd8 Iustin Pop

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

268 26ba2bd8 Iustin Pop
    @type instance: L{objects.Instance}
269 26ba2bd8 Iustin Pop
    @param instance: an Instance object
270 0eca8e0c Iustin Pop
    @type hvp: dict or None
271 5bbd3f7f Michael Hanselmann
    @param hvp: a dictionary with overridden hypervisor parameters
272 0eca8e0c Iustin Pop
    @type bep: dict or None
273 5bbd3f7f Michael Hanselmann
    @param bep: a dictionary with overridden backend parameters
274 26ba2bd8 Iustin Pop
    @rtype: dict
275 26ba2bd8 Iustin Pop
    @return: the instance dict, with the hvparams filled with the
276 26ba2bd8 Iustin Pop
        cluster defaults
277 26ba2bd8 Iustin Pop

278 26ba2bd8 Iustin Pop
    """
279 26ba2bd8 Iustin Pop
    idict = instance.ToDict()
280 5b442704 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
281 5b442704 Iustin Pop
    idict["hvparams"] = cluster.FillHV(instance)
282 0eca8e0c Iustin Pop
    if hvp is not None:
283 0eca8e0c Iustin Pop
      idict["hvparams"].update(hvp)
284 5b442704 Iustin Pop
    idict["beparams"] = cluster.FillBE(instance)
285 0eca8e0c Iustin Pop
    if bep is not None:
286 0eca8e0c Iustin Pop
      idict["beparams"].update(bep)
287 26ba2bd8 Iustin Pop
    return idict
288 26ba2bd8 Iustin Pop
289 84b45587 Iustin Pop
  def _ConnectList(self, client, node_list, call):
290 25348212 Iustin Pop
    """Helper for computing node addresses.
291 25348212 Iustin Pop

292 6af6270a Iustin Pop
    @type client: L{ganeti.rpc.Client}
293 25348212 Iustin Pop
    @param client: a C{Client} instance
294 25348212 Iustin Pop
    @type node_list: list
295 25348212 Iustin Pop
    @param node_list: the node list we should connect
296 84b45587 Iustin Pop
    @type call: string
297 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
298 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
299 25348212 Iustin Pop

300 25348212 Iustin Pop
    """
301 25348212 Iustin Pop
    all_nodes = self._cfg.GetAllNodesInfo()
302 ed83f5cc Iustin Pop
    name_list = []
303 25348212 Iustin Pop
    addr_list = []
304 ed83f5cc Iustin Pop
    skip_dict = {}
305 25348212 Iustin Pop
    for node in node_list:
306 25348212 Iustin Pop
      if node in all_nodes:
307 ed83f5cc Iustin Pop
        if all_nodes[node].offline:
308 84b45587 Iustin Pop
          skip_dict[node] = RpcResult(node=node, offline=True, call=call)
309 ed83f5cc Iustin Pop
          continue
310 25348212 Iustin Pop
        val = all_nodes[node].primary_ip
311 25348212 Iustin Pop
      else:
312 25348212 Iustin Pop
        val = None
313 25348212 Iustin Pop
      addr_list.append(val)
314 ed83f5cc Iustin Pop
      name_list.append(node)
315 ed83f5cc Iustin Pop
    if name_list:
316 ed83f5cc Iustin Pop
      client.ConnectList(name_list, address_list=addr_list)
317 ed83f5cc Iustin Pop
    return skip_dict
318 25348212 Iustin Pop
319 84b45587 Iustin Pop
  def _ConnectNode(self, client, node, call):
320 25348212 Iustin Pop
    """Helper for computing one node's address.
321 25348212 Iustin Pop

322 6af6270a Iustin Pop
    @type client: L{ganeti.rpc.Client}
323 25348212 Iustin Pop
    @param client: a C{Client} instance
324 25348212 Iustin Pop
    @type node: str
325 25348212 Iustin Pop
    @param node: the node we should connect
326 84b45587 Iustin Pop
    @type call: string
327 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
328 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
329 25348212 Iustin Pop

330 25348212 Iustin Pop
    """
331 25348212 Iustin Pop
    node_info = self._cfg.GetNodeInfo(node)
332 25348212 Iustin Pop
    if node_info is not None:
333 ed83f5cc Iustin Pop
      if node_info.offline:
334 84b45587 Iustin Pop
        return RpcResult(node=node, offline=True, call=call)
335 25348212 Iustin Pop
      addr = node_info.primary_ip
336 25348212 Iustin Pop
    else:
337 25348212 Iustin Pop
      addr = None
338 25348212 Iustin Pop
    client.ConnectNode(node, address=addr)
339 25348212 Iustin Pop
340 ed83f5cc Iustin Pop
  def _MultiNodeCall(self, node_list, procedure, args):
341 160e2921 Iustin Pop
    """Helper for making a multi-node call
342 160e2921 Iustin Pop

343 160e2921 Iustin Pop
    """
344 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
345 160e2921 Iustin Pop
    c = Client(procedure, body, self.port)
346 84b45587 Iustin Pop
    skip_dict = self._ConnectList(c, node_list, procedure)
347 ed83f5cc Iustin Pop
    skip_dict.update(c.GetResults())
348 ed83f5cc Iustin Pop
    return skip_dict
349 9a525d83 Michael Hanselmann
350 9a525d83 Michael Hanselmann
  @classmethod
351 9a525d83 Michael Hanselmann
  def _StaticMultiNodeCall(cls, node_list, procedure, args,
352 9a525d83 Michael Hanselmann
                           address_list=None):
353 160e2921 Iustin Pop
    """Helper for making a multi-node static 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, utils.GetNodeDaemonPort())
358 9a525d83 Michael Hanselmann
    c.ConnectList(node_list, address_list=address_list)
359 9a525d83 Michael Hanselmann
    return c.GetResults()
360 9a525d83 Michael Hanselmann
361 9a525d83 Michael Hanselmann
  def _SingleNodeCall(self, node, procedure, args):
362 160e2921 Iustin Pop
    """Helper for making a single-node call
363 9a525d83 Michael Hanselmann

364 9a525d83 Michael Hanselmann
    """
365 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
366 160e2921 Iustin Pop
    c = Client(procedure, body, self.port)
367 84b45587 Iustin Pop
    result = self._ConnectNode(c, node, procedure)
368 ed83f5cc Iustin Pop
    if result is None:
369 ed83f5cc Iustin Pop
      # we did connect, node is not offline
370 ed83f5cc Iustin Pop
      result = c.GetResults()[node]
371 ed83f5cc Iustin Pop
    return result
372 9a525d83 Michael Hanselmann
373 9a525d83 Michael Hanselmann
  @classmethod
374 9a525d83 Michael Hanselmann
  def _StaticSingleNodeCall(cls, node, procedure, args):
375 160e2921 Iustin Pop
    """Helper for making a single-node static call
376 9a525d83 Michael Hanselmann

377 9a525d83 Michael Hanselmann
    """
378 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
379 160e2921 Iustin Pop
    c = Client(procedure, body, utils.GetNodeDaemonPort())
380 3097c858 Michael Hanselmann
    c.ConnectNode(node)
381 ed83f5cc Iustin Pop
    return c.GetResults()[node]
382 9a525d83 Michael Hanselmann
383 12bce260 Michael Hanselmann
  @staticmethod
384 12bce260 Michael Hanselmann
  def _Compress(data):
385 12bce260 Michael Hanselmann
    """Compresses a string for transport over RPC.
386 12bce260 Michael Hanselmann

387 12bce260 Michael Hanselmann
    Small amounts of data are not compressed.
388 12bce260 Michael Hanselmann

389 12bce260 Michael Hanselmann
    @type data: str
390 12bce260 Michael Hanselmann
    @param data: Data
391 12bce260 Michael Hanselmann
    @rtype: tuple
392 12bce260 Michael Hanselmann
    @return: Encoded data to send
393 12bce260 Michael Hanselmann

394 12bce260 Michael Hanselmann
    """
395 12bce260 Michael Hanselmann
    # Small amounts of data are not compressed
396 12bce260 Michael Hanselmann
    if len(data) < 512:
397 12bce260 Michael Hanselmann
      return (constants.RPC_ENCODING_NONE, data)
398 12bce260 Michael Hanselmann
399 12bce260 Michael Hanselmann
    # Compress with zlib and encode in base64
400 12bce260 Michael Hanselmann
    return (constants.RPC_ENCODING_ZLIB_BASE64,
401 12bce260 Michael Hanselmann
            base64.b64encode(zlib.compress(data, 3)))
402 12bce260 Michael Hanselmann
403 781de953 Iustin Pop
  #
404 781de953 Iustin Pop
  # Begin RPC calls
405 781de953 Iustin Pop
  #
406 781de953 Iustin Pop
407 72737a7f Iustin Pop
  def call_volume_list(self, node_list, vg_name):
408 72737a7f Iustin Pop
    """Gets the logical volumes present in a given volume group.
409 a8083063 Iustin Pop

410 72737a7f Iustin Pop
    This is a multi-node call.
411 a8083063 Iustin Pop

412 72737a7f Iustin Pop
    """
413 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "volume_list", [vg_name])
414 a8083063 Iustin Pop
415 72737a7f Iustin Pop
  def call_vg_list(self, node_list):
416 72737a7f Iustin Pop
    """Gets the volume group list.
417 a8083063 Iustin Pop

418 72737a7f Iustin Pop
    This is a multi-node call.
419 a8083063 Iustin Pop

420 72737a7f Iustin Pop
    """
421 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "vg_list", [])
422 a8083063 Iustin Pop
423 72737a7f Iustin Pop
  def call_bridges_exist(self, node, bridges_list):
424 72737a7f Iustin Pop
    """Checks if a node has all the bridges given.
425 a8083063 Iustin Pop

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

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

432 72737a7f Iustin Pop
    """
433 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "bridges_exist", [bridges_list])
434 a8083063 Iustin Pop
435 0eca8e0c Iustin Pop
  def call_instance_start(self, node, instance, hvp, bep):
436 72737a7f Iustin Pop
    """Starts an instance.
437 a8083063 Iustin Pop

438 72737a7f Iustin Pop
    This is a single-node call.
439 a8083063 Iustin Pop

440 72737a7f Iustin Pop
    """
441 0eca8e0c Iustin Pop
    idict = self._InstDict(instance, hvp=hvp, bep=bep)
442 0eca8e0c Iustin Pop
    return self._SingleNodeCall(node, "instance_start", [idict])
443 a8083063 Iustin Pop
444 72737a7f Iustin Pop
  def call_instance_shutdown(self, node, instance):
445 72737a7f Iustin Pop
    """Stops an instance.
446 a8083063 Iustin Pop

447 72737a7f Iustin Pop
    This is a single-node call.
448 2a10865c Iustin Pop

449 72737a7f Iustin Pop
    """
450 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_shutdown",
451 9a525d83 Michael Hanselmann
                                [self._InstDict(instance)])
452 2a10865c Iustin Pop
453 6906a9d8 Guido Trotter
  def call_migration_info(self, node, instance):
454 6906a9d8 Guido Trotter
    """Gather the information necessary to prepare an instance migration.
455 6906a9d8 Guido Trotter

456 6906a9d8 Guido Trotter
    This is a single-node call.
457 6906a9d8 Guido Trotter

458 6906a9d8 Guido Trotter
    @type node: string
459 6906a9d8 Guido Trotter
    @param node: the node on which the instance is currently running
460 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
461 6906a9d8 Guido Trotter
    @param instance: the instance definition
462 6906a9d8 Guido Trotter

463 6906a9d8 Guido Trotter
    """
464 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "migration_info",
465 6906a9d8 Guido Trotter
                                [self._InstDict(instance)])
466 6906a9d8 Guido Trotter
467 6906a9d8 Guido Trotter
  def call_accept_instance(self, node, instance, info, target):
468 6906a9d8 Guido Trotter
    """Prepare a node to accept an instance.
469 6906a9d8 Guido Trotter

470 6906a9d8 Guido Trotter
    This is a single-node call.
471 6906a9d8 Guido Trotter

472 6906a9d8 Guido Trotter
    @type node: string
473 6906a9d8 Guido Trotter
    @param node: the target node for the migration
474 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
475 6906a9d8 Guido Trotter
    @param instance: the instance definition
476 6906a9d8 Guido Trotter
    @type info: opaque/hypervisor specific (string/data)
477 6906a9d8 Guido Trotter
    @param info: result for the call_migration_info call
478 6906a9d8 Guido Trotter
    @type target: string
479 6906a9d8 Guido Trotter
    @param target: target hostname (usually ip address) (on the node itself)
480 6906a9d8 Guido Trotter

481 6906a9d8 Guido Trotter
    """
482 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "accept_instance",
483 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, target])
484 6906a9d8 Guido Trotter
485 6906a9d8 Guido Trotter
  def call_finalize_migration(self, node, instance, info, success):
486 6906a9d8 Guido Trotter
    """Finalize any target-node migration specific operation.
487 6906a9d8 Guido Trotter

488 6906a9d8 Guido Trotter
    This is called both in case of a successful migration and in case of error
489 6906a9d8 Guido Trotter
    (in which case it should abort the migration).
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 success: boolean
500 6906a9d8 Guido Trotter
    @param success: whether the migration was a success or a failure
501 6906a9d8 Guido Trotter

502 6906a9d8 Guido Trotter
    """
503 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "finalize_migration",
504 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, success])
505 6906a9d8 Guido Trotter
506 72737a7f Iustin Pop
  def call_instance_migrate(self, node, instance, target, live):
507 72737a7f Iustin Pop
    """Migrate an instance.
508 2a10865c Iustin Pop

509 72737a7f Iustin Pop
    This is a single-node call.
510 2a10865c Iustin Pop

511 72737a7f Iustin Pop
    @type node: string
512 72737a7f Iustin Pop
    @param node: the node on which the instance is currently running
513 72737a7f Iustin Pop
    @type instance: C{objects.Instance}
514 72737a7f Iustin Pop
    @param instance: the instance definition
515 72737a7f Iustin Pop
    @type target: string
516 72737a7f Iustin Pop
    @param target: the target node name
517 72737a7f Iustin Pop
    @type live: boolean
518 72737a7f Iustin Pop
    @param live: whether the migration should be done live or not (the
519 72737a7f Iustin Pop
        interpretation of this parameter is left to the hypervisor)
520 007a2f3e Alexander Schreiber

521 72737a7f Iustin Pop
    """
522 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_migrate",
523 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), target, live])
524 007a2f3e Alexander Schreiber
525 07813a9e Iustin Pop
  def call_instance_reboot(self, node, instance, reboot_type):
526 72737a7f Iustin Pop
    """Reboots an instance.
527 007a2f3e Alexander Schreiber

528 72737a7f Iustin Pop
    This is a single-node call.
529 a8083063 Iustin Pop

530 72737a7f Iustin Pop
    """
531 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_reboot",
532 07813a9e Iustin Pop
                                [self._InstDict(instance), reboot_type])
533 a8083063 Iustin Pop
534 d15a9ad3 Guido Trotter
  def call_instance_os_add(self, node, inst):
535 72737a7f Iustin Pop
    """Installs an OS on the given instance.
536 a8083063 Iustin Pop

537 72737a7f Iustin Pop
    This is a single-node call.
538 decd5f45 Iustin Pop

539 72737a7f Iustin Pop
    """
540 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_add",
541 9a525d83 Michael Hanselmann
                                [self._InstDict(inst)])
542 decd5f45 Iustin Pop
543 d15a9ad3 Guido Trotter
  def call_instance_run_rename(self, node, inst, old_name):
544 72737a7f Iustin Pop
    """Run the OS rename script for an instance.
545 decd5f45 Iustin Pop

546 72737a7f Iustin Pop
    This is a single-node call.
547 a8083063 Iustin Pop

548 72737a7f Iustin Pop
    """
549 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_run_rename",
550 9a525d83 Michael Hanselmann
                                [self._InstDict(inst), old_name])
551 a8083063 Iustin Pop
552 72737a7f Iustin Pop
  def call_instance_info(self, node, instance, hname):
553 72737a7f Iustin Pop
    """Returns information about a single instance.
554 a8083063 Iustin Pop

555 72737a7f Iustin Pop
    This is a single-node call.
556 a8083063 Iustin Pop

557 9a525d83 Michael Hanselmann
    @type node: list
558 9a525d83 Michael Hanselmann
    @param node: the list of nodes to query
559 72737a7f Iustin Pop
    @type instance: string
560 72737a7f Iustin Pop
    @param instance: the instance name
561 72737a7f Iustin Pop
    @type hname: string
562 72737a7f Iustin Pop
    @param hname: the hypervisor type of the instance
563 a8083063 Iustin Pop

564 72737a7f Iustin Pop
    """
565 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_info", [instance, hname])
566 e69d05fd Iustin Pop
567 56e7640c Iustin Pop
  def call_instance_migratable(self, node, instance):
568 56e7640c Iustin Pop
    """Checks whether the given instance can be migrated.
569 56e7640c Iustin Pop

570 56e7640c Iustin Pop
    This is a single-node call.
571 56e7640c Iustin Pop

572 56e7640c Iustin Pop
    @param node: the node to query
573 56e7640c Iustin Pop
    @type instance: L{objects.Instance}
574 56e7640c Iustin Pop
    @param instance: the instance to check
575 56e7640c Iustin Pop

576 56e7640c Iustin Pop

577 56e7640c Iustin Pop
    """
578 56e7640c Iustin Pop
    return self._SingleNodeCall(node, "instance_migratable",
579 56e7640c Iustin Pop
                                [self._InstDict(instance)])
580 56e7640c Iustin Pop
581 72737a7f Iustin Pop
  def call_all_instances_info(self, node_list, hypervisor_list):
582 72737a7f Iustin Pop
    """Returns information about all instances on the given nodes.
583 a8083063 Iustin Pop

584 72737a7f Iustin Pop
    This is a multi-node call.
585 a8083063 Iustin Pop

586 72737a7f Iustin Pop
    @type node_list: list
587 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
588 72737a7f Iustin Pop
    @type hypervisor_list: list
589 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
590 a8083063 Iustin Pop

591 72737a7f Iustin Pop
    """
592 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "all_instances_info",
593 9a525d83 Michael Hanselmann
                               [hypervisor_list])
594 e69d05fd Iustin Pop
595 72737a7f Iustin Pop
  def call_instance_list(self, node_list, hypervisor_list):
596 72737a7f Iustin Pop
    """Returns the list of running instances on a given node.
597 a8083063 Iustin Pop

598 72737a7f Iustin Pop
    This is a multi-node call.
599 a8083063 Iustin Pop

600 72737a7f Iustin Pop
    @type node_list: list
601 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
602 72737a7f Iustin Pop
    @type hypervisor_list: list
603 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
604 16abfbc2 Alexander Schreiber

605 72737a7f Iustin Pop
    """
606 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "instance_list", [hypervisor_list])
607 16abfbc2 Alexander Schreiber
608 72737a7f Iustin Pop
  def call_node_tcp_ping(self, node, source, target, port, timeout,
609 72737a7f Iustin Pop
                         live_port_needed):
610 72737a7f Iustin Pop
    """Do a TcpPing on the remote node
611 a8083063 Iustin Pop

612 72737a7f Iustin Pop
    This is a single-node call.
613 caad16e2 Iustin Pop

614 72737a7f Iustin Pop
    """
615 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_tcp_ping",
616 9a525d83 Michael Hanselmann
                                [source, target, port, timeout,
617 72737a7f Iustin Pop
                                 live_port_needed])
618 a8083063 Iustin Pop
619 caad16e2 Iustin Pop
  def call_node_has_ip_address(self, node, address):
620 caad16e2 Iustin Pop
    """Checks if a node has the given IP address.
621 caad16e2 Iustin Pop

622 caad16e2 Iustin Pop
    This is a single-node call.
623 caad16e2 Iustin Pop

624 caad16e2 Iustin Pop
    """
625 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_has_ip_address", [address])
626 a8083063 Iustin Pop
627 72737a7f Iustin Pop
  def call_node_info(self, node_list, vg_name, hypervisor_type):
628 72737a7f Iustin Pop
    """Return node information.
629 e69d05fd Iustin Pop

630 72737a7f Iustin Pop
    This will return memory information and volume group size and free
631 72737a7f Iustin Pop
    space.
632 a8083063 Iustin Pop

633 72737a7f Iustin Pop
    This is a multi-node call.
634 a8083063 Iustin Pop

635 72737a7f Iustin Pop
    @type node_list: list
636 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
637 c41eea6e Iustin Pop
    @type vg_name: C{string}
638 c41eea6e Iustin Pop
    @param vg_name: the name of the volume group to ask for disk space
639 72737a7f Iustin Pop
        information
640 72737a7f Iustin Pop
    @type hypervisor_type: C{str}
641 72737a7f Iustin Pop
    @param hypervisor_type: the name of the hypervisor to ask for
642 72737a7f Iustin Pop
        memory information
643 a8083063 Iustin Pop

644 72737a7f Iustin Pop
    """
645 9a525d83 Michael Hanselmann
    retux = self._MultiNodeCall(node_list, "node_info",
646 9a525d83 Michael Hanselmann
                                [vg_name, hypervisor_type])
647 a8083063 Iustin Pop
648 781de953 Iustin Pop
    for result in retux.itervalues():
649 781de953 Iustin Pop
      if result.failed or not isinstance(result.data, dict):
650 781de953 Iustin Pop
        result.data = {}
651 186ec53c Iustin Pop
      if result.offline:
652 186ec53c Iustin Pop
        log_name = None
653 186ec53c Iustin Pop
      else:
654 186ec53c Iustin Pop
        log_name = "call_node_info"
655 781de953 Iustin Pop
656 781de953 Iustin Pop
      utils.CheckDict(result.data, {
657 781de953 Iustin Pop
        'memory_total' : '-',
658 781de953 Iustin Pop
        'memory_dom0' : '-',
659 781de953 Iustin Pop
        'memory_free' : '-',
660 781de953 Iustin Pop
        'vg_size' : 'node_unreachable',
661 781de953 Iustin Pop
        'vg_free' : '-',
662 186ec53c Iustin Pop
        }, log_name)
663 72737a7f Iustin Pop
    return retux
664 a8083063 Iustin Pop
665 72737a7f Iustin Pop
  def call_node_add(self, node, dsa, dsapub, rsa, rsapub, ssh, sshpub):
666 72737a7f Iustin Pop
    """Add a node to the cluster.
667 a8083063 Iustin Pop

668 72737a7f Iustin Pop
    This is a single-node call.
669 a8083063 Iustin Pop

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

677 72737a7f Iustin Pop
    This is a multi-node call.
678 a8083063 Iustin Pop

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

687 72737a7f Iustin Pop
    This is a single-node call.
688 a8083063 Iustin Pop

689 72737a7f Iustin Pop
    """
690 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "node_start_master",
691 2503680f Guido Trotter
                                     [start_daemons, no_voting])
692 a8083063 Iustin Pop
693 9a525d83 Michael Hanselmann
  @classmethod
694 9a525d83 Michael Hanselmann
  def call_node_stop_master(cls, node, stop_daemons):
695 72737a7f Iustin Pop
    """Tells a node to demote itself from master status.
696 a8083063 Iustin Pop

697 72737a7f Iustin Pop
    This is a single-node call.
698 4e071d3b Iustin Pop

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

706 72737a7f Iustin Pop
    This is a multi-node call.
707 a8083063 Iustin Pop

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

715 72737a7f Iustin Pop
    This is a multi-node call.
716 a8083063 Iustin Pop

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

723 72737a7f Iustin Pop
    This is a single-node call.
724 a8083063 Iustin Pop

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

732 72737a7f Iustin Pop
    This is a single-node call.
733 f3e513ad Iustin Pop

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

740 72737a7f Iustin Pop
    This is a single-node call.
741 a8083063 Iustin Pop

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

749 72737a7f Iustin Pop
    This is a single-node call.
750 a8083063 Iustin Pop

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

758 72737a7f Iustin Pop
    This is a single-node call.
759 a8083063 Iustin Pop

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

766 72737a7f Iustin Pop
    This is a single-node call.
767 a8083063 Iustin Pop

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

776 72737a7f Iustin Pop
    This is a single-node call.
777 a8083063 Iustin Pop

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

786 72737a7f Iustin Pop
    This is a single-node call.
787 a8083063 Iustin Pop

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

795 72737a7f Iustin Pop
    This is a single-node call.
796 a8083063 Iustin Pop

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

803 72737a7f Iustin Pop
    This is a single-node call.
804 d61cbe76 Iustin Pop

805 72737a7f Iustin Pop
    """
806 b2e7666a Iustin Pop
    params = [instance_name, [cf.ToDict() for cf in disks]]
807 b2e7666a Iustin Pop
    return self._SingleNodeCall(node, "blockdev_close", params)
808 a8083063 Iustin Pop
809 968a7623 Iustin Pop
  def call_blockdev_getsizes(self, node, disks):
810 968a7623 Iustin Pop
    """Returns the size of the given disks.
811 968a7623 Iustin Pop

812 968a7623 Iustin Pop
    This is a single-node call.
813 968a7623 Iustin Pop

814 968a7623 Iustin Pop
    """
815 968a7623 Iustin Pop
    params = [[cf.ToDict() for cf in disks]]
816 968a7623 Iustin Pop
    return self._SingleNodeCall(node, "blockdev_getsize", params)
817 968a7623 Iustin Pop
818 6b93ec9d Iustin Pop
  def call_drbd_disconnect_net(self, node_list, nodes_ip, disks):
819 6b93ec9d Iustin Pop
    """Disconnects the network of the given drbd devices.
820 6b93ec9d Iustin Pop

821 6b93ec9d Iustin Pop
    This is a multi-node call.
822 6b93ec9d Iustin Pop

823 6b93ec9d Iustin Pop
    """
824 6b93ec9d Iustin Pop
    return self._MultiNodeCall(node_list, "drbd_disconnect_net",
825 6b93ec9d Iustin Pop
                               [nodes_ip, [cf.ToDict() for cf in disks]])
826 6b93ec9d Iustin Pop
827 6b93ec9d Iustin Pop
  def call_drbd_attach_net(self, node_list, nodes_ip,
828 6b93ec9d Iustin Pop
                           disks, instance_name, multimaster):
829 6b93ec9d Iustin Pop
    """Disconnects the given drbd devices.
830 6b93ec9d Iustin Pop

831 6b93ec9d Iustin Pop
    This is a multi-node call.
832 6b93ec9d Iustin Pop

833 6b93ec9d Iustin Pop
    """
834 6b93ec9d Iustin Pop
    return self._MultiNodeCall(node_list, "drbd_attach_net",
835 6b93ec9d Iustin Pop
                               [nodes_ip, [cf.ToDict() for cf in disks],
836 6b93ec9d Iustin Pop
                                instance_name, multimaster])
837 6b93ec9d Iustin Pop
838 6b93ec9d Iustin Pop
  def call_drbd_wait_sync(self, node_list, nodes_ip, disks):
839 6b93ec9d Iustin Pop
    """Waits for the synchronization of drbd devices is complete.
840 6b93ec9d Iustin Pop

841 6b93ec9d Iustin Pop
    This is a multi-node call.
842 6b93ec9d Iustin Pop

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

851 72737a7f Iustin Pop
    The node will refuse the operation in case the file is not on the
852 72737a7f Iustin Pop
    approved file list.
853 72737a7f Iustin Pop

854 72737a7f Iustin Pop
    This is a multi-node call.
855 a8083063 Iustin Pop

856 6b294c53 Iustin Pop
    @type node_list: list
857 6b294c53 Iustin Pop
    @param node_list: the list of node names to upload to
858 6b294c53 Iustin Pop
    @type file_name: str
859 6b294c53 Iustin Pop
    @param file_name: the filename to upload
860 6b294c53 Iustin Pop
    @type address_list: list or None
861 6b294c53 Iustin Pop
    @keyword address_list: an optional list of node addresses, in order
862 6b294c53 Iustin Pop
        to optimize the RPC speed
863 6b294c53 Iustin Pop

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

877 6ddc95ec Michael Hanselmann
    This is a multi-node call.
878 6ddc95ec Michael Hanselmann

879 6ddc95ec Michael Hanselmann
    """
880 03d1dba2 Michael Hanselmann
    return cls._StaticMultiNodeCall(node_list, "write_ssconf_files", [values])
881 6ddc95ec Michael Hanselmann
882 72737a7f Iustin Pop
  def call_os_diagnose(self, node_list):
883 72737a7f Iustin Pop
    """Request a diagnose of OS definitions.
884 72737a7f Iustin Pop

885 72737a7f Iustin Pop
    This is a multi-node call.
886 a8083063 Iustin Pop

887 72737a7f Iustin Pop
    """
888 9a525d83 Michael Hanselmann
    result = self._MultiNodeCall(node_list, "os_diagnose", [])
889 9a525d83 Michael Hanselmann
890 fab1e3a4 Iustin Pop
    for node_result in result.values():
891 781de953 Iustin Pop
      if not node_result.failed and node_result.data:
892 781de953 Iustin Pop
        node_result.data = [objects.OS.FromDict(oss)
893 781de953 Iustin Pop
                            for oss in node_result.data]
894 781de953 Iustin Pop
    return result
895 a8083063 Iustin Pop
896 72737a7f Iustin Pop
  def call_os_get(self, node, name):
897 72737a7f Iustin Pop
    """Returns an OS definition.
898 a8083063 Iustin Pop

899 72737a7f Iustin Pop
    This is a single-node call.
900 a8083063 Iustin Pop

901 72737a7f Iustin Pop
    """
902 9a525d83 Michael Hanselmann
    result = self._SingleNodeCall(node, "os_get", [name])
903 781de953 Iustin Pop
    if not result.failed and isinstance(result.data, dict):
904 781de953 Iustin Pop
      result.data = objects.OS.FromDict(result.data)
905 781de953 Iustin Pop
    return result
906 a8083063 Iustin Pop
907 72737a7f Iustin Pop
  def call_hooks_runner(self, node_list, hpath, phase, env):
908 72737a7f Iustin Pop
    """Call the hooks runner.
909 a8083063 Iustin Pop

910 72737a7f Iustin Pop
    Args:
911 72737a7f Iustin Pop
      - op: the OpCode instance
912 72737a7f Iustin Pop
      - env: a dictionary with the environment
913 a8083063 Iustin Pop

914 72737a7f Iustin Pop
    This is a multi-node call.
915 a8083063 Iustin Pop

916 72737a7f Iustin Pop
    """
917 72737a7f Iustin Pop
    params = [hpath, phase, env]
918 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "hooks_runner", params)
919 a8083063 Iustin Pop
920 72737a7f Iustin Pop
  def call_iallocator_runner(self, node, name, idata):
921 72737a7f Iustin Pop
    """Call an iallocator on a remote node
922 8d528b7c Iustin Pop

923 72737a7f Iustin Pop
    Args:
924 72737a7f Iustin Pop
      - name: the iallocator name
925 72737a7f Iustin Pop
      - input: the json-encoded input string
926 8d528b7c Iustin Pop

927 72737a7f Iustin Pop
    This is a single-node call.
928 8d528b7c Iustin Pop

929 72737a7f Iustin Pop
    """
930 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "iallocator_runner", [name, idata])
931 8d528b7c Iustin Pop
932 72737a7f Iustin Pop
  def call_blockdev_grow(self, node, cf_bdev, amount):
933 72737a7f Iustin Pop
    """Request a snapshot of the given block device.
934 4c8ba8b3 Iustin Pop

935 72737a7f Iustin Pop
    This is a single-node call.
936 4c8ba8b3 Iustin Pop

937 72737a7f Iustin Pop
    """
938 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_grow",
939 9a525d83 Michael Hanselmann
                                [cf_bdev.ToDict(), amount])
940 4c8ba8b3 Iustin Pop
941 72737a7f Iustin Pop
  def call_blockdev_snapshot(self, node, cf_bdev):
942 72737a7f Iustin Pop
    """Request a snapshot of the given block device.
943 a8083063 Iustin Pop

944 72737a7f Iustin Pop
    This is a single-node call.
945 a8083063 Iustin Pop

946 72737a7f Iustin Pop
    """
947 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "blockdev_snapshot", [cf_bdev.ToDict()])
948 a8083063 Iustin Pop
949 72737a7f Iustin Pop
  def call_snapshot_export(self, node, snap_bdev, dest_node, instance,
950 74c47259 Iustin Pop
                           cluster_name, idx):
951 72737a7f Iustin Pop
    """Request the export of a given snapshot.
952 a8083063 Iustin Pop

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

955 72737a7f Iustin Pop
    """
956 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "snapshot_export",
957 9a525d83 Michael Hanselmann
                                [snap_bdev.ToDict(), dest_node,
958 9a525d83 Michael Hanselmann
                                 self._InstDict(instance), cluster_name, idx])
959 a8083063 Iustin Pop
960 72737a7f Iustin Pop
  def call_finalize_export(self, node, instance, snap_disks):
961 72737a7f Iustin Pop
    """Request the completion of an export operation.
962 a8083063 Iustin Pop

963 72737a7f Iustin Pop
    This writes the export config file, etc.
964 a8083063 Iustin Pop

965 72737a7f Iustin Pop
    This is a single-node call.
966 a8083063 Iustin Pop

967 72737a7f Iustin Pop
    """
968 72737a7f Iustin Pop
    flat_disks = []
969 72737a7f Iustin Pop
    for disk in snap_disks:
970 a97da6b7 Iustin Pop
      if isinstance(disk, bool):
971 a97da6b7 Iustin Pop
        flat_disks.append(disk)
972 a97da6b7 Iustin Pop
      else:
973 a97da6b7 Iustin Pop
        flat_disks.append(disk.ToDict())
974 9a525d83 Michael Hanselmann
975 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "finalize_export",
976 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), flat_disks])
977 a8083063 Iustin Pop
978 72737a7f Iustin Pop
  def call_export_info(self, node, path):
979 72737a7f Iustin Pop
    """Queries the export information in a given path.
980 a8083063 Iustin Pop

981 72737a7f Iustin Pop
    This is a single-node call.
982 a8083063 Iustin Pop

983 72737a7f Iustin Pop
    """
984 9a525d83 Michael Hanselmann
    result = self._SingleNodeCall(node, "export_info", [path])
985 781de953 Iustin Pop
    if not result.failed and result.data:
986 781de953 Iustin Pop
      result.data = objects.SerializableConfigParser.Loads(str(result.data))
987 781de953 Iustin Pop
    return result
988 a8083063 Iustin Pop
989 6c0af70e Guido Trotter
  def call_instance_os_import(self, node, inst, src_node, src_images,
990 6c0af70e Guido Trotter
                              cluster_name):
991 72737a7f Iustin Pop
    """Request the import of a backup into an instance.
992 a8083063 Iustin Pop

993 72737a7f Iustin Pop
    This is a single-node call.
994 a8083063 Iustin Pop

995 72737a7f Iustin Pop
    """
996 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_import",
997 9a525d83 Michael Hanselmann
                                [self._InstDict(inst), src_node, src_images,
998 9a525d83 Michael Hanselmann
                                 cluster_name])
999 a8083063 Iustin Pop
1000 72737a7f Iustin Pop
  def call_export_list(self, node_list):
1001 72737a7f Iustin Pop
    """Gets the stored exports list.
1002 a8083063 Iustin Pop

1003 72737a7f Iustin Pop
    This is a multi-node call.
1004 a8083063 Iustin Pop

1005 72737a7f Iustin Pop
    """
1006 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "export_list", [])
1007 a8083063 Iustin Pop
1008 72737a7f Iustin Pop
  def call_export_remove(self, node, export):
1009 72737a7f Iustin Pop
    """Requests removal of a given export.
1010 a8083063 Iustin Pop

1011 72737a7f Iustin Pop
    This is a single-node call.
1012 a8083063 Iustin Pop

1013 72737a7f Iustin Pop
    """
1014 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "export_remove", [export])
1015 a8083063 Iustin Pop
1016 9a525d83 Michael Hanselmann
  @classmethod
1017 9a525d83 Michael Hanselmann
  def call_node_leave_cluster(cls, node):
1018 72737a7f Iustin Pop
    """Requests a node to clean the cluster information it has.
1019 a8083063 Iustin Pop

1020 72737a7f Iustin Pop
    This will remove the configuration information from the ganeti data
1021 72737a7f Iustin Pop
    dir.
1022 a8083063 Iustin Pop

1023 72737a7f Iustin Pop
    This is a single-node call.
1024 a8083063 Iustin Pop

1025 72737a7f Iustin Pop
    """
1026 9a525d83 Michael Hanselmann
    return cls._StaticSingleNodeCall(node, "node_leave_cluster", [])
1027 dcb93971 Michael Hanselmann
1028 72737a7f Iustin Pop
  def call_node_volumes(self, node_list):
1029 72737a7f Iustin Pop
    """Gets all volumes on node(s).
1030 dcb93971 Michael Hanselmann

1031 72737a7f Iustin Pop
    This is a multi-node call.
1032 dcb93971 Michael Hanselmann

1033 72737a7f Iustin Pop
    """
1034 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "node_volumes", [])
1035 06009e27 Iustin Pop
1036 56aa9fd5 Iustin Pop
  def call_node_demote_from_mc(self, node):
1037 56aa9fd5 Iustin Pop
    """Demote a node from the master candidate role.
1038 56aa9fd5 Iustin Pop

1039 56aa9fd5 Iustin Pop
    This is a single-node call.
1040 56aa9fd5 Iustin Pop

1041 56aa9fd5 Iustin Pop
    """
1042 56aa9fd5 Iustin Pop
    return self._SingleNodeCall(node, "node_demote_from_mc", [])
1043 56aa9fd5 Iustin Pop
1044 72737a7f Iustin Pop
  def call_test_delay(self, node_list, duration):
1045 72737a7f Iustin Pop
    """Sleep for a fixed time on given node(s).
1046 06009e27 Iustin Pop

1047 72737a7f Iustin Pop
    This is a multi-node call.
1048 06009e27 Iustin Pop

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

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

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

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

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

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

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

1084 72737a7f Iustin Pop
    This is a multi-node call.
1085 ca52cdeb Michael Hanselmann

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

1095 72737a7f Iustin Pop
    This is a single-node call.
1096 ca52cdeb Michael Hanselmann

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

1104 72737a7f Iustin Pop
    This is a multi-node call.
1105 af5ebcb1 Michael Hanselmann

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

1114 5d672980 Iustin Pop
    This is a multi-node call.
1115 5d672980 Iustin Pop

1116 5d672980 Iustin Pop
    @type node_list: list
1117 5d672980 Iustin Pop
    @param node_list: the list of nodes to query
1118 5d672980 Iustin Pop
    @type drain_flag: bool
1119 5d672980 Iustin Pop
    @param drain_flag: if True, will set the drain flag, otherwise reset it.
1120 5d672980 Iustin Pop

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

1128 6217e295 Iustin Pop
    This is a multi-node call.
1129 6217e295 Iustin Pop

1130 6217e295 Iustin Pop
    @type node_list: list
1131 6217e295 Iustin Pop
    @param node_list: the list of nodes to query
1132 6217e295 Iustin Pop
    @type hvname: string
1133 6217e295 Iustin Pop
    @param hvname: the hypervisor name
1134 6217e295 Iustin Pop
    @type hvparams: dict
1135 6217e295 Iustin Pop
    @param hvparams: the hypervisor parameters to be validated
1136 6217e295 Iustin Pop

1137 6217e295 Iustin Pop
    """
1138 6217e295 Iustin Pop
    cluster = self._cfg.GetClusterInfo()
1139 6217e295 Iustin Pop
    hv_full = cluster.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
1140 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "hypervisor_validate_params",
1141 9a525d83 Michael Hanselmann
                               [hvname, hv_full])