Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ 0436da49

History | View | Annotate | Download (108.7 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 397693d3 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 360b0dc2 Iustin Pop
"""Functions used by the node daemon
23 360b0dc2 Iustin Pop

24 360b0dc2 Iustin Pop
@var _ALLOWED_UPLOAD_FILES: denotes which files are accepted in
25 360b0dc2 Iustin Pop
     the L{UploadFile} function
26 714ea7ca Iustin Pop
@var _ALLOWED_CLEAN_DIRS: denotes which directories are accepted
27 714ea7ca Iustin Pop
     in the L{_CleanDirectory} function
28 360b0dc2 Iustin Pop

29 360b0dc2 Iustin Pop
"""
30 a8083063 Iustin Pop
31 b459a848 Andrea Spadaccini
# pylint: disable=E1103
32 6c881c52 Iustin Pop
33 6c881c52 Iustin Pop
# E1103: %s %r has no %r member (but some types could not be
34 6c881c52 Iustin Pop
# inferred), because the _TryOSFromDisk returns either (True, os_obj)
35 6c881c52 Iustin Pop
# or (False, "string") which confuses pylint
36 6c881c52 Iustin Pop
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
import os
39 a8083063 Iustin Pop
import os.path
40 a8083063 Iustin Pop
import shutil
41 a8083063 Iustin Pop
import time
42 a8083063 Iustin Pop
import stat
43 a8083063 Iustin Pop
import errno
44 a8083063 Iustin Pop
import re
45 b544cfe0 Iustin Pop
import random
46 18682bca Iustin Pop
import logging
47 3b9e6a30 Iustin Pop
import tempfile
48 12bce260 Michael Hanselmann
import zlib
49 12bce260 Michael Hanselmann
import base64
50 f81c4737 Michael Hanselmann
import signal
51 a8083063 Iustin Pop
52 a8083063 Iustin Pop
from ganeti import errors
53 a8083063 Iustin Pop
from ganeti import utils
54 a8083063 Iustin Pop
from ganeti import ssh
55 a8083063 Iustin Pop
from ganeti import hypervisor
56 a8083063 Iustin Pop
from ganeti import constants
57 a8083063 Iustin Pop
from ganeti import bdev
58 a8083063 Iustin Pop
from ganeti import objects
59 880478f8 Iustin Pop
from ganeti import ssconf
60 1651d116 Michael Hanselmann
from ganeti import serializer
61 a744b676 Manuel Franceschini
from ganeti import netutils
62 82b22e19 René Nussbaumer
from ganeti import runtime
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
65 13998ef2 Michael Hanselmann
_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id"
66 714ea7ca Iustin Pop
_ALLOWED_CLEAN_DIRS = frozenset([
67 714ea7ca Iustin Pop
  constants.DATA_DIR,
68 714ea7ca Iustin Pop
  constants.JOB_QUEUE_ARCHIVE_DIR,
69 714ea7ca Iustin Pop
  constants.QUEUE_DIR,
70 f942a838 Michael Hanselmann
  constants.CRYPTO_KEYS_DIR,
71 714ea7ca Iustin Pop
  ])
72 f942a838 Michael Hanselmann
_MAX_SSL_CERT_VALIDITY = 7 * 24 * 60 * 60
73 f942a838 Michael Hanselmann
_X509_KEY_FILE = "key"
74 f942a838 Michael Hanselmann
_X509_CERT_FILE = "cert"
75 1651d116 Michael Hanselmann
_IES_STATUS_FILE = "status"
76 1651d116 Michael Hanselmann
_IES_PID_FILE = "pid"
77 1651d116 Michael Hanselmann
_IES_CA_FILE = "ca"
78 13998ef2 Michael Hanselmann
79 0b5303da Iustin Pop
#: Valid LVS output line regex
80 84d7e26b Dmitry Chernyak
_LVSLINE_REGEX = re.compile("^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6})\|?$")
81 0b5303da Iustin Pop
82 13998ef2 Michael Hanselmann
83 2cc6781a Iustin Pop
class RPCFail(Exception):
84 2cc6781a Iustin Pop
  """Class denoting RPC failure.
85 2cc6781a Iustin Pop

86 2cc6781a Iustin Pop
  Its argument is the error message.
87 2cc6781a Iustin Pop

88 2cc6781a Iustin Pop
  """
89 2cc6781a Iustin Pop
90 13998ef2 Michael Hanselmann
91 2cc6781a Iustin Pop
def _Fail(msg, *args, **kwargs):
92 2cc6781a Iustin Pop
  """Log an error and the raise an RPCFail exception.
93 2cc6781a Iustin Pop

94 2cc6781a Iustin Pop
  This exception is then handled specially in the ganeti daemon and
95 2cc6781a Iustin Pop
  turned into a 'failed' return type. As such, this function is a
96 2cc6781a Iustin Pop
  useful shortcut for logging the error and returning it to the master
97 2cc6781a Iustin Pop
  daemon.
98 2cc6781a Iustin Pop

99 2cc6781a Iustin Pop
  @type msg: string
100 2cc6781a Iustin Pop
  @param msg: the text of the exception
101 2cc6781a Iustin Pop
  @raise RPCFail
102 2cc6781a Iustin Pop

103 2cc6781a Iustin Pop
  """
104 2cc6781a Iustin Pop
  if args:
105 2cc6781a Iustin Pop
    msg = msg % args
106 afdc3985 Iustin Pop
  if "log" not in kwargs or kwargs["log"]: # if we should log this error
107 afdc3985 Iustin Pop
    if "exc" in kwargs and kwargs["exc"]:
108 afdc3985 Iustin Pop
      logging.exception(msg)
109 afdc3985 Iustin Pop
    else:
110 afdc3985 Iustin Pop
      logging.error(msg)
111 2cc6781a Iustin Pop
  raise RPCFail(msg)
112 2cc6781a Iustin Pop
113 2cc6781a Iustin Pop
114 c657dcc9 Michael Hanselmann
def _GetConfig():
115 93384844 Iustin Pop
  """Simple wrapper to return a SimpleStore.
116 10c2650b Iustin Pop

117 93384844 Iustin Pop
  @rtype: L{ssconf.SimpleStore}
118 93384844 Iustin Pop
  @return: a SimpleStore instance
119 10c2650b Iustin Pop

120 10c2650b Iustin Pop
  """
121 93384844 Iustin Pop
  return ssconf.SimpleStore()
122 c657dcc9 Michael Hanselmann
123 c657dcc9 Michael Hanselmann
124 62c9ec92 Iustin Pop
def _GetSshRunner(cluster_name):
125 10c2650b Iustin Pop
  """Simple wrapper to return an SshRunner.
126 10c2650b Iustin Pop

127 10c2650b Iustin Pop
  @type cluster_name: str
128 10c2650b Iustin Pop
  @param cluster_name: the cluster name, which is needed
129 10c2650b Iustin Pop
      by the SshRunner constructor
130 10c2650b Iustin Pop
  @rtype: L{ssh.SshRunner}
131 10c2650b Iustin Pop
  @return: an SshRunner instance
132 10c2650b Iustin Pop

133 10c2650b Iustin Pop
  """
134 62c9ec92 Iustin Pop
  return ssh.SshRunner(cluster_name)
135 c92b310a Michael Hanselmann
136 c92b310a Michael Hanselmann
137 12bce260 Michael Hanselmann
def _Decompress(data):
138 12bce260 Michael Hanselmann
  """Unpacks data compressed by the RPC client.
139 12bce260 Michael Hanselmann

140 12bce260 Michael Hanselmann
  @type data: list or tuple
141 12bce260 Michael Hanselmann
  @param data: Data sent by RPC client
142 12bce260 Michael Hanselmann
  @rtype: str
143 12bce260 Michael Hanselmann
  @return: Decompressed data
144 12bce260 Michael Hanselmann

145 12bce260 Michael Hanselmann
  """
146 52e2f66e Michael Hanselmann
  assert isinstance(data, (list, tuple))
147 12bce260 Michael Hanselmann
  assert len(data) == 2
148 12bce260 Michael Hanselmann
  (encoding, content) = data
149 12bce260 Michael Hanselmann
  if encoding == constants.RPC_ENCODING_NONE:
150 12bce260 Michael Hanselmann
    return content
151 12bce260 Michael Hanselmann
  elif encoding == constants.RPC_ENCODING_ZLIB_BASE64:
152 12bce260 Michael Hanselmann
    return zlib.decompress(base64.b64decode(content))
153 12bce260 Michael Hanselmann
  else:
154 12bce260 Michael Hanselmann
    raise AssertionError("Unknown data encoding")
155 12bce260 Michael Hanselmann
156 12bce260 Michael Hanselmann
157 3bc6be5c Iustin Pop
def _CleanDirectory(path, exclude=None):
158 76ab5558 Michael Hanselmann
  """Removes all regular files in a directory.
159 76ab5558 Michael Hanselmann

160 10c2650b Iustin Pop
  @type path: str
161 10c2650b Iustin Pop
  @param path: the directory to clean
162 76ab5558 Michael Hanselmann
  @type exclude: list
163 10c2650b Iustin Pop
  @param exclude: list of files to be excluded, defaults
164 10c2650b Iustin Pop
      to the empty list
165 76ab5558 Michael Hanselmann

166 76ab5558 Michael Hanselmann
  """
167 714ea7ca Iustin Pop
  if path not in _ALLOWED_CLEAN_DIRS:
168 714ea7ca Iustin Pop
    _Fail("Path passed to _CleanDirectory not in allowed clean targets: '%s'",
169 714ea7ca Iustin Pop
          path)
170 714ea7ca Iustin Pop
171 3956cee1 Michael Hanselmann
  if not os.path.isdir(path):
172 3956cee1 Michael Hanselmann
    return
173 3bc6be5c Iustin Pop
  if exclude is None:
174 3bc6be5c Iustin Pop
    exclude = []
175 3bc6be5c Iustin Pop
  else:
176 3bc6be5c Iustin Pop
    # Normalize excluded paths
177 3bc6be5c Iustin Pop
    exclude = [os.path.normpath(i) for i in exclude]
178 76ab5558 Michael Hanselmann
179 3956cee1 Michael Hanselmann
  for rel_name in utils.ListVisibleFiles(path):
180 c4feafe8 Iustin Pop
    full_name = utils.PathJoin(path, rel_name)
181 76ab5558 Michael Hanselmann
    if full_name in exclude:
182 76ab5558 Michael Hanselmann
      continue
183 3956cee1 Michael Hanselmann
    if os.path.isfile(full_name) and not os.path.islink(full_name):
184 3956cee1 Michael Hanselmann
      utils.RemoveFile(full_name)
185 3956cee1 Michael Hanselmann
186 3956cee1 Michael Hanselmann
187 360b0dc2 Iustin Pop
def _BuildUploadFileList():
188 360b0dc2 Iustin Pop
  """Build the list of allowed upload files.
189 360b0dc2 Iustin Pop

190 360b0dc2 Iustin Pop
  This is abstracted so that it's built only once at module import time.
191 360b0dc2 Iustin Pop

192 360b0dc2 Iustin Pop
  """
193 b397a7d2 Iustin Pop
  allowed_files = set([
194 b397a7d2 Iustin Pop
    constants.CLUSTER_CONF_FILE,
195 b397a7d2 Iustin Pop
    constants.ETC_HOSTS,
196 b397a7d2 Iustin Pop
    constants.SSH_KNOWN_HOSTS_FILE,
197 b397a7d2 Iustin Pop
    constants.VNC_PASSWORD_FILE,
198 b397a7d2 Iustin Pop
    constants.RAPI_CERT_FILE,
199 bfe86c76 Andrea Spadaccini
    constants.SPICE_CERT_FILE,
200 bfe86c76 Andrea Spadaccini
    constants.SPICE_CACERT_FILE,
201 b397a7d2 Iustin Pop
    constants.RAPI_USERS_FILE,
202 6b7d5878 Michael Hanselmann
    constants.CONFD_HMAC_KEY,
203 ff89a747 Michael Hanselmann
    constants.CLUSTER_DOMAIN_SECRET_FILE,
204 b397a7d2 Iustin Pop
    ])
205 b397a7d2 Iustin Pop
206 b397a7d2 Iustin Pop
  for hv_name in constants.HYPER_TYPES:
207 e5a45a16 Iustin Pop
    hv_class = hypervisor.GetHypervisorClass(hv_name)
208 69ab2e12 Guido Trotter
    allowed_files.update(hv_class.GetAncillaryFiles()[0])
209 b397a7d2 Iustin Pop
210 b397a7d2 Iustin Pop
  return frozenset(allowed_files)
211 360b0dc2 Iustin Pop
212 360b0dc2 Iustin Pop
213 360b0dc2 Iustin Pop
_ALLOWED_UPLOAD_FILES = _BuildUploadFileList()
214 360b0dc2 Iustin Pop
215 360b0dc2 Iustin Pop
216 1bc59f76 Michael Hanselmann
def JobQueuePurge():
217 10c2650b Iustin Pop
  """Removes job queue files and archived jobs.
218 10c2650b Iustin Pop

219 c8457ce7 Iustin Pop
  @rtype: tuple
220 c8457ce7 Iustin Pop
  @return: True, None
221 24fc781f Michael Hanselmann

222 24fc781f Michael Hanselmann
  """
223 1bc59f76 Michael Hanselmann
  _CleanDirectory(constants.QUEUE_DIR, exclude=[constants.JOB_QUEUE_LOCK_FILE])
224 24fc781f Michael Hanselmann
  _CleanDirectory(constants.JOB_QUEUE_ARCHIVE_DIR)
225 24fc781f Michael Hanselmann
226 24fc781f Michael Hanselmann
227 bd1e4562 Iustin Pop
def GetMasterInfo():
228 bd1e4562 Iustin Pop
  """Returns master information.
229 bd1e4562 Iustin Pop

230 bd1e4562 Iustin Pop
  This is an utility function to compute master information, either
231 bd1e4562 Iustin Pop
  for consumption here or from the node daemon.
232 bd1e4562 Iustin Pop

233 bd1e4562 Iustin Pop
  @rtype: tuple
234 909b3a0e Andrea Spadaccini
  @return: master_netdev, master_ip, master_name, primary_ip_family,
235 909b3a0e Andrea Spadaccini
    master_netmask
236 2a52a064 Iustin Pop
  @raise RPCFail: in case of errors
237 b1b6ea87 Iustin Pop

238 b1b6ea87 Iustin Pop
  """
239 b1b6ea87 Iustin Pop
  try:
240 c657dcc9 Michael Hanselmann
    cfg = _GetConfig()
241 c657dcc9 Michael Hanselmann
    master_netdev = cfg.GetMasterNetdev()
242 c657dcc9 Michael Hanselmann
    master_ip = cfg.GetMasterIP()
243 5a8648eb Andrea Spadaccini
    master_netmask = cfg.GetMasterNetmask()
244 c657dcc9 Michael Hanselmann
    master_node = cfg.GetMasterNode()
245 d8e0caa6 Manuel Franceschini
    primary_ip_family = cfg.GetPrimaryIPFamily()
246 b1b6ea87 Iustin Pop
  except errors.ConfigurationError, err:
247 29921401 Iustin Pop
    _Fail("Cluster configuration incomplete: %s", err, exc=True)
248 909b3a0e Andrea Spadaccini
  return (master_netdev, master_ip, master_node, primary_ip_family,
249 909b3a0e Andrea Spadaccini
      master_netmask)
250 b1b6ea87 Iustin Pop
251 b1b6ea87 Iustin Pop
252 fb460cf7 Andrea Spadaccini
def ActivateMasterIp():
253 fb460cf7 Andrea Spadaccini
  """Activate the IP address of the master daemon.
254 fb460cf7 Andrea Spadaccini

255 fb460cf7 Andrea Spadaccini
  """
256 fb460cf7 Andrea Spadaccini
  # GetMasterInfo will raise an exception if not able to return data
257 909b3a0e Andrea Spadaccini
  master_netdev, master_ip, _, family, master_netmask = GetMasterInfo()
258 fb460cf7 Andrea Spadaccini
259 fb460cf7 Andrea Spadaccini
  err_msg = None
260 fb460cf7 Andrea Spadaccini
  if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
261 fb460cf7 Andrea Spadaccini
    if netutils.IPAddress.Own(master_ip):
262 fb460cf7 Andrea Spadaccini
      # we already have the ip:
263 fb460cf7 Andrea Spadaccini
      logging.debug("Master IP already configured, doing nothing")
264 fb460cf7 Andrea Spadaccini
    else:
265 fb460cf7 Andrea Spadaccini
      err_msg = "Someone else has the master ip, not activating"
266 fb460cf7 Andrea Spadaccini
      logging.error(err_msg)
267 fb460cf7 Andrea Spadaccini
  else:
268 fb460cf7 Andrea Spadaccini
    ipcls = netutils.IP4Address
269 fb460cf7 Andrea Spadaccini
    if family == netutils.IP6Address.family:
270 fb460cf7 Andrea Spadaccini
      ipcls = netutils.IP6Address
271 fb460cf7 Andrea Spadaccini
272 fb460cf7 Andrea Spadaccini
    result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
273 5a8648eb Andrea Spadaccini
                           "%s/%s" % (master_ip, master_netmask),
274 fb460cf7 Andrea Spadaccini
                           "dev", master_netdev, "label",
275 fb460cf7 Andrea Spadaccini
                           "%s:0" % master_netdev])
276 fb460cf7 Andrea Spadaccini
    if result.failed:
277 fb460cf7 Andrea Spadaccini
      err_msg = "Can't activate master IP: %s" % result.output
278 fb460cf7 Andrea Spadaccini
      logging.error(err_msg)
279 fb460cf7 Andrea Spadaccini
280 9888b9e6 Andrea Spadaccini
    else:
281 9888b9e6 Andrea Spadaccini
      # we ignore the exit code of the following cmds
282 9888b9e6 Andrea Spadaccini
      if ipcls == netutils.IP4Address:
283 9888b9e6 Andrea Spadaccini
        utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev, "-s",
284 9888b9e6 Andrea Spadaccini
                      master_ip, master_ip])
285 9888b9e6 Andrea Spadaccini
      elif ipcls == netutils.IP6Address:
286 9888b9e6 Andrea Spadaccini
        try:
287 9888b9e6 Andrea Spadaccini
          utils.RunCmd(["ndisc6", "-q", "-r 3", master_ip, master_netdev])
288 9888b9e6 Andrea Spadaccini
        except errors.OpExecError:
289 9888b9e6 Andrea Spadaccini
          # TODO: Better error reporting
290 9888b9e6 Andrea Spadaccini
          logging.warning("Can't execute ndisc6, please install if missing")
291 fb460cf7 Andrea Spadaccini
292 fb460cf7 Andrea Spadaccini
  if err_msg:
293 fb460cf7 Andrea Spadaccini
    _Fail(err_msg)
294 fb460cf7 Andrea Spadaccini
295 fb460cf7 Andrea Spadaccini
296 fb460cf7 Andrea Spadaccini
def StartMasterDaemons(no_voting):
297 a8083063 Iustin Pop
  """Activate local node as master node.
298 a8083063 Iustin Pop

299 fb460cf7 Andrea Spadaccini
  The function will start the master daemons (ganeti-masterd and ganeti-rapi).
300 10c2650b Iustin Pop

301 3583908a Guido Trotter
  @type no_voting: boolean
302 3583908a Guido Trotter
  @param no_voting: whether to start ganeti-masterd without a node vote
303 fb460cf7 Andrea Spadaccini
      but still non-interactively
304 10c2650b Iustin Pop
  @rtype: None
305 a8083063 Iustin Pop

306 a8083063 Iustin Pop
  """
307 a8083063 Iustin Pop
308 fb460cf7 Andrea Spadaccini
  if no_voting:
309 fb460cf7 Andrea Spadaccini
    masterd_args = "--no-voting --yes-do-it"
310 fb460cf7 Andrea Spadaccini
  else:
311 fb460cf7 Andrea Spadaccini
    masterd_args = ""
312 f154a7a3 Michael Hanselmann
313 fb460cf7 Andrea Spadaccini
  env = {
314 fb460cf7 Andrea Spadaccini
    "EXTRA_MASTERD_ARGS": masterd_args,
315 fb460cf7 Andrea Spadaccini
    }
316 fb460cf7 Andrea Spadaccini
317 fb460cf7 Andrea Spadaccini
  result = utils.RunCmd([constants.DAEMON_UTIL, "start-master"], env=env)
318 fb460cf7 Andrea Spadaccini
  if result.failed:
319 fb460cf7 Andrea Spadaccini
    msg = "Can't start Ganeti master: %s" % result.output
320 fb460cf7 Andrea Spadaccini
    logging.error(msg)
321 fb460cf7 Andrea Spadaccini
    _Fail(msg)
322 f154a7a3 Michael Hanselmann
323 fb460cf7 Andrea Spadaccini
324 fb460cf7 Andrea Spadaccini
def DeactivateMasterIp():
325 fb460cf7 Andrea Spadaccini
  """Deactivate the master IP on this node.
326 a8083063 Iustin Pop

327 a8083063 Iustin Pop
  """
328 6c00d19a Iustin Pop
  # TODO: log and report back to the caller the error failures; we
329 6c00d19a Iustin Pop
  # need to decide in which case we fail the RPC for this
330 2a52a064 Iustin Pop
331 2a52a064 Iustin Pop
  # GetMasterInfo will raise an exception if not able to return data
332 909b3a0e Andrea Spadaccini
  master_netdev, master_ip, _, _, master_netmask = GetMasterInfo()
333 e7323b5e Manuel Franceschini
334 c4dfb0b6 Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
335 5a8648eb Andrea Spadaccini
                         "%s/%s" % (master_ip, master_netmask),
336 b1b6ea87 Iustin Pop
                         "dev", master_netdev])
337 a8083063 Iustin Pop
  if result.failed:
338 3b9e6a30 Iustin Pop
    logging.error("Can't remove the master IP, error: %s", result.output)
339 b1b6ea87 Iustin Pop
    # but otherwise ignore the failure
340 b1b6ea87 Iustin Pop
341 fb460cf7 Andrea Spadaccini
342 fb460cf7 Andrea Spadaccini
def StopMasterDaemons():
343 fb460cf7 Andrea Spadaccini
  """Stop the master daemons on this node.
344 fb460cf7 Andrea Spadaccini

345 fb460cf7 Andrea Spadaccini
  Stop the master daemons (ganeti-masterd and ganeti-rapi) on this node.
346 fb460cf7 Andrea Spadaccini

347 fb460cf7 Andrea Spadaccini
  @rtype: None
348 fb460cf7 Andrea Spadaccini

349 fb460cf7 Andrea Spadaccini
  """
350 fb460cf7 Andrea Spadaccini
  # TODO: log and report back to the caller the error failures; we
351 fb460cf7 Andrea Spadaccini
  # need to decide in which case we fail the RPC for this
352 fb460cf7 Andrea Spadaccini
353 fb460cf7 Andrea Spadaccini
  result = utils.RunCmd([constants.DAEMON_UTIL, "stop-master"])
354 fb460cf7 Andrea Spadaccini
  if result.failed:
355 fb460cf7 Andrea Spadaccini
    logging.error("Could not stop Ganeti master, command %s had exitcode %s"
356 fb460cf7 Andrea Spadaccini
                  " and error %s",
357 fb460cf7 Andrea Spadaccini
                  result.cmd, result.exit_code, result.output)
358 a8083063 Iustin Pop
359 a8083063 Iustin Pop
360 5a8648eb Andrea Spadaccini
def ChangeMasterNetmask(netmask):
361 5a8648eb Andrea Spadaccini
  """Change the netmask of the master IP.
362 5a8648eb Andrea Spadaccini

363 5a8648eb Andrea Spadaccini
  """
364 909b3a0e Andrea Spadaccini
  master_netdev, master_ip, _, _, old_netmask = GetMasterInfo()
365 5a8648eb Andrea Spadaccini
  if old_netmask == netmask:
366 5a8648eb Andrea Spadaccini
    return
367 5a8648eb Andrea Spadaccini
368 5a8648eb Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
369 5a8648eb Andrea Spadaccini
                         "%s/%s" % (master_ip, netmask),
370 5a8648eb Andrea Spadaccini
                         "dev", master_netdev, "label",
371 5a8648eb Andrea Spadaccini
                         "%s:0" % master_netdev])
372 5a8648eb Andrea Spadaccini
  if result.failed:
373 5a8648eb Andrea Spadaccini
    _Fail("Could not change the master IP netmask")
374 5a8648eb Andrea Spadaccini
375 5a8648eb Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
376 5a8648eb Andrea Spadaccini
                         "%s/%s" % (master_ip, old_netmask),
377 5a8648eb Andrea Spadaccini
                         "dev", master_netdev, "label",
378 5a8648eb Andrea Spadaccini
                         "%s:0" % master_netdev])
379 5a8648eb Andrea Spadaccini
  if result.failed:
380 5a8648eb Andrea Spadaccini
    _Fail("Could not change the master IP netmask")
381 5a8648eb Andrea Spadaccini
382 5a8648eb Andrea Spadaccini
383 19ddc57a René Nussbaumer
def EtcHostsModify(mode, host, ip):
384 19ddc57a René Nussbaumer
  """Modify a host entry in /etc/hosts.
385 19ddc57a René Nussbaumer

386 19ddc57a René Nussbaumer
  @param mode: The mode to operate. Either add or remove entry
387 19ddc57a René Nussbaumer
  @param host: The host to operate on
388 19ddc57a René Nussbaumer
  @param ip: The ip associated with the entry
389 19ddc57a René Nussbaumer

390 19ddc57a René Nussbaumer
  """
391 19ddc57a René Nussbaumer
  if mode == constants.ETC_HOSTS_ADD:
392 19ddc57a René Nussbaumer
    if not ip:
393 19ddc57a René Nussbaumer
      RPCFail("Mode 'add' needs 'ip' parameter, but parameter not"
394 19ddc57a René Nussbaumer
              " present")
395 19ddc57a René Nussbaumer
    utils.AddHostToEtcHosts(host, ip)
396 19ddc57a René Nussbaumer
  elif mode == constants.ETC_HOSTS_REMOVE:
397 19ddc57a René Nussbaumer
    if ip:
398 19ddc57a René Nussbaumer
      RPCFail("Mode 'remove' does not allow 'ip' parameter, but"
399 19ddc57a René Nussbaumer
              " parameter is present")
400 19ddc57a René Nussbaumer
    utils.RemoveHostFromEtcHosts(host)
401 19ddc57a René Nussbaumer
  else:
402 19ddc57a René Nussbaumer
    RPCFail("Mode not supported")
403 19ddc57a René Nussbaumer
404 19ddc57a René Nussbaumer
405 b989b9d9 Ken Wehr
def LeaveCluster(modify_ssh_setup):
406 10c2650b Iustin Pop
  """Cleans up and remove the current node.
407 10c2650b Iustin Pop

408 10c2650b Iustin Pop
  This function cleans up and prepares the current node to be removed
409 10c2650b Iustin Pop
  from the cluster.
410 10c2650b Iustin Pop

411 10c2650b Iustin Pop
  If processing is successful, then it raises an
412 c41eea6e Iustin Pop
  L{errors.QuitGanetiException} which is used as a special case to
413 10c2650b Iustin Pop
  shutdown the node daemon.
414 a8083063 Iustin Pop

415 b989b9d9 Ken Wehr
  @param modify_ssh_setup: boolean
416 b989b9d9 Ken Wehr

417 a8083063 Iustin Pop
  """
418 f78346f5 Michael Hanselmann
  _CleanDirectory(constants.DATA_DIR)
419 f942a838 Michael Hanselmann
  _CleanDirectory(constants.CRYPTO_KEYS_DIR)
420 1bc59f76 Michael Hanselmann
  JobQueuePurge()
421 f78346f5 Michael Hanselmann
422 b989b9d9 Ken Wehr
  if modify_ssh_setup:
423 b989b9d9 Ken Wehr
    try:
424 b989b9d9 Ken Wehr
      priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
425 7900ed01 Iustin Pop
426 b989b9d9 Ken Wehr
      utils.RemoveAuthorizedKey(auth_keys, utils.ReadFile(pub_key))
427 a8083063 Iustin Pop
428 b989b9d9 Ken Wehr
      utils.RemoveFile(priv_key)
429 b989b9d9 Ken Wehr
      utils.RemoveFile(pub_key)
430 b989b9d9 Ken Wehr
    except errors.OpExecError:
431 b989b9d9 Ken Wehr
      logging.exception("Error while processing ssh files")
432 a8083063 Iustin Pop
433 ed008420 Guido Trotter
  try:
434 6b7d5878 Michael Hanselmann
    utils.RemoveFile(constants.CONFD_HMAC_KEY)
435 ed008420 Guido Trotter
    utils.RemoveFile(constants.RAPI_CERT_FILE)
436 bfe86c76 Andrea Spadaccini
    utils.RemoveFile(constants.SPICE_CERT_FILE)
437 bfe86c76 Andrea Spadaccini
    utils.RemoveFile(constants.SPICE_CACERT_FILE)
438 168c1de2 Michael Hanselmann
    utils.RemoveFile(constants.NODED_CERT_FILE)
439 b459a848 Andrea Spadaccini
  except: # pylint: disable=W0702
440 ed008420 Guido Trotter
    logging.exception("Error while removing cluster secrets")
441 ed008420 Guido Trotter
442 f154a7a3 Michael Hanselmann
  result = utils.RunCmd([constants.DAEMON_UTIL, "stop", constants.CONFD])
443 f154a7a3 Michael Hanselmann
  if result.failed:
444 f154a7a3 Michael Hanselmann
    logging.error("Command %s failed with exitcode %s and error %s",
445 f154a7a3 Michael Hanselmann
                  result.cmd, result.exit_code, result.output)
446 ed008420 Guido Trotter
447 0623d351 Iustin Pop
  # Raise a custom exception (handled in ganeti-noded)
448 d0c8c01d Iustin Pop
  raise errors.QuitGanetiException(True, "Shutdown scheduled")
