Statistics
| Branch: | Tag: | Revision:

root / lib / rpc.py @ 3eccac06

History | View | Annotate | Download (33.3 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 81010134 Iustin Pop
import socket
35 58b311ca Iustin Pop
import logging
36 12bce260 Michael Hanselmann
import zlib
37 12bce260 Michael Hanselmann
import base64
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
from ganeti import utils
40 a8083063 Iustin Pop
from ganeti import objects
41 ecfe9491 Michael Hanselmann
from ganeti import http
42 7c28c575 Michael Hanselmann
from ganeti import serializer
43 eafd8762 Michael Hanselmann
from ganeti import constants
44 781de953 Iustin Pop
from ganeti import errors
45 a8083063 Iustin Pop
46 ae88ef45 Michael Hanselmann
import ganeti.http.client
47 ae88ef45 Michael Hanselmann
48 a8083063 Iustin Pop
49 4331f6cd Michael Hanselmann
# Module level variable
50 4331f6cd Michael Hanselmann
_http_manager = None
51 4331f6cd Michael Hanselmann
52 4331f6cd Michael Hanselmann
53 4331f6cd Michael Hanselmann
def Init():
54 4331f6cd Michael Hanselmann
  """Initializes the module-global HTTP client manager.
55 4331f6cd Michael Hanselmann

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

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

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

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

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

86 ed83f5cc Iustin Pop
  @ivar data: the data payload, for successfull results, or None
87 ed83f5cc Iustin Pop
  @type failed: boolean
88 ed83f5cc Iustin Pop
  @ivar failed: whether the operation failed at RPC level (not
89 ed83f5cc Iustin Pop
      application level on the remote node)
90 ed83f5cc Iustin Pop
  @ivar call: the name of the RPC call
91 ed83f5cc Iustin Pop
  @ivar node: the name of the node to which we made the call
92 ed83f5cc Iustin Pop
  @ivar offline: whether the operation failed because the node was
93 ed83f5cc Iustin Pop
      offline, as opposed to actual failure; offline=True will always
94 ed83f5cc Iustin Pop
      imply failed=True, in order to allow simpler checking if
95 ed83f5cc Iustin Pop
      the user doesn't care about the exact failure mode
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 ed83f5cc Iustin Pop
      self.error = "Node is marked offline"
107 f2def43a Iustin Pop
      self.data = self.payload = None
108 ed83f5cc Iustin Pop
    elif failed:
109 781de953 Iustin Pop
      self.error = data
110 f2def43a Iustin Pop
      self.data = self.payload = None
111 781de953 Iustin Pop
    else:
112 781de953 Iustin Pop
      self.data = data
113 781de953 Iustin Pop
      self.error = None
114 f2def43a Iustin Pop
      if isinstance(data, (tuple, list)) and len(data) == 2:
115 f2def43a Iustin Pop
        self.payload = data[1]
116 f2def43a Iustin Pop
      else:
117 f2def43a Iustin Pop
        self.payload = None
118 781de953 Iustin Pop
119 781de953 Iustin Pop
  def Raise(self):
120 781de953 Iustin Pop
    """If the result has failed, raise an OpExecError.
121 781de953 Iustin Pop

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

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

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

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

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

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

164 a8083063 Iustin Pop
  One current bug is that generic failure is still signalled by
165 a8083063 Iustin Pop
  'False' result, which is not good. This overloading of values can
166 a8083063 Iustin Pop
  cause bugs.
167 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

297 25348212 Iustin Pop
    @type client: L{Client}
298 25348212 Iustin Pop
    @param client: a C{Client} instance
299 25348212 Iustin Pop
    @type node_list: list
300 25348212 Iustin Pop
    @param node_list: the node list we should connect
301 84b45587 Iustin Pop
    @type call: string
302 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
303 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
304 25348212 Iustin Pop

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

327 25348212 Iustin Pop
    @type client: L{Client}
328 25348212 Iustin Pop
    @param client: a C{Client} instance
329 25348212 Iustin Pop
    @type node: str
330 25348212 Iustin Pop
    @param node: the node we should connect
331 84b45587 Iustin Pop
    @type call: string
332 84b45587 Iustin Pop
    @param call: the name of the remote procedure call, for filling in
333 84b45587 Iustin Pop
        correctly any eventual offline nodes' results
334 25348212 Iustin Pop

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

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

360 160e2921 Iustin Pop
    """
361 160e2921 Iustin Pop
    body = serializer.DumpJson(args, indent=False)
362 160e2921 Iustin Pop
    c = Client(procedure, body, utils.GetNodeDaemonPort())
363 9a525d83 Michael Hanselmann
    c.ConnectList(node_list, address_list=address_list)
364 9a525d83 Michael Hanselmann
    return c.GetResults()
365 9a525d83 Michael Hanselmann
366 9a525d83 Michael Hanselmann
  def _SingleNodeCall(self, node, procedure, args):
367 160e2921 Iustin Pop
    """Helper for making a single-node call
368 9a525d83 Michael Hanselmann

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

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

392 12bce260 Michael Hanselmann
    Small amounts of data are not compressed.
393 12bce260 Michael Hanselmann

394 12bce260 Michael Hanselmann
    @type data: str
395 12bce260 Michael Hanselmann
    @param data: Data
396 12bce260 Michael Hanselmann
    @rtype: tuple
397 12bce260 Michael Hanselmann
    @return: Encoded data to send
398 12bce260 Michael Hanselmann

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

415 72737a7f Iustin Pop
    This is a multi-node call.
416 a8083063 Iustin Pop

417 72737a7f Iustin Pop
    """
418 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "volume_list", [vg_name])
419 a8083063 Iustin Pop
420 72737a7f Iustin Pop
  def call_vg_list(self, node_list):
421 72737a7f Iustin Pop
    """Gets the volume group list.
422 a8083063 Iustin Pop

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

425 72737a7f Iustin Pop
    """
426 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "vg_list", [])
427 a8083063 Iustin Pop
428 72737a7f Iustin Pop
  def call_bridges_exist(self, node, bridges_list):
429 72737a7f Iustin Pop
    """Checks if a node has all the bridges given.
430 a8083063 Iustin Pop

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

435 72737a7f Iustin Pop
    This is a single-node call.
436 a8083063 Iustin Pop

437 72737a7f Iustin Pop
    """
438 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "bridges_exist", [bridges_list])
439 a8083063 Iustin Pop
440 0eca8e0c Iustin Pop
  def call_instance_start(self, node, instance, hvp, bep):
441 72737a7f Iustin Pop
    """Starts an instance.
442 a8083063 Iustin Pop

443 72737a7f Iustin Pop
    This is a single-node call.
444 a8083063 Iustin Pop

445 72737a7f Iustin Pop
    """
446 0eca8e0c Iustin Pop
    idict = self._InstDict(instance, hvp=hvp, bep=bep)
447 0eca8e0c Iustin Pop
    return self._SingleNodeCall(node, "instance_start", [idict])
448 a8083063 Iustin Pop
449 72737a7f Iustin Pop
  def call_instance_shutdown(self, node, instance):
450 72737a7f Iustin Pop
    """Stops an instance.
451 a8083063 Iustin Pop

452 72737a7f Iustin Pop
    This is a single-node call.
453 2a10865c Iustin Pop

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

461 6906a9d8 Guido Trotter
    This is a single-node call.
462 6906a9d8 Guido Trotter

463 6906a9d8 Guido Trotter
    @type node: string
464 6906a9d8 Guido Trotter
    @param node: the node on which the instance is currently running
465 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
466 6906a9d8 Guido Trotter
    @param instance: the instance definition
467 6906a9d8 Guido Trotter

468 6906a9d8 Guido Trotter
    """
469 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "migration_info",
470 6906a9d8 Guido Trotter
                                [self._InstDict(instance)])
471 6906a9d8 Guido Trotter
472 6906a9d8 Guido Trotter
  def call_accept_instance(self, node, instance, info, target):
473 6906a9d8 Guido Trotter
    """Prepare a node to accept an instance.
474 6906a9d8 Guido Trotter

475 6906a9d8 Guido Trotter
    This is a single-node call.
476 6906a9d8 Guido Trotter

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

486 6906a9d8 Guido Trotter
    """
487 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "accept_instance",
488 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, target])
489 6906a9d8 Guido Trotter
490 6906a9d8 Guido Trotter
  def call_finalize_migration(self, node, instance, info, success):
491 6906a9d8 Guido Trotter
    """Finalize any target-node migration specific operation.
492 6906a9d8 Guido Trotter

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

496 6906a9d8 Guido Trotter
    This is a single-node call.
497 6906a9d8 Guido Trotter

498 6906a9d8 Guido Trotter
    @type node: string
499 6906a9d8 Guido Trotter
    @param node: the target node for the migration
500 6906a9d8 Guido Trotter
    @type instance: C{objects.Instance}
501 6906a9d8 Guido Trotter
    @param instance: the instance definition
502 6906a9d8 Guido Trotter
    @type info: opaque/hypervisor specific (string/data)
503 6906a9d8 Guido Trotter
    @param info: result for the call_migration_info call
504 6906a9d8 Guido Trotter
    @type success: boolean
505 6906a9d8 Guido Trotter
    @param success: whether the migration was a success or a failure
506 6906a9d8 Guido Trotter

507 6906a9d8 Guido Trotter
    """
508 6906a9d8 Guido Trotter
    return self._SingleNodeCall(node, "finalize_migration",
509 6906a9d8 Guido Trotter
                                [self._InstDict(instance), info, success])
510 6906a9d8 Guido Trotter
511 72737a7f Iustin Pop
  def call_instance_migrate(self, node, instance, target, live):
512 72737a7f Iustin Pop
    """Migrate an instance.
513 2a10865c Iustin Pop

514 72737a7f Iustin Pop
    This is a single-node call.
515 2a10865c Iustin Pop

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

526 72737a7f Iustin Pop
    """
527 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_migrate",
528 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), target, live])
529 007a2f3e Alexander Schreiber
530 07813a9e Iustin Pop
  def call_instance_reboot(self, node, instance, reboot_type):
531 72737a7f Iustin Pop
    """Reboots an instance.
532 007a2f3e Alexander Schreiber

533 72737a7f Iustin Pop
    This is a single-node call.
534 a8083063 Iustin Pop

535 72737a7f Iustin Pop
    """
536 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_reboot",
537 07813a9e Iustin Pop
                                [self._InstDict(instance), reboot_type])
538 a8083063 Iustin Pop
539 e557bae9 Guido Trotter
  def call_instance_os_add(self, node, inst, reinstall):
540 72737a7f Iustin Pop
    """Installs an OS on the given instance.
541 a8083063 Iustin Pop

542 72737a7f Iustin Pop
    This is a single-node call.
543 decd5f45 Iustin Pop

544 72737a7f Iustin Pop
    """
545 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_os_add",
546 e557bae9 Guido Trotter
                                [self._InstDict(inst), reinstall])
547 decd5f45 Iustin Pop
548 d15a9ad3 Guido Trotter
  def call_instance_run_rename(self, node, inst, old_name):
549 72737a7f Iustin Pop
    """Run the OS rename script for an instance.
550 decd5f45 Iustin Pop

551 72737a7f Iustin Pop
    This is a single-node call.
552 a8083063 Iustin Pop

553 72737a7f Iustin Pop
    """
554 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_run_rename",
555 9a525d83 Michael Hanselmann
                                [self._InstDict(inst), old_name])
556 a8083063 Iustin Pop
557 72737a7f Iustin Pop
  def call_instance_info(self, node, instance, hname):
558 72737a7f Iustin Pop
    """Returns information about a single instance.
559 a8083063 Iustin Pop

560 72737a7f Iustin Pop
    This is a single-node call.
561 a8083063 Iustin Pop

562 9a525d83 Michael Hanselmann
    @type node: list
563 9a525d83 Michael Hanselmann
    @param node: the list of nodes to query
564 72737a7f Iustin Pop
    @type instance: string
565 72737a7f Iustin Pop
    @param instance: the instance name
566 72737a7f Iustin Pop
    @type hname: string
567 72737a7f Iustin Pop
    @param hname: the hypervisor type of the instance
568 a8083063 Iustin Pop

569 72737a7f Iustin Pop
    """
570 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "instance_info", [instance, hname])
571 e69d05fd Iustin Pop
572 56e7640c Iustin Pop
  def call_instance_migratable(self, node, instance):
573 56e7640c Iustin Pop
    """Checks whether the given instance can be migrated.
574 56e7640c Iustin Pop

575 56e7640c Iustin Pop
    This is a single-node call.
576 56e7640c Iustin Pop

577 56e7640c Iustin Pop
    @param node: the node to query
578 56e7640c Iustin Pop
    @type instance: L{objects.Instance}
579 56e7640c Iustin Pop
    @param instance: the instance to check
580 56e7640c Iustin Pop

581 56e7640c Iustin Pop

582 56e7640c Iustin Pop
    """
583 56e7640c Iustin Pop
    return self._SingleNodeCall(node, "instance_migratable",
584 56e7640c Iustin Pop
                                [self._InstDict(instance)])
585 56e7640c Iustin Pop
586 72737a7f Iustin Pop
  def call_all_instances_info(self, node_list, hypervisor_list):
587 72737a7f Iustin Pop
    """Returns information about all instances on the given nodes.
588 a8083063 Iustin Pop

589 72737a7f Iustin Pop
    This is a multi-node call.
590 a8083063 Iustin Pop

591 72737a7f Iustin Pop
    @type node_list: list
592 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
593 72737a7f Iustin Pop
    @type hypervisor_list: list
594 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
595 a8083063 Iustin Pop

596 72737a7f Iustin Pop
    """
597 9a525d83 Michael Hanselmann
    return self._MultiNodeCall(node_list, "all_instances_info",
598 9a525d83 Michael Hanselmann
                               [hypervisor_list])
599 e69d05fd Iustin Pop
600 72737a7f Iustin Pop
  def call_instance_list(self, node_list, hypervisor_list):
601 72737a7f Iustin Pop
    """Returns the list of running instances on a given node.
602 a8083063 Iustin Pop

603 72737a7f Iustin Pop
    This is a multi-node call.
604 a8083063 Iustin Pop

605 72737a7f Iustin Pop
    @type node_list: list
606 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
607 72737a7f Iustin Pop
    @type hypervisor_list: list
608 72737a7f Iustin Pop
    @param hypervisor_list: the hypervisors to query for instances
609 16abfbc2 Alexander Schreiber

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

617 72737a7f Iustin Pop
    This is a single-node call.
618 caad16e2 Iustin Pop

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

627 caad16e2 Iustin Pop
    This is a single-node call.
628 caad16e2 Iustin Pop

629 caad16e2 Iustin Pop
    """
630 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "node_has_ip_address", [address])
631 a8083063 Iustin Pop
632 72737a7f Iustin Pop
  def call_node_info(self, node_list, vg_name, hypervisor_type):
633 72737a7f Iustin Pop
    """Return node information.
634 e69d05fd Iustin Pop

635 72737a7f Iustin Pop
    This will return memory information and volume group size and free
636 72737a7f Iustin Pop
    space.
637 a8083063 Iustin Pop

638 72737a7f Iustin Pop
    This is a multi-node call.
639 a8083063 Iustin Pop

640 72737a7f Iustin Pop
    @type node_list: list
641 72737a7f Iustin Pop
    @param node_list: the list of nodes to query
642 c41eea6e Iustin Pop
    @type vg_name: C{string}
643 c41eea6e Iustin Pop
    @param vg_name: the name of the volume group to ask for disk space
644 72737a7f Iustin Pop
        information
645 72737a7f Iustin Pop
    @type hypervisor_type: C{str}
646 72737a7f Iustin Pop
    @param hypervisor_type: the name of the hypervisor to ask for
647 72737a7f Iustin Pop
        memory information
648 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

895 72737a7f Iustin Pop
    This is a single-node call.
896 a8083063 Iustin Pop

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

906 72737a7f Iustin Pop
    Args:
907 72737a7f Iustin Pop
      - op: the OpCode instance
908 72737a7f Iustin Pop
      - env: a dictionary with the environment
909 a8083063 Iustin Pop

910 72737a7f Iustin Pop
    This is a multi-node call.
911 a8083063 Iustin Pop

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

919 72737a7f Iustin Pop
    Args:
920 72737a7f Iustin Pop
      - name: the iallocator name
921 72737a7f Iustin Pop
      - input: the json-encoded input string
922 8d528b7c Iustin Pop

923 72737a7f Iustin Pop
    This is a single-node call.
924 8d528b7c Iustin Pop

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

931 72737a7f Iustin Pop
    This is a single-node call.
932 4c8ba8b3 Iustin Pop

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

940 72737a7f Iustin Pop
    This is a single-node call.
941 a8083063 Iustin Pop

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

949 72737a7f Iustin Pop
    This is a single-node call.
950 a8083063 Iustin Pop

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

959 72737a7f Iustin Pop
    This writes the export config file, etc.
960 a8083063 Iustin Pop

961 72737a7f Iustin Pop
    This is a single-node call.
962 a8083063 Iustin Pop

963 72737a7f Iustin Pop
    """
964 72737a7f Iustin Pop
    flat_disks = []
965 72737a7f Iustin Pop
    for disk in snap_disks:
966 72737a7f Iustin Pop
      flat_disks.append(disk.ToDict())
967 9a525d83 Michael Hanselmann
968 9a525d83 Michael Hanselmann
    return self._SingleNodeCall(node, "finalize_export",
969 9a525d83 Michael Hanselmann
                                [self._InstDict(instance), flat_disks])
970 a8083063 Iustin Pop
971 72737a7f Iustin Pop
  def call_export_info(self, node, path):
972 72737a7f Iustin Pop
    """Queries the export information in a given path.
973 a8083063 Iustin Pop

974 72737a7f Iustin Pop
    This is a single-node call.
975 a8083063 Iustin Pop

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

983 72737a7f Iustin Pop
    This is a single-node call.
984 a8083063 Iustin Pop

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

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

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

1001 72737a7f Iustin Pop
    This is a single-node call.
1002 a8083063 Iustin Pop

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

1010 72737a7f Iustin Pop
    This will remove the configuration information from the ganeti data
1011 72737a7f Iustin Pop
    dir.
1012 a8083063 Iustin Pop

1013 72737a7f Iustin Pop
    This is a single-node call.
1014 a8083063 Iustin Pop

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

1021 72737a7f Iustin Pop
    This is a multi-node call.
1022 dcb93971 Michael Hanselmann

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

1029 56aa9fd5 Iustin Pop
    This is a single-node call.
1030 56aa9fd5 Iustin Pop

1031 56aa9fd5 Iustin Pop
    """
1032 56aa9fd5 Iustin Pop
    return self._SingleNodeCall(node, "node_demote_from_mc", [])
1033 56aa9fd5 Iustin Pop
1034 f5118ade Iustin Pop
1035 f5118ade Iustin Pop
  def call_node_powercycle(self, node, hypervisor):
1036 f5118ade Iustin Pop
    """Tries to powercycle a node.
1037 f5118ade Iustin Pop

1038 f5118ade Iustin Pop
    This is a single-node call.
1039 f5118ade Iustin Pop

1040 f5118ade Iustin Pop
    """
1041 f5118ade Iustin Pop
    return self._SingleNodeCall(node, "node_powercycle", [hypervisor])
1042 f5118ade Iustin Pop
1043 f5118ade 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 abe609b2 Guido Trotter
    hv_full = objects.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])