449 6d8b6238 Guido Trotter
450 a8083063 Iustin Pop
451 e69d05fd Iustin Pop
def GetNodeInfo(vgname, hypervisor_type):
452 5bbd3f7f Michael Hanselmann
  """Gives back a hash with different information about the node.
453 a8083063 Iustin Pop

454 e69d05fd Iustin Pop
  @type vgname: C{string}
455 e69d05fd Iustin Pop
  @param vgname: the name of the volume group to ask for disk space information
456 e69d05fd Iustin Pop
  @type hypervisor_type: C{str}
457 e69d05fd Iustin Pop
  @param hypervisor_type: the name of the hypervisor to ask for
458 e69d05fd Iustin Pop
      memory information
459 e69d05fd Iustin Pop
  @rtype: C{dict}
460 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
461 e69d05fd Iustin Pop
      - vg_size is the size of the configured volume group in MiB
462 e69d05fd Iustin Pop
      - vg_free is the free size of the volume group in MiB
463 e69d05fd Iustin Pop
      - memory_dom0 is the memory allocated for domain0 in MiB
464 e69d05fd Iustin Pop
      - memory_free is the currently available (free) ram in MiB
465 e69d05fd Iustin Pop
      - memory_total is the total number of ram in MiB
466 34fbc862 Andrea Spadaccini
      - hv_version: the hypervisor version, if available
467 a8083063 Iustin Pop

468 098c0958 Michael Hanselmann
  """
469 a8083063 Iustin Pop
  outputarray = {}
470 673cd9c4 René Nussbaumer
471 cb6a0296 Iustin Pop
  if vgname is not None:
472 cb6a0296 Iustin Pop
    vginfo = bdev.LogicalVolume.GetVGInfo([vgname])
473 cb6a0296 Iustin Pop
    vg_free = vg_size = None
474 cb6a0296 Iustin Pop
    if vginfo:
475 cb6a0296 Iustin Pop
      vg_free = int(round(vginfo[0][0], 0))
476 cb6a0296 Iustin Pop
      vg_size = int(round(vginfo[0][1], 0))
477 d0c8c01d Iustin Pop
    outputarray["vg_size"] = vg_size
478 d0c8c01d Iustin Pop
    outputarray["vg_free"] = vg_free
479 cb6a0296 Iustin Pop
480 cb6a0296 Iustin Pop
  if hypervisor_type is not None:
481 cb6a0296 Iustin Pop
    hyper = hypervisor.GetHypervisor(hypervisor_type)
482 cb6a0296 Iustin Pop
    hyp_info = hyper.GetNodeInfo()
483 cb6a0296 Iustin Pop
    if hyp_info is not None:
484 cb6a0296 Iustin Pop
      outputarray.update(hyp_info)
485 a8083063 Iustin Pop
486 13998ef2 Michael Hanselmann
  outputarray["bootid"] = utils.ReadFile(_BOOT_ID_PATH, size=128).rstrip("\n")
487 3ef10550 Michael Hanselmann
488 c26a6bd2 Iustin Pop
  return outputarray
489 a8083063 Iustin Pop
490 a8083063 Iustin Pop
491 62c9ec92 Iustin Pop
def VerifyNode(what, cluster_name):
492 a8083063 Iustin Pop
  """Verify the status of the local node.
493 a8083063 Iustin Pop

494 e69d05fd Iustin Pop
  Based on the input L{what} parameter, various checks are done on the
495 e69d05fd Iustin Pop
  local node.
496 e69d05fd Iustin Pop

497 e69d05fd Iustin Pop
  If the I{filelist} key is present, this list of
498 e69d05fd Iustin Pop
  files is checksummed and the file/checksum pairs are returned.
499 e69d05fd Iustin Pop

500 e69d05fd Iustin Pop
  If the I{nodelist} key is present, we check that we have
501 e69d05fd Iustin Pop
  connectivity via ssh with the target nodes (and check the hostname
502 e69d05fd Iustin Pop
  report).
503 a8083063 Iustin Pop

504 e69d05fd Iustin Pop
  If the I{node-net-test} key is present, we check that we have
505 e69d05fd Iustin Pop
  connectivity to the given nodes via both primary IP and, if
506 e69d05fd Iustin Pop
  applicable, secondary IPs.
507 e69d05fd Iustin Pop

508 e69d05fd Iustin Pop
  @type what: C{dict}
509 e69d05fd Iustin Pop
  @param what: a dictionary of things to check:
510 e69d05fd Iustin Pop
      - filelist: list of files for which to compute checksums
511 e69d05fd Iustin Pop
      - nodelist: list of nodes we should check ssh communication with
512 e69d05fd Iustin Pop
      - node-net-test: list of nodes we should check node daemon port
513 e69d05fd Iustin Pop
        connectivity with
514 e69d05fd Iustin Pop
      - hypervisor: list with hypervisors to run the verify for
515 10c2650b Iustin Pop
  @rtype: dict
516 10c2650b Iustin Pop
  @return: a dictionary with the same keys as the input dict, and
517 10c2650b Iustin Pop
      values representing the result of the checks
518 a8083063 Iustin Pop

519 a8083063 Iustin Pop
  """
520 a8083063 Iustin Pop
  result = {}
521 b705c7a6 Manuel Franceschini
  my_name = netutils.Hostname.GetSysName()
522 a744b676 Manuel Franceschini
  port = netutils.GetDaemonPort(constants.NODED)
523 8964ee14 Iustin Pop
  vm_capable = my_name not in what.get(constants.NV_VMNODES, [])
524 a8083063 Iustin Pop
525 8964ee14 Iustin Pop
  if constants.NV_HYPERVISOR in what and vm_capable:
526 25361b9a Iustin Pop
    result[constants.NV_HYPERVISOR] = tmp = {}
527 25361b9a Iustin Pop
    for hv_name in what[constants.NV_HYPERVISOR]:
528 0cf5e7f5 Iustin Pop
      try:
529 0cf5e7f5 Iustin Pop
        val = hypervisor.GetHypervisor(hv_name).Verify()
530 0cf5e7f5 Iustin Pop
      except errors.HypervisorError, err:
531 0cf5e7f5 Iustin Pop
        val = "Error while checking hypervisor: %s" % str(err)
532 0cf5e7f5 Iustin Pop
      tmp[hv_name] = val
533 25361b9a Iustin Pop
534 58a59652 Iustin Pop
  if constants.NV_HVPARAMS in what and vm_capable:
535 58a59652 Iustin Pop
    result[constants.NV_HVPARAMS] = tmp = []
536 58a59652 Iustin Pop
    for source, hv_name, hvparms in what[constants.NV_HVPARAMS]:
537 58a59652 Iustin Pop
      try:
538 58a59652 Iustin Pop
        logging.info("Validating hv %s, %s", hv_name, hvparms)
539 58a59652 Iustin Pop
        hypervisor.GetHypervisor(hv_name).ValidateParameters(hvparms)
540 58a59652 Iustin Pop
      except errors.HypervisorError, err:
541 58a59652 Iustin Pop
        tmp.append((source, hv_name, str(err)))
542 58a59652 Iustin Pop
543 25361b9a Iustin Pop
  if constants.NV_FILELIST in what:
544 25361b9a Iustin Pop
    result[constants.NV_FILELIST] = utils.FingerprintFiles(
545 25361b9a Iustin Pop
      what[constants.NV_FILELIST])
546 25361b9a Iustin Pop
547 25361b9a Iustin Pop
  if constants.NV_NODELIST in what:
548 64c7b383 Michael Hanselmann
    (nodes, bynode) = what[constants.NV_NODELIST]
549 64c7b383 Michael Hanselmann
550 64c7b383 Michael Hanselmann
    # Add nodes from other groups (different for each node)
551 64c7b383 Michael Hanselmann
    try:
552 64c7b383 Michael Hanselmann
      nodes.extend(bynode[my_name])
553 64c7b383 Michael Hanselmann
    except KeyError:
554 64c7b383 Michael Hanselmann
      pass
555 64c7b383 Michael Hanselmann
556 64c7b383 Michael Hanselmann
    # Use a random order
557 64c7b383 Michael Hanselmann
    random.shuffle(nodes)
558 64c7b383 Michael Hanselmann
559 64c7b383 Michael Hanselmann
    # Try to contact all nodes
560 64c7b383 Michael Hanselmann
    val = {}
561 64c7b383 Michael Hanselmann
    for node in nodes:
562 62c9ec92 Iustin Pop
      success, message = _GetSshRunner(cluster_name).VerifyNodeHostname(node)
563 a8083063 Iustin Pop
      if not success:
564 64c7b383 Michael Hanselmann
        val[node] = message
565 64c7b383 Michael Hanselmann
566 64c7b383 Michael Hanselmann
    result[constants.NV_NODELIST] = val
567 25361b9a Iustin Pop
568 25361b9a Iustin Pop
  if constants.NV_NODENETTEST in what:
569 25361b9a Iustin Pop
    result[constants.NV_NODENETTEST] = tmp = {}
570 9d4bfc96 Iustin Pop
    my_pip = my_sip = None
571 25361b9a Iustin Pop
    for name, pip, sip in what[constants.NV_NODENETTEST]:
572 9d4bfc96 Iustin Pop
      if name == my_name:
573 9d4bfc96 Iustin Pop
        my_pip = pip
574 9d4bfc96 Iustin Pop
        my_sip = sip
575 9d4bfc96 Iustin Pop
        break
576 9d4bfc96 Iustin Pop
    if not my_pip:
577 25361b9a Iustin Pop
      tmp[my_name] = ("Can't find my own primary/secondary IP"
578 25361b9a Iustin Pop
                      " in the node list")
579 9d4bfc96 Iustin Pop
    else:
580 25361b9a Iustin Pop
      for name, pip, sip in what[constants.NV_NODENETTEST]:
581 9d4bfc96 Iustin Pop
        fail = []
582 a744b676 Manuel Franceschini
        if not netutils.TcpPing(pip, port, source=my_pip):
583 9d4bfc96 Iustin Pop
          fail.append("primary")
584 9d4bfc96 Iustin Pop
        if sip != pip:
585 a744b676 Manuel Franceschini
          if not netutils.TcpPing(sip, port, source=my_sip):
586 9d4bfc96 Iustin Pop
            fail.append("secondary")
587 9d4bfc96 Iustin Pop
        if fail:
588 25361b9a Iustin Pop
          tmp[name] = ("failure using the %s interface(s)" %
589 25361b9a Iustin Pop
                       " and ".join(fail))
590 25361b9a Iustin Pop
591 a3a5f850 Iustin Pop
  if constants.NV_MASTERIP in what:
592 a3a5f850 Iustin Pop
    # FIXME: add checks on incoming data structures (here and in the
593 a3a5f850 Iustin Pop
    # rest of the function)
594 a3a5f850 Iustin Pop
    master_name, master_ip = what[constants.NV_MASTERIP]
595 a3a5f850 Iustin Pop
    if master_name == my_name:
596 9769bb78 Manuel Franceschini
      source = constants.IP4_ADDRESS_LOCALHOST
597 a3a5f850 Iustin Pop
    else:
598 a3a5f850 Iustin Pop
      source = None
599 a744b676 Manuel Franceschini
    result[constants.NV_MASTERIP] = netutils.TcpPing(master_ip, port,
600 a3a5f850 Iustin Pop
                                                  source=source)
601 a3a5f850 Iustin Pop
602 16f41f24 René Nussbaumer
  if constants.NV_OOB_PATHS in what:
603 16f41f24 René Nussbaumer
    result[constants.NV_OOB_PATHS] = tmp = []
604 16f41f24 René Nussbaumer
    for path in what[constants.NV_OOB_PATHS]:
605 16f41f24 René Nussbaumer
      try:
606 16f41f24 René Nussbaumer
        st = os.stat(path)
607 16f41f24 René Nussbaumer
      except OSError, err:
608 16f41f24 René Nussbaumer
        tmp.append("error stating out of band helper: %s" % err)
609 16f41f24 René Nussbaumer
      else:
610 16f41f24 René Nussbaumer
        if stat.S_ISREG(st.st_mode):
611 16f41f24 René Nussbaumer
          if stat.S_IMODE(st.st_mode) & stat.S_IXUSR:
612 16f41f24 René Nussbaumer
            tmp.append(None)
613 16f41f24 René Nussbaumer
          else:
614 16f41f24 René Nussbaumer
            tmp.append("out of band helper %s is not executable" % path)
615 16f41f24 René Nussbaumer
        else:
616 16f41f24 René Nussbaumer
          tmp.append("out of band helper %s is not a file" % path)
617 16f41f24 René Nussbaumer
618 8964ee14 Iustin Pop
  if constants.NV_LVLIST in what and vm_capable:
619 ed904904 Iustin Pop
    try:
620 84d7e26b Dmitry Chernyak
      val = GetVolumeList(utils.ListVolumeGroups().keys())
621 ed904904 Iustin Pop
    except RPCFail, err:
622 ed904904 Iustin Pop
      val = str(err)
623 ed904904 Iustin Pop
    result[constants.NV_LVLIST] = val
624 25361b9a Iustin Pop
625 8964ee14 Iustin Pop
  if constants.NV_INSTANCELIST in what and vm_capable:
626 0cf5e7f5 Iustin Pop
    # GetInstanceList can fail
627 0cf5e7f5 Iustin Pop
    try:
628 0cf5e7f5 Iustin Pop
      val = GetInstanceList(what[constants.NV_INSTANCELIST])
629 0cf5e7f5 Iustin Pop
    except RPCFail, err:
630 0cf5e7f5 Iustin Pop
      val = str(err)
631 0cf5e7f5 Iustin Pop
    result[constants.NV_INSTANCELIST] = val
632 25361b9a Iustin Pop
633 8964ee14 Iustin Pop
  if constants.NV_VGLIST in what and vm_capable:
634 e480923b Iustin Pop
    result[constants.NV_VGLIST] = utils.ListVolumeGroups()
635 25361b9a Iustin Pop
636 8964ee14 Iustin Pop
  if constants.NV_PVLIST in what and vm_capable:
637 d091393e Iustin Pop
    result[constants.NV_PVLIST] = \
638 d091393e Iustin Pop
      bdev.LogicalVolume.GetPVInfo(what[constants.NV_PVLIST],
639 d091393e Iustin Pop
                                   filter_allocatable=False)
640 d091393e Iustin Pop
641 25361b9a Iustin Pop
  if constants.NV_VERSION in what:
642 e9ce0a64 Iustin Pop
    result[constants.NV_VERSION] = (constants.PROTOCOL_VERSION,
643 e9ce0a64 Iustin Pop
                                    constants.RELEASE_VERSION)
644 25361b9a Iustin Pop
645 8964ee14 Iustin Pop
  if constants.NV_HVINFO in what and vm_capable:
646 25361b9a Iustin Pop
    hyper = hypervisor.GetHypervisor(what[constants.NV_HVINFO])
647 25361b9a Iustin Pop
    result[constants.NV_HVINFO] = hyper.GetNodeInfo()
648 9d4bfc96 Iustin Pop
649 8964ee14 Iustin Pop
  if constants.NV_DRBDLIST in what and vm_capable:
650 6d2e83d5 Iustin Pop
    try:
651 6d2e83d5 Iustin Pop
      used_minors = bdev.DRBD8.GetUsedDevs().keys()
652 f6eaed12 Iustin Pop
    except errors.BlockDeviceError, err:
653 6d2e83d5 Iustin Pop
      logging.warning("Can't get used minors list", exc_info=True)
654 f6eaed12 Iustin Pop
      used_minors = str(err)
655 6d2e83d5 Iustin Pop
    result[constants.NV_DRBDLIST] = used_minors
656 6d2e83d5 Iustin Pop
657 8964ee14 Iustin Pop
  if constants.NV_DRBDHELPER in what and vm_capable:
658 7ef40fbe Luca Bigliardi
    status = True
659 7ef40fbe Luca Bigliardi
    try:
660 7ef40fbe Luca Bigliardi
      payload = bdev.BaseDRBD.GetUsermodeHelper()
661 7ef40fbe Luca Bigliardi
    except errors.BlockDeviceError, err:
662 7ef40fbe Luca Bigliardi
      logging.error("Can't get DRBD usermode helper: %s", str(err))
663 7ef40fbe Luca Bigliardi
      status = False
664 7ef40fbe Luca Bigliardi
      payload = str(err)
665 7ef40fbe Luca Bigliardi
    result[constants.NV_DRBDHELPER] = (status, payload)
666 7ef40fbe Luca Bigliardi
667 7c0aa8e9 Iustin Pop
  if constants.NV_NODESETUP in what:
668 7c0aa8e9 Iustin Pop
    result[constants.NV_NODESETUP] = tmpr = []
669 7c0aa8e9 Iustin Pop
    if not os.path.isdir("/sys/block") or not os.path.isdir("/sys/class/net"):
670 7c0aa8e9 Iustin Pop
      tmpr.append("The sysfs filesytem doesn't seem to be mounted"
671 7c0aa8e9 Iustin Pop
                  " under /sys, missing required directories /sys/block"
672 7c0aa8e9 Iustin Pop
                  " and /sys/class/net")
673 7c0aa8e9 Iustin Pop
    if (not os.path.isdir("/proc/sys") or
674 7c0aa8e9 Iustin Pop
        not os.path.isfile("/proc/sysrq-trigger")):
675 7c0aa8e9 Iustin Pop
      tmpr.append("The procfs filesystem doesn't seem to be mounted"
676 7c0aa8e9 Iustin Pop
                  " under /proc, missing required directory /proc/sys and"
677 7c0aa8e9 Iustin Pop
                  " the file /proc/sysrq-trigger")
678 313b2dd4 Michael Hanselmann
679 313b2dd4 Michael Hanselmann
  if constants.NV_TIME in what:
680 313b2dd4 Michael Hanselmann
    result[constants.NV_TIME] = utils.SplitTime(time.time())
681 313b2dd4 Michael Hanselmann
682 8964ee14 Iustin Pop
  if constants.NV_OSLIST in what and vm_capable:
683 b0d85178 Iustin Pop
    result[constants.NV_OSLIST] = DiagnoseOS()
684 b0d85178 Iustin Pop
685 20d317d4 Iustin Pop
  if constants.NV_BRIDGES in what and vm_capable:
686 20d317d4 Iustin Pop
    result[constants.NV_BRIDGES] = [bridge
687 20d317d4 Iustin Pop
                                    for bridge in what[constants.NV_BRIDGES]
688 20d317d4 Iustin Pop
                                    if not utils.BridgeExists(bridge)]
689 c26a6bd2 Iustin Pop
  return result
690 a8083063 Iustin Pop
691 a8083063 Iustin Pop
692 2be7273c Apollon Oikonomopoulos
def GetBlockDevSizes(devices):
693 2be7273c Apollon Oikonomopoulos
  """Return the size of the given block devices
694 2be7273c Apollon Oikonomopoulos

695 2be7273c Apollon Oikonomopoulos
  @type devices: list
696 2be7273c Apollon Oikonomopoulos
  @param devices: list of block device nodes to query
697 2be7273c Apollon Oikonomopoulos
  @rtype: dict
698 2be7273c Apollon Oikonomopoulos
  @return:
699 2be7273c Apollon Oikonomopoulos
    dictionary of all block devices under /dev (key). The value is their
700 2be7273c Apollon Oikonomopoulos
    size in MiB.
701 2be7273c Apollon Oikonomopoulos

702 2be7273c Apollon Oikonomopoulos
    {'/dev/disk/by-uuid/123456-12321231-312312-312': 124}
703 2be7273c Apollon Oikonomopoulos

704 2be7273c Apollon Oikonomopoulos
  """
705 2be7273c Apollon Oikonomopoulos
  DEV_PREFIX = "/dev/"
706 2be7273c Apollon Oikonomopoulos
  blockdevs = {}
707 2be7273c Apollon Oikonomopoulos
708 2be7273c Apollon Oikonomopoulos
  for devpath in devices:
709 cf00dba0 René Nussbaumer
    if not utils.IsBelowDir(DEV_PREFIX, devpath):
710 2be7273c Apollon Oikonomopoulos
      continue
711 2be7273c Apollon Oikonomopoulos
712 2be7273c Apollon Oikonomopoulos
    try:
713 2be7273c Apollon Oikonomopoulos
      st = os.stat(devpath)
714 2be7273c Apollon Oikonomopoulos
    except EnvironmentError, err:
715 2be7273c Apollon Oikonomopoulos
      logging.warning("Error stat()'ing device %s: %s", devpath, str(err))
716 2be7273c Apollon Oikonomopoulos
      continue
717 2be7273c Apollon Oikonomopoulos
718 2be7273c Apollon Oikonomopoulos
    if stat.S_ISBLK(st.st_mode):
719 2be7273c Apollon Oikonomopoulos
      result = utils.RunCmd(["blockdev", "--getsize64", devpath])
720 2be7273c Apollon Oikonomopoulos
      if result.failed:
721 2be7273c Apollon Oikonomopoulos
        # We don't want to fail, just do not list this device as available
722 2be7273c Apollon Oikonomopoulos
        logging.warning("Cannot get size for block device %s", devpath)
723 2be7273c Apollon Oikonomopoulos
        continue
724 2be7273c Apollon Oikonomopoulos
725 2be7273c Apollon Oikonomopoulos
      size = int(result.stdout) / (1024 * 1024)
726 2be7273c Apollon Oikonomopoulos
      blockdevs[devpath] = size
727 2be7273c Apollon Oikonomopoulos
  return blockdevs
728 2be7273c Apollon Oikonomopoulos
729 2be7273c Apollon Oikonomopoulos
730 84d7e26b Dmitry Chernyak
def GetVolumeList(vg_names):
731 a8083063 Iustin Pop
  """Compute list of logical volumes and their size.
732 a8083063 Iustin Pop

733 84d7e26b Dmitry Chernyak
  @type vg_names: list
734 397693d3 Iustin Pop
  @param vg_names: the volume groups whose LVs we should list, or
735 397693d3 Iustin Pop
      empty for all volume groups
736 10c2650b Iustin Pop
  @rtype: dict
737 10c2650b Iustin Pop
  @return:
738 10c2650b Iustin Pop
      dictionary of all partions (key) with value being a tuple of
739 10c2650b Iustin Pop
      their size (in MiB), inactive and online status::
740 10c2650b Iustin Pop

741 84d7e26b Dmitry Chernyak
        {'xenvg/test1': ('20.06', True, True)}
742 10c2650b Iustin Pop

743 10c2650b Iustin Pop
      in case of errors, a string is returned with the error
744 10c2650b Iustin Pop
      details.
745 a8083063 Iustin Pop

746 a8083063 Iustin Pop
  """
747 cb2037a2 Iustin Pop
  lvs = {}
748 d0c8c01d Iustin Pop
  sep = "|"
749 397693d3 Iustin Pop
  if not vg_names:
750 397693d3 Iustin Pop
    vg_names = []
751 cb2037a2 Iustin Pop
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
752 cb2037a2 Iustin Pop
                         "--separator=%s" % sep,
753 84d7e26b Dmitry Chernyak
                         "-ovg_name,lv_name,lv_size,lv_attr"] + vg_names)
754 a8083063 Iustin Pop
  if result.failed:
755 29d376ec Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s", result.output)
756 cb2037a2 Iustin Pop
757 cb2037a2 Iustin Pop
  for line in result.stdout.splitlines():
758 df4c2628 Iustin Pop
    line = line.strip()
759 0b5303da Iustin Pop
    match = _LVSLINE_REGEX.match(line)
760 df4c2628 Iustin Pop
    if not match:
761 18682bca Iustin Pop
      logging.error("Invalid line returned from lvs output: '%s'", line)
762 df4c2628 Iustin Pop
      continue
763 84d7e26b Dmitry Chernyak
    vg_name, name, size, attr = match.groups()
764 d0c8c01d Iustin Pop
    inactive = attr[4] == "-"
765 d0c8c01d Iustin Pop
    online = attr[5] == "o"
766 d0c8c01d Iustin Pop
    virtual = attr[0] == "v"
767 33f2a81a Iustin Pop
    if virtual:
768 33f2a81a Iustin Pop
      # we don't want to report such volumes as existing, since they
769 33f2a81a Iustin Pop
      # don't really hold data
770 33f2a81a Iustin Pop
      continue
771 e687ec01 Michael Hanselmann
    lvs[vg_name + "/" + name] = (size, inactive, online)
772 cb2037a2 Iustin Pop
773 cb2037a2 Iustin Pop
  return lvs
774 a8083063 Iustin Pop
775 a8083063 Iustin Pop
776 a8083063 Iustin Pop
def ListVolumeGroups():
777 2f8598a5 Alexander Schreiber
  """List the volume groups and their size.
778 a8083063 Iustin Pop

779 10c2650b Iustin Pop
  @rtype: dict
780 10c2650b Iustin Pop
  @return: dictionary with keys volume name and values the
781 10c2650b Iustin Pop
      size of the volume
782 a8083063 Iustin Pop

783 a8083063 Iustin Pop
  """
784 c26a6bd2 Iustin Pop
  return utils.ListVolumeGroups()
785 a8083063 Iustin Pop
786 a8083063 Iustin Pop
787 dcb93971 Michael Hanselmann
def NodeVolumes():
788 dcb93971 Michael Hanselmann
  """List all volumes on this node.
789 dcb93971 Michael Hanselmann

790 10c2650b Iustin Pop
  @rtype: list
791 10c2650b Iustin Pop
  @return:
792 10c2650b Iustin Pop
    A list of dictionaries, each having four keys:
793 10c2650b Iustin Pop
      - name: the logical volume name,
794 10c2650b Iustin Pop
      - size: the size of the logical volume
795 10c2650b Iustin Pop
      - dev: the physical device on which the LV lives
796 10c2650b Iustin Pop
      - vg: the volume group to which it belongs
797 10c2650b Iustin Pop

798 10c2650b Iustin Pop
    In case of errors, we return an empty list and log the
799 10c2650b Iustin Pop
    error.
800 10c2650b Iustin Pop

801 10c2650b Iustin Pop
    Note that since a logical volume can live on multiple physical
802 10c2650b Iustin Pop
    volumes, the resulting list might include a logical volume
803 10c2650b Iustin Pop
    multiple times.
804 10c2650b Iustin Pop

805 dcb93971 Michael Hanselmann
  """
806 dcb93971 Michael Hanselmann
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
807 dcb93971 Michael Hanselmann
                         "--separator=|",
808 dcb93971 Michael Hanselmann
                         "--options=lv_name,lv_size,devices,vg_name"])
809 dcb93971 Michael Hanselmann
  if result.failed:
810 10bfe6cb Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s",
811 10bfe6cb Iustin Pop
          result.output)
812 dcb93971 Michael Hanselmann
813 dcb93971 Michael Hanselmann
  def parse_dev(dev):
814 d0c8c01d Iustin Pop
    return dev.split("(")[0]
815 89e5ab02 Iustin Pop
816 89e5ab02 Iustin Pop
  def handle_dev(dev):
817 89e5ab02 Iustin Pop
    return [parse_dev(x) for x in dev.split(",")]
818 dcb93971 Michael Hanselmann
819 dcb93971 Michael Hanselmann
  def map_line(line):
820 89e5ab02 Iustin Pop
    line = [v.strip() for v in line]
821 d0c8c01d Iustin Pop
    return [{"name": line[0], "size": line[1],
822 d0c8c01d Iustin Pop
             "dev": dev, "vg": line[3]} for dev in handle_dev(line[2])]
823 89e5ab02 Iustin Pop
824 89e5ab02 Iustin Pop
  all_devs = []
825 89e5ab02 Iustin Pop
  for line in result.stdout.splitlines():
826 d0c8c01d Iustin Pop
    if line.count("|") >= 3:
827 d0c8c01d Iustin Pop
      all_devs.extend(map_line(line.split("|")))
828 89e5ab02 Iustin Pop
    else:
829 89e5ab02 Iustin Pop
      logging.warning("Strange line in the output from lvs: '%s'", line)
830 89e5ab02 Iustin Pop
  return all_devs
831 dcb93971 Michael Hanselmann
832 dcb93971 Michael Hanselmann
833 a8083063 Iustin Pop
def BridgesExist(bridges_list):
834 2f8598a5 Alexander Schreiber
  """Check if a list of bridges exist on the current node.
835 a8083063 Iustin Pop

836 b1206984 Iustin Pop
  @rtype: boolean
837 b1206984 Iustin Pop
  @return: C{True} if all of them exist, C{False} otherwise
838 a8083063 Iustin Pop

839 a8083063 Iustin Pop
  """
840 35c0c8da Iustin Pop
  missing = []
841 a8083063 Iustin Pop
  for bridge in bridges_list:
842 a8083063 Iustin Pop
    if not utils.BridgeExists(bridge):
843 35c0c8da Iustin Pop
      missing.append(bridge)
844 a8083063 Iustin Pop
845 35c0c8da Iustin Pop
  if missing:
846 1f864b60 Iustin Pop
    _Fail("Missing bridges %s", utils.CommaJoin(missing))
847 35c0c8da Iustin Pop
848 a8083063 Iustin Pop
849 e69d05fd Iustin Pop
def GetInstanceList(hypervisor_list):
850 2f8598a5 Alexander Schreiber
  """Provides a list of instances.
851 a8083063 Iustin Pop

852 e69d05fd Iustin Pop
  @type hypervisor_list: list
853 e69d05fd Iustin Pop
  @param hypervisor_list: the list of hypervisors to query information
854 e69d05fd Iustin Pop

855 e69d05fd Iustin Pop
  @rtype: list
856 e69d05fd Iustin Pop
  @return: a list of all running instances on the current node
857 10c2650b Iustin Pop
    - instance1.example.com
858 10c2650b Iustin Pop
    - instance2.example.com
859 a8083063 Iustin Pop

860 098c0958 Michael Hanselmann
  """
861 e69d05fd Iustin Pop
  results = []
862 e69d05fd Iustin Pop
  for hname in hypervisor_list:
863 e69d05fd Iustin Pop
    try:
864 e69d05fd Iustin Pop
      names = hypervisor.GetHypervisor(hname).ListInstances()
865 e69d05fd Iustin Pop
      results.extend(names)
866 e69d05fd Iustin Pop
    except errors.HypervisorError, err:
867 aca13712 Iustin Pop
      _Fail("Error enumerating instances (hypervisor %s): %s",
868 aca13712 Iustin Pop
            hname, err, exc=True)
869 a8083063 Iustin Pop
870 e69d05fd Iustin Pop
  return results
871 a8083063 Iustin Pop
872 a8083063 Iustin Pop
873 e69d05fd Iustin Pop
def GetInstanceInfo(instance, hname):
874 5bbd3f7f Michael Hanselmann
  """Gives back the information about an instance as a dictionary.
875 a8083063 Iustin Pop

876 e69d05fd Iustin Pop
  @type instance: string
877 e69d05fd Iustin Pop
  @param instance: the instance name
878 e69d05fd Iustin Pop
  @type hname: string
879 e69d05fd Iustin Pop
  @param hname: the hypervisor type of the instance
880 a8083063 Iustin Pop

881 e69d05fd Iustin Pop
  @rtype: dict
882 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
883 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
884 e69d05fd Iustin Pop
      - state: xen state of instance (string)
885 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
886 a8083063 Iustin Pop

887 098c0958 Michael Hanselmann
  """
888 a8083063 Iustin Pop
  output = {}
889 a8083063 Iustin Pop
890 e69d05fd Iustin Pop
  iinfo = hypervisor.GetHypervisor(hname).GetInstanceInfo(instance)
891 a8083063 Iustin Pop
  if iinfo is not None:
892 d0c8c01d Iustin Pop
    output["memory"] = iinfo[2]
893 d0c8c01d Iustin Pop
    output["state"] = iinfo[4]
894 d0c8c01d Iustin Pop
    output["time"] = iinfo[5]
895 a8083063 Iustin Pop
896 c26a6bd2 Iustin Pop
  return output
897 a8083063 Iustin Pop
898 a8083063 Iustin Pop
899 56e7640c Iustin Pop
def GetInstanceMigratable(instance):
900 56e7640c Iustin Pop
  """Gives whether an instance can be migrated.
901 56e7640c Iustin Pop

902 56e7640c Iustin Pop
  @type instance: L{objects.Instance}
903 56e7640c Iustin Pop
  @param instance: object representing the instance to be checked.
904 56e7640c Iustin Pop

905 56e7640c Iustin Pop
  @rtype: tuple
906 56e7640c Iustin Pop
  @return: tuple of (result, description) where:
907 56e7640c Iustin Pop
      - result: whether the instance can be migrated or not
908 56e7640c Iustin Pop
      - description: a description of the issue, if relevant
909 56e7640c Iustin Pop

910 56e7640c Iustin Pop
  """
911 56e7640c Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
912 afdc3985 Iustin Pop
  iname = instance.name
913 afdc3985 Iustin Pop
  if iname not in hyper.ListInstances():
914 afdc3985 Iustin Pop
    _Fail("Instance %s is not running", iname)
915 56e7640c Iustin Pop
916 56e7640c Iustin Pop
  for idx in range(len(instance.disks)):
917 afdc3985 Iustin Pop
    link_name = _GetBlockDevSymlinkPath(iname, idx)
918 56e7640c Iustin Pop
    if not os.path.islink(link_name):
919 b8ebd37b Iustin Pop
      logging.warning("Instance %s is missing symlink %s for disk %d",
920 b8ebd37b Iustin Pop
                      iname, link_name, idx)
921 56e7640c Iustin Pop
922 56e7640c Iustin Pop
923 e69d05fd Iustin Pop
def GetAllInstancesInfo(hypervisor_list):
924 a8083063 Iustin Pop
  """Gather data about all instances.
925 a8083063 Iustin Pop

926 10c2650b Iustin Pop
  This is the equivalent of L{GetInstanceInfo}, except that it
927 a8083063 Iustin Pop
  computes data for all instances at once, thus being faster if one
928 a8083063 Iustin Pop
  needs data about more than one instance.
929 a8083063 Iustin Pop

930 e69d05fd Iustin Pop
  @type hypervisor_list: list
931 e69d05fd Iustin Pop
  @param hypervisor_list: list of hypervisors to query for instance data
932 e69d05fd Iustin Pop

933 955db481 Guido Trotter
  @rtype: dict
934 e69d05fd Iustin Pop
  @return: dictionary of instance: data, with data having the following keys:
935 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
936 e69d05fd Iustin Pop
      - state: xen state of instance (string)
937 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
938 10c2650b Iustin Pop
      - vcpus: the number of vcpus
939 a8083063 Iustin Pop

940 098c0958 Michael Hanselmann
  """
941 a8083063 Iustin Pop
  output = {}
942 a8083063 Iustin Pop
943 e69d05fd Iustin Pop
  for hname in hypervisor_list:
944 e69d05fd Iustin Pop
    iinfo = hypervisor.GetHypervisor(hname).GetAllInstancesInfo()
945 e69d05fd Iustin Pop
    if iinfo:
946 29921401 Iustin Pop
      for name, _, memory, vcpus, state, times in iinfo:
947 f23b5ae8 Iustin Pop
        value = {
948 d0c8c01d Iustin Pop
          "memory": memory,
949 d0c8c01d Iustin Pop
          "vcpus": vcpus,
950 d0c8c01d Iustin Pop
          "state": state,
951 d0c8c01d Iustin Pop
          "time": times,
952 e69d05fd Iustin Pop
          }
953 b33b6f55 Iustin Pop
        if name in output:
954 b33b6f55 Iustin Pop
          # we only check static parameters, like memory and vcpus,
955 b33b6f55 Iustin Pop
          # and not state and time which can change between the
956 b33b6f55 Iustin Pop
          # invocations of the different hypervisors
957 d0c8c01d Iustin Pop
          for key in "memory", "vcpus":
958 b33b6f55 Iustin Pop
            if value[key] != output[name][key]:
959 2fa74ef4 Iustin Pop
              _Fail("Instance %s is running twice"
960 2fa74ef4 Iustin Pop
                    " with different parameters", name)
961 f23b5ae8 Iustin Pop
        output[name] = value
962 a8083063 Iustin Pop
963 c26a6bd2 Iustin Pop
  return output
964 a8083063 Iustin Pop
965 a8083063 Iustin Pop
966 6aa7a354 Iustin Pop
def _InstanceLogName(kind, os_name, instance, component):
967 81a3406c Iustin Pop
  """Compute the OS log filename for a given instance and operation.
968 81a3406c Iustin Pop

969 81a3406c Iustin Pop
  The instance name and os name are passed in as strings since not all
970 81a3406c Iustin Pop
  operations have these as part of an instance object.
971 81a3406c Iustin Pop

972 81a3406c Iustin Pop
  @type kind: string
973 81a3406c Iustin Pop
  @param kind: the operation type (e.g. add, import, etc.)
974 81a3406c Iustin Pop
  @type os_name: string
975 81a3406c Iustin Pop
  @param os_name: the os name
976 81a3406c Iustin Pop
  @type instance: string
977 81a3406c Iustin Pop
  @param instance: the name of the instance being imported/added/etc.
978 6aa7a354 Iustin Pop
  @type component: string or None
979 6aa7a354 Iustin Pop
  @param component: the name of the component of the instance being
980 6aa7a354 Iustin Pop
      transferred
981 81a3406c Iustin Pop

982 81a3406c Iustin Pop
  """
983 1651d116 Michael Hanselmann
  # TODO: Use tempfile.mkstemp to create unique filename
984 6aa7a354 Iustin Pop
  if component:
985 6aa7a354 Iustin Pop
    assert "/" not in component
986 6aa7a354 Iustin Pop
    c_msg = "-%s" % component
987 6aa7a354 Iustin Pop
  else:
988 6aa7a354 Iustin Pop
    c_msg = ""
989 6aa7a354 Iustin Pop
  base = ("%s-%s-%s%s-%s.log" %
990 6aa7a354 Iustin Pop
          (kind, os_name, instance, c_msg, utils.TimestampForFilename()))
991 81a3406c Iustin Pop
  return utils.PathJoin(constants.LOG_OS_DIR, base)
992 81a3406c Iustin Pop
993 81a3406c Iustin Pop
994 4a0e011f Iustin Pop
def InstanceOsAdd(instance, reinstall, debug):
995 2f8598a5 Alexander Schreiber
  """Add an OS to an instance.
996 a8083063 Iustin Pop

997 d15a9ad3 Guido Trotter
  @type instance: L{objects.Instance}
998 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
999 e557bae9 Guido Trotter
  @type reinstall: boolean
1000 e557bae9 Guido Trotter
  @param reinstall: whether this is an instance reinstall
1001 4a0e011f Iustin Pop
  @type debug: integer
1002 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1003 c26a6bd2 Iustin Pop
  @rtype: None
1004 a8083063 Iustin Pop

1005 a8083063 Iustin Pop
  """
1006 255dcebd Iustin Pop
  inst_os = OSFromDisk(instance.os)
1007 255dcebd Iustin Pop
1008 4a0e011f Iustin Pop
  create_env = OSEnvironment(instance, inst_os, debug)
1009 e557bae9 Guido Trotter
  if reinstall:
1010 d0c8c01d Iustin Pop
    create_env["INSTANCE_REINSTALL"] = "1"
1011 a8083063 Iustin Pop
1012 6aa7a354 Iustin Pop
  logfile = _InstanceLogName("add", instance.os, instance.name, None)
1013 decd5f45 Iustin Pop
1014 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.create_script], env=create_env,
1015 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1016 decd5f45 Iustin Pop
  if result.failed:
1017 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s, logfile: %s,"
1018 d868edb4 Iustin Pop
                  " output: %s", result.cmd, result.fail_reason, logfile,
1019 18682bca Iustin Pop
                  result.output)
1020 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1021 20e01edd Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1022 afdc3985 Iustin Pop
    _Fail("OS create script failed (%s), last lines in the"
1023 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1024 decd5f45 Iustin Pop
1025 decd5f45 Iustin Pop
1026 4a0e011f Iustin Pop
def RunRenameInstance(instance, old_name, debug):
1027 decd5f45 Iustin Pop
  """Run the OS rename script for an instance.
1028 decd5f45 Iustin Pop

1029 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1030 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1031 d15a9ad3 Guido Trotter
  @type old_name: string
1032 d15a9ad3 Guido Trotter
  @param old_name: previous instance name
1033 4a0e011f Iustin Pop
  @type debug: integer
1034 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1035 10c2650b Iustin Pop
  @rtype: boolean
1036 10c2650b Iustin Pop
  @return: the success of the operation
1037 decd5f45 Iustin Pop

1038 decd5f45 Iustin Pop
  """
1039 decd5f45 Iustin Pop
  inst_os = OSFromDisk(instance.os)
1040 decd5f45 Iustin Pop
1041 4a0e011f Iustin Pop
  rename_env = OSEnvironment(instance, inst_os, debug)
1042 d0c8c01d Iustin Pop
  rename_env["OLD_INSTANCE_NAME"] = old_name
1043 decd5f45 Iustin Pop
1044 81a3406c Iustin Pop
  logfile = _InstanceLogName("rename", instance.os,
1045 6aa7a354 Iustin Pop
                             "%s-%s" % (old_name, instance.name), None)
1046 a8083063 Iustin Pop
1047 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.rename_script], env=rename_env,
1048 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1049 a8083063 Iustin Pop
1050 a8083063 Iustin Pop
  if result.failed:
1051 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s output: %s",
1052 d868edb4 Iustin Pop
                  result.cmd, result.fail_reason, result.output)
1053 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1054 96841384 Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1055 afdc3985 Iustin Pop
    _Fail("OS rename script failed (%s), last lines in the"
1056 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1057 a8083063 Iustin Pop
1058 a8083063 Iustin Pop
1059 5282084b Iustin Pop
def _GetBlockDevSymlinkPath(instance_name, idx):
1060 3536c792 Iustin Pop
  return utils.PathJoin(constants.DISK_LINKS_DIR, "%s%s%d" %
1061 3536c792 Iustin Pop
                        (instance_name, constants.DISK_SEPARATOR, idx))
1062 5282084b Iustin Pop
1063 5282084b Iustin Pop
1064 5282084b Iustin Pop
def _SymlinkBlockDev(instance_name, device_path, idx):
1065 9332fd8a Iustin Pop
  """Set up symlinks to a instance's block device.
1066 9332fd8a Iustin Pop

1067 9332fd8a Iustin Pop
  This is an auxiliary function run when an instance is start (on the primary
1068 9332fd8a Iustin Pop
  node) or when an instance is migrated (on the target node).
1069 9332fd8a Iustin Pop

1070 9332fd8a Iustin Pop

1071 5282084b Iustin Pop
  @param instance_name: the name of the target instance
1072 5282084b Iustin Pop
  @param device_path: path of the physical block device, on the node
1073 5282084b Iustin Pop
  @param idx: the disk index
1074 5282084b Iustin Pop
  @return: absolute path to the disk's symlink
1075 9332fd8a Iustin Pop

1076 9332fd8a Iustin Pop
  """
1077 5282084b Iustin Pop
  link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1078 9332fd8a Iustin Pop
  try:
1079 9332fd8a Iustin Pop
    os.symlink(device_path, link_name)
1080 5282084b Iustin Pop
  except OSError, err:
1081 5282084b Iustin Pop
    if err.errno == errno.EEXIST:
1082 9332fd8a Iustin Pop
      if (not os.path.islink(link_name) or
1083 9332fd8a Iustin Pop
          os.readlink(link_name) != device_path):
1084 9332fd8a Iustin Pop
        os.remove(link_name)
1085 9332fd8a Iustin Pop
        os.symlink(device_path, link_name)
1086 9332fd8a Iustin Pop
    else:
1087 9332fd8a Iustin Pop
      raise
1088 9332fd8a Iustin Pop
1089 9332fd8a Iustin Pop
  return link_name
1090 9332fd8a Iustin Pop
1091 9332fd8a Iustin Pop
1092 5282084b Iustin Pop
def _RemoveBlockDevLinks(instance_name, disks):
1093 3c9c571d Iustin Pop
  """Remove the block device symlinks belonging to the given instance.
1094 3c9c571d Iustin Pop

1095 3c9c571d Iustin Pop
  """
1096 29921401 Iustin Pop
  for idx, _ in enumerate(disks):
1097 5282084b Iustin Pop
    link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1098 5282084b Iustin Pop
    if os.path.islink(link_name):
1099 3c9c571d Iustin Pop
      try:
1100 03dfa658 Iustin Pop
        os.remove(link_name)
1101 03dfa658 Iustin Pop
      except OSError:
1102 03dfa658 Iustin Pop
        logging.exception("Can't remove symlink '%s'", link_name)
1103 3c9c571d Iustin Pop
1104 3c9c571d Iustin Pop
1105 9332fd8a Iustin Pop
def _GatherAndLinkBlockDevs(instance):
1106 a8083063 Iustin Pop
  """Set up an instance's block device(s).
1107 a8083063 Iustin Pop

1108 a8083063 Iustin Pop
  This is run on the primary node at instance startup. The block
1109 a8083063 Iustin Pop
  devices must be already assembled.
1110 a8083063 Iustin Pop

1111 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1112 10c2650b Iustin Pop
  @param instance: the instance whose disks we shoul assemble
1113 069cfbf1 Iustin Pop
  @rtype: list
1114 069cfbf1 Iustin Pop
  @return: list of (disk_object, device_path)
1115 10c2650b Iustin Pop

1116 a8083063 Iustin Pop
  """
1117 a8083063 Iustin Pop
  block_devices = []
1118 9332fd8a Iustin Pop
  for idx, disk in enumerate(instance.disks):
1119 a8083063 Iustin Pop
    device = _RecursiveFindBD(disk)
1120 a8083063 Iustin Pop
    if device is None:
1121 a8083063 Iustin Pop
      raise errors.BlockDeviceError("Block device '%s' is not set up." %
1122 a8083063 Iustin Pop
                                    str(disk))
1123 a8083063 Iustin Pop
    device.Open()
1124 9332fd8a Iustin Pop
    try:
1125 5282084b Iustin Pop
      link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
1126 9332fd8a Iustin Pop
    except OSError, e:
1127 9332fd8a Iustin Pop
      raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
1128 9332fd8a Iustin Pop
                                    e.strerror)
1129 9332fd8a Iustin Pop
1130 9332fd8a Iustin Pop
    block_devices.append((disk, link_name))
1131 9332fd8a Iustin Pop
1132 a8083063 Iustin Pop
  return block_devices
1133 a8083063 Iustin Pop
1134 a8083063 Iustin Pop
1135 323f9095 Stephen Shirley
def StartInstance(instance, startup_paused):
1136 a8083063 Iustin Pop
  """Start an instance.
1137 a8083063 Iustin Pop

1138 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1139 e69d05fd Iustin Pop
  @param instance: the instance object
1140 323f9095 Stephen Shirley
  @type startup_paused: bool
1141 323f9095 Stephen Shirley
  @param instance: pause instance at startup?
1142 c26a6bd2 Iustin Pop
  @rtype: None
1143 a8083063 Iustin Pop

1144 098c0958 Michael Hanselmann
  """
1145 e69d05fd Iustin Pop
  running_instances = GetInstanceList([instance.hypervisor])
1146 a8083063 Iustin Pop
1147 a8083063 Iustin Pop
  if instance.name in running_instances:
1148 c26a6bd2 Iustin Pop
    logging.info("Instance %s already running, not starting", instance.name)
1149 c26a6bd2 Iustin Pop
    return
1150 a8083063 Iustin Pop
1151 a8083063 Iustin Pop
  try:
1152 ec596c24 Iustin Pop
    block_devices = _GatherAndLinkBlockDevs(instance)
1153 ec596c24 Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
1154 323f9095 Stephen Shirley
    hyper.StartInstance(instance, block_devices, startup_paused)
1155 ec596c24 Iustin Pop
  except errors.BlockDeviceError, err:
1156 2cc6781a Iustin Pop
    _Fail("Block device error: %s", err, exc=True)
1157 a8083063 Iustin Pop
  except errors.HypervisorError, err:
1158 5282084b Iustin Pop
    _RemoveBlockDevLinks(instance.name, instance.disks)
1159 2cc6781a Iustin Pop
    _Fail("Hypervisor error: %s", err, exc=True)
1160 a8083063 Iustin Pop
1161 a8083063 Iustin Pop
1162 6263189c Guido Trotter
def InstanceShutdown(instance, timeout):
1163 a8083063 Iustin Pop
  """Shut an instance down.
1164 a8083063 Iustin Pop

1165 10c2650b Iustin Pop
  @note: this functions uses polling with a hardcoded timeout.
1166 10c2650b Iustin Pop

1167 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1168 e69d05fd Iustin Pop
  @param instance: the instance object
1169 6263189c Guido Trotter
  @type timeout: integer
1170 6263189c Guido Trotter
  @param timeout: maximum timeout for soft shutdown
1171 c26a6bd2 Iustin Pop
  @rtype: None
1172 a8083063 Iustin Pop

1173 098c0958 Michael Hanselmann
  """
1174 e69d05fd Iustin Pop
  hv_name = instance.hypervisor
1175 e4e9b806 Guido Trotter
  hyper = hypervisor.GetHypervisor(hv_name)
1176 c26a6bd2 Iustin Pop
  iname = instance.name
1177 a8083063 Iustin Pop
1178 3c0cdc83 Michael Hanselmann
  if instance.name not in hyper.ListInstances():
1179 c26a6bd2 Iustin Pop
    logging.info("Instance %s not running, doing nothing", iname)
1180 c26a6bd2 Iustin Pop
    return
1181 a8083063 Iustin Pop
1182 3c0cdc83 Michael Hanselmann
  class _TryShutdown:
1183 3c0cdc83 Michael Hanselmann
    def __init__(self):
1184 3c0cdc83 Michael Hanselmann
      self.tried_once = False
1185 a8083063 Iustin Pop
1186 3c0cdc83 Michael Hanselmann
    def __call__(self):
1187 3c0cdc83 Michael Hanselmann
      if iname not in hyper.ListInstances():
1188 3c0cdc83 Michael Hanselmann
        return
1189 3c0cdc83 Michael Hanselmann
1190 3c0cdc83 Michael Hanselmann
      try:
1191 3c0cdc83 Michael Hanselmann
        hyper.StopInstance(instance, retry=self.tried_once)
1192 3c0cdc83 Michael Hanselmann
      except errors.HypervisorError, err:
1193 3c0cdc83 Michael Hanselmann
        if iname not in hyper.ListInstances():
1194 3c0cdc83 Michael Hanselmann
          # if the instance is no longer existing, consider this a
1195 3c0cdc83 Michael Hanselmann
          # success and go to cleanup
1196 3c0cdc83 Michael Hanselmann
          return
1197 3c0cdc83 Michael Hanselmann
1198 3c0cdc83 Michael Hanselmann
        _Fail("Failed to stop instance %s: %s", iname, err)
1199 3c0cdc83 Michael Hanselmann
1200 3c0cdc83 Michael Hanselmann
      self.tried_once = True
1201 3c0cdc83 Michael Hanselmann
1202 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
1203 3c0cdc83 Michael Hanselmann
1204 3c0cdc83 Michael Hanselmann
  try:
1205 3c0cdc83 Michael Hanselmann
    utils.Retry(_TryShutdown(), 5, timeout)
1206 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
1207 a8083063 Iustin Pop
    # the shutdown did not succeed
1208 e4e9b806 Guido Trotter
    logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
1209 a8083063 Iustin Pop
1210 a8083063 Iustin Pop
    try:
1211 a8083063 Iustin Pop
      hyper.StopInstance(instance, force=True)
1212 a8083063 Iustin Pop
    except errors.HypervisorError, err:
1213 3c0cdc83 Michael Hanselmann
      if iname in hyper.ListInstances():
1214 3782acd7 Iustin Pop
        # only raise an error if the instance still exists, otherwise
1215 3782acd7 Iustin Pop
        # the error could simply be "instance ... unknown"!
1216 3782acd7 Iustin Pop
        _Fail("Failed to force stop instance %s: %s", iname, err)
1217 a8083063 Iustin Pop
1218 a8083063 Iustin Pop
    time.sleep(1)
1219 3c0cdc83 Michael Hanselmann
1220 3c0cdc83 Michael Hanselmann
    if iname in hyper.ListInstances():
1221 c26a6bd2 Iustin Pop
      _Fail("Could not shutdown instance %s even by destroy", iname)
1222 3c9c571d Iustin Pop
1223 f28ec899 Guido Trotter
  try:
1224 f28ec899 Guido Trotter
    hyper.CleanupInstance(instance.name)
1225 f28ec899 Guido Trotter
  except errors.HypervisorError, err:
1226 f28ec899 Guido Trotter
    logging.warning("Failed to execute post-shutdown cleanup step: %s", err)
1227 f28ec899 Guido Trotter
1228 c26a6bd2 Iustin Pop
  _RemoveBlockDevLinks(iname, instance.disks)
1229 a8083063 Iustin Pop
1230 a8083063 Iustin Pop
1231 17c3f802 Guido Trotter
def InstanceReboot(instance, reboot_type, shutdown_timeout):
1232 007a2f3e Alexander Schreiber
  """Reboot an instance.
1233 007a2f3e Alexander Schreiber

1234 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1235 10c2650b Iustin Pop
  @param instance: the instance object to reboot
1236 10c2650b Iustin Pop
  @type reboot_type: str
1237 10c2650b Iustin Pop
  @param reboot_type: the type of reboot, one the following
1238 10c2650b Iustin Pop
    constants:
1239 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_SOFT}: only reboot the
1240 10c2650b Iustin Pop
        instance OS, do not recreate the VM
1241 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_HARD}: tear down and
1242 10c2650b Iustin Pop
        restart the VM (at the hypervisor level)
1243 73e5a4f4 Iustin Pop
      - the other reboot type (L{constants.INSTANCE_REBOOT_FULL}) is
1244 73e5a4f4 Iustin Pop
        not accepted here, since that mode is handled differently, in
1245 73e5a4f4 Iustin Pop
        cmdlib, and translates into full stop and start of the
1246 73e5a4f4 Iustin Pop
        instance (instead of a call_instance_reboot RPC)
1247 23057d29 Michael Hanselmann
  @type shutdown_timeout: integer
1248 23057d29 Michael Hanselmann
  @param shutdown_timeout: maximum timeout for soft shutdown
1249 c26a6bd2 Iustin Pop
  @rtype: None
1250 007a2f3e Alexander Schreiber

1251 007a2f3e Alexander Schreiber
  """
1252 e69d05fd Iustin Pop
  running_instances = GetInstanceList([instance.hypervisor])
1253 007a2f3e Alexander Schreiber
1254 007a2f3e Alexander Schreiber
  if instance.name not in running_instances:
1255 2cc6781a Iustin Pop
    _Fail("Cannot reboot instance %s that is not running", instance.name)
1256 007a2f3e Alexander Schreiber
1257 e69d05fd Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1258 007a2f3e Alexander Schreiber
  if reboot_type == constants.INSTANCE_REBOOT_SOFT:
1259 007a2f3e Alexander Schreiber
    try:
1260 007a2f3e Alexander Schreiber
      hyper.RebootInstance(instance)
1261 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1262 2cc6781a Iustin Pop
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1263 007a2f3e Alexander Schreiber
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1264 007a2f3e Alexander Schreiber
    try:
1265 17c3f802 Guido Trotter
      InstanceShutdown(instance, shutdown_timeout)
1266 82bc21e2 Stephen Shirley
      return StartInstance(instance, False)
1267 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1268 2cc6781a Iustin Pop
      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
1269 007a2f3e Alexander Schreiber
  else:
1270 2cc6781a Iustin Pop
    _Fail("Invalid reboot_type received: %s", reboot_type)
1271 007a2f3e Alexander Schreiber
1272 007a2f3e Alexander Schreiber
1273 6906a9d8 Guido Trotter
def MigrationInfo(instance):
1274 6906a9d8 Guido Trotter
  """Gather information about an instance to be migrated.
1275 6906a9d8 Guido Trotter

1276 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1277 6906a9d8 Guido Trotter
  @param instance: the instance definition
1278 6906a9d8 Guido Trotter

1279 6906a9d8 Guido Trotter
  """
1280 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1281 cd42d0ad Guido Trotter
  try:
1282 cd42d0ad Guido Trotter
    info = hyper.MigrationInfo(instance)
1283 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1284 2cc6781a Iustin Pop
    _Fail("Failed to fetch migration information: %s", err, exc=True)
1285 c26a6bd2 Iustin Pop
  return info
1286 6906a9d8 Guido Trotter
1287 6906a9d8 Guido Trotter
1288 6906a9d8 Guido Trotter
def AcceptInstance(instance, info, target):
1289 6906a9d8 Guido Trotter
  """Prepare the node to accept an instance.
1290 6906a9d8 Guido Trotter

1291 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1292 6906a9d8 Guido Trotter
  @param instance: the instance definition
1293 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
1294 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
1295 6906a9d8 Guido Trotter
  @type target: string
1296 6906a9d8 Guido Trotter
  @param target: target host (usually ip), on this node
1297 6906a9d8 Guido Trotter

1298 6906a9d8 Guido Trotter
  """
1299 77fcff4a Apollon Oikonomopoulos
  # TODO: why is this required only for DTS_EXT_MIRROR?
1300 77fcff4a Apollon Oikonomopoulos
  if instance.disk_template in constants.DTS_EXT_MIRROR:
1301 77fcff4a Apollon Oikonomopoulos
    # Create the symlinks, as the disks are not active
1302 77fcff4a Apollon Oikonomopoulos
    # in any way
1303 77fcff4a Apollon Oikonomopoulos
    try:
1304 77fcff4a Apollon Oikonomopoulos
      _GatherAndLinkBlockDevs(instance)
1305 77fcff4a Apollon Oikonomopoulos
    except errors.BlockDeviceError, err:
1306 77fcff4a Apollon Oikonomopoulos
      _Fail("Block device error: %s", err, exc=True)
1307 77fcff4a Apollon Oikonomopoulos
1308 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1309 cd42d0ad Guido Trotter
  try:
1310 cd42d0ad Guido Trotter
    hyper.AcceptInstance(instance, info, target)
1311 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1312 77fcff4a Apollon Oikonomopoulos
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1313 77fcff4a Apollon Oikonomopoulos
      _RemoveBlockDevLinks(instance.name, instance.disks)
1314 2cc6781a Iustin Pop
    _Fail("Failed to accept instance: %s", err, exc=True)
1315 6906a9d8 Guido Trotter
1316 6906a9d8 Guido Trotter
1317 6a1434d7 Andrea Spadaccini
def FinalizeMigrationDst(instance, info, success):
1318 6906a9d8 Guido Trotter
  """Finalize any preparation to accept an instance.
1319 6906a9d8 Guido Trotter

1320 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1321 6906a9d8 Guido Trotter
  @param instance: the instance definition
1322 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
1323 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
1324 6906a9d8 Guido Trotter
  @type success: boolean
1325 6906a9d8 Guido Trotter
  @param success: whether the migration was a success or a failure
1326 6906a9d8 Guido Trotter

1327 6906a9d8 Guido Trotter
  """
1328 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1329 cd42d0ad Guido Trotter
  try:
1330 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationDst(instance, info, success)
1331 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1332 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize migration on the target node: %s", err, exc=True)
1333 6906a9d8 Guido Trotter
1334 6906a9d8 Guido Trotter
1335 2a10865c Iustin Pop
def MigrateInstance(instance, target, live):
1336 2a10865c Iustin Pop
  """Migrates an instance to another node.
1337 2a10865c Iustin Pop

1338 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1339 9f0e6b37 Iustin Pop
  @param instance: the instance definition
1340 9f0e6b37 Iustin Pop
  @type target: string
1341 9f0e6b37 Iustin Pop
  @param target: the target node name
1342 9f0e6b37 Iustin Pop
  @type live: boolean
1343 9f0e6b37 Iustin Pop
  @param live: whether the migration should be done live or not (the
1344 9f0e6b37 Iustin Pop
      interpretation of this parameter is left to the hypervisor)
1345 c03fe62b Andrea Spadaccini
  @raise RPCFail: if migration fails for some reason
1346 9f0e6b37 Iustin Pop

1347 2a10865c Iustin Pop
  """
1348 53c776b5 Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1349 2a10865c Iustin Pop
1350 2a10865c Iustin Pop
  try:
1351 58d38b02 Iustin Pop
    hyper.MigrateInstance(instance, target, live)
1352 2a10865c Iustin Pop
  except errors.HypervisorError, err:
1353 2cc6781a Iustin Pop
    _Fail("Failed to migrate instance: %s", err, exc=True)
1354 2a10865c Iustin Pop
1355 2a10865c Iustin Pop
1356 6a1434d7 Andrea Spadaccini
def FinalizeMigrationSource(instance, success, live):
1357 6a1434d7 Andrea Spadaccini
  """Finalize the instance migration on the source node.
1358 6a1434d7 Andrea Spadaccini

1359 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
1360 6a1434d7 Andrea Spadaccini
  @param instance: the instance definition of the migrated instance
1361 6a1434d7 Andrea Spadaccini
  @type success: bool
1362 6a1434d7 Andrea Spadaccini
  @param success: whether the migration succeeded or not
1363 6a1434d7 Andrea Spadaccini
  @type live: bool
1364 6a1434d7 Andrea Spadaccini
  @param live: whether the user requested a live migration or not
1365 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the execution fails for some reason
1366 6a1434d7 Andrea Spadaccini

1367 6a1434d7 Andrea Spadaccini
  """
1368 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1369 6a1434d7 Andrea Spadaccini
1370 6a1434d7 Andrea Spadaccini
  try:
1371 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationSource(instance, success, live)
1372 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
1373 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize the migration on the source node: %s", err,
1374 6a1434d7 Andrea Spadaccini
          exc=True)
1375 6a1434d7 Andrea Spadaccini
1376 6a1434d7 Andrea Spadaccini
1377 6a1434d7 Andrea Spadaccini
def GetMigrationStatus(instance):
1378 6a1434d7 Andrea Spadaccini
  """Get the migration status
1379 6a1434d7 Andrea Spadaccini

1380 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
1381 6a1434d7 Andrea Spadaccini
  @param instance: the instance that is being migrated
1382 6a1434d7 Andrea Spadaccini
  @rtype: L{objects.MigrationStatus}
1383 6a1434d7 Andrea Spadaccini
  @return: the status of the current migration (one of
1384 6a1434d7 Andrea Spadaccini
           L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1385 6a1434d7 Andrea Spadaccini
           progress info that can be retrieved from the hypervisor
1386 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the migration status cannot be retrieved
1387 6a1434d7 Andrea Spadaccini

1388 6a1434d7 Andrea Spadaccini
  """
1389 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1390 6a1434d7 Andrea Spadaccini
  try:
1391 6a1434d7 Andrea Spadaccini
    return hyper.GetMigrationStatus(instance)
1392 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
1393 6a1434d7 Andrea Spadaccini
    _Fail("Failed to get migration status: %s", err, exc=True)
1394 6a1434d7 Andrea Spadaccini
1395 6a1434d7 Andrea Spadaccini
1396 821d1bd1 Iustin Pop
def BlockdevCreate(disk, size, owner, on_primary, info):
1397 a8083063 Iustin Pop
  """Creates a block device for an instance.
1398 a8083063 Iustin Pop

1399 b1206984 Iustin Pop
  @type disk: L{objects.Disk}
1400 b1206984 Iustin Pop
  @param disk: the object describing the disk we should create
1401 b1206984 Iustin Pop
  @type size: int
1402 b1206984 Iustin Pop
  @param size: the size of the physical underlying device, in MiB
1403 b1206984 Iustin Pop
  @type owner: str
1404 b1206984 Iustin Pop
  @param owner: the name of the instance for which disk is created,
1405 b1206984 Iustin Pop
      used for device cache data
1406 b1206984 Iustin Pop
  @type on_primary: boolean
1407 b1206984 Iustin Pop
  @param on_primary:  indicates if it is the primary node or not
1408 b1206984 Iustin Pop
  @type info: string
1409 b1206984 Iustin Pop
  @param info: string that will be sent to the physical device
1410 b1206984 Iustin Pop
      creation, used for example to set (LVM) tags on LVs
1411 b1206984 Iustin Pop

1412 b1206984 Iustin Pop
  @return: the new unique_id of the device (this can sometime be
1413 b1206984 Iustin Pop
      computed only after creation), or None. On secondary nodes,
1414 b1206984 Iustin Pop
      it's not required to return anything.
1415 a8083063 Iustin Pop

1416 a8083063 Iustin Pop
  """
1417 d0c8c01d Iustin Pop
  # TODO: remove the obsolete "size" argument
1418 b459a848 Andrea Spadaccini
  # pylint: disable=W0613
1419 a8083063 Iustin Pop
  clist = []
1420 a8083063 Iustin Pop
  if disk.children:
1421 a8083063 Iustin Pop
    for child in disk.children:
1422 1063abd1 Iustin Pop
      try:
1423 1063abd1 Iustin Pop
        crdev = _RecursiveAssembleBD(child, owner, on_primary)
1424 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
1425 2cc6781a Iustin Pop
        _Fail("Can't assemble device %s: %s", child, err)
1426 a8083063 Iustin Pop
      if on_primary or disk.AssembleOnSecondary():
1427 a8083063 Iustin Pop
        # we need the children open in case the device itself has to
1428 a8083063 Iustin Pop
        # be assembled
1429 1063abd1 Iustin Pop
        try:
1430 b459a848 Andrea Spadaccini
          # pylint: disable=E1103
1431 1063abd1 Iustin Pop
          crdev.Open()
1432 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
1433 2cc6781a Iustin Pop
          _Fail("Can't make child '%s' read-write: %s", child, err)
1434 a8083063 Iustin Pop
      clist.append(crdev)
1435 a8083063 Iustin Pop
1436 dab69e97 Iustin Pop
  try:
1437 464f8daf Iustin Pop
    device = bdev.Create(disk.dev_type, disk.physical_id, clist, disk.size)
1438 1063abd1 Iustin Pop
  except errors.BlockDeviceError, err:
1439 2cc6781a Iustin Pop
    _Fail("Can't create block device: %s", err)
1440 6c626518 Iustin Pop
1441 a8083063 Iustin Pop
  if on_primary or disk.AssembleOnSecondary():
1442 1063abd1 Iustin Pop
    try:
1443 1063abd1 Iustin Pop
      device.Assemble()
1444 1063abd1 Iustin Pop
    except errors.BlockDeviceError, err:
1445 2cc6781a Iustin Pop
      _Fail("Can't assemble device after creation, unusual event: %s", err)
1446 e31c43f7 Michael Hanselmann
    device.SetSyncSpeed(constants.SYNC_SPEED)
1447 a8083063 Iustin Pop
    if on_primary or disk.OpenOnSecondary():
1448 1063abd1 Iustin Pop
      try:
1449 1063abd1 Iustin Pop
        device.Open(force=True)
1450 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
1451 2cc6781a Iustin Pop
        _Fail("Can't make device r/w after creation, unusual event: %s", err)
1452 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(device.dev_path, owner,
1453 3f78eef2 Iustin Pop
                                on_primary, disk.iv_name)
1454 a0c3fea1 Michael Hanselmann
1455 a0c3fea1 Michael Hanselmann
  device.SetInfo(info)
1456 a0c3fea1 Michael Hanselmann
1457 c26a6bd2 Iustin Pop
  return device.unique_id
1458 a8083063 Iustin Pop
1459 a8083063 Iustin Pop
1460 da63bb4e René Nussbaumer
def _WipeDevice(path, offset, size):
1461 69dd363f René Nussbaumer
  """This function actually wipes the device.
1462 69dd363f René Nussbaumer

1463 69dd363f René Nussbaumer
  @param path: The path to the device to wipe
1464 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
1465 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
1466 69dd363f René Nussbaumer

1467 69dd363f René Nussbaumer
  """
1468 da63bb4e René Nussbaumer
  cmd = [constants.DD_CMD, "if=/dev/zero", "seek=%d" % offset,
1469 da63bb4e René Nussbaumer
         "bs=%d" % constants.WIPE_BLOCK_SIZE, "oflag=direct", "of=%s" % path,
1470 da63bb4e René Nussbaumer
         "count=%d" % size]
1471 da63bb4e René Nussbaumer
  result = utils.RunCmd(cmd)
1472 69dd363f René Nussbaumer
1473 69dd363f René Nussbaumer
  if result.failed:
1474 69dd363f René Nussbaumer
    _Fail("Wipe command '%s' exited with error: %s; output: %s", result.cmd,
1475 69dd363f René Nussbaumer
          result.fail_reason, result.output)
1476 69dd363f René Nussbaumer
1477 69dd363f René Nussbaumer
1478 da63bb4e René Nussbaumer
def BlockdevWipe(disk, offset, size):
1479 69dd363f René Nussbaumer
  """Wipes a block device.
1480 69dd363f René Nussbaumer

1481 69dd363f René Nussbaumer
  @type disk: L{objects.Disk}
1482 69dd363f René Nussbaumer
  @param disk: the disk object we want to wipe
1483 da63bb4e René Nussbaumer
  @type offset: int
1484 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
1485 da63bb4e René Nussbaumer
  @type size: int
1486 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
1487 69dd363f René Nussbaumer

1488 69dd363f René Nussbaumer
  """
1489 69dd363f René Nussbaumer
  try:
1490 69dd363f René Nussbaumer
    rdev = _RecursiveFindBD(disk)
1491 da63bb4e René Nussbaumer
  except errors.BlockDeviceError:
1492 da63bb4e René Nussbaumer
    rdev = None
1493 da63bb4e René Nussbaumer
1494 da63bb4e René Nussbaumer
  if not rdev:
1495 da63bb4e René Nussbaumer
    _Fail("Cannot execute wipe for device %s: device not found", disk.iv_name)
1496 da63bb4e René Nussbaumer
1497 da63bb4e René Nussbaumer
  # Do cross verify some of the parameters
1498 da63bb4e René Nussbaumer
  if offset > rdev.size:
1499 da63bb4e René Nussbaumer
    _Fail("Offset is bigger than device size")
1500 da63bb4e René Nussbaumer
  if (offset + size) > rdev.size:
1501 da63bb4e René Nussbaumer
    _Fail("The provided offset and size to wipe is bigger than device size")
1502 69dd363f René Nussbaumer
1503 da63bb4e René Nussbaumer
  _WipeDevice(rdev.dev_path, offset, size)
1504 69dd363f René Nussbaumer
1505 69dd363f René Nussbaumer
1506 5119c79e René Nussbaumer
def BlockdevPauseResumeSync(disks, pause):
1507 5119c79e René Nussbaumer
  """Pause or resume the sync of the block device.
1508 5119c79e René Nussbaumer

1509 0f39886a René Nussbaumer
  @type disks: list of L{objects.Disk}
1510 0f39886a René Nussbaumer
  @param disks: the disks object we want to pause/resume
1511 5119c79e René Nussbaumer
  @type pause: bool
1512 5119c79e René Nussbaumer
  @param pause: Wheater to pause or resume
1513 5119c79e René Nussbaumer

1514 5119c79e René Nussbaumer
  """
1515 5119c79e René Nussbaumer
  success = []
1516 5119c79e René Nussbaumer
  for disk in disks:
1517 5119c79e René Nussbaumer
    try:
1518 5119c79e René Nussbaumer
      rdev = _RecursiveFindBD(disk)
1519 5119c79e René Nussbaumer
    except errors.BlockDeviceError:
1520 5119c79e René Nussbaumer
      rdev = None
1521 5119c79e René Nussbaumer
1522 5119c79e René Nussbaumer
    if not rdev:
1523 5119c79e René Nussbaumer
      success.append((False, ("Cannot change sync for device %s:"
1524 5119c79e René Nussbaumer
                              " device not found" % disk.iv_name)))
1525 5119c79e René Nussbaumer
      continue
1526 5119c79e René Nussbaumer
1527 5119c79e René Nussbaumer
    result = rdev.PauseResumeSync(pause)
1528 5119c79e René Nussbaumer
1529 5119c79e René Nussbaumer
    if result:
1530 5119c79e René Nussbaumer
      success.append((result, None))
1531 5119c79e René Nussbaumer
    else:
1532 5119c79e René Nussbaumer
      if pause:
1533 5119c79e René Nussbaumer
        msg = "Pause"
1534 5119c79e René Nussbaumer
      else:
1535 5119c79e René Nussbaumer
        msg = "Resume"
1536 5119c79e René Nussbaumer
      success.append((result, "%s for device %s failed" % (msg, disk.iv_name)))
1537 5119c79e René Nussbaumer
1538 5119c79e René Nussbaumer
  return success
1539 5119c79e René Nussbaumer
1540 5119c79e René Nussbaumer
1541 821d1bd1 Iustin Pop
def BlockdevRemove(disk):
1542 a8083063 Iustin Pop
  """Remove a block device.
1543 a8083063 Iustin Pop

1544 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
1545 10c2650b Iustin Pop

1546 c41eea6e Iustin Pop
  @type disk: L{objects.Disk}
1547 10c2650b Iustin Pop
  @param disk: the disk object we should remove
1548 10c2650b Iustin Pop
  @rtype: boolean
1549 10c2650b Iustin Pop
  @return: the success of the operation
1550 a8083063 Iustin Pop

1551 a8083063 Iustin Pop
  """
1552 e1bc0878 Iustin Pop
  msgs = []
1553 a8083063 Iustin Pop
  try:
1554 bca2e7f4 Iustin Pop
    rdev = _RecursiveFindBD(disk)
1555 a8083063 Iustin Pop
  except errors.BlockDeviceError, err:
1556 a8083063 Iustin Pop
    # probably can't attach
1557 18682bca Iustin Pop
    logging.info("Can't attach to device %s in remove", disk)
1558 a8083063 Iustin Pop
    rdev = None
1559 a8083063 Iustin Pop
  if rdev is not None:
1560 3f78eef2 Iustin Pop
    r_path = rdev.dev_path
1561 e1bc0878 Iustin Pop
    try:
1562 0c6c04ec Iustin Pop
      rdev.Remove()
1563 e1bc0878 Iustin Pop
    except errors.BlockDeviceError, err:
1564 e1bc0878 Iustin Pop
      msgs.append(str(err))
1565 c26a6bd2 Iustin Pop
    if not msgs:
1566 3f78eef2 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
1567 e1bc0878 Iustin Pop
1568 a8083063 Iustin Pop
  if disk.children:
1569 a8083063 Iustin Pop
    for child in disk.children:
1570 c26a6bd2 Iustin Pop
      try:
1571 c26a6bd2 Iustin Pop
        BlockdevRemove(child)
1572 c26a6bd2 Iustin Pop
      except RPCFail, err:
1573 c26a6bd2 Iustin Pop
        msgs.append(str(err))
1574 e1bc0878 Iustin Pop
1575 c26a6bd2 Iustin Pop
  if msgs:
1576 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
1577 afdc3985 Iustin Pop
1578 a8083063 Iustin Pop
1579 3f78eef2 Iustin Pop
def _RecursiveAssembleBD(disk, owner, as_primary):
1580 a8083063 Iustin Pop
  """Activate a block device for an instance.
1581 a8083063 Iustin Pop

1582 a8083063 Iustin Pop
  This is run on the primary and secondary nodes for an instance.
1583 a8083063 Iustin Pop

1584 10c2650b Iustin Pop
  @note: this function is called recursively.
1585 a8083063 Iustin Pop

1586 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1587 10c2650b Iustin Pop
  @param disk: the disk we try to assemble
1588 10c2650b Iustin Pop
  @type owner: str
1589 10c2650b Iustin Pop
  @param owner: the name of the instance which owns the disk
1590 10c2650b Iustin Pop
  @type as_primary: boolean
1591 10c2650b Iustin Pop
  @param as_primary: if we should make the block device
1592 10c2650b Iustin Pop
      read/write
1593 a8083063 Iustin Pop

1594 10c2650b Iustin Pop
  @return: the assembled device or None (in case no device
1595 10c2650b Iustin Pop
      was assembled)
1596 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: in case there is an error
1597 10c2650b Iustin Pop
      during the activation of the children or the device
1598 10c2650b Iustin Pop
      itself
1599 a8083063 Iustin Pop

1600 a8083063 Iustin Pop
  """
1601 a8083063 Iustin Pop
  children = []
1602 a8083063 Iustin Pop
  if disk.children:
1603 fc1dc9d7 Iustin Pop
    mcn = disk.ChildrenNeeded()
1604 fc1dc9d7 Iustin Pop
    if mcn == -1:
1605 fc1dc9d7 Iustin Pop
      mcn = 0 # max number of Nones allowed
1606 fc1dc9d7 Iustin Pop
    else:
1607 fc1dc9d7 Iustin Pop
      mcn = len(disk.children) - mcn # max number of Nones
1608 a8083063 Iustin Pop
    for chld_disk in disk.children:
1609 fc1dc9d7 Iustin Pop
      try:
1610 fc1dc9d7 Iustin Pop
        cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary)
1611 fc1dc9d7 Iustin Pop
      except errors.BlockDeviceError, err:
1612 7803d4d3 Iustin Pop
        if children.count(None) >= mcn:
1613 fc1dc9d7 Iustin Pop
          raise
1614 fc1dc9d7 Iustin Pop
        cdev = None
1615 1063abd1 Iustin Pop
        logging.error("Error in child activation (but continuing): %s",
1616 1063abd1 Iustin Pop
                      str(err))
1617 fc1dc9d7 Iustin Pop
      children.append(cdev)
1618 a8083063 Iustin Pop
1619 a8083063 Iustin Pop
  if as_primary or disk.AssembleOnSecondary():
1620 464f8daf Iustin Pop
    r_dev = bdev.Assemble(disk.dev_type, disk.physical_id, children, disk.size)
1621 e31c43f7 Michael Hanselmann
    r_dev.SetSyncSpeed(constants.SYNC_SPEED)
1622 a8083063 Iustin Pop
    result = r_dev
1623 a8083063 Iustin Pop
    if as_primary or disk.OpenOnSecondary():
1624 a8083063 Iustin Pop
      r_dev.Open()
1625 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(r_dev.dev_path, owner,
1626 3f78eef2 Iustin Pop
                                as_primary, disk.iv_name)
1627 3f78eef2 Iustin Pop
1628 a8083063 Iustin Pop
  else:
1629 a8083063 Iustin Pop
    result = True
1630 a8083063 Iustin Pop
  return result
1631 a8083063 Iustin Pop
1632 a8083063 Iustin Pop
1633 c417e115 Iustin Pop
def BlockdevAssemble(disk, owner, as_primary, idx):
1634 a8083063 Iustin Pop
  """Activate a block device for an instance.
1635 a8083063 Iustin Pop

1636 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
1637 a8083063 Iustin Pop

1638 b1206984 Iustin Pop
  @rtype: str or boolean
1639 b1206984 Iustin Pop
  @return: a C{/dev/...} path for primary nodes, and
1640 b1206984 Iustin Pop
      C{True} for secondary nodes
1641 a8083063 Iustin Pop

1642 a8083063 Iustin Pop
  """
1643 53c14ef1 Iustin Pop
  try:
1644 53c14ef1 Iustin Pop
    result = _RecursiveAssembleBD(disk, owner, as_primary)
1645 53c14ef1 Iustin Pop
    if isinstance(result, bdev.BlockDev):
1646 b459a848 Andrea Spadaccini
      # pylint: disable=E1103
1647 53c14ef1 Iustin Pop
      result = result.dev_path
1648 c417e115 Iustin Pop
      if as_primary:
1649 c417e115 Iustin Pop
        _SymlinkBlockDev(owner, result, idx)
1650 53c14ef1 Iustin Pop
  except errors.BlockDeviceError, err:
1651 afdc3985 Iustin Pop
    _Fail("Error while assembling disk: %s", err, exc=True)
1652 c417e115 Iustin Pop
  except OSError, err:
1653 c417e115 Iustin Pop
    _Fail("Error while symlinking disk: %s", err, exc=True)
1654 afdc3985 Iustin Pop
1655 c26a6bd2 Iustin Pop
  return result
1656 a8083063 Iustin Pop
1657 a8083063 Iustin Pop
1658 821d1bd1 Iustin Pop
def BlockdevShutdown(disk):
1659 a8083063 Iustin Pop
  """Shut down a block device.
1660 a8083063 Iustin Pop

1661 5bbd3f7f Michael Hanselmann
  First, if the device is assembled (Attach() is successful), then
1662 c41eea6e Iustin Pop
  the device is shutdown. Then the children of the device are
1663 c41eea6e Iustin Pop
  shutdown.
1664 a8083063 Iustin Pop

1665 a8083063 Iustin Pop
  This function is called recursively. Note that we don't cache the
1666 a8083063 Iustin Pop
  children or such, as oppossed to assemble, shutdown of different
1667 a8083063 Iustin Pop
  devices doesn't require that the upper device was active.
1668 a8083063 Iustin Pop

1669 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1670 10c2650b Iustin Pop
  @param disk: the description of the disk we should
1671 10c2650b Iustin Pop
      shutdown
1672 c26a6bd2 Iustin Pop
  @rtype: None
1673 10c2650b Iustin Pop

1674 a8083063 Iustin Pop
  """
1675 cacfd1fd Iustin Pop
  msgs = []
1676 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
1677 a8083063 Iustin Pop
  if r_dev is not None:
1678 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
1679 cacfd1fd Iustin Pop
    try:
1680 746f7476 Iustin Pop
      r_dev.Shutdown()
1681 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
1682 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
1683 cacfd1fd Iustin Pop
      msgs.append(str(err))
1684 746f7476 Iustin Pop
1685 a8083063 Iustin Pop
  if disk.children:
1686 a8083063 Iustin Pop
    for child in disk.children:
1687 c26a6bd2 Iustin Pop
      try:
1688 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
1689 c26a6bd2 Iustin Pop
      except RPCFail, err:
1690 c26a6bd2 Iustin Pop
        msgs.append(str(err))
1691 746f7476 Iustin Pop
1692 c26a6bd2 Iustin Pop
  if msgs:
1693 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
1694 a8083063 Iustin Pop
1695 a8083063 Iustin Pop
1696 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
1697 153d9724 Iustin Pop
  """Extend a mirrored block device.
1698 a8083063 Iustin Pop

1699 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
1700 10c2650b Iustin Pop
  @param parent_cdev: the disk to which we should add children
1701 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
1702 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should add
1703 c26a6bd2 Iustin Pop
  @rtype: None
1704 10c2650b Iustin Pop

1705 a8083063 Iustin Pop
  """
1706 bca2e7f4 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
1707 153d9724 Iustin Pop
  if parent_bdev is None:
1708 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in add children", parent_cdev)
1709 153d9724 Iustin Pop
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
1710 153d9724 Iustin Pop
  if new_bdevs.count(None) > 0:
1711 2cc6781a Iustin Pop
    _Fail("Can't find new device(s) to add: %s:%s", new_bdevs, new_cdevs)
1712 153d9724 Iustin Pop
  parent_bdev.AddChildren(new_bdevs)
1713 a8083063 Iustin Pop
1714 a8083063 Iustin Pop
1715 821d1bd1 Iustin Pop
def BlockdevRemovechildren(parent_cdev, new_cdevs):
1716 153d9724 Iustin Pop
  """Shrink a mirrored block device.
1717 a8083063 Iustin Pop

1718 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
1719 10c2650b Iustin Pop
  @param parent_cdev: the disk from which we should remove children
1720 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
1721 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should remove
1722 c26a6bd2 Iustin Pop
  @rtype: None
1723 10c2650b Iustin Pop

1724 a8083063 Iustin Pop
  """
1725 153d9724 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
1726 153d9724 Iustin Pop
  if parent_bdev is None:
1727 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in remove children", parent_cdev)
1728 e739bd57 Iustin Pop
  devs = []
1729 e739bd57 Iustin Pop
  for disk in new_cdevs:
1730 e739bd57 Iustin Pop
    rpath = disk.StaticDevPath()
1731 e739bd57 Iustin Pop
    if rpath is None:
1732 e739bd57 Iustin Pop
      bd = _RecursiveFindBD(disk)
1733 e739bd57 Iustin Pop
      if bd is None:
1734 2cc6781a Iustin Pop
        _Fail("Can't find device %s while removing children", disk)
1735 e739bd57 Iustin Pop
      else:
1736 e739bd57 Iustin Pop
        devs.append(bd.dev_path)
1737 e739bd57 Iustin Pop
    else:
1738 e51db2a6 Iustin Pop
      if not utils.IsNormAbsPath(rpath):
1739 e51db2a6 Iustin Pop
        _Fail("Strange path returned from StaticDevPath: '%s'", rpath)
1740 e739bd57 Iustin Pop
      devs.append(rpath)
1741 e739bd57 Iustin Pop
  parent_bdev.RemoveChildren(devs)
1742 a8083063 Iustin Pop
1743 a8083063 Iustin Pop
1744 821d1bd1 Iustin Pop
def BlockdevGetmirrorstatus(disks):
1745 a8083063 Iustin Pop
  """Get the mirroring status of a list of devices.
1746 a8083063 Iustin Pop

1747 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
1748 10c2650b Iustin Pop
  @param disks: the list of disks which we should query
1749 10c2650b Iustin Pop
  @rtype: disk
1750 c6a9dffa Michael Hanselmann
  @return: List of L{objects.BlockDevStatus}, one for each disk
1751 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if any of the disks cannot be
1752 10c2650b Iustin Pop
      found
1753 a8083063 Iustin Pop

1754 a8083063 Iustin Pop
  """
1755 a8083063 Iustin Pop
  stats = []
1756 a8083063 Iustin Pop
  for dsk in disks:
1757 a8083063 Iustin Pop
    rbd = _RecursiveFindBD(dsk)
1758 a8083063 Iustin Pop
    if rbd is None:
1759 3efa9051 Iustin Pop
      _Fail("Can't find device %s", dsk)
1760 96acbc09 Michael Hanselmann
1761 36145b12 Michael Hanselmann
    stats.append(rbd.CombinedSyncStatus())
1762 96acbc09 Michael Hanselmann
1763 c26a6bd2 Iustin Pop
  return stats
1764 a8083063 Iustin Pop
1765 a8083063 Iustin Pop
1766 c6a9dffa Michael Hanselmann
def BlockdevGetmirrorstatusMulti(disks):
1767 c6a9dffa Michael Hanselmann
  """Get the mirroring status of a list of devices.
1768 c6a9dffa Michael Hanselmann

1769 c6a9dffa Michael Hanselmann
  @type disks: list of L{objects.Disk}
1770 c6a9dffa Michael Hanselmann
  @param disks: the list of disks which we should query
1771 c6a9dffa Michael Hanselmann
  @rtype: disk
1772 c6a9dffa Michael Hanselmann
  @return: List of tuples, (bool, status), one for each disk; bool denotes
1773 c6a9dffa Michael Hanselmann
    success/failure, status is L{objects.BlockDevStatus} on success, string
1774 c6a9dffa Michael Hanselmann
    otherwise
1775 c6a9dffa Michael Hanselmann

1776 c6a9dffa Michael Hanselmann
  """
1777 c6a9dffa Michael Hanselmann
  result = []
1778 c6a9dffa Michael Hanselmann
  for disk in disks:
1779 c6a9dffa Michael Hanselmann
    try:
1780 c6a9dffa Michael Hanselmann
      rbd = _RecursiveFindBD(disk)
1781 c6a9dffa Michael Hanselmann
      if rbd is None:
1782 c6a9dffa Michael Hanselmann
        result.append((False, "Can't find device %s" % disk))
1783 c6a9dffa Michael Hanselmann
        continue
1784 c6a9dffa Michael Hanselmann
1785 c6a9dffa Michael Hanselmann
      status = rbd.CombinedSyncStatus()
1786 c6a9dffa Michael Hanselmann
    except errors.BlockDeviceError, err:
1787 c6a9dffa Michael Hanselmann
      logging.exception("Error while getting disk status")
1788 c6a9dffa Michael Hanselmann
      result.append((False, str(err)))
1789 c6a9dffa Michael Hanselmann
    else:
1790 c6a9dffa Michael Hanselmann
      result.append((True, status))
1791 c6a9dffa Michael Hanselmann
1792 c6a9dffa Michael Hanselmann
  assert len(disks) == len(result)
1793 c6a9dffa Michael Hanselmann
1794 c6a9dffa Michael Hanselmann
  return result
1795 c6a9dffa Michael Hanselmann
1796 c6a9dffa Michael Hanselmann
1797 bca2e7f4 Iustin Pop
def _RecursiveFindBD(disk):
1798 a8083063 Iustin Pop
  """Check if a device is activated.
1799 a8083063 Iustin Pop

1800 5bbd3f7f Michael Hanselmann
  If so, return information about the real device.
1801 a8083063 Iustin Pop

1802 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1803 10c2650b Iustin Pop
  @param disk: the disk object we need to find
1804 a8083063 Iustin Pop

1805 10c2650b Iustin Pop
  @return: None if the device can't be found,
1806 10c2650b Iustin Pop
      otherwise the device instance
1807 a8083063 Iustin Pop

1808 a8083063 Iustin Pop
  """
1809 a8083063 Iustin Pop
  children = []
1810 a8083063 Iustin Pop
  if disk.children:
1811 a8083063 Iustin Pop
    for chdisk in disk.children:
1812 a8083063 Iustin Pop
      children.append(_RecursiveFindBD(chdisk))
1813 a8083063 Iustin Pop
1814 464f8daf Iustin Pop
  return bdev.FindDevice(disk.dev_type, disk.physical_id, children, disk.size)
1815 a8083063 Iustin Pop
1816 a8083063 Iustin Pop
1817 f2e07bb4 Michael Hanselmann
def _OpenRealBD(disk):
1818 f2e07bb4 Michael Hanselmann
  """Opens the underlying block device of a disk.
1819 f2e07bb4 Michael Hanselmann

1820 f2e07bb4 Michael Hanselmann
  @type disk: L{objects.Disk}
1821 f2e07bb4 Michael Hanselmann
  @param disk: the disk object we want to open
1822 f2e07bb4 Michael Hanselmann

1823 f2e07bb4 Michael Hanselmann
  """
1824 f2e07bb4 Michael Hanselmann
  real_disk = _RecursiveFindBD(disk)
1825 f2e07bb4 Michael Hanselmann
  if real_disk is None:
1826 f2e07bb4 Michael Hanselmann
    _Fail("Block device '%s' is not set up", disk)
1827 f2e07bb4 Michael Hanselmann
1828 f2e07bb4 Michael Hanselmann
  real_disk.Open()
1829 f2e07bb4 Michael Hanselmann
1830 f2e07bb4 Michael Hanselmann
  return real_disk
1831 f2e07bb4 Michael Hanselmann
1832 f2e07bb4 Michael Hanselmann
1833 821d1bd1 Iustin Pop
def BlockdevFind(disk):
1834 a8083063 Iustin Pop
  """Check if a device is activated.
1835 a8083063 Iustin Pop

1836 5bbd3f7f Michael Hanselmann
  If it is, return information about the real device.
1837 a8083063 Iustin Pop

1838 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1839 10c2650b Iustin Pop
  @param disk: the disk to find
1840 96acbc09 Michael Hanselmann
  @rtype: None or objects.BlockDevStatus
1841 96acbc09 Michael Hanselmann
  @return: None if the disk cannot be found, otherwise a the current
1842 96acbc09 Michael Hanselmann
           information
1843 a8083063 Iustin Pop

1844 a8083063 Iustin Pop
  """
1845 23829f6f Iustin Pop
  try:
1846 23829f6f Iustin Pop
    rbd = _RecursiveFindBD(disk)
1847 23829f6f Iustin Pop
  except errors.BlockDeviceError, err:
1848 2cc6781a Iustin Pop
    _Fail("Failed to find device: %s", err, exc=True)
1849 96acbc09 Michael Hanselmann
1850 a8083063 Iustin Pop
  if rbd is None:
1851 c26a6bd2 Iustin Pop
    return None
1852 96acbc09 Michael Hanselmann
1853 96acbc09 Michael Hanselmann
  return rbd.GetSyncStatus()
1854 a8083063 Iustin Pop
1855 a8083063 Iustin Pop
1856 968a7623 Iustin Pop
def BlockdevGetsize(disks):
1857 968a7623 Iustin Pop
  """Computes the size of the given disks.
1858 968a7623 Iustin Pop

1859 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
1860 968a7623 Iustin Pop

1861 968a7623 Iustin Pop
  @type disks: list of L{objects.Disk}
1862 968a7623 Iustin Pop
  @param disks: the list of disk to compute the size for
1863 968a7623 Iustin Pop
  @rtype: list
1864 968a7623 Iustin Pop
  @return: list with elements None if the disk cannot be found,
1865 968a7623 Iustin Pop
      otherwise the size
1866 968a7623 Iustin Pop

1867 968a7623 Iustin Pop
  """
1868 968a7623 Iustin Pop
  result = []
1869 968a7623 Iustin Pop
  for cf in disks:
1870 968a7623 Iustin Pop
    try:
1871 968a7623 Iustin Pop
      rbd = _RecursiveFindBD(cf)
1872 1122eb25 Iustin Pop
    except errors.BlockDeviceError:
1873 968a7623 Iustin Pop
      result.append(None)
1874 968a7623 Iustin Pop
      continue
1875 968a7623 Iustin Pop
    if rbd is None:
1876 968a7623 Iustin Pop
      result.append(None)
1877 968a7623 Iustin Pop
    else:
1878 968a7623 Iustin Pop
      result.append(rbd.GetActualSize())
1879 968a7623 Iustin Pop
  return result
1880 968a7623 Iustin Pop
1881 968a7623 Iustin Pop
1882 858f3d18 Iustin Pop
def BlockdevExport(disk, dest_node, dest_path, cluster_name):
1883 858f3d18 Iustin Pop
  """Export a block device to a remote node.
1884 858f3d18 Iustin Pop

1885 858f3d18 Iustin Pop
  @type disk: L{objects.Disk}
1886 858f3d18 Iustin Pop
  @param disk: the description of the disk to export
1887 858f3d18 Iustin Pop
  @type dest_node: str
1888 858f3d18 Iustin Pop
  @param dest_node: the destination node to export to
1889 858f3d18 Iustin Pop
  @type dest_path: str
1890 858f3d18 Iustin Pop
  @param dest_path: the destination path on the target node
1891 858f3d18 Iustin Pop
  @type cluster_name: str
1892 858f3d18 Iustin Pop
  @param cluster_name: the cluster name, needed for SSH hostalias
1893 858f3d18 Iustin Pop
  @rtype: None
1894 858f3d18 Iustin Pop

1895 858f3d18 Iustin Pop
  """
1896 f2e07bb4 Michael Hanselmann
  real_disk = _OpenRealBD(disk)
1897 858f3d18 Iustin Pop
1898 858f3d18 Iustin Pop
  # the block size on the read dd is 1MiB to match our units
1899 858f3d18 Iustin Pop
  expcmd = utils.BuildShellCmd("set -e; set -o pipefail; "
1900 858f3d18 Iustin Pop
                               "dd if=%s bs=1048576 count=%s",
1901 858f3d18 Iustin Pop
                               real_disk.dev_path, str(disk.size))
1902 858f3d18 Iustin Pop
1903 858f3d18 Iustin Pop
  # we set here a smaller block size as, due to ssh buffering, more
1904 858f3d18 Iustin Pop
  # than 64-128k will mostly ignored; we use nocreat to fail if the
1905 858f3d18 Iustin Pop
  # device is not already there or we pass a wrong path; we use
1906 858f3d18 Iustin Pop
  # notrunc to no attempt truncate on an LV device; we use oflag=dsync
1907 858f3d18 Iustin Pop
  # to not buffer too much memory; this means that at best, we flush
1908 858f3d18 Iustin Pop
  # every 64k, which will not be very fast
1909 858f3d18 Iustin Pop
  destcmd = utils.BuildShellCmd("dd of=%s conv=nocreat,notrunc bs=65536"
1910 858f3d18 Iustin Pop
                                " oflag=dsync", dest_path)
1911 858f3d18 Iustin Pop
1912 858f3d18 Iustin Pop
  remotecmd = _GetSshRunner(cluster_name).BuildCmd(dest_node,
1913 858f3d18 Iustin Pop
                                                   constants.GANETI_RUNAS,
1914 858f3d18 Iustin Pop
                                                   destcmd)
1915 858f3d18 Iustin Pop
1916 858f3d18 Iustin Pop
  # all commands have been checked, so we're safe to combine them
1917 d0c8c01d Iustin Pop
  command = "|".join([expcmd, utils.ShellQuoteArgs(remotecmd)])
1918 858f3d18 Iustin Pop
1919 858f3d18 Iustin Pop
  result = utils.RunCmd(["bash", "-c", command])
1920 858f3d18 Iustin Pop
1921 858f3d18 Iustin Pop
  if result.failed:
1922 858f3d18 Iustin Pop
    _Fail("Disk copy command '%s' returned error: %s"
1923 858f3d18 Iustin Pop
          " output: %s", command, result.fail_reason, result.output)
1924 858f3d18 Iustin Pop
1925 858f3d18 Iustin Pop
1926 a8083063 Iustin Pop
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
1927 a8083063 Iustin Pop
  """Write a file to the filesystem.
1928 a8083063 Iustin Pop

1929 a8083063 Iustin Pop
  This allows the master to overwrite(!) a file. It will only perform
1930 a8083063 Iustin Pop
  the operation if the file belongs to a list of configuration files.
1931 a8083063 Iustin Pop

1932 10c2650b Iustin Pop
  @type file_name: str
1933 10c2650b Iustin Pop
  @param file_name: the target file name
1934 10c2650b Iustin Pop
  @type data: str
1935 10c2650b Iustin Pop
  @param data: the new contents of the file
1936 10c2650b Iustin Pop
  @type mode: int
1937 10c2650b Iustin Pop
  @param mode: the mode to give the file (can be None)
1938 9a914f7a René Nussbaumer
  @type uid: string
1939 9a914f7a René Nussbaumer
  @param uid: the owner of the file
1940 9a914f7a René Nussbaumer
  @type gid: string
1941 9a914f7a René Nussbaumer
  @param gid: the group of the file
1942 10c2650b Iustin Pop
  @type atime: float
1943 10c2650b Iustin Pop
  @param atime: the atime to set on the file (can be None)
1944 10c2650b Iustin Pop
  @type mtime: float
1945 10c2650b Iustin Pop
  @param mtime: the mtime to set on the file (can be None)
1946 c26a6bd2 Iustin Pop
  @rtype: None
1947 10c2650b Iustin Pop

1948 a8083063 Iustin Pop
  """
1949 a8083063 Iustin Pop
  if not os.path.isabs(file_name):
1950 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile is not absolute: '%s'", file_name)
1951 a8083063 Iustin Pop
1952 360b0dc2 Iustin Pop
  if file_name not in _ALLOWED_UPLOAD_FILES:
1953 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile not in allowed upload targets: '%s'",
1954 2cc6781a Iustin Pop
          file_name)
1955 a8083063 Iustin Pop
1956 12bce260 Michael Hanselmann
  raw_data = _Decompress(data)
1957 12bce260 Michael Hanselmann
1958 9a914f7a René Nussbaumer
  if not (isinstance(uid, basestring) and isinstance(gid, basestring)):
1959 9a914f7a René Nussbaumer
    _Fail("Invalid username/groupname type")
1960 9a914f7a René Nussbaumer
1961 9a914f7a René Nussbaumer
  getents = runtime.GetEnts()
1962 9a914f7a René Nussbaumer
  uid = getents.LookupUser(uid)
1963 9a914f7a René Nussbaumer
  gid = getents.LookupGroup(gid)
1964 9a914f7a René Nussbaumer
1965 8f065ae2 Iustin Pop
  utils.SafeWriteFile(file_name, None,
1966 8f065ae2 Iustin Pop
                      data=raw_data, mode=mode, uid=uid, gid=gid,
1967 8f065ae2 Iustin Pop
                      atime=atime, mtime=mtime)
1968 a8083063 Iustin Pop
1969 386b57af Iustin Pop
1970 b2f29800 René Nussbaumer
def RunOob(oob_program, command, node, timeout):
1971 b2f29800 René Nussbaumer
  """Executes oob_program with given command on given node.
1972 b2f29800 René Nussbaumer

1973 b2f29800 René Nussbaumer
  @param oob_program: The path to the executable oob_program
1974 b2f29800 René Nussbaumer
  @param command: The command to invoke on oob_program
1975 b2f29800 René Nussbaumer
  @param node: The node given as an argument to the program
1976 b2f29800 René Nussbaumer
  @param timeout: Timeout after which we kill the oob program
1977 b2f29800 René Nussbaumer

1978 b2f29800 René Nussbaumer
  @return: stdout
1979 b2f29800 René Nussbaumer
  @raise RPCFail: If execution fails for some reason
1980 b2f29800 René Nussbaumer

1981 b2f29800 René Nussbaumer
  """
1982 b2f29800 René Nussbaumer
  result = utils.RunCmd([oob_program, command, node], timeout=timeout)
1983 b2f29800 René Nussbaumer
1984 b2f29800 René Nussbaumer
  if result.failed:
1985 b2f29800 René Nussbaumer
    _Fail("'%s' failed with reason '%s'; output: %s", result.cmd,
1986 b2f29800 René Nussbaumer
          result.fail_reason, result.output)
1987 b2f29800 René Nussbaumer
1988 b2f29800 René Nussbaumer
  return result.stdout
1989 b2f29800 René Nussbaumer
1990 b2f29800 René Nussbaumer
1991 03d1dba2 Michael Hanselmann
def WriteSsconfFiles(values):
1992 89b14f05 Iustin Pop
  """Update all ssconf files.
1993 89b14f05 Iustin Pop

1994 89b14f05 Iustin Pop
  Wrapper around the SimpleStore.WriteFiles.
1995 89b14f05 Iustin Pop

1996 89b14f05 Iustin Pop
  """
1997 89b14f05 Iustin Pop
  ssconf.SimpleStore().WriteFiles(values)
1998 6ddc95ec Michael Hanselmann
1999 6ddc95ec Michael Hanselmann
2000 a8083063 Iustin Pop
def _ErrnoOrStr(err):
2001 a8083063 Iustin Pop
  """Format an EnvironmentError exception.
2002 a8083063 Iustin Pop

2003 10c2650b Iustin Pop
  If the L{err} argument has an errno attribute, it will be looked up
2004 10c2650b Iustin Pop
  and converted into a textual C{E...} description. Otherwise the
2005 10c2650b Iustin Pop
  string representation of the error will be returned.
2006 10c2650b Iustin Pop

2007 10c2650b Iustin Pop
  @type err: L{EnvironmentError}
2008 10c2650b Iustin Pop
  @param err: the exception to format
2009 a8083063 Iustin Pop

2010 a8083063 Iustin Pop
  """
2011 d0c8c01d Iustin Pop
  if hasattr(err, "errno"):
2012 a8083063 Iustin Pop
    detail = errno.errorcode[err.errno]
2013 a8083063 Iustin Pop
  else:
2014 a8083063 Iustin Pop
    detail = str(err)
2015 a8083063 Iustin Pop
  return detail
2016 a8083063 Iustin Pop
2017 5d0fe286 Iustin Pop
2018 c19f9810 Iustin Pop
def _OSOndiskAPIVersion(os_dir):
2019 2f8598a5 Alexander Schreiber
  """Compute and return the API version of a given OS.
2020 a8083063 Iustin Pop

2021 c19f9810 Iustin Pop
  This function will try to read the API version of the OS residing in
2022 c19f9810 Iustin Pop
  the 'os_dir' directory.
2023 7c3d51d4 Guido Trotter

2024 10c2650b Iustin Pop
  @type os_dir: str
2025 c19f9810 Iustin Pop
  @param os_dir: the directory in which we should look for the OS
2026 8e70b181 Iustin Pop
  @rtype: tuple
2027 8e70b181 Iustin Pop
  @return: tuple (status, data) with status denoting the validity and
2028 8e70b181 Iustin Pop
      data holding either the vaid versions or an error message
2029 a8083063 Iustin Pop

2030 a8083063 Iustin Pop
  """
2031 e02b9114 Iustin Pop
  api_file = utils.PathJoin(os_dir, constants.OS_API_FILE)
2032 a8083063 Iustin Pop
2033 a8083063 Iustin Pop
  try:
2034 a8083063 Iustin Pop
    st = os.stat(api_file)
2035 a8083063 Iustin Pop
  except EnvironmentError, err:
2036 b6b45e0d Guido Trotter
    return False, ("Required file '%s' not found under path %s: %s" %
2037 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir, _ErrnoOrStr(err)))
2038 a8083063 Iustin Pop
2039 a8083063 Iustin Pop
  if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2040 b6b45e0d Guido Trotter
    return False, ("File '%s' in %s is not a regular file" %
2041 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir))
2042 a8083063 Iustin Pop
2043 a8083063 Iustin Pop
  try:
2044 3374afa9 Guido Trotter
    api_versions = utils.ReadFile(api_file).splitlines()
2045 a8083063 Iustin Pop
  except EnvironmentError, err:
2046 255dcebd Iustin Pop
    return False, ("Error while reading the API version file at %s: %s" %
2047 255dcebd Iustin Pop
                   (api_file, _ErrnoOrStr(err)))
2048 a8083063 Iustin Pop
2049 a8083063 Iustin Pop
  try:
2050 63b9b186 Guido Trotter
    api_versions = [int(version.strip()) for version in api_versions]
2051 a8083063 Iustin Pop
  except (TypeError, ValueError), err:
2052 255dcebd Iustin Pop
    return False, ("API version(s) can't be converted to integer: %s" %
2053 255dcebd Iustin Pop
                   str(err))
2054 a8083063 Iustin Pop
2055 255dcebd Iustin Pop
  return True, api_versions
2056 a8083063 Iustin Pop
2057 386b57af Iustin Pop
2058 7c3d51d4 Guido Trotter
def DiagnoseOS(top_dirs=None):
2059 a8083063 Iustin Pop
  """Compute the validity for all OSes.
2060 a8083063 Iustin Pop

2061 10c2650b Iustin Pop
  @type top_dirs: list
2062 10c2650b Iustin Pop
  @param top_dirs: the list of directories in which to
2063 10c2650b Iustin Pop
      search (if not given defaults to
2064 10c2650b Iustin Pop
      L{constants.OS_SEARCH_PATH})
2065 10c2650b Iustin Pop
  @rtype: list of L{objects.OS}
2066 bad78e66 Iustin Pop
  @return: a list of tuples (name, path, status, diagnose, variants,
2067 bad78e66 Iustin Pop
      parameters, api_version) for all (potential) OSes under all
2068 bad78e66 Iustin Pop
      search paths, where:
2069 255dcebd Iustin Pop
          - name is the (potential) OS name
2070 255dcebd Iustin Pop
          - path is the full path to the OS
2071 255dcebd Iustin Pop
          - status True/False is the validity of the OS
2072 255dcebd Iustin Pop
          - diagnose is the error message for an invalid OS, otherwise empty
2073 ba00557a Guido Trotter
          - variants is a list of supported OS variants, if any
2074 c7d04a6b Iustin Pop
          - parameters is a list of (name, help) parameters, if any
2075 bad78e66 Iustin Pop
          - api_version is a list of support OS API versions
2076 a8083063 Iustin Pop

2077 a8083063 Iustin Pop
  """
2078 7c3d51d4 Guido Trotter
  if top_dirs is None:
2079 7c3d51d4 Guido Trotter
    top_dirs = constants.OS_SEARCH_PATH
2080 a8083063 Iustin Pop
2081 a8083063 Iustin Pop
  result = []
2082 65fe4693 Iustin Pop
  for dir_name in top_dirs:
2083 65fe4693 Iustin Pop
    if os.path.isdir(dir_name):
2084 7c3d51d4 Guido Trotter
      try:
2085 65fe4693 Iustin Pop
        f_names = utils.ListVisibleFiles(dir_name)
2086 7c3d51d4 Guido Trotter
      except EnvironmentError, err:
2087 29921401 Iustin Pop
        logging.exception("Can't list the OS directory %s: %s", dir_name, err)
2088 7c3d51d4 Guido Trotter
        break
2089 7c3d51d4 Guido Trotter
      for name in f_names:
2090 e02b9114 Iustin Pop
        os_path = utils.PathJoin(dir_name, name)
2091 255dcebd Iustin Pop
        status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
2092 255dcebd Iustin Pop
        if status:
2093 255dcebd Iustin Pop
          diagnose = ""
2094 ba00557a Guido Trotter
          variants = os_inst.supported_variants
2095 c7d04a6b Iustin Pop
          parameters = os_inst.supported_parameters
2096 bad78e66 Iustin Pop
          api_versions = os_inst.api_versions
2097 255dcebd Iustin Pop
        else:
2098 255dcebd Iustin Pop
          diagnose = os_inst
2099 bad78e66 Iustin Pop
          variants = parameters = api_versions = []
2100 bad78e66 Iustin Pop
        result.append((name, os_path, status, diagnose, variants,
2101 bad78e66 Iustin Pop
                       parameters, api_versions))
2102 a8083063 Iustin Pop
2103 c26a6bd2 Iustin Pop
  return result
2104 a8083063 Iustin Pop
2105 a8083063 Iustin Pop
2106 255dcebd Iustin Pop
def _TryOSFromDisk(name, base_dir=None):
2107 a8083063 Iustin Pop
  """Create an OS instance from disk.
2108 a8083063 Iustin Pop

2109 a8083063 Iustin Pop
  This function will return an OS instance if the given name is a
2110 8e70b181 Iustin Pop
  valid OS name.
2111 a8083063 Iustin Pop

2112 8ee4dc80 Guido Trotter
  @type base_dir: string
2113 8ee4dc80 Guido Trotter
  @keyword base_dir: Base directory containing OS installations.
2114 8ee4dc80 Guido Trotter
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2115 255dcebd Iustin Pop
  @rtype: tuple
2116 255dcebd Iustin Pop
  @return: success and either the OS instance if we find a valid one,
2117 255dcebd Iustin Pop
      or error message
2118 7c3d51d4 Guido Trotter

2119 a8083063 Iustin Pop
  """
2120 56bcd3f4 Guido Trotter
  if base_dir is None:
2121 57c177af Iustin Pop
    os_dir = utils.FindFile(name, constants.OS_SEARCH_PATH, os.path.isdir)
2122 c34c0cfd Iustin Pop
  else:
2123 f95c81bf Iustin Pop
    os_dir = utils.FindFile(name, [base_dir], os.path.isdir)
2124 f95c81bf Iustin Pop
2125 f95c81bf Iustin Pop
  if os_dir is None:
2126 5c0433d6 Iustin Pop
    return False, "Directory for OS %s not found in search path" % name
2127 a8083063 Iustin Pop
2128 c19f9810 Iustin Pop
  status, api_versions = _OSOndiskAPIVersion(os_dir)
2129 255dcebd Iustin Pop
  if not status:
2130 255dcebd Iustin Pop
    # push the error up
2131 255dcebd Iustin Pop
    return status, api_versions
2132 a8083063 Iustin Pop
2133 d1a7d66f Guido Trotter
  if not constants.OS_API_VERSIONS.intersection(api_versions):
2134 255dcebd Iustin Pop
    return False, ("API version mismatch for path '%s': found %s, want %s." %
2135 d1a7d66f Guido Trotter
                   (os_dir, api_versions, constants.OS_API_VERSIONS))
2136 a8083063 Iustin Pop
2137 35007011 Iustin Pop
  # OS Files dictionary, we will populate it with the absolute path
2138 35007011 Iustin Pop
  # names; if the value is True, then it is a required file, otherwise
2139 35007011 Iustin Pop
  # an optional one
2140 35007011 Iustin Pop
  os_files = dict.fromkeys(constants.OS_SCRIPTS, True)
2141 a8083063 Iustin Pop
2142 95075fba Guido Trotter
  if max(api_versions) >= constants.OS_API_V15:
2143 35007011 Iustin Pop
    os_files[constants.OS_VARIANTS_FILE] = False
2144 95075fba Guido Trotter
2145 c7d04a6b Iustin Pop
  if max(api_versions) >= constants.OS_API_V20:
2146 35007011 Iustin Pop
    os_files[constants.OS_PARAMETERS_FILE] = True
2147 c7d04a6b Iustin Pop
  else:
2148 c7d04a6b Iustin Pop
    del os_files[constants.OS_SCRIPT_VERIFY]
2149 c7d04a6b Iustin Pop
2150 35007011 Iustin Pop
  for (filename, required) in os_files.items():
2151 e02b9114 Iustin Pop
    os_files[filename] = utils.PathJoin(os_dir, filename)
2152 a8083063 Iustin Pop
2153 a8083063 Iustin Pop
    try:
2154 ea79fc15 Michael Hanselmann
      st = os.stat(os_files[filename])
2155 a8083063 Iustin Pop
    except EnvironmentError, err:
2156 35007011 Iustin Pop
      if err.errno == errno.ENOENT and not required:
2157 35007011 Iustin Pop
        del os_files[filename]
2158 35007011 Iustin Pop
        continue
2159 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is missing (%s)" %
2160 ea79fc15 Michael Hanselmann
                     (filename, os_dir, _ErrnoOrStr(err)))
2161 a8083063 Iustin Pop
2162 a8083063 Iustin Pop
    if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2163 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is not a regular file" %
2164 ea79fc15 Michael Hanselmann
                     (filename, os_dir))
2165 255dcebd Iustin Pop
2166 ea79fc15 Michael Hanselmann
    if filename in constants.OS_SCRIPTS:
2167 0757c107 Guido Trotter
      if stat.S_IMODE(st.st_mode) & stat.S_IXUSR != stat.S_IXUSR:
2168 0757c107 Guido Trotter
        return False, ("File '%s' under path '%s' is not executable" %
2169 ea79fc15 Michael Hanselmann
                       (filename, os_dir))
2170 0757c107 Guido Trotter
2171 845da3e8 Iustin Pop
  variants = []
2172 95075fba Guido Trotter
  if constants.OS_VARIANTS_FILE in os_files:
2173 95075fba Guido Trotter
    variants_file = os_files[constants.OS_VARIANTS_FILE]
2174 95075fba Guido Trotter
    try:
2175 95075fba Guido Trotter
      variants = utils.ReadFile(variants_file).splitlines()
2176 95075fba Guido Trotter
    except EnvironmentError, err:
2177 35007011 Iustin Pop
      # we accept missing files, but not other errors
2178 35007011 Iustin Pop
      if err.errno != errno.ENOENT:
2179 35007011 Iustin Pop
        return False, ("Error while reading the OS variants file at %s: %s" %
2180 35007011 Iustin Pop
                       (variants_file, _ErrnoOrStr(err)))
2181 0757c107 Guido Trotter
2182 c7d04a6b Iustin Pop
  parameters = []
2183 c7d04a6b Iustin Pop
  if constants.OS_PARAMETERS_FILE in os_files:
2184 c7d04a6b Iustin Pop
    parameters_file = os_files[constants.OS_PARAMETERS_FILE]
2185 c7d04a6b Iustin Pop
    try:
2186 c7d04a6b Iustin Pop
      parameters = utils.ReadFile(parameters_file).splitlines()
2187 c7d04a6b Iustin Pop
    except EnvironmentError, err:
2188 c7d04a6b Iustin Pop
      return False, ("Error while reading the OS parameters file at %s: %s" %
2189 c7d04a6b Iustin Pop
                     (parameters_file, _ErrnoOrStr(err)))
2190 c7d04a6b Iustin Pop
    parameters = [v.split(None, 1) for v in parameters]
2191 c7d04a6b Iustin Pop
2192 8e70b181 Iustin Pop
  os_obj = objects.OS(name=name, path=os_dir,
2193 41ba4061 Guido Trotter
                      create_script=os_files[constants.OS_SCRIPT_CREATE],
2194 41ba4061 Guido Trotter
                      export_script=os_files[constants.OS_SCRIPT_EXPORT],
2195 41ba4061 Guido Trotter
                      import_script=os_files[constants.OS_SCRIPT_IMPORT],
2196 41ba4061 Guido Trotter
                      rename_script=os_files[constants.OS_SCRIPT_RENAME],
2197 40684c3a Iustin Pop
                      verify_script=os_files.get(constants.OS_SCRIPT_VERIFY,
2198 40684c3a Iustin Pop
                                                 None),
2199 95075fba Guido Trotter
                      supported_variants=variants,
2200 c7d04a6b Iustin Pop
                      supported_parameters=parameters,
2201 255dcebd Iustin Pop
                      api_versions=api_versions)
2202 255dcebd Iustin Pop
  return True, os_obj
2203 255dcebd Iustin Pop
2204 255dcebd Iustin Pop
2205 255dcebd Iustin Pop
def OSFromDisk(name, base_dir=None):
2206 255dcebd Iustin Pop
  """Create an OS instance from disk.
2207 255dcebd Iustin Pop

2208 255dcebd Iustin Pop
  This function will return an OS instance if the given name is a
2209 255dcebd Iustin Pop
  valid OS name. Otherwise, it will raise an appropriate
2210 255dcebd Iustin Pop
  L{RPCFail} exception, detailing why this is not a valid OS.
2211 255dcebd Iustin Pop

2212 255dcebd Iustin Pop
  This is just a wrapper over L{_TryOSFromDisk}, which doesn't raise
2213 255dcebd Iustin Pop
  an exception but returns true/false status data.
2214 255dcebd Iustin Pop

2215 255dcebd Iustin Pop
  @type base_dir: string
2216 255dcebd Iustin Pop
  @keyword base_dir: Base directory containing OS installations.
2217 255dcebd Iustin Pop
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2218 255dcebd Iustin Pop
  @rtype: L{objects.OS}
2219 255dcebd Iustin Pop
  @return: the OS instance if we find a valid one
2220 255dcebd Iustin Pop
  @raise RPCFail: if we don't find a valid OS
2221 255dcebd Iustin Pop

2222 255dcebd Iustin Pop
  """
2223 870dc44c Iustin Pop
  name_only = objects.OS.GetName(name)
2224 6ee7102a Guido Trotter
  status, payload = _TryOSFromDisk(name_only, base_dir)
2225 255dcebd Iustin Pop
2226 255dcebd Iustin Pop
  if not status:
2227 255dcebd Iustin Pop
    _Fail(payload)
2228 a8083063 Iustin Pop
2229 255dcebd Iustin Pop
  return payload
2230 a8083063 Iustin Pop
2231 a8083063 Iustin Pop
2232 a025e535 Vitaly Kuznetsov
def OSCoreEnv(os_name, inst_os, os_params, debug=0):
2233 efaa9b06 Iustin Pop
  """Calculate the basic environment for an os script.
2234 2266edb2 Guido Trotter

2235 a025e535 Vitaly Kuznetsov
  @type os_name: str
2236 a025e535 Vitaly Kuznetsov
  @param os_name: full operating system name (including variant)
2237 099c52ad Iustin Pop
  @type inst_os: L{objects.OS}
2238 099c52ad Iustin Pop
  @param inst_os: operating system for which the environment is being built
2239 1bdcbbab Iustin Pop
  @type os_params: dict
2240 1bdcbbab Iustin Pop
  @param os_params: the OS parameters
2241 2266edb2 Guido Trotter
  @type debug: integer
2242 10c2650b Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2243 2266edb2 Guido Trotter
  @rtype: dict
2244 2266edb2 Guido Trotter
  @return: dict of environment variables
2245 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2246 10c2650b Iustin Pop
      cannot be found
2247 2266edb2 Guido Trotter

2248 2266edb2 Guido Trotter
  """
2249 2266edb2 Guido Trotter
  result = {}
2250 099c52ad Iustin Pop
  api_version = \
2251 099c52ad Iustin Pop
    max(constants.OS_API_VERSIONS.intersection(inst_os.api_versions))
2252 d0c8c01d Iustin Pop
  result["OS_API_VERSION"] = "%d" % api_version
2253 d0c8c01d Iustin Pop
  result["OS_NAME"] = inst_os.name
2254 d0c8c01d Iustin Pop
  result["DEBUG_LEVEL"] = "%d" % debug
2255 efaa9b06 Iustin Pop
2256 efaa9b06 Iustin Pop
  # OS variants
2257 35007011 Iustin Pop
  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
2258 870dc44c Iustin Pop
    variant = objects.OS.GetVariant(os_name)
2259 870dc44c Iustin Pop
    if not variant:
2260 099c52ad Iustin Pop
      variant = inst_os.supported_variants[0]
2261 35007011 Iustin Pop
  else:
2262 35007011 Iustin Pop
    variant = ""
2263 35007011 Iustin Pop
  result["OS_VARIANT"] = variant
2264 efaa9b06 Iustin Pop
2265 1bdcbbab Iustin Pop
  # OS params
2266 1bdcbbab Iustin Pop
  for pname, pvalue in os_params.items():
2267 d0c8c01d Iustin Pop
    result["OSP_%s" % pname.upper()] = pvalue
2268 1bdcbbab Iustin Pop
2269 efaa9b06 Iustin Pop
  return result
2270 efaa9b06 Iustin Pop
2271 efaa9b06 Iustin Pop
2272 efaa9b06 Iustin Pop
def OSEnvironment(instance, inst_os, debug=0):
2273 efaa9b06 Iustin Pop
  """Calculate the environment for an os script.
2274 efaa9b06 Iustin Pop

2275 efaa9b06 Iustin Pop
  @type instance: L{objects.Instance}
2276 efaa9b06 Iustin Pop
  @param instance: target instance for the os script run
2277 efaa9b06 Iustin Pop
  @type inst_os: L{objects.OS}
2278 efaa9b06 Iustin Pop
  @param inst_os: operating system for which the environment is being built
2279 efaa9b06 Iustin Pop
  @type debug: integer
2280 efaa9b06 Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2281 efaa9b06 Iustin Pop
  @rtype: dict
2282 efaa9b06 Iustin Pop
  @return: dict of environment variables
2283 efaa9b06 Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2284 efaa9b06 Iustin Pop
      cannot be found
2285 efaa9b06 Iustin Pop

2286 efaa9b06 Iustin Pop
  """
2287 a025e535 Vitaly Kuznetsov
  result = OSCoreEnv(instance.os, inst_os, instance.osparams, debug=debug)
2288 efaa9b06 Iustin Pop
2289 519719fd Marco Casavecchia
  for attr in ["name", "os", "uuid", "ctime", "mtime", "primary_node"]:
2290 f2165b8a Iustin Pop
    result["INSTANCE_%s" % attr.upper()] = str(getattr(instance, attr))
2291 f2165b8a Iustin Pop
2292 d0c8c01d Iustin Pop
  result["HYPERVISOR"] = instance.hypervisor
2293 d0c8c01d Iustin Pop
  result["DISK_COUNT"] = "%d" % len(instance.disks)
2294 d0c8c01d Iustin Pop
  result["NIC_COUNT"] = "%d" % len(instance.nics)
2295 d0c8c01d Iustin Pop
  result["INSTANCE_SECONDARY_NODES"] = \
2296 d0c8c01d Iustin Pop
      ("%s" % " ".join(instance.secondary_nodes))
2297 efaa9b06 Iustin Pop
2298 efaa9b06 Iustin Pop
  # Disks
2299 2266edb2 Guido Trotter
  for idx, disk in enumerate(instance.disks):
2300 f2e07bb4 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
2301 d0c8c01d Iustin Pop
    result["DISK_%d_PATH" % idx] = real_disk.dev_path
2302 d0c8c01d Iustin Pop
    result["DISK_%d_ACCESS" % idx] = disk.mode
2303 2266edb2 Guido Trotter
    if constants.HV_DISK_TYPE in instance.hvparams:
2304 d0c8c01d Iustin Pop
      result["DISK_%d_FRONTEND_TYPE" % idx] = \
2305 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_DISK_TYPE]
2306 2266edb2 Guido Trotter
    if disk.dev_type in constants.LDS_BLOCK:
2307 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = "block"
2308 2266edb2 Guido Trotter
    elif disk.dev_type == constants.LD_FILE:
2309 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = \
2310 d0c8c01d Iustin Pop
        "file:%s" % disk.physical_id[0]
2311 efaa9b06 Iustin Pop
2312 efaa9b06 Iustin Pop
  # NICs
2313 2266edb2 Guido Trotter
  for idx, nic in enumerate(instance.nics):
2314 d0c8c01d Iustin Pop
    result["NIC_%d_MAC" % idx] = nic.mac
2315 2266edb2 Guido Trotter
    if nic.ip:
2316 d0c8c01d Iustin Pop
      result["NIC_%d_IP" % idx] = nic.ip
2317 d0c8c01d Iustin Pop
    result["NIC_%d_MODE" % idx] = nic.nicparams[constants.NIC_MODE]
2318 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2319 d0c8c01d Iustin Pop
      result["NIC_%d_BRIDGE" % idx] = nic.nicparams[constants.NIC_LINK]
2320 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_LINK]:
2321 d0c8c01d Iustin Pop
      result["NIC_%d_LINK" % idx] = nic.nicparams[constants.NIC_LINK]
2322 2266edb2 Guido Trotter
    if constants.HV_NIC_TYPE in instance.hvparams:
2323 d0c8c01d Iustin Pop
      result["NIC_%d_FRONTEND_TYPE" % idx] = \
2324 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_NIC_TYPE]
2325 2266edb2 Guido Trotter
2326 efaa9b06 Iustin Pop
  # HV/BE params
2327 67fc3042 Iustin Pop
  for source, kind in [(instance.beparams, "BE"), (instance.hvparams, "HV")]:
2328 67fc3042 Iustin Pop
    for key, value in source.items():
2329 030b218a Iustin Pop
      result["INSTANCE_%s_%s" % (kind, key)] = str(value)
2330 67fc3042 Iustin Pop
2331 2266edb2 Guido Trotter
  return result
2332 a8083063 Iustin Pop
2333 f2e07bb4 Michael Hanselmann
2334 a59faf4b Iustin Pop
def BlockdevGrow(disk, amount, dryrun):
2335 594609c0 Iustin Pop
  """Grow a stack of block devices.
2336 594609c0 Iustin Pop

2337 594609c0 Iustin Pop
  This function is called recursively, with the childrens being the
2338 10c2650b Iustin Pop
  first ones to resize.
2339 594609c0 Iustin Pop

2340 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2341 10c2650b Iustin Pop
  @param disk: the disk to be grown
2342 a59faf4b Iustin Pop
  @type amount: integer
2343 a59faf4b Iustin Pop
  @param amount: the amount (in mebibytes) to grow with
2344 a59faf4b Iustin Pop
  @type dryrun: boolean
2345 a59faf4b Iustin Pop
  @param dryrun: whether to execute the operation in simulation mode
2346 a59faf4b Iustin Pop
      only, without actually increasing the size
2347 10c2650b Iustin Pop
  @rtype: (status, result)
2348 a59faf4b Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
2349 a59faf4b Iustin Pop
      the errors message if status is False
2350 594609c0 Iustin Pop

2351 594609c0 Iustin Pop
  """
2352 594609c0 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2353 594609c0 Iustin Pop
  if r_dev is None:
2354 afdc3985 Iustin Pop
    _Fail("Cannot find block device %s", disk)
2355 594609c0 Iustin Pop
2356 594609c0 Iustin Pop
  try:
2357 a59faf4b Iustin Pop
    r_dev.Grow(amount, dryrun)
2358 594609c0 Iustin Pop
  except errors.BlockDeviceError, err:
2359 2cc6781a Iustin Pop
    _Fail("Failed to grow block device: %s", err, exc=True)
2360 594609c0 Iustin Pop
2361 594609c0 Iustin Pop
2362 821d1bd1 Iustin Pop
def BlockdevSnapshot(disk):
2363 a8083063 Iustin Pop
  """Create a snapshot copy of a block device.
2364 a8083063 Iustin Pop

2365 a8083063 Iustin Pop
  This function is called recursively, and the snapshot is actually created
2366 a8083063 Iustin Pop
  just for the leaf lvm backend device.
2367 a8083063 Iustin Pop

2368 e9e9263d Guido Trotter
  @type disk: L{objects.Disk}
2369 e9e9263d Guido Trotter
  @param disk: the disk to be snapshotted
2370 e9e9263d Guido Trotter
  @rtype: string
2371 800ac399 Iustin Pop
  @return: snapshot disk ID as (vg, lv)
2372 a8083063 Iustin Pop

2373 098c0958 Michael Hanselmann
  """
2374 433c63aa Iustin Pop
  if disk.dev_type == constants.LD_DRBD8:
2375 433c63aa Iustin Pop
    if not disk.children:
2376 433c63aa Iustin Pop
      _Fail("DRBD device '%s' without backing storage cannot be snapshotted",
2377 433c63aa Iustin Pop
            disk.unique_id)
2378 433c63aa Iustin Pop
    return BlockdevSnapshot(disk.children[0])
2379 fe96220b Iustin Pop
  elif disk.dev_type == constants.LD_LV:
2380 a8083063 Iustin Pop
    r_dev = _RecursiveFindBD(disk)
2381 a8083063 Iustin Pop
    if r_dev is not None:
2382 433c63aa Iustin Pop
      # FIXME: choose a saner value for the snapshot size
2383 a8083063 Iustin Pop
      # let's stay on the safe side and ask for the full size, for now
2384 c26a6bd2 Iustin Pop
      return r_dev.Snapshot(disk.size)
2385 a8083063 Iustin Pop
    else:
2386 87812fd3 Iustin Pop
      _Fail("Cannot find block device %s", disk)
2387 a8083063 Iustin Pop
  else:
2388 87812fd3 Iustin Pop
    _Fail("Cannot snapshot non-lvm block device '%s' of type '%s'",
2389 87812fd3 Iustin Pop
          disk.unique_id, disk.dev_type)
2390 a8083063 Iustin Pop
2391 a8083063 Iustin Pop
2392 a8083063 Iustin Pop
def FinalizeExport(instance, snap_disks):
2393 a8083063 Iustin Pop
  """Write out the export configuration information.
2394 a8083063 Iustin Pop

2395 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
2396 10c2650b Iustin Pop
  @param instance: the instance which we export, used for
2397 10c2650b Iustin Pop
      saving configuration
2398 10c2650b Iustin Pop
  @type snap_disks: list of L{objects.Disk}
2399 10c2650b Iustin Pop
  @param snap_disks: list of snapshot block devices, which
2400 10c2650b Iustin Pop
      will be used to get the actual name of the dump file
2401 a8083063 Iustin Pop

2402 c26a6bd2 Iustin Pop
  @rtype: None
2403 a8083063 Iustin Pop

2404 098c0958 Michael Hanselmann
  """
2405 c4feafe8 Iustin Pop
  destdir = utils.PathJoin(constants.EXPORT_DIR, instance.name + ".new")
2406 c4feafe8 Iustin Pop
  finaldestdir = utils.PathJoin(constants.EXPORT_DIR, instance.name)
2407 a8083063 Iustin Pop
2408 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
2409 a8083063 Iustin Pop
2410 a8083063 Iustin Pop
  config.add_section(constants.INISECT_EXP)
2411 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "version", "0")
2412 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "timestamp", "%d" % int(time.time()))
2413 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "source", instance.primary_node)
2414 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "os", instance.os)
2415 775b8743 Michael Hanselmann
  config.set(constants.INISECT_EXP, "compression", "none")
2416 a8083063 Iustin Pop
2417 a8083063 Iustin Pop
  config.add_section(constants.INISECT_INS)
2418 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "name", instance.name)
2419 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "memory", "%d" %
2420 51de46bf Iustin Pop
             instance.beparams[constants.BE_MEMORY])
2421 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "vcpus", "%d" %
2422 51de46bf Iustin Pop
             instance.beparams[constants.BE_VCPUS])
2423 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "disk_template", instance.disk_template)
2424 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "hypervisor", instance.hypervisor)
2425 fbb2c636 Michael Hanselmann
  config.set(constants.INISECT_INS, "tags", " ".join(instance.GetTags()))
2426 66f93869 Manuel Franceschini
2427 95268cc3 Iustin Pop
  nic_total = 0
2428 a8083063 Iustin Pop
  for nic_count, nic in enumerate(instance.nics):
2429 95268cc3 Iustin Pop
    nic_total += 1
2430 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_mac" %
2431 d0c8c01d Iustin Pop
               nic_count, "%s" % nic.mac)
2432 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_ip" % nic_count, "%s" % nic.ip)
2433 6801eb5c Iustin Pop
    for param in constants.NICS_PARAMETER_TYPES:
2434 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "nic%d_%s" % (nic_count, param),
2435 d0c8c01d Iustin Pop
                 "%s" % nic.nicparams.get(param, None))
2436 a8083063 Iustin Pop
  # TODO: redundant: on load can read nics until it doesn't exist
2437 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "nic_count", "%d" % nic_total)
2438 a8083063 Iustin Pop
2439 726d7d68 Iustin Pop
  disk_total = 0
2440 a8083063 Iustin Pop
  for disk_count, disk in enumerate(snap_disks):
2441 19d7f90a Guido Trotter
    if disk:
2442 726d7d68 Iustin Pop
      disk_total += 1
2443 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_ivname" % disk_count,
2444 d0c8c01d Iustin Pop
                 ("%s" % disk.iv_name))
2445 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_dump" % disk_count,
2446 d0c8c01d Iustin Pop
                 ("%s" % disk.physical_id[1]))
2447 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_size" % disk_count,
2448 d0c8c01d Iustin Pop
                 ("%d" % disk.size))
2449 d0c8c01d Iustin Pop
2450 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "disk_count", "%d" % disk_total)
2451 a8083063 Iustin Pop
2452 3c8954ad Iustin Pop
  # New-style hypervisor/backend parameters
2453 3c8954ad Iustin Pop
2454 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_HYP)
2455 3c8954ad Iustin Pop
  for name, value in instance.hvparams.items():
2456 3c8954ad Iustin Pop
    if name not in constants.HVC_GLOBALS:
2457 3c8954ad Iustin Pop
      config.set(constants.INISECT_HYP, name, str(value))
2458 3c8954ad Iustin Pop
2459 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_BEP)
2460 3c8954ad Iustin Pop
  for name, value in instance.beparams.items():
2461 3c8954ad Iustin Pop
    config.set(constants.INISECT_BEP, name, str(value))
2462 3c8954ad Iustin Pop
2463 535b49cb Iustin Pop
  config.add_section(constants.INISECT_OSP)
2464 535b49cb Iustin Pop
  for name, value in instance.osparams.items():
2465 535b49cb Iustin Pop
    config.set(constants.INISECT_OSP, name, str(value))
2466 535b49cb Iustin Pop
2467 c4feafe8 Iustin Pop
  utils.WriteFile(utils.PathJoin(destdir, constants.EXPORT_CONF_FILE),
2468 726d7d68 Iustin Pop
                  data=config.Dumps())
2469 56569f4e Michael Hanselmann
  shutil.rmtree(finaldestdir, ignore_errors=True)
2470 a8083063 Iustin Pop
  shutil.move(destdir, finaldestdir)
2471 a8083063 Iustin Pop
2472 a8083063 Iustin Pop
2473 a8083063 Iustin Pop
def ExportInfo(dest):
2474 a8083063 Iustin Pop
  """Get export configuration information.
2475 a8083063 Iustin Pop

2476 10c2650b Iustin Pop
  @type dest: str
2477 10c2650b Iustin Pop
  @param dest: directory containing the export
2478 a8083063 Iustin Pop

2479 10c2650b Iustin Pop
  @rtype: L{objects.SerializableConfigParser}
2480 10c2650b Iustin Pop
  @return: a serializable config file containing the
2481 10c2650b Iustin Pop
      export info
2482 a8083063 Iustin Pop

2483 a8083063 Iustin Pop
  """
2484 c4feafe8 Iustin Pop
  cff = utils.PathJoin(dest, constants.EXPORT_CONF_FILE)
2485 a8083063 Iustin Pop
2486 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
2487 a8083063 Iustin Pop
  config.read(cff)
2488 a8083063 Iustin Pop
2489 a8083063 Iustin Pop
  if (not config.has_section(constants.INISECT_EXP) or
2490 a8083063 Iustin Pop
      not config.has_section(constants.INISECT_INS)):
2491 3eccac06 Iustin Pop
    _Fail("Export info file doesn't have the required fields")
2492 a8083063 Iustin Pop
2493 c26a6bd2 Iustin Pop
  return config.Dumps()
2494 a8083063 Iustin Pop
2495 a8083063 Iustin Pop
2496 a8083063 Iustin Pop
def ListExports():
2497 a8083063 Iustin Pop
  """Return a list of exports currently available on this machine.
2498 098c0958 Michael Hanselmann

2499 10c2650b Iustin Pop
  @rtype: list
2500 10c2650b Iustin Pop
  @return: list of the exports
2501 10c2650b Iustin Pop

2502 a8083063 Iustin Pop
  """
2503 a8083063 Iustin Pop
  if os.path.isdir(constants.EXPORT_DIR):
2504 b5b8309d Guido Trotter
    return sorted(utils.ListVisibleFiles(constants.EXPORT_DIR))
2505 a8083063 Iustin Pop
  else:
2506 afdc3985 Iustin Pop
    _Fail("No exports directory")
2507 a8083063 Iustin Pop
2508 a8083063 Iustin Pop
2509 a8083063 Iustin Pop
def RemoveExport(export):
2510 a8083063 Iustin Pop
  """Remove an existing export from the node.
2511 a8083063 Iustin Pop

2512 10c2650b Iustin Pop
  @type export: str
2513 10c2650b Iustin Pop
  @param export: the name of the export to remove
2514 c26a6bd2 Iustin Pop
  @rtype: None
2515 a8083063 Iustin Pop

2516 098c0958 Michael Hanselmann
  """
2517 c4feafe8 Iustin Pop
  target = utils.PathJoin(constants.EXPORT_DIR, export)
2518 a8083063 Iustin Pop
2519 35fbcd11 Iustin Pop
  try:
2520 35fbcd11 Iustin Pop
    shutil.rmtree(target)
2521 35fbcd11 Iustin Pop
  except EnvironmentError, err:
2522 35fbcd11 Iustin Pop
    _Fail("Error while removing the export: %s", err, exc=True)
2523 a8083063 Iustin Pop
2524 a8083063 Iustin Pop
2525 821d1bd1 Iustin Pop
def BlockdevRename(devlist):
2526 f3e513ad Iustin Pop
  """Rename a list of block devices.
2527 f3e513ad Iustin Pop

2528 10c2650b Iustin Pop
  @type devlist: list of tuples
2529 10c2650b Iustin Pop
  @param devlist: list of tuples of the form  (disk,
2530 10c2650b Iustin Pop
      new_logical_id, new_physical_id); disk is an
2531 10c2650b Iustin Pop
      L{objects.Disk} object describing the current disk,
2532 10c2650b Iustin Pop
      and new logical_id/physical_id is the name we
2533 10c2650b Iustin Pop
      rename it to
2534 10c2650b Iustin Pop
  @rtype: boolean
2535 10c2650b Iustin Pop
  @return: True if all renames succeeded, False otherwise
2536 f3e513ad Iustin Pop

2537 f3e513ad Iustin Pop
  """
2538 6b5e3f70 Iustin Pop
  msgs = []
2539 f3e513ad Iustin Pop
  result = True
2540 f3e513ad Iustin Pop
  for disk, unique_id in devlist:
2541 f3e513ad Iustin Pop
    dev = _RecursiveFindBD(disk)
2542 f3e513ad Iustin Pop
    if dev is None:
2543 6b5e3f70 Iustin Pop
      msgs.append("Can't find device %s in rename" % str(disk))
2544 f3e513ad Iustin Pop
      result = False
2545 f3e513ad Iustin Pop
      continue
2546 f3e513ad Iustin Pop
    try:
2547 3f78eef2 Iustin Pop
      old_rpath = dev.dev_path
2548 f3e513ad Iustin Pop
      dev.Rename(unique_id)
2549 3f78eef2 Iustin Pop
      new_rpath = dev.dev_path
2550 3f78eef2 Iustin Pop
      if old_rpath != new_rpath:
2551 3f78eef2 Iustin Pop
        DevCacheManager.RemoveCache(old_rpath)
2552 3f78eef2 Iustin Pop
        # FIXME: we should add the new cache information here, like:
2553 3f78eef2 Iustin Pop
        # DevCacheManager.UpdateCache(new_rpath, owner, ...)
2554 3f78eef2 Iustin Pop
        # but we don't have the owner here - maybe parse from existing
2555 3f78eef2 Iustin Pop
        # cache? for now, we only lose lvm data when we rename, which
2556 3f78eef2 Iustin Pop
        # is less critical than DRBD or MD
2557 f3e513ad Iustin Pop
    except errors.BlockDeviceError, err:
2558 6b5e3f70 Iustin Pop
      msgs.append("Can't rename device '%s' to '%s': %s" %
2559 6b5e3f70 Iustin Pop
                  (dev, unique_id, err))
2560 18682bca Iustin Pop
      logging.exception("Can't rename device '%s' to '%s'", dev, unique_id)
2561 f3e513ad Iustin Pop
      result = False
2562 afdc3985 Iustin Pop
  if not result:
2563 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2564 f3e513ad Iustin Pop
2565 f3e513ad Iustin Pop
2566 4b97f902 Apollon Oikonomopoulos
def _TransformFileStorageDir(fs_dir):
2567 778b75bb Manuel Franceschini
  """Checks whether given file_storage_dir is valid.
2568 778b75bb Manuel Franceschini

2569 4b97f902 Apollon Oikonomopoulos
  Checks wheter the given fs_dir is within the cluster-wide default
2570 4b97f902 Apollon Oikonomopoulos
  file_storage_dir or the shared_file_storage_dir, which are stored in
2571 4b97f902 Apollon Oikonomopoulos
  SimpleStore. Only paths under those directories are allowed.
2572 778b75bb Manuel Franceschini

2573 4b97f902 Apollon Oikonomopoulos
  @type fs_dir: str
2574 4b97f902 Apollon Oikonomopoulos
  @param fs_dir: the path to check
2575 d61cbe76 Iustin Pop

2576 b1206984 Iustin Pop
  @return: the normalized path if valid, None otherwise
2577 778b75bb Manuel Franceschini

2578 778b75bb Manuel Franceschini
  """
2579 cb7c0198 Iustin Pop
  if not constants.ENABLE_FILE_STORAGE:
2580 cb7c0198 Iustin Pop
    _Fail("File storage disabled at configure time")
2581 c657dcc9 Michael Hanselmann
  cfg = _GetConfig()
2582 4b97f902 Apollon Oikonomopoulos
  fs_dir = os.path.normpath(fs_dir)
2583 4b97f902 Apollon Oikonomopoulos
  base_fstore = cfg.GetFileStorageDir()
2584 4b97f902 Apollon Oikonomopoulos
  base_shared = cfg.GetSharedFileStorageDir()
2585 cf00dba0 René Nussbaumer
  if not (utils.IsBelowDir(base_fstore, fs_dir) or
2586 cf00dba0 René Nussbaumer
          utils.IsBelowDir(base_shared, fs_dir)):
2587 b2b8bcce Iustin Pop
    _Fail("File storage directory '%s' is not under base file"
2588 4b97f902 Apollon Oikonomopoulos
          " storage directory '%s' or shared storage directory '%s'",
2589 4b97f902 Apollon Oikonomopoulos
          fs_dir, base_fstore, base_shared)
2590 4b97f902 Apollon Oikonomopoulos
  return fs_dir
2591 778b75bb Manuel Franceschini
2592 778b75bb Manuel Franceschini
2593 778b75bb Manuel Franceschini
def CreateFileStorageDir(file_storage_dir):
2594 778b75bb Manuel Franceschini
  """Create file storage directory.
2595 778b75bb Manuel Franceschini

2596 b1206984 Iustin Pop
  @type file_storage_dir: str
2597 b1206984 Iustin Pop
  @param file_storage_dir: directory to create
2598 778b75bb Manuel Franceschini

2599 b1206984 Iustin Pop
  @rtype: tuple
2600 b1206984 Iustin Pop
  @return: tuple with first element a boolean indicating wheter dir
2601 b1206984 Iustin Pop
      creation was successful or not
2602 778b75bb Manuel Franceschini

2603 778b75bb Manuel Franceschini
  """
2604 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
2605 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
2606 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
2607 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
2608 b2b8bcce Iustin Pop
            file_storage_dir)
2609 778b75bb Manuel Franceschini
  else:
2610 b2b8bcce Iustin Pop
    try:
2611 b2b8bcce Iustin Pop
      os.makedirs(file_storage_dir, 0750)
2612 b2b8bcce Iustin Pop
    except OSError, err:
2613 b2b8bcce Iustin Pop
      _Fail("Cannot create file storage directory '%s': %s",
2614 b2b8bcce Iustin Pop
            file_storage_dir, err, exc=True)
2615 778b75bb Manuel Franceschini
2616 778b75bb Manuel Franceschini
2617 778b75bb Manuel Franceschini
def RemoveFileStorageDir(file_storage_dir):
2618 778b75bb Manuel Franceschini
  """Remove file storage directory.
2619 778b75bb Manuel Franceschini

2620 778b75bb Manuel Franceschini
  Remove it only if it's empty. If not log an error and return.
2621 778b75bb Manuel Franceschini

2622 10c2650b Iustin Pop
  @type file_storage_dir: str
2623 10c2650b Iustin Pop
  @param file_storage_dir: the directory we should cleanup
2624 10c2650b Iustin Pop
  @rtype: tuple (success,)
2625 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
2626 5bbd3f7f Michael Hanselmann
      whether the operation was successful
2627 778b75bb Manuel Franceschini

2628 778b75bb Manuel Franceschini
  """
2629 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
2630 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
2631 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
2632 b2b8bcce Iustin Pop
      _Fail("Specified Storage directory '%s' is not a directory",
2633 b2b8bcce Iustin Pop
            file_storage_dir)
2634 afdc3985 Iustin Pop
    # deletes dir only if empty, otherwise we want to fail the rpc call
2635 b2b8bcce Iustin Pop
    try:
2636 b2b8bcce Iustin Pop
      os.rmdir(file_storage_dir)
2637 b2b8bcce Iustin Pop
    except OSError, err:
2638 b2b8bcce Iustin Pop
      _Fail("Cannot remove file storage directory '%s': %s",
2639 b2b8bcce Iustin Pop
            file_storage_dir, err)
2640 b2b8bcce Iustin Pop
2641 778b75bb Manuel Franceschini
2642 778b75bb Manuel Franceschini
def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir):
2643 778b75bb Manuel Franceschini
  """Rename the file storage directory.
2644 778b75bb Manuel Franceschini

2645 10c2650b Iustin Pop
  @type old_file_storage_dir: str
2646 10c2650b Iustin Pop
  @param old_file_storage_dir: the current path
2647 10c2650b Iustin Pop
  @type new_file_storage_dir: str
2648 10c2650b Iustin Pop
  @param new_file_storage_dir: the name we should rename to
2649 10c2650b Iustin Pop
  @rtype: tuple (success,)
2650 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
2651 10c2650b Iustin Pop
      whether the operation was successful
2652 778b75bb Manuel Franceschini

2653 778b75bb Manuel Franceschini
  """
2654 778b75bb Manuel Franceschini
  old_file_storage_dir = _TransformFileStorageDir(old_file_storage_dir)
2655 778b75bb Manuel Franceschini
  new_file_storage_dir = _TransformFileStorageDir(new_file_storage_dir)
2656 b2b8bcce Iustin Pop
  if not os.path.exists(new_file_storage_dir):
2657 b2b8bcce Iustin Pop
    if os.path.isdir(old_file_storage_dir):
2658 b2b8bcce Iustin Pop
      try:
2659 b2b8bcce Iustin Pop
        os.rename(old_file_storage_dir, new_file_storage_dir)
2660 b2b8bcce Iustin Pop
      except OSError, err:
2661 b2b8bcce Iustin Pop
        _Fail("Cannot rename '%s' to '%s': %s",
2662 b2b8bcce Iustin Pop
              old_file_storage_dir, new_file_storage_dir, err)
2663 778b75bb Manuel Franceschini
    else:
2664 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
2665 b2b8bcce Iustin Pop
            old_file_storage_dir)
2666 b2b8bcce Iustin Pop
  else:
2667 b2b8bcce Iustin Pop
    if os.path.exists(old_file_storage_dir):
2668 b2b8bcce Iustin Pop
      _Fail("Cannot rename '%s' to '%s': both locations exist",
2669 b2b8bcce Iustin Pop
            old_file_storage_dir, new_file_storage_dir)
2670 778b75bb Manuel Franceschini
2671 778b75bb Manuel Franceschini
2672 c8457ce7 Iustin Pop
def _EnsureJobQueueFile(file_name):
2673 dc31eae3 Michael Hanselmann
  """Checks whether the given filename is in the queue directory.
2674 ca52cdeb Michael Hanselmann

2675 10c2650b Iustin Pop
  @type file_name: str
2676 10c2650b Iustin Pop
  @param file_name: the file name we should check
2677 c8457ce7 Iustin Pop
  @rtype: None
2678 c8457ce7 Iustin Pop
  @raises RPCFail: if the file is not valid
2679 10c2650b Iustin Pop

2680 ca52cdeb Michael Hanselmann
  """
2681 ca52cdeb Michael Hanselmann
  queue_dir = os.path.normpath(constants.QUEUE_DIR)
2682 dc31eae3 Michael Hanselmann
  result = (os.path.commonprefix([queue_dir, file_name]) == queue_dir)
2683 dc31eae3 Michael Hanselmann
2684 dc31eae3 Michael Hanselmann
  if not result:
2685 c8457ce7 Iustin Pop
    _Fail("Passed job queue file '%s' does not belong to"
2686 c8457ce7 Iustin Pop
          " the queue directory '%s'", file_name, queue_dir)
2687 dc31eae3 Michael Hanselmann
2688 dc31eae3 Michael Hanselmann
2689 dc31eae3 Michael Hanselmann
def JobQueueUpdate(file_name, content):
2690 dc31eae3 Michael Hanselmann
  """Updates a file in the queue directory.
2691 dc31eae3 Michael Hanselmann

2692 3865ca48 Michael Hanselmann
  This is just a wrapper over L{utils.io.WriteFile}, with proper
2693 10c2650b Iustin Pop
  checking.
2694 10c2650b Iustin Pop

2695 10c2650b Iustin Pop
  @type file_name: str
2696 10c2650b Iustin Pop
  @param file_name: the job file name
2697 10c2650b Iustin Pop
  @type content: str
2698 10c2650b Iustin Pop
  @param content: the new job contents
2699 10c2650b Iustin Pop
  @rtype: boolean
2700 10c2650b Iustin Pop
  @return: the success of the operation
2701 10c2650b Iustin Pop

2702 dc31eae3 Michael Hanselmann
  """
2703 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(file_name)
2704 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
2705 ca52cdeb Michael Hanselmann
2706 ca52cdeb Michael Hanselmann
  # Write and replace the file atomically
2707 82b22e19 René Nussbaumer
  utils.WriteFile(file_name, data=_Decompress(content), uid=getents.masterd_uid,
2708 82b22e19 René Nussbaumer
                  gid=getents.masterd_gid)
2709 ca52cdeb Michael Hanselmann
2710 ca52cdeb Michael Hanselmann
2711 af5ebcb1 Michael Hanselmann
def JobQueueRename(old, new):
2712 af5ebcb1 Michael Hanselmann
  """Renames a job queue file.
2713 af5ebcb1 Michael Hanselmann

2714 c41eea6e Iustin Pop
  This is just a wrapper over os.rename with proper checking.
2715 10c2650b Iustin Pop

2716 10c2650b Iustin Pop
  @type old: str
2717 10c2650b Iustin Pop
  @param old: the old (actual) file name
2718 10c2650b Iustin Pop
  @type new: str
2719 10c2650b Iustin Pop
  @param new: the desired file name
2720 c8457ce7 Iustin Pop
  @rtype: tuple
2721 c8457ce7 Iustin Pop
  @return: the success of the operation and payload
2722 10c2650b Iustin Pop

2723 af5ebcb1 Michael Hanselmann
  """
2724 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(old)
2725 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(new)
2726 af5ebcb1 Michael Hanselmann
2727 58b22b6e Michael Hanselmann
  utils.RenameFile(old, new, mkdir=True)
2728 af5ebcb1 Michael Hanselmann
2729 af5ebcb1 Michael Hanselmann
2730 821d1bd1 Iustin Pop
def BlockdevClose(instance_name, disks):
2731 d61cbe76 Iustin Pop
  """Closes the given block devices.
2732 d61cbe76 Iustin Pop

2733 10c2650b Iustin Pop
  This means they will be switched to secondary mode (in case of
2734 10c2650b Iustin Pop
  DRBD).
2735 10c2650b Iustin Pop

2736 b2e7666a Iustin Pop
  @param instance_name: if the argument is not empty, the symlinks
2737 b2e7666a Iustin Pop
      of this instance will be removed
2738 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
2739 10c2650b Iustin Pop
  @param disks: the list of disks to be closed
2740 10c2650b Iustin Pop
  @rtype: tuple (success, message)
2741 10c2650b Iustin Pop
  @return: a tuple of success and message, where success
2742 10c2650b Iustin Pop
      indicates the succes of the operation, and message
2743 10c2650b Iustin Pop
      which will contain the error details in case we
2744 10c2650b Iustin Pop
      failed
2745 d61cbe76 Iustin Pop

2746 d61cbe76 Iustin Pop
  """
2747 d61cbe76 Iustin Pop
  bdevs = []
2748 d61cbe76 Iustin Pop
  for cf in disks:
2749 d61cbe76 Iustin Pop
    rd = _RecursiveFindBD(cf)
2750 d61cbe76 Iustin Pop
    if rd is None:
2751 2cc6781a Iustin Pop
      _Fail("Can't find device %s", cf)
2752 d61cbe76 Iustin Pop
    bdevs.append(rd)
2753 d61cbe76 Iustin Pop
2754 d61cbe76 Iustin Pop
  msg = []
2755 d61cbe76 Iustin Pop
  for rd in bdevs:
2756 d61cbe76 Iustin Pop
    try:
2757 d61cbe76 Iustin Pop
      rd.Close()
2758 d61cbe76 Iustin Pop
    except errors.BlockDeviceError, err:
2759 d61cbe76 Iustin Pop
      msg.append(str(err))
2760 d61cbe76 Iustin Pop
  if msg:
2761 afdc3985 Iustin Pop
    _Fail("Can't make devices secondary: %s", ",".join(msg))
2762 d61cbe76 Iustin Pop
  else:
2763 b2e7666a Iustin Pop
    if instance_name:
2764 5282084b Iustin Pop
      _RemoveBlockDevLinks(instance_name, disks)
2765 d61cbe76 Iustin Pop
2766 d61cbe76 Iustin Pop
2767 6217e295 Iustin Pop
def ValidateHVParams(hvname, hvparams):
2768 6217e295 Iustin Pop
  """Validates the given hypervisor parameters.
2769 6217e295 Iustin Pop

2770 6217e295 Iustin Pop
  @type hvname: string
2771 6217e295 Iustin Pop
  @param hvname: the hypervisor name
2772 6217e295 Iustin Pop
  @type hvparams: dict
2773 6217e295 Iustin Pop
  @param hvparams: the hypervisor parameters to be validated
2774 c26a6bd2 Iustin Pop
  @rtype: None
2775 6217e295 Iustin Pop

2776 6217e295 Iustin Pop
  """
2777 6217e295 Iustin Pop
  try:
2778 6217e295 Iustin Pop
    hv_type = hypervisor.GetHypervisor(hvname)
2779 6217e295 Iustin Pop
    hv_type.ValidateParameters(hvparams)
2780 6217e295 Iustin Pop
  except errors.HypervisorError, err:
2781 afdc3985 Iustin Pop
    _Fail(str(err), log=False)
2782 6217e295 Iustin Pop
2783 6217e295 Iustin Pop
2784 acd9ff9e Iustin Pop
def _CheckOSPList(os_obj, parameters):
2785 acd9ff9e Iustin Pop
  """Check whether a list of parameters is supported by the OS.
2786 acd9ff9e Iustin Pop

2787 acd9ff9e Iustin Pop
  @type os_obj: L{objects.OS}
2788 acd9ff9e Iustin Pop
  @param os_obj: OS object to check
2789 acd9ff9e Iustin Pop
  @type parameters: list
2790 acd9ff9e Iustin Pop
  @param parameters: the list of parameters to check
2791 acd9ff9e Iustin Pop

2792 acd9ff9e Iustin Pop
  """
2793 acd9ff9e Iustin Pop
  supported = [v[0] for v in os_obj.supported_parameters]
2794 acd9ff9e Iustin Pop
  delta = frozenset(parameters).difference(supported)
2795 acd9ff9e Iustin Pop
  if delta:
2796 acd9ff9e Iustin Pop
    _Fail("The following parameters are not supported"
2797 acd9ff9e Iustin Pop
          " by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
2798 acd9ff9e Iustin Pop
2799 acd9ff9e Iustin Pop
2800 acd9ff9e Iustin Pop
def ValidateOS(required, osname, checks, osparams):
2801 acd9ff9e Iustin Pop
  """Validate the given OS' parameters.
2802 acd9ff9e Iustin Pop

2803 acd9ff9e Iustin Pop
  @type required: boolean
2804 acd9ff9e Iustin Pop
  @param required: whether absence of the OS should translate into
2805 acd9ff9e Iustin Pop
      failure or not
2806 acd9ff9e Iustin Pop
  @type osname: string
2807 acd9ff9e Iustin Pop
  @param osname: the OS to be validated
2808 acd9ff9e Iustin Pop
  @type checks: list
2809 acd9ff9e Iustin Pop
  @param checks: list of the checks to run (currently only 'parameters')
2810 acd9ff9e Iustin Pop
  @type osparams: dict
2811 acd9ff9e Iustin Pop
  @param osparams: dictionary with OS parameters
2812 acd9ff9e Iustin Pop
  @rtype: boolean
2813 acd9ff9e Iustin Pop
  @return: True if the validation passed, or False if the OS was not
2814 acd9ff9e Iustin Pop
      found and L{required} was false
2815 acd9ff9e Iustin Pop

2816 acd9ff9e Iustin Pop
  """
2817 acd9ff9e Iustin Pop
  if not constants.OS_VALIDATE_CALLS.issuperset(checks):
2818 acd9ff9e Iustin Pop
    _Fail("Unknown checks required for OS %s: %s", osname,
2819 acd9ff9e Iustin Pop
          set(checks).difference(constants.OS_VALIDATE_CALLS))
2820 acd9ff9e Iustin Pop
2821 870dc44c Iustin Pop
  name_only = objects.OS.GetName(osname)
2822 acd9ff9e Iustin Pop
  status, tbv = _TryOSFromDisk(name_only, None)
2823 acd9ff9e Iustin Pop
2824 acd9ff9e Iustin Pop
  if not status:
2825 acd9ff9e Iustin Pop
    if required:
2826 acd9ff9e Iustin Pop
      _Fail(tbv)
2827 acd9ff9e Iustin Pop
    else:
2828 acd9ff9e Iustin Pop
      return False
2829 acd9ff9e Iustin Pop
2830 72db3fd7 Iustin Pop
  if max(tbv.api_versions) < constants.OS_API_V20:
2831 72db3fd7 Iustin Pop
    return True
2832 72db3fd7 Iustin Pop
2833 acd9ff9e Iustin Pop
  if constants.OS_VALIDATE_PARAMETERS in checks:
2834 acd9ff9e Iustin Pop
    _CheckOSPList(tbv, osparams.keys())
2835 acd9ff9e Iustin Pop
2836 a025e535 Vitaly Kuznetsov
  validate_env = OSCoreEnv(osname, tbv, osparams)
2837 acd9ff9e Iustin Pop
  result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
2838 896a03f6 Iustin Pop
                        cwd=tbv.path, reset_env=True)
2839 acd9ff9e Iustin Pop
  if result.failed:
2840 acd9ff9e Iustin Pop
    logging.error("os validate command '%s' returned error: %s output: %s",
2841 acd9ff9e Iustin Pop
                  result.cmd, result.fail_reason, result.output)
2842 acd9ff9e Iustin Pop
    _Fail("OS validation script failed (%s), output: %s",
2843 acd9ff9e Iustin Pop
          result.fail_reason, result.output, log=False)
2844 acd9ff9e Iustin Pop
2845 acd9ff9e Iustin Pop
  return True
2846 acd9ff9e Iustin Pop
2847 acd9ff9e Iustin Pop
2848 56aa9fd5 Iustin Pop
def DemoteFromMC():
2849 56aa9fd5 Iustin Pop
  """Demotes the current node from master candidate role.
2850 56aa9fd5 Iustin Pop

2851 56aa9fd5 Iustin Pop
  """
2852 56aa9fd5 Iustin Pop
  # try to ensure we're not the master by mistake
2853 56aa9fd5 Iustin Pop
  master, myself = ssconf.GetMasterAndMyself()
2854 56aa9fd5 Iustin Pop
  if master == myself:
2855 afdc3985 Iustin Pop
    _Fail("ssconf status shows I'm the master node, will not demote")
2856 f154a7a3 Michael Hanselmann
2857 f154a7a3 Michael Hanselmann
  result = utils.RunCmd([constants.DAEMON_UTIL, "check", constants.MASTERD])
2858 f154a7a3 Michael Hanselmann
  if not result.failed:
2859 afdc3985 Iustin Pop
    _Fail("The master daemon is running, will not demote")
2860 f154a7a3 Michael Hanselmann
2861 56aa9fd5 Iustin Pop
  try:
2862 9a5cb537 Iustin Pop
    if os.path.isfile(constants.CLUSTER_CONF_FILE):
2863 9a5cb537 Iustin Pop
      utils.CreateBackup(constants.CLUSTER_CONF_FILE)
2864 56aa9fd5 Iustin Pop
  except EnvironmentError, err:
2865 56aa9fd5 Iustin Pop
    if err.errno != errno.ENOENT:
2866 afdc3985 Iustin Pop
      _Fail("Error while backing up cluster file: %s", err, exc=True)
2867 f154a7a3 Michael Hanselmann
2868 56aa9fd5 Iustin Pop
  utils.RemoveFile(constants.CLUSTER_CONF_FILE)
2869 56aa9fd5 Iustin Pop
2870 56aa9fd5 Iustin Pop
2871 f942a838 Michael Hanselmann
def _GetX509Filenames(cryptodir, name):
2872 f942a838 Michael Hanselmann
  """Returns the full paths for the private key and certificate.
2873 f942a838 Michael Hanselmann

2874 f942a838 Michael Hanselmann
  """
2875 f942a838 Michael Hanselmann
  return (utils.PathJoin(cryptodir, name),
2876 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_KEY_FILE),
2877 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_CERT_FILE))
2878 f942a838 Michael Hanselmann
2879 f942a838 Michael Hanselmann
2880 f942a838 Michael Hanselmann
def CreateX509Certificate(validity, cryptodir=constants.CRYPTO_KEYS_DIR):
2881 f942a838 Michael Hanselmann
  """Creates a new X509 certificate for SSL/TLS.
2882 f942a838 Michael Hanselmann

2883 f942a838 Michael Hanselmann
  @type validity: int
2884 f942a838 Michael Hanselmann
  @param validity: Validity in seconds
2885 f942a838 Michael Hanselmann
  @rtype: tuple; (string, string)
2886 f942a838 Michael Hanselmann
  @return: Certificate name and public part
2887 f942a838 Michael Hanselmann

2888 f942a838 Michael Hanselmann
  """
2889 f942a838 Michael Hanselmann
  (key_pem, cert_pem) = \
2890 b705c7a6 Manuel Franceschini
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
2891 f942a838 Michael Hanselmann
                                     min(validity, _MAX_SSL_CERT_VALIDITY))
2892 f942a838 Michael Hanselmann
2893 f942a838 Michael Hanselmann
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
2894 f942a838 Michael Hanselmann
                              prefix="x509-%s-" % utils.TimestampForFilename())
2895 f942a838 Michael Hanselmann
  try:
2896 f942a838 Michael Hanselmann
    name = os.path.basename(cert_dir)
2897 f942a838 Michael Hanselmann
    assert len(name) > 5
2898 f942a838 Michael Hanselmann
2899 f942a838 Michael Hanselmann
    (_, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
2900 f942a838 Michael Hanselmann
2901 f942a838 Michael Hanselmann
    utils.WriteFile(key_file, mode=0400, data=key_pem)
2902 f942a838 Michael Hanselmann
    utils.WriteFile(cert_file, mode=0400, data=cert_pem)
2903 f942a838 Michael Hanselmann
2904 f942a838 Michael Hanselmann
    # Never return private key as it shouldn't leave the node
2905 f942a838 Michael Hanselmann
    return (name, cert_pem)
2906 f942a838 Michael Hanselmann
  except Exception:
2907 f942a838 Michael Hanselmann
    shutil.rmtree(cert_dir, ignore_errors=True)
2908 f942a838 Michael Hanselmann
    raise
2909 f942a838 Michael Hanselmann
2910 f942a838 Michael Hanselmann
2911 f942a838 Michael Hanselmann
def RemoveX509Certificate(name, cryptodir=constants.CRYPTO_KEYS_DIR):
2912 f942a838 Michael Hanselmann
  """Removes a X509 certificate.
2913 f942a838 Michael Hanselmann

2914 f942a838 Michael Hanselmann
  @type name: string
2915 f942a838 Michael Hanselmann
  @param name: Certificate name
2916 f942a838 Michael Hanselmann

2917 f942a838 Michael Hanselmann
  """
2918 f942a838 Michael Hanselmann
  (cert_dir, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
2919 f942a838 Michael Hanselmann
2920 f942a838 Michael Hanselmann
  utils.RemoveFile(key_file)
2921 f942a838 Michael Hanselmann
  utils.RemoveFile(cert_file)
2922 f942a838 Michael Hanselmann
2923 f942a838 Michael Hanselmann
  try:
2924 f942a838 Michael Hanselmann
    os.rmdir(cert_dir)
2925 f942a838 Michael Hanselmann
  except EnvironmentError, err:
2926 f942a838 Michael Hanselmann
    _Fail("Cannot remove certificate directory '%s': %s",
2927 f942a838 Michael Hanselmann
          cert_dir, err)
2928 f942a838 Michael Hanselmann
2929 f942a838 Michael Hanselmann
2930 1651d116 Michael Hanselmann
def _GetImportExportIoCommand(instance, mode, ieio, ieargs):
2931 1651d116 Michael Hanselmann
  """Returns the command for the requested input/output.
2932 1651d116 Michael Hanselmann

2933 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
2934 1651d116 Michael Hanselmann
  @param instance: The instance object
2935 1651d116 Michael Hanselmann
  @param mode: Import/export mode
2936 1651d116 Michael Hanselmann
  @param ieio: Input/output type
2937 1651d116 Michael Hanselmann
  @param ieargs: Input/output arguments
2938 1651d116 Michael Hanselmann

2939 1651d116 Michael Hanselmann
  """
2940 1651d116 Michael Hanselmann
  assert mode in (constants.IEM_IMPORT, constants.IEM_EXPORT)
2941 1651d116 Michael Hanselmann
2942 1651d116 Michael Hanselmann
  env = None
2943 1651d116 Michael Hanselmann
  prefix = None
2944 1651d116 Michael Hanselmann
  suffix = None
2945 2ad5550d Michael Hanselmann
  exp_size = None
2946 1651d116 Michael Hanselmann
2947 1651d116 Michael Hanselmann
  if ieio == constants.IEIO_FILE:
2948 1651d116 Michael Hanselmann
    (filename, ) = ieargs
2949 1651d116 Michael Hanselmann
2950 1651d116 Michael Hanselmann
    if not utils.IsNormAbsPath(filename):
2951 1651d116 Michael Hanselmann
      _Fail("Path '%s' is not normalized or absolute", filename)
2952 1651d116 Michael Hanselmann
2953 748c9884 René Nussbaumer
    real_filename = os.path.realpath(filename)
2954 748c9884 René Nussbaumer
    directory = os.path.dirname(real_filename)
2955 1651d116 Michael Hanselmann
2956 945859e0 René Nussbaumer
    if not utils.IsBelowDir(constants.EXPORT_DIR, real_filename):
2957 748c9884 René Nussbaumer
      _Fail("File '%s' is not under exports directory '%s': %s",
2958 748c9884 René Nussbaumer
            filename, constants.EXPORT_DIR, real_filename)
2959 1651d116 Michael Hanselmann
2960 1651d116 Michael Hanselmann
    # Create directory
2961 1651d116 Michael Hanselmann
    utils.Makedirs(directory, mode=0750)
2962 1651d116 Michael Hanselmann
2963 1651d116 Michael Hanselmann
    quoted_filename = utils.ShellQuote(filename)
2964 1651d116 Michael Hanselmann
2965 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2966 1651d116 Michael Hanselmann
      suffix = "> %s" % quoted_filename
2967 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2968 1651d116 Michael Hanselmann
      suffix = "< %s" % quoted_filename
2969 1651d116 Michael Hanselmann
2970 2ad5550d Michael Hanselmann
      # Retrieve file size
2971 2ad5550d Michael Hanselmann
      try:
2972 2ad5550d Michael Hanselmann
        st = os.stat(filename)
2973 2ad5550d Michael Hanselmann
      except EnvironmentError, err:
2974 2ad5550d Michael Hanselmann
        logging.error("Can't stat(2) %s: %s", filename, err)
2975 2ad5550d Michael Hanselmann
      else:
2976 2ad5550d Michael Hanselmann
        exp_size = utils.BytesToMebibyte(st.st_size)
2977 2ad5550d Michael Hanselmann
2978 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_RAW_DISK:
2979 1651d116 Michael Hanselmann
    (disk, ) = ieargs
2980 1651d116 Michael Hanselmann
2981 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
2982 1651d116 Michael Hanselmann
2983 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2984 1651d116 Michael Hanselmann
      # we set here a smaller block size as, due to transport buffering, more
2985 1651d116 Michael Hanselmann
      # than 64-128k will mostly ignored; we use nocreat to fail if the device
2986 1651d116 Michael Hanselmann
      # is not already there or we pass a wrong path; we use notrunc to no
2987 1651d116 Michael Hanselmann
      # attempt truncate on an LV device; we use oflag=dsync to not buffer too
2988 1651d116 Michael Hanselmann
      # much memory; this means that at best, we flush every 64k, which will
2989 1651d116 Michael Hanselmann
      # not be very fast
2990 1651d116 Michael Hanselmann
      suffix = utils.BuildShellCmd(("| dd of=%s conv=nocreat,notrunc"
2991 1651d116 Michael Hanselmann
                                    " bs=%s oflag=dsync"),
2992 1651d116 Michael Hanselmann
                                    real_disk.dev_path,
2993 1651d116 Michael Hanselmann
                                    str(64 * 1024))
2994 1651d116 Michael Hanselmann
2995 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2996 1651d116 Michael Hanselmann
      # the block size on the read dd is 1MiB to match our units
2997 1651d116 Michael Hanselmann
      prefix = utils.BuildShellCmd("dd if=%s bs=%s count=%s |",
2998 1651d116 Michael Hanselmann
                                   real_disk.dev_path,
2999 1651d116 Michael Hanselmann
                                   str(1024 * 1024), # 1 MB
3000 1651d116 Michael Hanselmann
                                   str(disk.size))
3001 2ad5550d Michael Hanselmann
      exp_size = disk.size
3002 1651d116 Michael Hanselmann
3003 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_SCRIPT:
3004 1651d116 Michael Hanselmann
    (disk, disk_index, ) = ieargs
3005 1651d116 Michael Hanselmann
3006 1651d116 Michael Hanselmann
    assert isinstance(disk_index, (int, long))
3007 1651d116 Michael Hanselmann
3008 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
3009 1651d116 Michael Hanselmann
3010 1651d116 Michael Hanselmann
    inst_os = OSFromDisk(instance.os)
3011 1651d116 Michael Hanselmann
    env = OSEnvironment(instance, inst_os)
3012 1651d116 Michael Hanselmann
3013 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3014 1651d116 Michael Hanselmann
      env["IMPORT_DEVICE"] = env["DISK_%d_PATH" % disk_index]
3015 1651d116 Michael Hanselmann
      env["IMPORT_INDEX"] = str(disk_index)
3016 1651d116 Michael Hanselmann
      script = inst_os.import_script
3017 1651d116 Michael Hanselmann
3018 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3019 1651d116 Michael Hanselmann
      env["EXPORT_DEVICE"] = real_disk.dev_path
3020 1651d116 Michael Hanselmann
      env["EXPORT_INDEX"] = str(disk_index)
3021 1651d116 Michael Hanselmann
      script = inst_os.export_script
3022 1651d116 Michael Hanselmann
3023 1651d116 Michael Hanselmann
    # TODO: Pass special environment only to script
3024 1651d116 Michael Hanselmann
    script_cmd = utils.BuildShellCmd("( cd %s && %s; )", inst_os.path, script)
3025 1651d116 Michael Hanselmann
3026 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3027 1651d116 Michael Hanselmann
      suffix = "| %s" % script_cmd
3028 1651d116 Michael Hanselmann
3029 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3030 1651d116 Michael Hanselmann
      prefix = "%s |" % script_cmd
3031 1651d116 Michael Hanselmann
3032 2ad5550d Michael Hanselmann
    # Let script predict size
3033 2ad5550d Michael Hanselmann
    exp_size = constants.IE_CUSTOM_SIZE
3034 2ad5550d Michael Hanselmann
3035 1651d116 Michael Hanselmann
  else:
3036 1651d116 Michael Hanselmann
    _Fail("Invalid %s I/O mode %r", mode, ieio)
3037 1651d116 Michael Hanselmann
3038 2ad5550d Michael Hanselmann
  return (env, prefix, suffix, exp_size)
3039 1651d116 Michael Hanselmann
3040 1651d116 Michael Hanselmann
3041 1651d116 Michael Hanselmann
def _CreateImportExportStatusDir(prefix):
3042 1651d116 Michael Hanselmann
  """Creates status directory for import/export.
3043 1651d116 Michael Hanselmann

3044 1651d116 Michael Hanselmann
  """
3045 1651d116 Michael Hanselmann
  return tempfile.mkdtemp(dir=constants.IMPORT_EXPORT_DIR,
3046 1651d116 Michael Hanselmann
                          prefix=("%s-%s-" %
3047 1651d116 Michael Hanselmann
                                  (prefix, utils.TimestampForFilename())))
3048 1651d116 Michael Hanselmann
3049 1651d116 Michael Hanselmann
3050 6613661a Iustin Pop
def StartImportExportDaemon(mode, opts, host, port, instance, component,
3051 6613661a Iustin Pop
                            ieio, ieioargs):
3052 1651d116 Michael Hanselmann
  """Starts an import or export daemon.
3053 1651d116 Michael Hanselmann

3054 1651d116 Michael Hanselmann
  @param mode: Import/output mode
3055 eb630f50 Michael Hanselmann
  @type opts: L{objects.ImportExportOptions}
3056 eb630f50 Michael Hanselmann
  @param opts: Daemon options
3057 1651d116 Michael Hanselmann
  @type host: string
3058 1651d116 Michael Hanselmann
  @param host: Remote host for export (None for import)
3059 1651d116 Michael Hanselmann
  @type port: int
3060 1651d116 Michael Hanselmann
  @param port: Remote port for export (None for import)
3061 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
3062 1651d116 Michael Hanselmann
  @param instance: Instance object
3063 6613661a Iustin Pop
  @type component: string
3064 6613661a Iustin Pop
  @param component: which part of the instance is transferred now,
3065 6613661a Iustin Pop
      e.g. 'disk/0'
3066 1651d116 Michael Hanselmann
  @param ieio: Input/output type
3067 1651d116 Michael Hanselmann
  @param ieioargs: Input/output arguments
3068 1651d116 Michael Hanselmann

3069 1651d116 Michael Hanselmann
  """
3070 1651d116 Michael Hanselmann
  if mode == constants.IEM_IMPORT:
3071 1651d116 Michael Hanselmann
    prefix = "import"
3072 1651d116 Michael Hanselmann
3073 1651d116 Michael Hanselmann
    if not (host is None and port is None):
3074 1651d116 Michael Hanselmann
      _Fail("Can not specify host or port on import")
3075 1651d116 Michael Hanselmann
3076 1651d116 Michael Hanselmann
  elif mode == constants.IEM_EXPORT:
3077 1651d116 Michael Hanselmann
    prefix = "export"
3078 1651d116 Michael Hanselmann
3079 1651d116 Michael Hanselmann
    if host is None or port is None:
3080 1651d116 Michael Hanselmann
      _Fail("Host and port must be specified for an export")
3081 1651d116 Michael Hanselmann
3082 1651d116 Michael Hanselmann
  else:
3083 1651d116 Michael Hanselmann
    _Fail("Invalid mode %r", mode)
3084 1651d116 Michael Hanselmann
3085 eb630f50 Michael Hanselmann
  if (opts.key_name is None) ^ (opts.ca_pem is None):
3086 1651d116 Michael Hanselmann
    _Fail("Cluster certificate can only be used for both key and CA")
3087 1651d116 Michael Hanselmann
3088 2ad5550d Michael Hanselmann
  (cmd_env, cmd_prefix, cmd_suffix, exp_size) = \
3089 1651d116 Michael Hanselmann
    _GetImportExportIoCommand(instance, mode, ieio, ieioargs)
3090 1651d116 Michael Hanselmann
3091 eb630f50 Michael Hanselmann
  if opts.key_name is None:
3092 1651d116 Michael Hanselmann
    # Use server.pem
3093 1651d116 Michael Hanselmann
    key_path = constants.NODED_CERT_FILE
3094 1651d116 Michael Hanselmann
    cert_path = constants.NODED_CERT_FILE
3095 eb630f50 Michael Hanselmann
    assert opts.ca_pem is None
3096 1651d116 Michael Hanselmann
  else:
3097 1651d116 Michael Hanselmann
    (_, key_path, cert_path) = _GetX509Filenames(constants.CRYPTO_KEYS_DIR,
3098 eb630f50 Michael Hanselmann
                                                 opts.key_name)
3099 eb630f50 Michael Hanselmann
    assert opts.ca_pem is not None
3100 1651d116 Michael Hanselmann
3101 63bcea2a Michael Hanselmann
  for i in [key_path, cert_path]:
3102 dcaabc4f Michael Hanselmann
    if not os.path.exists(i):
3103 63bcea2a Michael Hanselmann
      _Fail("File '%s' does not exist" % i)
3104 63bcea2a Michael Hanselmann
3105 6613661a Iustin Pop
  status_dir = _CreateImportExportStatusDir("%s-%s" % (prefix, component))
3106 1651d116 Michael Hanselmann
  try:
3107 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(status_dir, _IES_STATUS_FILE)
3108 1651d116 Michael Hanselmann
    pid_file = utils.PathJoin(status_dir, _IES_PID_FILE)
3109 63bcea2a Michael Hanselmann
    ca_file = utils.PathJoin(status_dir, _IES_CA_FILE)
3110 1651d116 Michael Hanselmann
3111 eb630f50 Michael Hanselmann
    if opts.ca_pem is None:
3112 1651d116 Michael Hanselmann
      # Use server.pem
3113 63bcea2a Michael Hanselmann
      ca = utils.ReadFile(constants.NODED_CERT_FILE)
3114 eb630f50 Michael Hanselmann
    else:
3115 eb630f50 Michael Hanselmann
      ca = opts.ca_pem
3116 63bcea2a Michael Hanselmann
3117 eb630f50 Michael Hanselmann
    # Write CA file
3118 63bcea2a Michael Hanselmann
    utils.WriteFile(ca_file, data=ca, mode=0400)
3119 1651d116 Michael Hanselmann
3120 1651d116 Michael Hanselmann
    cmd = [
3121 1651d116 Michael Hanselmann
      constants.IMPORT_EXPORT_DAEMON,
3122 1651d116 Michael Hanselmann
      status_file, mode,
3123 1651d116 Michael Hanselmann
      "--key=%s" % key_path,
3124 1651d116 Michael Hanselmann
      "--cert=%s" % cert_path,
3125 63bcea2a Michael Hanselmann
      "--ca=%s" % ca_file,
3126 1651d116 Michael Hanselmann
      ]
3127 1651d116 Michael Hanselmann
3128 1651d116 Michael Hanselmann
    if host:
3129 1651d116 Michael Hanselmann
      cmd.append("--host=%s" % host)
3130 1651d116 Michael Hanselmann
3131 1651d116 Michael Hanselmann
    if port:
3132 1651d116 Michael Hanselmann
      cmd.append("--port=%s" % port)
3133 1651d116 Michael Hanselmann
3134 855d2fc7 Michael Hanselmann
    if opts.ipv6:
3135 855d2fc7 Michael Hanselmann
      cmd.append("--ipv6")
3136 855d2fc7 Michael Hanselmann
    else:
3137 855d2fc7 Michael Hanselmann
      cmd.append("--ipv4")
3138 855d2fc7 Michael Hanselmann
3139 a5310c2a Michael Hanselmann
    if opts.compress:
3140 a5310c2a Michael Hanselmann
      cmd.append("--compress=%s" % opts.compress)
3141 a5310c2a Michael Hanselmann
3142 af1d39b1 Michael Hanselmann
    if opts.magic:
3143 af1d39b1 Michael Hanselmann
      cmd.append("--magic=%s" % opts.magic)
3144 af1d39b1 Michael Hanselmann
3145 2ad5550d Michael Hanselmann
    if exp_size is not None:
3146 2ad5550d Michael Hanselmann
      cmd.append("--expected-size=%s" % exp_size)
3147 2ad5550d Michael Hanselmann
3148 1651d116 Michael Hanselmann
    if cmd_prefix:
3149 1651d116 Michael Hanselmann
      cmd.append("--cmd-prefix=%s" % cmd_prefix)
3150 1651d116 Michael Hanselmann
3151 1651d116 Michael Hanselmann
    if cmd_suffix:
3152 1651d116 Michael Hanselmann
      cmd.append("--cmd-suffix=%s" % cmd_suffix)
3153 1651d116 Michael Hanselmann
3154 4478301b Michael Hanselmann
    if mode == constants.IEM_EXPORT:
3155 4478301b Michael Hanselmann
      # Retry connection a few times when connecting to remote peer
3156 4478301b Michael Hanselmann
      cmd.append("--connect-retries=%s" % constants.RIE_CONNECT_RETRIES)
3157 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % constants.RIE_CONNECT_ATTEMPT_TIMEOUT)
3158 4478301b Michael Hanselmann
    elif opts.connect_timeout is not None:
3159 4478301b Michael Hanselmann
      assert mode == constants.IEM_IMPORT
3160 4478301b Michael Hanselmann
      # Overall timeout for establishing connection while listening
3161 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % opts.connect_timeout)
3162 4478301b Michael Hanselmann
3163 6aa7a354 Iustin Pop
    logfile = _InstanceLogName(prefix, instance.os, instance.name, component)
3164 1651d116 Michael Hanselmann
3165 1651d116 Michael Hanselmann
    # TODO: Once _InstanceLogName uses tempfile.mkstemp, StartDaemon has
3166 1651d116 Michael Hanselmann
    # support for receiving a file descriptor for output
3167 1651d116 Michael Hanselmann
    utils.StartDaemon(cmd, env=cmd_env, pidfile=pid_file,
3168 1651d116 Michael Hanselmann
                      output=logfile)
3169 1651d116 Michael Hanselmann
3170 1651d116 Michael Hanselmann
    # The import/export name is simply the status directory name
3171 1651d116 Michael Hanselmann
    return os.path.basename(status_dir)
3172 1651d116 Michael Hanselmann
3173 1651d116 Michael Hanselmann
  except Exception:
3174 1651d116 Michael Hanselmann
    shutil.rmtree(status_dir, ignore_errors=True)
3175 1651d116 Michael Hanselmann
    raise
3176 1651d116 Michael Hanselmann
3177 1651d116 Michael Hanselmann
3178 1651d116 Michael Hanselmann
def GetImportExportStatus(names):
3179 1651d116 Michael Hanselmann
  """Returns import/export daemon status.
3180 1651d116 Michael Hanselmann

3181 1651d116 Michael Hanselmann
  @type names: sequence
3182 1651d116 Michael Hanselmann
  @param names: List of names
3183 1651d116 Michael Hanselmann
  @rtype: List of dicts
3184 1651d116 Michael Hanselmann
  @return: Returns a list of the state of each named import/export or None if a
3185 1651d116 Michael Hanselmann
           status couldn't be read
3186 1651d116 Michael Hanselmann

3187 1651d116 Michael Hanselmann
  """
3188 1651d116 Michael Hanselmann
  result = []
3189 1651d116 Michael Hanselmann
3190 1651d116 Michael Hanselmann
  for name in names:
3191 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name,
3192 1651d116 Michael Hanselmann
                                 _IES_STATUS_FILE)
3193 1651d116 Michael Hanselmann
3194 1651d116 Michael Hanselmann
    try:
3195 1651d116 Michael Hanselmann
      data = utils.ReadFile(status_file)
3196 1651d116 Michael Hanselmann
    except EnvironmentError, err:
3197 1651d116 Michael Hanselmann
      if err.errno != errno.ENOENT:
3198 1651d116 Michael Hanselmann
        raise
3199 1651d116 Michael Hanselmann
      data = None
3200 1651d116 Michael Hanselmann
3201 1651d116 Michael Hanselmann
    if not data:
3202 1651d116 Michael Hanselmann
      result.append(None)
3203 1651d116 Michael Hanselmann
      continue
3204 1651d116 Michael Hanselmann
3205 1651d116 Michael Hanselmann
    result.append(serializer.LoadJson(data))
3206 1651d116 Michael Hanselmann
3207 1651d116 Michael Hanselmann
  return result
3208 1651d116 Michael Hanselmann
3209 1651d116 Michael Hanselmann
3210 f81c4737 Michael Hanselmann
def AbortImportExport(name):
3211 f81c4737 Michael Hanselmann
  """Sends SIGTERM to a running import/export daemon.
3212 f81c4737 Michael Hanselmann

3213 f81c4737 Michael Hanselmann
  """
3214 f81c4737 Michael Hanselmann
  logging.info("Abort import/export %s", name)
3215 f81c4737 Michael Hanselmann
3216 f81c4737 Michael Hanselmann
  status_dir = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name)
3217 f81c4737 Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
3218 f81c4737 Michael Hanselmann
3219 f81c4737 Michael Hanselmann
  if pid:
3220 f81c4737 Michael Hanselmann
    logging.info("Import/export %s is running with PID %s, sending SIGTERM",
3221 f81c4737 Michael Hanselmann
                 name, pid)
3222 560cbec1 Michael Hanselmann
    utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
3223 f81c4737 Michael Hanselmann
3224 f81c4737 Michael Hanselmann
3225 1651d116 Michael Hanselmann
def CleanupImportExport(name):
3226 1651d116 Michael Hanselmann
  """Cleanup after an import or export.
3227 1651d116 Michael Hanselmann

3228 1651d116 Michael Hanselmann
  If the import/export daemon is still running it's killed. Afterwards the
3229 1651d116 Michael Hanselmann
  whole status directory is removed.
3230 1651d116 Michael Hanselmann

3231 1651d116 Michael Hanselmann
  """
3232 1651d116 Michael Hanselmann
  logging.info("Finalizing import/export %s", name)
3233 1651d116 Michael Hanselmann
3234 1651d116 Michael Hanselmann
  status_dir = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name)
3235 1651d116 Michael Hanselmann
3236 debed9ae Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
3237 1651d116 Michael Hanselmann
3238 1651d116 Michael Hanselmann
  if pid:
3239 1651d116 Michael Hanselmann
    logging.info("Import/export %s is still running with PID %s",
3240 1651d116 Michael Hanselmann
                 name, pid)
3241 1651d116 Michael Hanselmann
    utils.KillProcess(pid, waitpid=False)
3242 1651d116 Michael Hanselmann
3243 1651d116 Michael Hanselmann
  shutil.rmtree(status_dir, ignore_errors=True)
3244 1651d116 Michael Hanselmann
3245 1651d116 Michael Hanselmann
3246 6b93ec9d Iustin Pop
def _FindDisks(nodes_ip, disks):
3247 6b93ec9d Iustin Pop
  """Sets the physical ID on disks and returns the block devices.
3248 6b93ec9d Iustin Pop

3249 6b93ec9d Iustin Pop
  """
3250 6b93ec9d Iustin Pop
  # set the correct physical ID
3251 b705c7a6 Manuel Franceschini
  my_name = netutils.Hostname.GetSysName()
3252 6b93ec9d Iustin Pop
  for cf in disks:
3253 6b93ec9d Iustin Pop
    cf.SetPhysicalID(my_name, nodes_ip)
3254 6b93ec9d Iustin Pop
3255 6b93ec9d Iustin Pop
  bdevs = []
3256 6b93ec9d Iustin Pop
3257 6b93ec9d Iustin Pop
  for cf in disks:
3258 6b93ec9d Iustin Pop
    rd = _RecursiveFindBD(cf)
3259 6b93ec9d Iustin Pop
    if rd is None:
3260 5a533f8a Iustin Pop
      _Fail("Can't find device %s", cf)
3261 6b93ec9d Iustin Pop
    bdevs.append(rd)
3262 5a533f8a Iustin Pop
  return bdevs
3263 6b93ec9d Iustin Pop
3264 6b93ec9d Iustin Pop
3265 6b93ec9d Iustin Pop
def DrbdDisconnectNet(nodes_ip, disks):
3266 6b93ec9d Iustin Pop
  """Disconnects the network on a list of drbd devices.
3267 6b93ec9d Iustin Pop

3268 6b93ec9d Iustin Pop
  """
3269 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3270 6b93ec9d Iustin Pop
3271 6b93ec9d Iustin Pop
  # disconnect disks
3272 6b93ec9d Iustin Pop
  for rd in bdevs:
3273 6b93ec9d Iustin Pop
    try:
3274 6b93ec9d Iustin Pop
      rd.DisconnectNet()
3275 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
3276 2cc6781a Iustin Pop
      _Fail("Can't change network configuration to standalone mode: %s",
3277 2cc6781a Iustin Pop
            err, exc=True)
3278 6b93ec9d Iustin Pop
3279 6b93ec9d Iustin Pop
3280 6b93ec9d Iustin Pop
def DrbdAttachNet(nodes_ip, disks, instance_name, multimaster):
3281 6b93ec9d Iustin Pop
  """Attaches the network on a list of drbd devices.
3282 6b93ec9d Iustin Pop

3283 6b93ec9d Iustin Pop
  """
3284 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3285 6b93ec9d Iustin Pop
3286 6b93ec9d Iustin Pop
  if multimaster:
3287 53c776b5 Iustin Pop
    for idx, rd in enumerate(bdevs):
3288 6b93ec9d Iustin Pop
      try:
3289 53c776b5 Iustin Pop
        _SymlinkBlockDev(instance_name, rd.dev_path, idx)
3290 6b93ec9d Iustin Pop
      except EnvironmentError, err:
3291 2cc6781a Iustin Pop
        _Fail("Can't create symlink: %s", err)
3292 6b93ec9d Iustin Pop
  # reconnect disks, switch to new master configuration and if
3293 6b93ec9d Iustin Pop
  # needed primary mode
3294 6b93ec9d Iustin Pop
  for rd in bdevs:
3295 6b93ec9d Iustin Pop
    try:
3296 6b93ec9d Iustin Pop
      rd.AttachNet(multimaster)
3297 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
3298 2cc6781a Iustin Pop
      _Fail("Can't change network configuration: %s", err)
3299 3c0cdc83 Michael Hanselmann
3300 6b93ec9d Iustin Pop
  # wait until the disks are connected; we need to retry the re-attach
3301 6b93ec9d Iustin Pop
  # if the device becomes standalone, as this might happen if the one
3302 6b93ec9d Iustin Pop
  # node disconnects and reconnects in a different mode before the
3303 6b93ec9d Iustin Pop
  # other node reconnects; in this case, one or both of the nodes will
3304 6b93ec9d Iustin Pop
  # decide it has wrong configuration and switch to standalone
3305 3c0cdc83 Michael Hanselmann
3306 3c0cdc83 Michael Hanselmann
  def _Attach():
3307 6b93ec9d Iustin Pop
    all_connected = True
3308 3c0cdc83 Michael Hanselmann
3309 6b93ec9d Iustin Pop
    for rd in bdevs:
3310 6b93ec9d Iustin Pop
      stats = rd.GetProcStatus()
3311 3c0cdc83 Michael Hanselmann
3312 3c0cdc83 Michael Hanselmann
      all_connected = (all_connected and
3313 3c0cdc83 Michael Hanselmann
                       (stats.is_connected or stats.is_in_resync))
3314 3c0cdc83 Michael Hanselmann
3315 6b93ec9d Iustin Pop
      if stats.is_standalone:
3316 6b93ec9d Iustin Pop
        # peer had different config info and this node became
3317 6b93ec9d Iustin Pop
        # standalone, even though this should not happen with the
3318 6b93ec9d Iustin Pop
        # new staged way of changing disk configs
3319 6b93ec9d Iustin Pop
        try:
3320 c738375b Iustin Pop
          rd.AttachNet(multimaster)
3321 6b93ec9d Iustin Pop
        except errors.BlockDeviceError, err:
3322 2cc6781a Iustin Pop
          _Fail("Can't change network configuration: %s", err)
3323 3c0cdc83 Michael Hanselmann
3324 3c0cdc83 Michael Hanselmann
    if not all_connected:
3325 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
3326 3c0cdc83 Michael Hanselmann
3327 3c0cdc83 Michael Hanselmann
  try:
3328 3c0cdc83 Michael Hanselmann
    # Start with a delay of 100 miliseconds and go up to 5 seconds
3329 3c0cdc83 Michael Hanselmann
    utils.Retry(_Attach, (0.1, 1.5, 5.0), 2 * 60)
3330 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
3331 afdc3985 Iustin Pop
    _Fail("Timeout in disk reconnecting")
3332 3c0cdc83 Michael Hanselmann
3333 6b93ec9d Iustin Pop
  if multimaster:
3334 6b93ec9d Iustin Pop
    # change to primary mode
3335 6b93ec9d Iustin Pop
    for rd in bdevs:
3336 d3da87b8 Iustin Pop
      try:
3337 d3da87b8 Iustin Pop
        rd.Open()
3338 d3da87b8 Iustin Pop
      except errors.BlockDeviceError, err:
3339 2cc6781a Iustin Pop
        _Fail("Can't change to primary mode: %s", err)
3340 6b93ec9d Iustin Pop
3341 6b93ec9d Iustin Pop
3342 6b93ec9d Iustin Pop
def DrbdWaitSync(nodes_ip, disks):
3343 6b93ec9d Iustin Pop
  """Wait until DRBDs have synchronized.
3344 6b93ec9d Iustin Pop

3345 6b93ec9d Iustin Pop
  """
3346 db8667b7 Iustin Pop
  def _helper(rd):
3347 db8667b7 Iustin Pop
    stats = rd.GetProcStatus()
3348 db8667b7 Iustin Pop
    if not (stats.is_connected or stats.is_in_resync):
3349 db8667b7 Iustin Pop
      raise utils.RetryAgain()
3350 db8667b7 Iustin Pop
    return stats
3351 db8667b7 Iustin Pop
3352 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3353 6b93ec9d Iustin Pop
3354 6b93ec9d Iustin Pop
  min_resync = 100
3355 6b93ec9d Iustin Pop
  alldone = True
3356 6b93ec9d Iustin Pop
  for rd in bdevs:
3357 db8667b7 Iustin Pop
    try:
3358 db8667b7 Iustin Pop
      # poll each second for 15 seconds
3359 db8667b7 Iustin Pop
      stats = utils.Retry(_helper, 1, 15, args=[rd])
3360 db8667b7 Iustin Pop
    except utils.RetryTimeout:
3361 db8667b7 Iustin Pop
      stats = rd.GetProcStatus()
3362 db8667b7 Iustin Pop
      # last check
3363 db8667b7 Iustin Pop
      if not (stats.is_connected or stats.is_in_resync):
3364 db8667b7 Iustin Pop
        _Fail("DRBD device %s is not in sync: stats=%s", rd, stats)
3365 6b93ec9d Iustin Pop
    alldone = alldone and (not stats.is_in_resync)
3366 6b93ec9d Iustin Pop
    if stats.sync_percent is not None:
3367 6b93ec9d Iustin Pop
      min_resync = min(min_resync, stats.sync_percent)
3368 afdc3985 Iustin Pop
3369 c26a6bd2 Iustin Pop
  return (alldone, min_resync)
3370 6b93ec9d Iustin Pop
3371 6b93ec9d Iustin Pop
3372 c46b9782 Luca Bigliardi
def GetDrbdUsermodeHelper():
3373 c46b9782 Luca Bigliardi
  """Returns DRBD usermode helper currently configured.
3374 c46b9782 Luca Bigliardi

3375 c46b9782 Luca Bigliardi
  """
3376 c46b9782 Luca Bigliardi
  try:
3377 c46b9782 Luca Bigliardi
    return bdev.BaseDRBD.GetUsermodeHelper()
3378 c46b9782 Luca Bigliardi
  except errors.BlockDeviceError, err:
3379 c46b9782 Luca Bigliardi
    _Fail(str(err))
3380 c46b9782 Luca Bigliardi
3381 c46b9782 Luca Bigliardi
3382 f5118ade Iustin Pop
def PowercycleNode(hypervisor_type):
3383 f5118ade Iustin Pop
  """Hard-powercycle the node.
3384 f5118ade Iustin Pop

3385 f5118ade Iustin Pop
  Because we need to return first, and schedule the powercycle in the
3386 f5118ade Iustin Pop
  background, we won't be able to report failures nicely.
3387 f5118ade Iustin Pop

3388 f5118ade Iustin Pop
  """
3389 f5118ade Iustin Pop
  hyper = hypervisor.GetHypervisor(hypervisor_type)
3390 f5118ade Iustin Pop
  try:
3391 f5118ade Iustin Pop
    pid = os.fork()
3392 29921401 Iustin Pop
  except OSError:
3393 f5118ade Iustin Pop
    # if we can't fork, we'll pretend that we're in the child process
3394 f5118ade Iustin Pop
    pid = 0
3395 f5118ade Iustin Pop
  if pid > 0:
3396 c26a6bd2 Iustin Pop
    return "Reboot scheduled in 5 seconds"
3397 1af6ac0f Luca Bigliardi
  # ensure the child is running on ram
3398 1af6ac0f Luca Bigliardi
  try:
3399 1af6ac0f Luca Bigliardi
    utils.Mlockall()
3400 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
3401 1af6ac0f Luca Bigliardi
    pass
3402 f5118ade Iustin Pop
  time.sleep(5)
3403 f5118ade Iustin Pop
  hyper.PowercycleNode()
3404 f5118ade Iustin Pop
3405 f5118ade Iustin Pop
3406 a8083063 Iustin Pop
class HooksRunner(object):
3407 a8083063 Iustin Pop
  """Hook runner.
3408 a8083063 Iustin Pop

3409 10c2650b Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not
3410 10c2650b Iustin Pop
  on the master side.
3411 a8083063 Iustin Pop

3412 a8083063 Iustin Pop
  """
3413 a8083063 Iustin Pop
  def __init__(self, hooks_base_dir=None):
3414 a8083063 Iustin Pop
    """Constructor for hooks runner.
3415 a8083063 Iustin Pop

3416 10c2650b Iustin Pop
    @type hooks_base_dir: str or None
3417 10c2650b Iustin Pop
    @param hooks_base_dir: if not None, this overrides the
3418 10c2650b Iustin Pop
        L{constants.HOOKS_BASE_DIR} (useful for unittests)
3419 a8083063 Iustin Pop

3420 a8083063 Iustin Pop
    """
3421 a8083063 Iustin Pop
    if hooks_base_dir is None:
3422 a8083063 Iustin Pop
      hooks_base_dir = constants.HOOKS_BASE_DIR
3423 fe267188 Iustin Pop
    # yeah, _BASE_DIR is not valid for attributes, we use it like a
3424 fe267188 Iustin Pop
    # constant
3425 b459a848 Andrea Spadaccini
    self._BASE_DIR = hooks_base_dir # pylint: disable=C0103
3426 a8083063 Iustin Pop
3427 a8083063 Iustin Pop
  def RunHooks(self, hpath, phase, env):
3428 a8083063 Iustin Pop
    """Run the scripts in the hooks directory.
3429 a8083063 Iustin Pop

3430 10c2650b Iustin Pop
    @type hpath: str
3431 10c2650b Iustin Pop
    @param hpath: the path to the hooks directory which
3432 10c2650b Iustin Pop
        holds the scripts
3433 10c2650b Iustin Pop
    @type phase: str
3434 10c2650b Iustin Pop
    @param phase: either L{constants.HOOKS_PHASE_PRE} or
3435 10c2650b Iustin Pop
        L{constants.HOOKS_PHASE_POST}
3436 10c2650b Iustin Pop
    @type env: dict
3437 10c2650b Iustin Pop
    @param env: dictionary with the environment for the hook
3438 10c2650b Iustin Pop
    @rtype: list
3439 10c2650b Iustin Pop
    @return: list of 3-element tuples:
3440 10c2650b Iustin Pop
      - script path
3441 10c2650b Iustin Pop
      - script result, either L{constants.HKR_SUCCESS} or
3442 10c2650b Iustin Pop
        L{constants.HKR_FAIL}
3443 10c2650b Iustin Pop
      - output of the script
3444 10c2650b Iustin Pop

3445 10c2650b Iustin Pop
    @raise errors.ProgrammerError: for invalid input
3446 10c2650b Iustin Pop
        parameters
3447 a8083063 Iustin Pop

3448 a8083063 Iustin Pop
    """
3449 a8083063 Iustin Pop
    if phase == constants.HOOKS_PHASE_PRE:
3450 a8083063 Iustin Pop
      suffix = "pre"
3451 a8083063 Iustin Pop
    elif phase == constants.HOOKS_PHASE_POST:
3452 a8083063 Iustin Pop
      suffix = "post"
3453 a8083063 Iustin Pop
    else:
3454 3fb4f740 Iustin Pop
      _Fail("Unknown hooks phase '%s'", phase)
3455 3fb4f740 Iustin Pop
3456 a8083063 Iustin Pop
    subdir = "%s-%s.d" % (hpath, suffix)
3457 0411c011 Iustin Pop
    dir_name = utils.PathJoin(self._BASE_DIR, subdir)
3458 6bb65e3a Guido Trotter
3459 6bb65e3a Guido Trotter
    results = []
3460 a9b7e346 Iustin Pop
3461 a9b7e346 Iustin Pop
    if not os.path.isdir(dir_name):
3462 a9b7e346 Iustin Pop
      # for non-existing/non-dirs, we simply exit instead of logging a
3463 a9b7e346 Iustin Pop
      # warning at every operation
3464 a9b7e346 Iustin Pop
      return results
3465 a9b7e346 Iustin Pop
3466 a9b7e346 Iustin Pop
    runparts_results = utils.RunParts(dir_name, env=env, reset_env=True)
3467 a9b7e346 Iustin Pop
3468 6bb65e3a Guido Trotter
    for (relname, relstatus, runresult)  in runparts_results:
3469 6bb65e3a Guido Trotter
      if relstatus == constants.RUNPARTS_SKIP:
3470 a8083063 Iustin Pop
        rrval = constants.HKR_SKIP
3471 a8083063 Iustin Pop
        output = ""
3472 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_ERR:
3473 6bb65e3a Guido Trotter
        rrval = constants.HKR_FAIL
3474 6bb65e3a Guido Trotter
        output = "Hook script execution error: %s" % runresult
3475 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_RUN:
3476 6bb65e3a Guido Trotter
        if runresult.failed:
3477 a8083063 Iustin Pop
          rrval = constants.HKR_FAIL
3478 a8083063 Iustin Pop
        else:
3479 6bb65e3a Guido Trotter
          rrval = constants.HKR_SUCCESS
3480 6bb65e3a Guido Trotter
        output = utils.SafeEncode(runresult.output.strip())
3481 6bb65e3a Guido Trotter
      results.append(("%s/%s" % (subdir, relname), rrval, output))
3482 6bb65e3a Guido Trotter
3483 6bb65e3a Guido Trotter
    return results
3484 3f78eef2 Iustin Pop
3485 3f78eef2 Iustin Pop
3486 8d528b7c Iustin Pop
class IAllocatorRunner(object):
3487 8d528b7c Iustin Pop
  """IAllocator runner.
3488 8d528b7c Iustin Pop

3489 8d528b7c Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not on
3490 8d528b7c Iustin Pop
  the master side.
3491 8d528b7c Iustin Pop

3492 8d528b7c Iustin Pop
  """
3493 7e950d31 Iustin Pop
  @staticmethod
3494 7e950d31 Iustin Pop
  def Run(name, idata):
3495 8d528b7c Iustin Pop
    """Run an iallocator script.
3496 8d528b7c Iustin Pop

3497 10c2650b Iustin Pop
    @type name: str
3498 10c2650b Iustin Pop
    @param name: the iallocator script name
3499 10c2650b Iustin Pop
    @type idata: str
3500 10c2650b Iustin Pop
    @param idata: the allocator input data
3501 10c2650b Iustin Pop

3502 10c2650b Iustin Pop
    @rtype: tuple
3503 87f5c298 Iustin Pop
    @return: two element tuple of:
3504 87f5c298 Iustin Pop
       - status
3505 87f5c298 Iustin Pop
       - either error message or stdout of allocator (for success)
3506 8d528b7c Iustin Pop

3507 8d528b7c Iustin Pop
    """
3508 8d528b7c Iustin Pop
    alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
3509 8d528b7c Iustin Pop
                                  os.path.isfile)
3510 8d528b7c Iustin Pop
    if alloc_script is None:
3511 87f5c298 Iustin Pop
      _Fail("iallocator module '%s' not found in the search path", name)
3512 8d528b7c Iustin Pop
3513 8d528b7c Iustin Pop
    fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
3514 8d528b7c Iustin Pop
    try:
3515 8d528b7c Iustin Pop
      os.write(fd, idata)
3516 8d528b7c Iustin Pop
      os.close(fd)
3517 8d528b7c Iustin Pop
      result = utils.RunCmd([alloc_script, fin_name])
3518 8d528b7c Iustin Pop
      if result.failed:
3519 87f5c298 Iustin Pop
        _Fail("iallocator module '%s' failed: %s, output '%s'",
3520 87f5c298 Iustin Pop
              name, result.fail_reason, result.output)
3521 8d528b7c Iustin Pop
    finally:
3522 8d528b7c Iustin Pop
      os.unlink(fin_name)
3523 8d528b7c Iustin Pop
3524 c26a6bd2 Iustin Pop
    return result.stdout
3525 8d528b7c Iustin Pop
3526 8d528b7c Iustin Pop
3527 3f78eef2 Iustin Pop
class DevCacheManager(object):
3528 c99a3cc0 Manuel Franceschini
  """Simple class for managing a cache of block device information.
3529 3f78eef2 Iustin Pop

3530 3f78eef2 Iustin Pop
  """
3531 3f78eef2 Iustin Pop
  _DEV_PREFIX = "/dev/"
3532 3f78eef2 Iustin Pop
  _ROOT_DIR = constants.BDEV_CACHE_DIR
3533 3f78eef2 Iustin Pop
3534 3f78eef2 Iustin Pop
  @classmethod
3535 3f78eef2 Iustin Pop
  def _ConvertPath(cls, dev_path):
3536 3f78eef2 Iustin Pop
    """Converts a /dev/name path to the cache file name.
3537 3f78eef2 Iustin Pop

3538 3f78eef2 Iustin Pop
    This replaces slashes with underscores and strips the /dev
3539 10c2650b Iustin Pop
    prefix. It then returns the full path to the cache file.
3540 10c2650b Iustin Pop

3541 10c2650b Iustin Pop
    @type dev_path: str
3542 10c2650b Iustin Pop
    @param dev_path: the C{/dev/} path name
3543 10c2650b Iustin Pop
    @rtype: str
3544 10c2650b Iustin Pop
    @return: the converted path name
3545 3f78eef2 Iustin Pop

3546 3f78eef2 Iustin Pop
    """
3547 3f78eef2 Iustin Pop
    if dev_path.startswith(cls._DEV_PREFIX):
3548 3f78eef2 Iustin Pop
      dev_path = dev_path[len(cls._DEV_PREFIX):]
3549 3f78eef2 Iustin Pop
    dev_path = dev_path.replace("/", "_")
3550 0411c011 Iustin Pop
    fpath = utils.PathJoin(cls._ROOT_DIR, "bdev_%s" % dev_path)
3551 3f78eef2 Iustin Pop
    return fpath
3552 3f78eef2 Iustin Pop
3553 3f78eef2 Iustin Pop
  @classmethod
3554 3f78eef2 Iustin Pop
  def UpdateCache(cls, dev_path, owner, on_primary, iv_name):
3555 3f78eef2 Iustin Pop
    """Updates the cache information for a given device.
3556 3f78eef2 Iustin Pop

3557 10c2650b Iustin Pop
    @type dev_path: str
3558 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
3559 10c2650b Iustin Pop
    @type owner: str
3560 10c2650b Iustin Pop
    @param owner: the owner (instance name) of the device
3561 10c2650b Iustin Pop
    @type on_primary: bool
3562 10c2650b Iustin Pop
    @param on_primary: whether this is the primary
3563 10c2650b Iustin Pop
        node nor not
3564 10c2650b Iustin Pop
    @type iv_name: str
3565 10c2650b Iustin Pop
    @param iv_name: the instance-visible name of the
3566 c41eea6e Iustin Pop
        device, as in objects.Disk.iv_name
3567 10c2650b Iustin Pop

3568 10c2650b Iustin Pop
    @rtype: None
3569 10c2650b Iustin Pop

3570 3f78eef2 Iustin Pop
    """
3571 cf5a8306 Iustin Pop
    if dev_path is None:
3572 18682bca Iustin Pop
      logging.error("DevCacheManager.UpdateCache got a None dev_path")
3573 cf5a8306 Iustin Pop
      return
3574 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
3575 3f78eef2 Iustin Pop
    if on_primary:
3576 3f78eef2 Iustin Pop
      state = "primary"
3577 3f78eef2 Iustin Pop
    else:
3578 3f78eef2 Iustin Pop
      state = "secondary"
3579 3f78eef2 Iustin Pop
    if iv_name is None:
3580 3f78eef2 Iustin Pop
      iv_name = "not_visible"
3581 3f78eef2 Iustin Pop
    fdata = "%s %s %s\n" % (str(owner), state, iv_name)
3582 3f78eef2 Iustin Pop
    try:
3583 3f78eef2 Iustin Pop
      utils.WriteFile(fpath, data=fdata)
3584 3f78eef2 Iustin Pop
    except EnvironmentError, err:
3585 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)
3586 3f78eef2 Iustin Pop
3587 3f78eef2 Iustin Pop
  @classmethod
3588 3f78eef2 Iustin Pop
  def RemoveCache(cls, dev_path):
3589 3f78eef2 Iustin Pop
    """Remove data for a dev_path.
3590 3f78eef2 Iustin Pop

3591 3865ca48 Michael Hanselmann
    This is just a wrapper over L{utils.io.RemoveFile} with a converted
3592 10c2650b Iustin Pop
    path name and logging.
3593 10c2650b Iustin Pop

3594 10c2650b Iustin Pop
    @type dev_path: str
3595 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
3596 10c2650b Iustin Pop

3597 10c2650b Iustin Pop
    @rtype: None
3598 10c2650b Iustin Pop

3599 3f78eef2 Iustin Pop
    """
3600 cf5a8306 Iustin Pop
    if dev_path is None:
3601 18682bca Iustin Pop
      logging.error("DevCacheManager.RemoveCache got a None dev_path")
3602 cf5a8306 Iustin Pop
      return
3603 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
3604 3f78eef2 Iustin Pop
    try:
3605 3f78eef2 Iustin Pop
      utils.RemoveFile(fpath)
3606 3f78eef2 Iustin Pop
    except EnvironmentError, err:
3607 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)