Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ c06e0c83

History | View | Annotate | Download (106.4 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 b397a7d2 Iustin Pop
    allowed_files.update(hv_class.GetAncillaryFiles())
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 d8e0caa6 Manuel Franceschini
  @return: master_netdev, master_ip, master_name, primary_ip_family
235 2a52a064 Iustin Pop
  @raise RPCFail: in case of errors
236 b1b6ea87 Iustin Pop

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

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

295 c06e0c83 Andrea Spadaccini
  The function will start the master daemons (ganeti-masterd and ganeti-rapi).
296 10c2650b Iustin Pop

297 3583908a Guido Trotter
  @type no_voting: boolean
298 3583908a Guido Trotter
  @param no_voting: whether to start ganeti-masterd without a node vote
299 c06e0c83 Andrea Spadaccini
      but still non-interactively
300 10c2650b Iustin Pop
  @rtype: None
301 a8083063 Iustin Pop

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

323 a8083063 Iustin Pop
  """
324 6c00d19a Iustin Pop
  # TODO: log and report back to the caller the error failures; we
325 6c00d19a Iustin Pop
  # need to decide in which case we fail the RPC for this
326 2a52a064 Iustin Pop
327 2a52a064 Iustin Pop
  # GetMasterInfo will raise an exception if not able to return data
328 d8e0caa6 Manuel Franceschini
  master_netdev, master_ip, _, family = GetMasterInfo()
329 a8083063 Iustin Pop
330 d8e0caa6 Manuel Franceschini
  ipcls = netutils.IP4Address
331 d8e0caa6 Manuel Franceschini
  if family == netutils.IP6Address.family:
332 d8e0caa6 Manuel Franceschini
    ipcls = netutils.IP6Address
333 e7323b5e Manuel Franceschini
334 c4dfb0b6 Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
335 d8e0caa6 Manuel Franceschini
                         "%s/%d" % (master_ip, ipcls.iplen),
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 c06e0c83 Andrea Spadaccini
342 c06e0c83 Andrea Spadaccini
def StopMasterDaemons():
343 c06e0c83 Andrea Spadaccini
  """Stop the master daemons on this node.
344 c06e0c83 Andrea Spadaccini

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

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

349 c06e0c83 Andrea Spadaccini
  """
350 c06e0c83 Andrea Spadaccini
  # TODO: log and report back to the caller the error failures; we
351 c06e0c83 Andrea Spadaccini
  # need to decide in which case we fail the RPC for this
352 c06e0c83 Andrea Spadaccini
353 c06e0c83 Andrea Spadaccini
  result = utils.RunCmd([constants.DAEMON_UTIL, "stop-master"])
354 c06e0c83 Andrea Spadaccini
  if result.failed:
355 c06e0c83 Andrea Spadaccini
    logging.error("Could not stop Ganeti master, command %s had exitcode %s"
356 c06e0c83 Andrea Spadaccini
                  " and error %s",
357 c06e0c83 Andrea Spadaccini
                  result.cmd, result.exit_code, result.output)
358 a8083063 Iustin Pop
359 a8083063 Iustin Pop
360 19ddc57a René Nussbaumer
def EtcHostsModify(mode, host, ip):
361 19ddc57a René Nussbaumer
  """Modify a host entry in /etc/hosts.
362 19ddc57a René Nussbaumer

363 19ddc57a René Nussbaumer
  @param mode: The mode to operate. Either add or remove entry
364 19ddc57a René Nussbaumer
  @param host: The host to operate on
365 19ddc57a René Nussbaumer
  @param ip: The ip associated with the entry
366 19ddc57a René Nussbaumer

367 19ddc57a René Nussbaumer
  """
368 19ddc57a René Nussbaumer
  if mode == constants.ETC_HOSTS_ADD:
369 19ddc57a René Nussbaumer
    if not ip:
370 19ddc57a René Nussbaumer
      RPCFail("Mode 'add' needs 'ip' parameter, but parameter not"
371 19ddc57a René Nussbaumer
              " present")
372 19ddc57a René Nussbaumer
    utils.AddHostToEtcHosts(host, ip)
373 19ddc57a René Nussbaumer
  elif mode == constants.ETC_HOSTS_REMOVE:
374 19ddc57a René Nussbaumer
    if ip:
375 19ddc57a René Nussbaumer
      RPCFail("Mode 'remove' does not allow 'ip' parameter, but"
376 19ddc57a René Nussbaumer
              " parameter is present")
377 19ddc57a René Nussbaumer
    utils.RemoveHostFromEtcHosts(host)
378 19ddc57a René Nussbaumer
  else:
379 19ddc57a René Nussbaumer
    RPCFail("Mode not supported")
380 19ddc57a René Nussbaumer
381 19ddc57a René Nussbaumer
382 b989b9d9 Ken Wehr
def LeaveCluster(modify_ssh_setup):
383 10c2650b Iustin Pop
  """Cleans up and remove the current node.
384 10c2650b Iustin Pop

385 10c2650b Iustin Pop
  This function cleans up and prepares the current node to be removed
386 10c2650b Iustin Pop
  from the cluster.
387 10c2650b Iustin Pop

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

392 b989b9d9 Ken Wehr
  @param modify_ssh_setup: boolean
393 b989b9d9 Ken Wehr

394 a8083063 Iustin Pop
  """
395 f78346f5 Michael Hanselmann
  _CleanDirectory(constants.DATA_DIR)
396 f942a838 Michael Hanselmann
  _CleanDirectory(constants.CRYPTO_KEYS_DIR)
397 1bc59f76 Michael Hanselmann
  JobQueuePurge()
398 f78346f5 Michael Hanselmann
399 b989b9d9 Ken Wehr
  if modify_ssh_setup:
400 b989b9d9 Ken Wehr
    try:
401 b989b9d9 Ken Wehr
      priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
402 7900ed01 Iustin Pop
403 b989b9d9 Ken Wehr
      utils.RemoveAuthorizedKey(auth_keys, utils.ReadFile(pub_key))
404 a8083063 Iustin Pop
405 b989b9d9 Ken Wehr
      utils.RemoveFile(priv_key)
406 b989b9d9 Ken Wehr
      utils.RemoveFile(pub_key)
407 b989b9d9 Ken Wehr
    except errors.OpExecError:
408 b989b9d9 Ken Wehr
      logging.exception("Error while processing ssh files")
409 a8083063 Iustin Pop
410 ed008420 Guido Trotter
  try:
411 6b7d5878 Michael Hanselmann
    utils.RemoveFile(constants.CONFD_HMAC_KEY)
412 ed008420 Guido Trotter
    utils.RemoveFile(constants.RAPI_CERT_FILE)
413 bfe86c76 Andrea Spadaccini
    utils.RemoveFile(constants.SPICE_CERT_FILE)
414 bfe86c76 Andrea Spadaccini
    utils.RemoveFile(constants.SPICE_CACERT_FILE)
415 168c1de2 Michael Hanselmann
    utils.RemoveFile(constants.NODED_CERT_FILE)
416 b459a848 Andrea Spadaccini
  except: # pylint: disable=W0702
417 ed008420 Guido Trotter
    logging.exception("Error while removing cluster secrets")
418 ed008420 Guido Trotter
419 f154a7a3 Michael Hanselmann
  result = utils.RunCmd([constants.DAEMON_UTIL, "stop", constants.CONFD])
420 f154a7a3 Michael Hanselmann
  if result.failed:
421 f154a7a3 Michael Hanselmann
    logging.error("Command %s failed with exitcode %s and error %s",
422 f154a7a3 Michael Hanselmann
                  result.cmd, result.exit_code, result.output)
423 ed008420 Guido Trotter
424 0623d351 Iustin Pop
  # Raise a custom exception (handled in ganeti-noded)
425 d0c8c01d Iustin Pop
  raise errors.QuitGanetiException(True, "Shutdown scheduled")
426 6d8b6238 Guido Trotter
427 a8083063 Iustin Pop
428 e69d05fd Iustin Pop
def GetNodeInfo(vgname, hypervisor_type):
429 5bbd3f7f Michael Hanselmann
  """Gives back a hash with different information about the node.
430 a8083063 Iustin Pop

431 e69d05fd Iustin Pop
  @type vgname: C{string}
432 e69d05fd Iustin Pop
  @param vgname: the name of the volume group to ask for disk space information
433 e69d05fd Iustin Pop
  @type hypervisor_type: C{str}
434 e69d05fd Iustin Pop
  @param hypervisor_type: the name of the hypervisor to ask for
435 e69d05fd Iustin Pop
      memory information
436 e69d05fd Iustin Pop
  @rtype: C{dict}
437 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
438 e69d05fd Iustin Pop
      - vg_size is the size of the configured volume group in MiB
439 e69d05fd Iustin Pop
      - vg_free is the free size of the volume group in MiB
440 e69d05fd Iustin Pop
      - memory_dom0 is the memory allocated for domain0 in MiB
441 e69d05fd Iustin Pop
      - memory_free is the currently available (free) ram in MiB
442 e69d05fd Iustin Pop
      - memory_total is the total number of ram in MiB
443 34fbc862 Andrea Spadaccini
      - hv_version: the hypervisor version, if available
444 a8083063 Iustin Pop

445 098c0958 Michael Hanselmann
  """
446 a8083063 Iustin Pop
  outputarray = {}
447 673cd9c4 René Nussbaumer
448 cb6a0296 Iustin Pop
  if vgname is not None:
449 cb6a0296 Iustin Pop
    vginfo = bdev.LogicalVolume.GetVGInfo([vgname])
450 cb6a0296 Iustin Pop
    vg_free = vg_size = None
451 cb6a0296 Iustin Pop
    if vginfo:
452 cb6a0296 Iustin Pop
      vg_free = int(round(vginfo[0][0], 0))
453 cb6a0296 Iustin Pop
      vg_size = int(round(vginfo[0][1], 0))
454 d0c8c01d Iustin Pop
    outputarray["vg_size"] = vg_size
455 d0c8c01d Iustin Pop
    outputarray["vg_free"] = vg_free
456 cb6a0296 Iustin Pop
457 cb6a0296 Iustin Pop
  if hypervisor_type is not None:
458 cb6a0296 Iustin Pop
    hyper = hypervisor.GetHypervisor(hypervisor_type)
459 cb6a0296 Iustin Pop
    hyp_info = hyper.GetNodeInfo()
460 cb6a0296 Iustin Pop
    if hyp_info is not None:
461 cb6a0296 Iustin Pop
      outputarray.update(hyp_info)
462 a8083063 Iustin Pop
463 13998ef2 Michael Hanselmann
  outputarray["bootid"] = utils.ReadFile(_BOOT_ID_PATH, size=128).rstrip("\n")
464 3ef10550 Michael Hanselmann
465 c26a6bd2 Iustin Pop
  return outputarray
466 a8083063 Iustin Pop
467 a8083063 Iustin Pop
468 62c9ec92 Iustin Pop
def VerifyNode(what, cluster_name):
469 a8083063 Iustin Pop
  """Verify the status of the local node.
470 a8083063 Iustin Pop

471 e69d05fd Iustin Pop
  Based on the input L{what} parameter, various checks are done on the
472 e69d05fd Iustin Pop
  local node.
473 e69d05fd Iustin Pop

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

477 e69d05fd Iustin Pop
  If the I{nodelist} key is present, we check that we have
478 e69d05fd Iustin Pop
  connectivity via ssh with the target nodes (and check the hostname
479 e69d05fd Iustin Pop
  report).
480 a8083063 Iustin Pop

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

485 e69d05fd Iustin Pop
  @type what: C{dict}
486 e69d05fd Iustin Pop
  @param what: a dictionary of things to check:
487 e69d05fd Iustin Pop
      - filelist: list of files for which to compute checksums
488 e69d05fd Iustin Pop
      - nodelist: list of nodes we should check ssh communication with
489 e69d05fd Iustin Pop
      - node-net-test: list of nodes we should check node daemon port
490 e69d05fd Iustin Pop
        connectivity with
491 e69d05fd Iustin Pop
      - hypervisor: list with hypervisors to run the verify for
492 10c2650b Iustin Pop
  @rtype: dict
493 10c2650b Iustin Pop
  @return: a dictionary with the same keys as the input dict, and
494 10c2650b Iustin Pop
      values representing the result of the checks
495 a8083063 Iustin Pop

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

659 2be7273c Apollon Oikonomopoulos
  @type devices: list
660 2be7273c Apollon Oikonomopoulos
  @param devices: list of block device nodes to query
661 2be7273c Apollon Oikonomopoulos
  @rtype: dict
662 2be7273c Apollon Oikonomopoulos
  @return:
663 2be7273c Apollon Oikonomopoulos
    dictionary of all block devices under /dev (key). The value is their
664 2be7273c Apollon Oikonomopoulos
    size in MiB.
665 2be7273c Apollon Oikonomopoulos

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

668 2be7273c Apollon Oikonomopoulos
  """
669 2be7273c Apollon Oikonomopoulos
  DEV_PREFIX = "/dev/"
670 2be7273c Apollon Oikonomopoulos
  blockdevs = {}
671 2be7273c Apollon Oikonomopoulos
672 2be7273c Apollon Oikonomopoulos
  for devpath in devices:
673 cf00dba0 René Nussbaumer
    if not utils.IsBelowDir(DEV_PREFIX, devpath):
674 2be7273c Apollon Oikonomopoulos
      continue
675 2be7273c Apollon Oikonomopoulos
676 2be7273c Apollon Oikonomopoulos
    try:
677 2be7273c Apollon Oikonomopoulos
      st = os.stat(devpath)
678 2be7273c Apollon Oikonomopoulos
    except EnvironmentError, err:
679 2be7273c Apollon Oikonomopoulos
      logging.warning("Error stat()'ing device %s: %s", devpath, str(err))
680 2be7273c Apollon Oikonomopoulos
      continue
681 2be7273c Apollon Oikonomopoulos
682 2be7273c Apollon Oikonomopoulos
    if stat.S_ISBLK(st.st_mode):
683 2be7273c Apollon Oikonomopoulos
      result = utils.RunCmd(["blockdev", "--getsize64", devpath])
684 2be7273c Apollon Oikonomopoulos
      if result.failed:
685 2be7273c Apollon Oikonomopoulos
        # We don't want to fail, just do not list this device as available
686 2be7273c Apollon Oikonomopoulos
        logging.warning("Cannot get size for block device %s", devpath)
687 2be7273c Apollon Oikonomopoulos
        continue
688 2be7273c Apollon Oikonomopoulos
689 2be7273c Apollon Oikonomopoulos
      size = int(result.stdout) / (1024 * 1024)
690 2be7273c Apollon Oikonomopoulos
      blockdevs[devpath] = size
691 2be7273c Apollon Oikonomopoulos
  return blockdevs
692 2be7273c Apollon Oikonomopoulos
693 2be7273c Apollon Oikonomopoulos
694 84d7e26b Dmitry Chernyak
def GetVolumeList(vg_names):
695 a8083063 Iustin Pop
  """Compute list of logical volumes and their size.
696 a8083063 Iustin Pop

697 84d7e26b Dmitry Chernyak
  @type vg_names: list
698 397693d3 Iustin Pop
  @param vg_names: the volume groups whose LVs we should list, or
699 397693d3 Iustin Pop
      empty for all volume groups
700 10c2650b Iustin Pop
  @rtype: dict
701 10c2650b Iustin Pop
  @return:
702 10c2650b Iustin Pop
      dictionary of all partions (key) with value being a tuple of
703 10c2650b Iustin Pop
      their size (in MiB), inactive and online status::
704 10c2650b Iustin Pop

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

707 10c2650b Iustin Pop
      in case of errors, a string is returned with the error
708 10c2650b Iustin Pop
      details.
709 a8083063 Iustin Pop

710 a8083063 Iustin Pop
  """
711 cb2037a2 Iustin Pop
  lvs = {}
712 d0c8c01d Iustin Pop
  sep = "|"
713 397693d3 Iustin Pop
  if not vg_names:
714 397693d3 Iustin Pop
    vg_names = []
715 cb2037a2 Iustin Pop
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
716 cb2037a2 Iustin Pop
                         "--separator=%s" % sep,
717 84d7e26b Dmitry Chernyak
                         "-ovg_name,lv_name,lv_size,lv_attr"] + vg_names)
718 a8083063 Iustin Pop
  if result.failed:
719 29d376ec Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s", result.output)
720 cb2037a2 Iustin Pop
721 cb2037a2 Iustin Pop
  for line in result.stdout.splitlines():
722 df4c2628 Iustin Pop
    line = line.strip()
723 0b5303da Iustin Pop
    match = _LVSLINE_REGEX.match(line)
724 df4c2628 Iustin Pop
    if not match:
725 18682bca Iustin Pop
      logging.error("Invalid line returned from lvs output: '%s'", line)
726 df4c2628 Iustin Pop
      continue
727 84d7e26b Dmitry Chernyak
    vg_name, name, size, attr = match.groups()
728 d0c8c01d Iustin Pop
    inactive = attr[4] == "-"
729 d0c8c01d Iustin Pop
    online = attr[5] == "o"
730 d0c8c01d Iustin Pop
    virtual = attr[0] == "v"
731 33f2a81a Iustin Pop
    if virtual:
732 33f2a81a Iustin Pop
      # we don't want to report such volumes as existing, since they
733 33f2a81a Iustin Pop
      # don't really hold data
734 33f2a81a Iustin Pop
      continue
735 e687ec01 Michael Hanselmann
    lvs[vg_name + "/" + name] = (size, inactive, online)
736 cb2037a2 Iustin Pop
737 cb2037a2 Iustin Pop
  return lvs
738 a8083063 Iustin Pop
739 a8083063 Iustin Pop
740 a8083063 Iustin Pop
def ListVolumeGroups():
741 2f8598a5 Alexander Schreiber
  """List the volume groups and their size.
742 a8083063 Iustin Pop

743 10c2650b Iustin Pop
  @rtype: dict
744 10c2650b Iustin Pop
  @return: dictionary with keys volume name and values the
745 10c2650b Iustin Pop
      size of the volume
746 a8083063 Iustin Pop

747 a8083063 Iustin Pop
  """
748 c26a6bd2 Iustin Pop
  return utils.ListVolumeGroups()
749 a8083063 Iustin Pop
750 a8083063 Iustin Pop
751 dcb93971 Michael Hanselmann
def NodeVolumes():
752 dcb93971 Michael Hanselmann
  """List all volumes on this node.
753 dcb93971 Michael Hanselmann

754 10c2650b Iustin Pop
  @rtype: list
755 10c2650b Iustin Pop
  @return:
756 10c2650b Iustin Pop
    A list of dictionaries, each having four keys:
757 10c2650b Iustin Pop
      - name: the logical volume name,
758 10c2650b Iustin Pop
      - size: the size of the logical volume
759 10c2650b Iustin Pop
      - dev: the physical device on which the LV lives
760 10c2650b Iustin Pop
      - vg: the volume group to which it belongs
761 10c2650b Iustin Pop

762 10c2650b Iustin Pop
    In case of errors, we return an empty list and log the
763 10c2650b Iustin Pop
    error.
764 10c2650b Iustin Pop

765 10c2650b Iustin Pop
    Note that since a logical volume can live on multiple physical
766 10c2650b Iustin Pop
    volumes, the resulting list might include a logical volume
767 10c2650b Iustin Pop
    multiple times.
768 10c2650b Iustin Pop

769 dcb93971 Michael Hanselmann
  """
770 dcb93971 Michael Hanselmann
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
771 dcb93971 Michael Hanselmann
                         "--separator=|",
772 dcb93971 Michael Hanselmann
                         "--options=lv_name,lv_size,devices,vg_name"])
773 dcb93971 Michael Hanselmann
  if result.failed:
774 10bfe6cb Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s",
775 10bfe6cb Iustin Pop
          result.output)
776 dcb93971 Michael Hanselmann
777 dcb93971 Michael Hanselmann
  def parse_dev(dev):
778 d0c8c01d Iustin Pop
    return dev.split("(")[0]
779 89e5ab02 Iustin Pop
780 89e5ab02 Iustin Pop
  def handle_dev(dev):
781 89e5ab02 Iustin Pop
    return [parse_dev(x) for x in dev.split(",")]
782 dcb93971 Michael Hanselmann
783 dcb93971 Michael Hanselmann
  def map_line(line):
784 89e5ab02 Iustin Pop
    line = [v.strip() for v in line]
785 d0c8c01d Iustin Pop
    return [{"name": line[0], "size": line[1],
786 d0c8c01d Iustin Pop
             "dev": dev, "vg": line[3]} for dev in handle_dev(line[2])]
787 89e5ab02 Iustin Pop
788 89e5ab02 Iustin Pop
  all_devs = []
789 89e5ab02 Iustin Pop
  for line in result.stdout.splitlines():
790 d0c8c01d Iustin Pop
    if line.count("|") >= 3:
791 d0c8c01d Iustin Pop
      all_devs.extend(map_line(line.split("|")))
792 89e5ab02 Iustin Pop
    else:
793 89e5ab02 Iustin Pop
      logging.warning("Strange line in the output from lvs: '%s'", line)
794 89e5ab02 Iustin Pop
  return all_devs
795 dcb93971 Michael Hanselmann
796 dcb93971 Michael Hanselmann
797 a8083063 Iustin Pop
def BridgesExist(bridges_list):
798 2f8598a5 Alexander Schreiber
  """Check if a list of bridges exist on the current node.
799 a8083063 Iustin Pop

800 b1206984 Iustin Pop
  @rtype: boolean
801 b1206984 Iustin Pop
  @return: C{True} if all of them exist, C{False} otherwise
802 a8083063 Iustin Pop

803 a8083063 Iustin Pop
  """
804 35c0c8da Iustin Pop
  missing = []
805 a8083063 Iustin Pop
  for bridge in bridges_list:
806 a8083063 Iustin Pop
    if not utils.BridgeExists(bridge):
807 35c0c8da Iustin Pop
      missing.append(bridge)
808 a8083063 Iustin Pop
809 35c0c8da Iustin Pop
  if missing:
810 1f864b60 Iustin Pop
    _Fail("Missing bridges %s", utils.CommaJoin(missing))
811 35c0c8da Iustin Pop
812 a8083063 Iustin Pop
813 e69d05fd Iustin Pop
def GetInstanceList(hypervisor_list):
814 2f8598a5 Alexander Schreiber
  """Provides a list of instances.
815 a8083063 Iustin Pop

816 e69d05fd Iustin Pop
  @type hypervisor_list: list
817 e69d05fd Iustin Pop
  @param hypervisor_list: the list of hypervisors to query information
818 e69d05fd Iustin Pop

819 e69d05fd Iustin Pop
  @rtype: list
820 e69d05fd Iustin Pop
  @return: a list of all running instances on the current node
821 10c2650b Iustin Pop
    - instance1.example.com
822 10c2650b Iustin Pop
    - instance2.example.com
823 a8083063 Iustin Pop

824 098c0958 Michael Hanselmann
  """
825 e69d05fd Iustin Pop
  results = []
826 e69d05fd Iustin Pop
  for hname in hypervisor_list:
827 e69d05fd Iustin Pop
    try:
828 e69d05fd Iustin Pop
      names = hypervisor.GetHypervisor(hname).ListInstances()
829 e69d05fd Iustin Pop
      results.extend(names)
830 e69d05fd Iustin Pop
    except errors.HypervisorError, err:
831 aca13712 Iustin Pop
      _Fail("Error enumerating instances (hypervisor %s): %s",
832 aca13712 Iustin Pop
            hname, err, exc=True)
833 a8083063 Iustin Pop
834 e69d05fd Iustin Pop
  return results
835 a8083063 Iustin Pop
836 a8083063 Iustin Pop
837 e69d05fd Iustin Pop
def GetInstanceInfo(instance, hname):
838 5bbd3f7f Michael Hanselmann
  """Gives back the information about an instance as a dictionary.
839 a8083063 Iustin Pop

840 e69d05fd Iustin Pop
  @type instance: string
841 e69d05fd Iustin Pop
  @param instance: the instance name
842 e69d05fd Iustin Pop
  @type hname: string
843 e69d05fd Iustin Pop
  @param hname: the hypervisor type of the instance
844 a8083063 Iustin Pop

845 e69d05fd Iustin Pop
  @rtype: dict
846 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
847 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
848 e69d05fd Iustin Pop
      - state: xen state of instance (string)
849 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
850 a8083063 Iustin Pop

851 098c0958 Michael Hanselmann
  """
852 a8083063 Iustin Pop
  output = {}
853 a8083063 Iustin Pop
854 e69d05fd Iustin Pop
  iinfo = hypervisor.GetHypervisor(hname).GetInstanceInfo(instance)
855 a8083063 Iustin Pop
  if iinfo is not None:
856 d0c8c01d Iustin Pop
    output["memory"] = iinfo[2]
857 d0c8c01d Iustin Pop
    output["state"] = iinfo[4]
858 d0c8c01d Iustin Pop
    output["time"] = iinfo[5]
859 a8083063 Iustin Pop
860 c26a6bd2 Iustin Pop
  return output
861 a8083063 Iustin Pop
862 a8083063 Iustin Pop
863 56e7640c Iustin Pop
def GetInstanceMigratable(instance):
864 56e7640c Iustin Pop
  """Gives whether an instance can be migrated.
865 56e7640c Iustin Pop

866 56e7640c Iustin Pop
  @type instance: L{objects.Instance}
867 56e7640c Iustin Pop
  @param instance: object representing the instance to be checked.
868 56e7640c Iustin Pop

869 56e7640c Iustin Pop
  @rtype: tuple
870 56e7640c Iustin Pop
  @return: tuple of (result, description) where:
871 56e7640c Iustin Pop
      - result: whether the instance can be migrated or not
872 56e7640c Iustin Pop
      - description: a description of the issue, if relevant
873 56e7640c Iustin Pop

874 56e7640c Iustin Pop
  """
875 56e7640c Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
876 afdc3985 Iustin Pop
  iname = instance.name
877 afdc3985 Iustin Pop
  if iname not in hyper.ListInstances():
878 afdc3985 Iustin Pop
    _Fail("Instance %s is not running", iname)
879 56e7640c Iustin Pop
880 56e7640c Iustin Pop
  for idx in range(len(instance.disks)):
881 afdc3985 Iustin Pop
    link_name = _GetBlockDevSymlinkPath(iname, idx)
882 56e7640c Iustin Pop
    if not os.path.islink(link_name):
883 b8ebd37b Iustin Pop
      logging.warning("Instance %s is missing symlink %s for disk %d",
884 b8ebd37b Iustin Pop
                      iname, link_name, idx)
885 56e7640c Iustin Pop
886 56e7640c Iustin Pop
887 e69d05fd Iustin Pop
def GetAllInstancesInfo(hypervisor_list):
888 a8083063 Iustin Pop
  """Gather data about all instances.
889 a8083063 Iustin Pop

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

894 e69d05fd Iustin Pop
  @type hypervisor_list: list
895 e69d05fd Iustin Pop
  @param hypervisor_list: list of hypervisors to query for instance data
896 e69d05fd Iustin Pop

897 955db481 Guido Trotter
  @rtype: dict
898 e69d05fd Iustin Pop
  @return: dictionary of instance: data, with data having the following keys:
899 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
900 e69d05fd Iustin Pop
      - state: xen state of instance (string)
901 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
902 10c2650b Iustin Pop
      - vcpus: the number of vcpus
903 a8083063 Iustin Pop

904 098c0958 Michael Hanselmann
  """
905 a8083063 Iustin Pop
  output = {}
906 a8083063 Iustin Pop
907 e69d05fd Iustin Pop
  for hname in hypervisor_list:
908 e69d05fd Iustin Pop
    iinfo = hypervisor.GetHypervisor(hname).GetAllInstancesInfo()
909 e69d05fd Iustin Pop
    if iinfo:
910 29921401 Iustin Pop
      for name, _, memory, vcpus, state, times in iinfo:
911 f23b5ae8 Iustin Pop
        value = {
912 d0c8c01d Iustin Pop
          "memory": memory,
913 d0c8c01d Iustin Pop
          "vcpus": vcpus,
914 d0c8c01d Iustin Pop
          "state": state,
915 d0c8c01d Iustin Pop
          "time": times,
916 e69d05fd Iustin Pop
          }
917 b33b6f55 Iustin Pop
        if name in output:
918 b33b6f55 Iustin Pop
          # we only check static parameters, like memory and vcpus,
919 b33b6f55 Iustin Pop
          # and not state and time which can change between the
920 b33b6f55 Iustin Pop
          # invocations of the different hypervisors
921 d0c8c01d Iustin Pop
          for key in "memory", "vcpus":
922 b33b6f55 Iustin Pop
            if value[key] != output[name][key]:
923 2fa74ef4 Iustin Pop
              _Fail("Instance %s is running twice"
924 2fa74ef4 Iustin Pop
                    " with different parameters", name)
925 f23b5ae8 Iustin Pop
        output[name] = value
926 a8083063 Iustin Pop
927 c26a6bd2 Iustin Pop
  return output
928 a8083063 Iustin Pop
929 a8083063 Iustin Pop
930 6aa7a354 Iustin Pop
def _InstanceLogName(kind, os_name, instance, component):
931 81a3406c Iustin Pop
  """Compute the OS log filename for a given instance and operation.
932 81a3406c Iustin Pop

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

936 81a3406c Iustin Pop
  @type kind: string
937 81a3406c Iustin Pop
  @param kind: the operation type (e.g. add, import, etc.)
938 81a3406c Iustin Pop
  @type os_name: string
939 81a3406c Iustin Pop
  @param os_name: the os name
940 81a3406c Iustin Pop
  @type instance: string
941 81a3406c Iustin Pop
  @param instance: the name of the instance being imported/added/etc.
942 6aa7a354 Iustin Pop
  @type component: string or None
943 6aa7a354 Iustin Pop
  @param component: the name of the component of the instance being
944 6aa7a354 Iustin Pop
      transferred
945 81a3406c Iustin Pop

946 81a3406c Iustin Pop
  """
947 1651d116 Michael Hanselmann
  # TODO: Use tempfile.mkstemp to create unique filename
948 6aa7a354 Iustin Pop
  if component:
949 6aa7a354 Iustin Pop
    assert "/" not in component
950 6aa7a354 Iustin Pop
    c_msg = "-%s" % component
951 6aa7a354 Iustin Pop
  else:
952 6aa7a354 Iustin Pop
    c_msg = ""
953 6aa7a354 Iustin Pop
  base = ("%s-%s-%s%s-%s.log" %
954 6aa7a354 Iustin Pop
          (kind, os_name, instance, c_msg, utils.TimestampForFilename()))
955 81a3406c Iustin Pop
  return utils.PathJoin(constants.LOG_OS_DIR, base)
956 81a3406c Iustin Pop
957 81a3406c Iustin Pop
958 4a0e011f Iustin Pop
def InstanceOsAdd(instance, reinstall, debug):
959 2f8598a5 Alexander Schreiber
  """Add an OS to an instance.
960 a8083063 Iustin Pop

961 d15a9ad3 Guido Trotter
  @type instance: L{objects.Instance}
962 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
963 e557bae9 Guido Trotter
  @type reinstall: boolean
964 e557bae9 Guido Trotter
  @param reinstall: whether this is an instance reinstall
965 4a0e011f Iustin Pop
  @type debug: integer
966 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
967 c26a6bd2 Iustin Pop
  @rtype: None
968 a8083063 Iustin Pop

969 a8083063 Iustin Pop
  """
970 255dcebd Iustin Pop
  inst_os = OSFromDisk(instance.os)
971 255dcebd Iustin Pop
972 4a0e011f Iustin Pop
  create_env = OSEnvironment(instance, inst_os, debug)
973 e557bae9 Guido Trotter
  if reinstall:
974 d0c8c01d Iustin Pop
    create_env["INSTANCE_REINSTALL"] = "1"
975 a8083063 Iustin Pop
976 6aa7a354 Iustin Pop
  logfile = _InstanceLogName("add", instance.os, instance.name, None)
977 decd5f45 Iustin Pop
978 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.create_script], env=create_env,
979 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
980 decd5f45 Iustin Pop
  if result.failed:
981 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s, logfile: %s,"
982 d868edb4 Iustin Pop
                  " output: %s", result.cmd, result.fail_reason, logfile,
983 18682bca Iustin Pop
                  result.output)
984 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
985 20e01edd Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
986 afdc3985 Iustin Pop
    _Fail("OS create script failed (%s), last lines in the"
987 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
988 decd5f45 Iustin Pop
989 decd5f45 Iustin Pop
990 4a0e011f Iustin Pop
def RunRenameInstance(instance, old_name, debug):
991 decd5f45 Iustin Pop
  """Run the OS rename script for an instance.
992 decd5f45 Iustin Pop

993 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
994 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
995 d15a9ad3 Guido Trotter
  @type old_name: string
996 d15a9ad3 Guido Trotter
  @param old_name: previous instance name
997 4a0e011f Iustin Pop
  @type debug: integer
998 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
999 10c2650b Iustin Pop
  @rtype: boolean
1000 10c2650b Iustin Pop
  @return: the success of the operation
1001 decd5f45 Iustin Pop

1002 decd5f45 Iustin Pop
  """
1003 decd5f45 Iustin Pop
  inst_os = OSFromDisk(instance.os)
1004 decd5f45 Iustin Pop
1005 4a0e011f Iustin Pop
  rename_env = OSEnvironment(instance, inst_os, debug)
1006 d0c8c01d Iustin Pop
  rename_env["OLD_INSTANCE_NAME"] = old_name
1007 decd5f45 Iustin Pop
1008 81a3406c Iustin Pop
  logfile = _InstanceLogName("rename", instance.os,
1009 6aa7a354 Iustin Pop
                             "%s-%s" % (old_name, instance.name), None)
1010 a8083063 Iustin Pop
1011 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.rename_script], env=rename_env,
1012 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1013 a8083063 Iustin Pop
1014 a8083063 Iustin Pop
  if result.failed:
1015 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s output: %s",
1016 d868edb4 Iustin Pop
                  result.cmd, result.fail_reason, result.output)
1017 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1018 96841384 Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1019 afdc3985 Iustin Pop
    _Fail("OS rename script failed (%s), last lines in the"
1020 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1021 a8083063 Iustin Pop
1022 a8083063 Iustin Pop
1023 5282084b Iustin Pop
def _GetBlockDevSymlinkPath(instance_name, idx):
1024 3536c792 Iustin Pop
  return utils.PathJoin(constants.DISK_LINKS_DIR, "%s%s%d" %
1025 3536c792 Iustin Pop
                        (instance_name, constants.DISK_SEPARATOR, idx))
1026 5282084b Iustin Pop
1027 5282084b Iustin Pop
1028 5282084b Iustin Pop
def _SymlinkBlockDev(instance_name, device_path, idx):
1029 9332fd8a Iustin Pop
  """Set up symlinks to a instance's block device.
1030 9332fd8a Iustin Pop

1031 9332fd8a Iustin Pop
  This is an auxiliary function run when an instance is start (on the primary
1032 9332fd8a Iustin Pop
  node) or when an instance is migrated (on the target node).
1033 9332fd8a Iustin Pop

1034 9332fd8a Iustin Pop

1035 5282084b Iustin Pop
  @param instance_name: the name of the target instance
1036 5282084b Iustin Pop
  @param device_path: path of the physical block device, on the node
1037 5282084b Iustin Pop
  @param idx: the disk index
1038 5282084b Iustin Pop
  @return: absolute path to the disk's symlink
1039 9332fd8a Iustin Pop

1040 9332fd8a Iustin Pop
  """
1041 5282084b Iustin Pop
  link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1042 9332fd8a Iustin Pop
  try:
1043 9332fd8a Iustin Pop
    os.symlink(device_path, link_name)
1044 5282084b Iustin Pop
  except OSError, err:
1045 5282084b Iustin Pop
    if err.errno == errno.EEXIST:
1046 9332fd8a Iustin Pop
      if (not os.path.islink(link_name) or
1047 9332fd8a Iustin Pop
          os.readlink(link_name) != device_path):
1048 9332fd8a Iustin Pop
        os.remove(link_name)
1049 9332fd8a Iustin Pop
        os.symlink(device_path, link_name)
1050 9332fd8a Iustin Pop
    else:
1051 9332fd8a Iustin Pop
      raise
1052 9332fd8a Iustin Pop
1053 9332fd8a Iustin Pop
  return link_name
1054 9332fd8a Iustin Pop
1055 9332fd8a Iustin Pop
1056 5282084b Iustin Pop
def _RemoveBlockDevLinks(instance_name, disks):
1057 3c9c571d Iustin Pop
  """Remove the block device symlinks belonging to the given instance.
1058 3c9c571d Iustin Pop

1059 3c9c571d Iustin Pop
  """
1060 29921401 Iustin Pop
  for idx, _ in enumerate(disks):
1061 5282084b Iustin Pop
    link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1062 5282084b Iustin Pop
    if os.path.islink(link_name):
1063 3c9c571d Iustin Pop
      try:
1064 03dfa658 Iustin Pop
        os.remove(link_name)
1065 03dfa658 Iustin Pop
      except OSError:
1066 03dfa658 Iustin Pop
        logging.exception("Can't remove symlink '%s'", link_name)
1067 3c9c571d Iustin Pop
1068 3c9c571d Iustin Pop
1069 9332fd8a Iustin Pop
def _GatherAndLinkBlockDevs(instance):
1070 a8083063 Iustin Pop
  """Set up an instance's block device(s).
1071 a8083063 Iustin Pop

1072 a8083063 Iustin Pop
  This is run on the primary node at instance startup. The block
1073 a8083063 Iustin Pop
  devices must be already assembled.
1074 a8083063 Iustin Pop

1075 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1076 10c2650b Iustin Pop
  @param instance: the instance whose disks we shoul assemble
1077 069cfbf1 Iustin Pop
  @rtype: list
1078 069cfbf1 Iustin Pop
  @return: list of (disk_object, device_path)
1079 10c2650b Iustin Pop

1080 a8083063 Iustin Pop
  """
1081 a8083063 Iustin Pop
  block_devices = []
1082 9332fd8a Iustin Pop
  for idx, disk in enumerate(instance.disks):
1083 a8083063 Iustin Pop
    device = _RecursiveFindBD(disk)
1084 a8083063 Iustin Pop
    if device is None:
1085 a8083063 Iustin Pop
      raise errors.BlockDeviceError("Block device '%s' is not set up." %
1086 a8083063 Iustin Pop
                                    str(disk))
1087 a8083063 Iustin Pop
    device.Open()
1088 9332fd8a Iustin Pop
    try:
1089 5282084b Iustin Pop
      link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
1090 9332fd8a Iustin Pop
    except OSError, e:
1091 9332fd8a Iustin Pop
      raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
1092 9332fd8a Iustin Pop
                                    e.strerror)
1093 9332fd8a Iustin Pop
1094 9332fd8a Iustin Pop
    block_devices.append((disk, link_name))
1095 9332fd8a Iustin Pop
1096 a8083063 Iustin Pop
  return block_devices
1097 a8083063 Iustin Pop
1098 a8083063 Iustin Pop
1099 323f9095 Stephen Shirley
def StartInstance(instance, startup_paused):
1100 a8083063 Iustin Pop
  """Start an instance.
1101 a8083063 Iustin Pop

1102 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1103 e69d05fd Iustin Pop
  @param instance: the instance object
1104 323f9095 Stephen Shirley
  @type startup_paused: bool
1105 323f9095 Stephen Shirley
  @param instance: pause instance at startup?
1106 c26a6bd2 Iustin Pop
  @rtype: None
1107 a8083063 Iustin Pop

1108 098c0958 Michael Hanselmann
  """
1109 e69d05fd Iustin Pop
  running_instances = GetInstanceList([instance.hypervisor])
1110 a8083063 Iustin Pop
1111 a8083063 Iustin Pop
  if instance.name in running_instances:
1112 c26a6bd2 Iustin Pop
    logging.info("Instance %s already running, not starting", instance.name)
1113 c26a6bd2 Iustin Pop
    return
1114 a8083063 Iustin Pop
1115 a8083063 Iustin Pop
  try:
1116 ec596c24 Iustin Pop
    block_devices = _GatherAndLinkBlockDevs(instance)
1117 ec596c24 Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
1118 323f9095 Stephen Shirley
    hyper.StartInstance(instance, block_devices, startup_paused)
1119 ec596c24 Iustin Pop
  except errors.BlockDeviceError, err:
1120 2cc6781a Iustin Pop
    _Fail("Block device error: %s", err, exc=True)
1121 a8083063 Iustin Pop
  except errors.HypervisorError, err:
1122 5282084b Iustin Pop
    _RemoveBlockDevLinks(instance.name, instance.disks)
1123 2cc6781a Iustin Pop
    _Fail("Hypervisor error: %s", err, exc=True)
1124 a8083063 Iustin Pop
1125 a8083063 Iustin Pop
1126 6263189c Guido Trotter
def InstanceShutdown(instance, timeout):
1127 a8083063 Iustin Pop
  """Shut an instance down.
1128 a8083063 Iustin Pop

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

1131 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1132 e69d05fd Iustin Pop
  @param instance: the instance object
1133 6263189c Guido Trotter
  @type timeout: integer
1134 6263189c Guido Trotter
  @param timeout: maximum timeout for soft shutdown
1135 c26a6bd2 Iustin Pop
  @rtype: None
1136 a8083063 Iustin Pop

1137 098c0958 Michael Hanselmann
  """
1138 e69d05fd Iustin Pop
  hv_name = instance.hypervisor
1139 e4e9b806 Guido Trotter
  hyper = hypervisor.GetHypervisor(hv_name)
1140 c26a6bd2 Iustin Pop
  iname = instance.name
1141 a8083063 Iustin Pop
1142 3c0cdc83 Michael Hanselmann
  if instance.name not in hyper.ListInstances():
1143 c26a6bd2 Iustin Pop
    logging.info("Instance %s not running, doing nothing", iname)
1144 c26a6bd2 Iustin Pop
    return
1145 a8083063 Iustin Pop
1146 3c0cdc83 Michael Hanselmann
  class _TryShutdown:
1147 3c0cdc83 Michael Hanselmann
    def __init__(self):
1148 3c0cdc83 Michael Hanselmann
      self.tried_once = False
1149 a8083063 Iustin Pop
1150 3c0cdc83 Michael Hanselmann
    def __call__(self):
1151 3c0cdc83 Michael Hanselmann
      if iname not in hyper.ListInstances():
1152 3c0cdc83 Michael Hanselmann
        return
1153 3c0cdc83 Michael Hanselmann
1154 3c0cdc83 Michael Hanselmann
      try:
1155 3c0cdc83 Michael Hanselmann
        hyper.StopInstance(instance, retry=self.tried_once)
1156 3c0cdc83 Michael Hanselmann
      except errors.HypervisorError, err:
1157 3c0cdc83 Michael Hanselmann
        if iname not in hyper.ListInstances():
1158 3c0cdc83 Michael Hanselmann
          # if the instance is no longer existing, consider this a
1159 3c0cdc83 Michael Hanselmann
          # success and go to cleanup
1160 3c0cdc83 Michael Hanselmann
          return
1161 3c0cdc83 Michael Hanselmann
1162 3c0cdc83 Michael Hanselmann
        _Fail("Failed to stop instance %s: %s", iname, err)
1163 3c0cdc83 Michael Hanselmann
1164 3c0cdc83 Michael Hanselmann
      self.tried_once = True
1165 3c0cdc83 Michael Hanselmann
1166 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
1167 3c0cdc83 Michael Hanselmann
1168 3c0cdc83 Michael Hanselmann
  try:
1169 3c0cdc83 Michael Hanselmann
    utils.Retry(_TryShutdown(), 5, timeout)
1170 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
1171 a8083063 Iustin Pop
    # the shutdown did not succeed
1172 e4e9b806 Guido Trotter
    logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
1173 a8083063 Iustin Pop
1174 a8083063 Iustin Pop
    try:
1175 a8083063 Iustin Pop
      hyper.StopInstance(instance, force=True)
1176 a8083063 Iustin Pop
    except errors.HypervisorError, err:
1177 3c0cdc83 Michael Hanselmann
      if iname in hyper.ListInstances():
1178 3782acd7 Iustin Pop
        # only raise an error if the instance still exists, otherwise
1179 3782acd7 Iustin Pop
        # the error could simply be "instance ... unknown"!
1180 3782acd7 Iustin Pop
        _Fail("Failed to force stop instance %s: %s", iname, err)
1181 a8083063 Iustin Pop
1182 a8083063 Iustin Pop
    time.sleep(1)
1183 3c0cdc83 Michael Hanselmann
1184 3c0cdc83 Michael Hanselmann
    if iname in hyper.ListInstances():
1185 c26a6bd2 Iustin Pop
      _Fail("Could not shutdown instance %s even by destroy", iname)
1186 3c9c571d Iustin Pop
1187 f28ec899 Guido Trotter
  try:
1188 f28ec899 Guido Trotter
    hyper.CleanupInstance(instance.name)
1189 f28ec899 Guido Trotter
  except errors.HypervisorError, err:
1190 f28ec899 Guido Trotter
    logging.warning("Failed to execute post-shutdown cleanup step: %s", err)
1191 f28ec899 Guido Trotter
1192 c26a6bd2 Iustin Pop
  _RemoveBlockDevLinks(iname, instance.disks)
1193 a8083063 Iustin Pop
1194 a8083063 Iustin Pop
1195 17c3f802 Guido Trotter
def InstanceReboot(instance, reboot_type, shutdown_timeout):
1196 007a2f3e Alexander Schreiber
  """Reboot an instance.
1197 007a2f3e Alexander Schreiber

1198 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1199 10c2650b Iustin Pop
  @param instance: the instance object to reboot
1200 10c2650b Iustin Pop
  @type reboot_type: str
1201 10c2650b Iustin Pop
  @param reboot_type: the type of reboot, one the following
1202 10c2650b Iustin Pop
    constants:
1203 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_SOFT}: only reboot the
1204 10c2650b Iustin Pop
        instance OS, do not recreate the VM
1205 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_HARD}: tear down and
1206 10c2650b Iustin Pop
        restart the VM (at the hypervisor level)
1207 73e5a4f4 Iustin Pop
      - the other reboot type (L{constants.INSTANCE_REBOOT_FULL}) is
1208 73e5a4f4 Iustin Pop
        not accepted here, since that mode is handled differently, in
1209 73e5a4f4 Iustin Pop
        cmdlib, and translates into full stop and start of the
1210 73e5a4f4 Iustin Pop
        instance (instead of a call_instance_reboot RPC)
1211 23057d29 Michael Hanselmann
  @type shutdown_timeout: integer
1212 23057d29 Michael Hanselmann
  @param shutdown_timeout: maximum timeout for soft shutdown
1213 c26a6bd2 Iustin Pop
  @rtype: None
1214 007a2f3e Alexander Schreiber

1215 007a2f3e Alexander Schreiber
  """
1216 e69d05fd Iustin Pop
  running_instances = GetInstanceList([instance.hypervisor])
1217 007a2f3e Alexander Schreiber
1218 007a2f3e Alexander Schreiber
  if instance.name not in running_instances:
1219 2cc6781a Iustin Pop
    _Fail("Cannot reboot instance %s that is not running", instance.name)
1220 007a2f3e Alexander Schreiber
1221 e69d05fd Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1222 007a2f3e Alexander Schreiber
  if reboot_type == constants.INSTANCE_REBOOT_SOFT:
1223 007a2f3e Alexander Schreiber
    try:
1224 007a2f3e Alexander Schreiber
      hyper.RebootInstance(instance)
1225 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1226 2cc6781a Iustin Pop
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1227 007a2f3e Alexander Schreiber
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1228 007a2f3e Alexander Schreiber
    try:
1229 17c3f802 Guido Trotter
      InstanceShutdown(instance, shutdown_timeout)
1230 82bc21e2 Stephen Shirley
      return StartInstance(instance, False)
1231 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1232 2cc6781a Iustin Pop
      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
1233 007a2f3e Alexander Schreiber
  else:
1234 2cc6781a Iustin Pop
    _Fail("Invalid reboot_type received: %s", reboot_type)
1235 007a2f3e Alexander Schreiber
1236 007a2f3e Alexander Schreiber
1237 6906a9d8 Guido Trotter
def MigrationInfo(instance):
1238 6906a9d8 Guido Trotter
  """Gather information about an instance to be migrated.
1239 6906a9d8 Guido Trotter

1240 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1241 6906a9d8 Guido Trotter
  @param instance: the instance definition
1242 6906a9d8 Guido Trotter

1243 6906a9d8 Guido Trotter
  """
1244 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1245 cd42d0ad Guido Trotter
  try:
1246 cd42d0ad Guido Trotter
    info = hyper.MigrationInfo(instance)
1247 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1248 2cc6781a Iustin Pop
    _Fail("Failed to fetch migration information: %s", err, exc=True)
1249 c26a6bd2 Iustin Pop
  return info
1250 6906a9d8 Guido Trotter
1251 6906a9d8 Guido Trotter
1252 6906a9d8 Guido Trotter
def AcceptInstance(instance, info, target):
1253 6906a9d8 Guido Trotter
  """Prepare the node to accept an instance.
1254 6906a9d8 Guido Trotter

1255 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1256 6906a9d8 Guido Trotter
  @param instance: the instance definition
1257 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
1258 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
1259 6906a9d8 Guido Trotter
  @type target: string
1260 6906a9d8 Guido Trotter
  @param target: target host (usually ip), on this node
1261 6906a9d8 Guido Trotter

1262 6906a9d8 Guido Trotter
  """
1263 77fcff4a Apollon Oikonomopoulos
  # TODO: why is this required only for DTS_EXT_MIRROR?
1264 77fcff4a Apollon Oikonomopoulos
  if instance.disk_template in constants.DTS_EXT_MIRROR:
1265 77fcff4a Apollon Oikonomopoulos
    # Create the symlinks, as the disks are not active
1266 77fcff4a Apollon Oikonomopoulos
    # in any way
1267 77fcff4a Apollon Oikonomopoulos
    try:
1268 77fcff4a Apollon Oikonomopoulos
      _GatherAndLinkBlockDevs(instance)
1269 77fcff4a Apollon Oikonomopoulos
    except errors.BlockDeviceError, err:
1270 77fcff4a Apollon Oikonomopoulos
      _Fail("Block device error: %s", err, exc=True)
1271 77fcff4a Apollon Oikonomopoulos
1272 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1273 cd42d0ad Guido Trotter
  try:
1274 cd42d0ad Guido Trotter
    hyper.AcceptInstance(instance, info, target)
1275 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1276 77fcff4a Apollon Oikonomopoulos
    if instance.disk_template in constants.DTS_EXT_MIRROR:
1277 77fcff4a Apollon Oikonomopoulos
      _RemoveBlockDevLinks(instance.name, instance.disks)
1278 2cc6781a Iustin Pop
    _Fail("Failed to accept instance: %s", err, exc=True)
1279 6906a9d8 Guido Trotter
1280 6906a9d8 Guido Trotter
1281 6906a9d8 Guido Trotter
def FinalizeMigration(instance, info, success):
1282 6906a9d8 Guido Trotter
  """Finalize any preparation to accept an instance.
1283 6906a9d8 Guido Trotter

1284 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1285 6906a9d8 Guido Trotter
  @param instance: the instance definition
1286 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
1287 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
1288 6906a9d8 Guido Trotter
  @type success: boolean
1289 6906a9d8 Guido Trotter
  @param success: whether the migration was a success or a failure
1290 6906a9d8 Guido Trotter

1291 6906a9d8 Guido Trotter
  """
1292 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1293 cd42d0ad Guido Trotter
  try:
1294 cd42d0ad Guido Trotter
    hyper.FinalizeMigration(instance, info, success)
1295 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1296 2cc6781a Iustin Pop
    _Fail("Failed to finalize migration: %s", err, exc=True)
1297 6906a9d8 Guido Trotter
1298 6906a9d8 Guido Trotter
1299 2a10865c Iustin Pop
def MigrateInstance(instance, target, live):
1300 2a10865c Iustin Pop
  """Migrates an instance to another node.
1301 2a10865c Iustin Pop

1302 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1303 9f0e6b37 Iustin Pop
  @param instance: the instance definition
1304 9f0e6b37 Iustin Pop
  @type target: string
1305 9f0e6b37 Iustin Pop
  @param target: the target node name
1306 9f0e6b37 Iustin Pop
  @type live: boolean
1307 9f0e6b37 Iustin Pop
  @param live: whether the migration should be done live or not (the
1308 9f0e6b37 Iustin Pop
      interpretation of this parameter is left to the hypervisor)
1309 9f0e6b37 Iustin Pop
  @rtype: tuple
1310 9f0e6b37 Iustin Pop
  @return: a tuple of (success, msg) where:
1311 9f0e6b37 Iustin Pop
      - succes is a boolean denoting the success/failure of the operation
1312 9f0e6b37 Iustin Pop
      - msg is a string with details in case of failure
1313 9f0e6b37 Iustin Pop

1314 2a10865c Iustin Pop
  """
1315 53c776b5 Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1316 2a10865c Iustin Pop
1317 2a10865c Iustin Pop
  try:
1318 58d38b02 Iustin Pop
    hyper.MigrateInstance(instance, target, live)
1319 2a10865c Iustin Pop
  except errors.HypervisorError, err:
1320 2cc6781a Iustin Pop
    _Fail("Failed to migrate instance: %s", err, exc=True)
1321 2a10865c Iustin Pop
1322 2a10865c Iustin Pop
1323 821d1bd1 Iustin Pop
def BlockdevCreate(disk, size, owner, on_primary, info):
1324 a8083063 Iustin Pop
  """Creates a block device for an instance.
1325 a8083063 Iustin Pop

1326 b1206984 Iustin Pop
  @type disk: L{objects.Disk}
1327 b1206984 Iustin Pop
  @param disk: the object describing the disk we should create
1328 b1206984 Iustin Pop
  @type size: int
1329 b1206984 Iustin Pop
  @param size: the size of the physical underlying device, in MiB
1330 b1206984 Iustin Pop
  @type owner: str
1331 b1206984 Iustin Pop
  @param owner: the name of the instance for which disk is created,
1332 b1206984 Iustin Pop
      used for device cache data
1333 b1206984 Iustin Pop
  @type on_primary: boolean
1334 b1206984 Iustin Pop
  @param on_primary:  indicates if it is the primary node or not
1335 b1206984 Iustin Pop
  @type info: string
1336 b1206984 Iustin Pop
  @param info: string that will be sent to the physical device
1337 b1206984 Iustin Pop
      creation, used for example to set (LVM) tags on LVs
1338 b1206984 Iustin Pop

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

1343 a8083063 Iustin Pop
  """
1344 d0c8c01d Iustin Pop
  # TODO: remove the obsolete "size" argument
1345 b459a848 Andrea Spadaccini
  # pylint: disable=W0613
1346 a8083063 Iustin Pop
  clist = []
1347 a8083063 Iustin Pop
  if disk.children:
1348 a8083063 Iustin Pop
    for child in disk.children:
1349 1063abd1 Iustin Pop
      try:
1350 1063abd1 Iustin Pop
        crdev = _RecursiveAssembleBD(child, owner, on_primary)
1351 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
1352 2cc6781a Iustin Pop
        _Fail("Can't assemble device %s: %s", child, err)
1353 a8083063 Iustin Pop
      if on_primary or disk.AssembleOnSecondary():
1354 a8083063 Iustin Pop
        # we need the children open in case the device itself has to
1355 a8083063 Iustin Pop
        # be assembled
1356 1063abd1 Iustin Pop
        try:
1357 b459a848 Andrea Spadaccini
          # pylint: disable=E1103
1358 1063abd1 Iustin Pop
          crdev.Open()
1359 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
1360 2cc6781a Iustin Pop
          _Fail("Can't make child '%s' read-write: %s", child, err)
1361 a8083063 Iustin Pop
      clist.append(crdev)
1362 a8083063 Iustin Pop
1363 dab69e97 Iustin Pop
  try:
1364 464f8daf Iustin Pop
    device = bdev.Create(disk.dev_type, disk.physical_id, clist, disk.size)
1365 1063abd1 Iustin Pop
  except errors.BlockDeviceError, err:
1366 2cc6781a Iustin Pop
    _Fail("Can't create block device: %s", err)
1367 6c626518 Iustin Pop
1368 a8083063 Iustin Pop
  if on_primary or disk.AssembleOnSecondary():
1369 1063abd1 Iustin Pop
    try:
1370 1063abd1 Iustin Pop
      device.Assemble()
1371 1063abd1 Iustin Pop
    except errors.BlockDeviceError, err:
1372 2cc6781a Iustin Pop
      _Fail("Can't assemble device after creation, unusual event: %s", err)
1373 e31c43f7 Michael Hanselmann
    device.SetSyncSpeed(constants.SYNC_SPEED)
1374 a8083063 Iustin Pop
    if on_primary or disk.OpenOnSecondary():
1375 1063abd1 Iustin Pop
      try:
1376 1063abd1 Iustin Pop
        device.Open(force=True)
1377 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
1378 2cc6781a Iustin Pop
        _Fail("Can't make device r/w after creation, unusual event: %s", err)
1379 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(device.dev_path, owner,
1380 3f78eef2 Iustin Pop
                                on_primary, disk.iv_name)
1381 a0c3fea1 Michael Hanselmann
1382 a0c3fea1 Michael Hanselmann
  device.SetInfo(info)
1383 a0c3fea1 Michael Hanselmann
1384 c26a6bd2 Iustin Pop
  return device.unique_id
1385 a8083063 Iustin Pop
1386 a8083063 Iustin Pop
1387 da63bb4e René Nussbaumer
def _WipeDevice(path, offset, size):
1388 69dd363f René Nussbaumer
  """This function actually wipes the device.
1389 69dd363f René Nussbaumer

1390 69dd363f René Nussbaumer
  @param path: The path to the device to wipe
1391 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
1392 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
1393 69dd363f René Nussbaumer

1394 69dd363f René Nussbaumer
  """
1395 da63bb4e René Nussbaumer
  cmd = [constants.DD_CMD, "if=/dev/zero", "seek=%d" % offset,
1396 da63bb4e René Nussbaumer
         "bs=%d" % constants.WIPE_BLOCK_SIZE, "oflag=direct", "of=%s" % path,
1397 da63bb4e René Nussbaumer
         "count=%d" % size]
1398 da63bb4e René Nussbaumer
  result = utils.RunCmd(cmd)
1399 69dd363f René Nussbaumer
1400 69dd363f René Nussbaumer
  if result.failed:
1401 69dd363f René Nussbaumer
    _Fail("Wipe command '%s' exited with error: %s; output: %s", result.cmd,
1402 69dd363f René Nussbaumer
          result.fail_reason, result.output)
1403 69dd363f René Nussbaumer
1404 69dd363f René Nussbaumer
1405 da63bb4e René Nussbaumer
def BlockdevWipe(disk, offset, size):
1406 69dd363f René Nussbaumer
  """Wipes a block device.
1407 69dd363f René Nussbaumer

1408 69dd363f René Nussbaumer
  @type disk: L{objects.Disk}
1409 69dd363f René Nussbaumer
  @param disk: the disk object we want to wipe
1410 da63bb4e René Nussbaumer
  @type offset: int
1411 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
1412 da63bb4e René Nussbaumer
  @type size: int
1413 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
1414 69dd363f René Nussbaumer

1415 69dd363f René Nussbaumer
  """
1416 69dd363f René Nussbaumer
  try:
1417 69dd363f René Nussbaumer
    rdev = _RecursiveFindBD(disk)
1418 da63bb4e René Nussbaumer
  except errors.BlockDeviceError:
1419 da63bb4e René Nussbaumer
    rdev = None
1420 da63bb4e René Nussbaumer
1421 da63bb4e René Nussbaumer
  if not rdev:
1422 da63bb4e René Nussbaumer
    _Fail("Cannot execute wipe for device %s: device not found", disk.iv_name)
1423 da63bb4e René Nussbaumer
1424 da63bb4e René Nussbaumer
  # Do cross verify some of the parameters
1425 da63bb4e René Nussbaumer
  if offset > rdev.size:
1426 da63bb4e René Nussbaumer
    _Fail("Offset is bigger than device size")
1427 da63bb4e René Nussbaumer
  if (offset + size) > rdev.size:
1428 da63bb4e René Nussbaumer
    _Fail("The provided offset and size to wipe is bigger than device size")
1429 69dd363f René Nussbaumer
1430 da63bb4e René Nussbaumer
  _WipeDevice(rdev.dev_path, offset, size)
1431 69dd363f René Nussbaumer
1432 69dd363f René Nussbaumer
1433 5119c79e René Nussbaumer
def BlockdevPauseResumeSync(disks, pause):
1434 5119c79e René Nussbaumer
  """Pause or resume the sync of the block device.
1435 5119c79e René Nussbaumer

1436 0f39886a René Nussbaumer
  @type disks: list of L{objects.Disk}
1437 0f39886a René Nussbaumer
  @param disks: the disks object we want to pause/resume
1438 5119c79e René Nussbaumer
  @type pause: bool
1439 5119c79e René Nussbaumer
  @param pause: Wheater to pause or resume
1440 5119c79e René Nussbaumer

1441 5119c79e René Nussbaumer
  """
1442 5119c79e René Nussbaumer
  success = []
1443 5119c79e René Nussbaumer
  for disk in disks:
1444 5119c79e René Nussbaumer
    try:
1445 5119c79e René Nussbaumer
      rdev = _RecursiveFindBD(disk)
1446 5119c79e René Nussbaumer
    except errors.BlockDeviceError:
1447 5119c79e René Nussbaumer
      rdev = None
1448 5119c79e René Nussbaumer
1449 5119c79e René Nussbaumer
    if not rdev:
1450 5119c79e René Nussbaumer
      success.append((False, ("Cannot change sync for device %s:"
1451 5119c79e René Nussbaumer
                              " device not found" % disk.iv_name)))
1452 5119c79e René Nussbaumer
      continue
1453 5119c79e René Nussbaumer
1454 5119c79e René Nussbaumer
    result = rdev.PauseResumeSync(pause)
1455 5119c79e René Nussbaumer
1456 5119c79e René Nussbaumer
    if result:
1457 5119c79e René Nussbaumer
      success.append((result, None))
1458 5119c79e René Nussbaumer
    else:
1459 5119c79e René Nussbaumer
      if pause:
1460 5119c79e René Nussbaumer
        msg = "Pause"
1461 5119c79e René Nussbaumer
      else:
1462 5119c79e René Nussbaumer
        msg = "Resume"
1463 5119c79e René Nussbaumer
      success.append((result, "%s for device %s failed" % (msg, disk.iv_name)))
1464 5119c79e René Nussbaumer
1465 5119c79e René Nussbaumer
  return success
1466 5119c79e René Nussbaumer
1467 5119c79e René Nussbaumer
1468 821d1bd1 Iustin Pop
def BlockdevRemove(disk):
1469 a8083063 Iustin Pop
  """Remove a block device.
1470 a8083063 Iustin Pop

1471 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
1472 10c2650b Iustin Pop

1473 c41eea6e Iustin Pop
  @type disk: L{objects.Disk}
1474 10c2650b Iustin Pop
  @param disk: the disk object we should remove
1475 10c2650b Iustin Pop
  @rtype: boolean
1476 10c2650b Iustin Pop
  @return: the success of the operation
1477 a8083063 Iustin Pop

1478 a8083063 Iustin Pop
  """
1479 e1bc0878 Iustin Pop
  msgs = []
1480 a8083063 Iustin Pop
  try:
1481 bca2e7f4 Iustin Pop
    rdev = _RecursiveFindBD(disk)
1482 a8083063 Iustin Pop
  except errors.BlockDeviceError, err:
1483 a8083063 Iustin Pop
    # probably can't attach
1484 18682bca Iustin Pop
    logging.info("Can't attach to device %s in remove", disk)
1485 a8083063 Iustin Pop
    rdev = None
1486 a8083063 Iustin Pop
  if rdev is not None:
1487 3f78eef2 Iustin Pop
    r_path = rdev.dev_path
1488 e1bc0878 Iustin Pop
    try:
1489 0c6c04ec Iustin Pop
      rdev.Remove()
1490 e1bc0878 Iustin Pop
    except errors.BlockDeviceError, err:
1491 e1bc0878 Iustin Pop
      msgs.append(str(err))
1492 c26a6bd2 Iustin Pop
    if not msgs:
1493 3f78eef2 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
1494 e1bc0878 Iustin Pop
1495 a8083063 Iustin Pop
  if disk.children:
1496 a8083063 Iustin Pop
    for child in disk.children:
1497 c26a6bd2 Iustin Pop
      try:
1498 c26a6bd2 Iustin Pop
        BlockdevRemove(child)
1499 c26a6bd2 Iustin Pop
      except RPCFail, err:
1500 c26a6bd2 Iustin Pop
        msgs.append(str(err))
1501 e1bc0878 Iustin Pop
1502 c26a6bd2 Iustin Pop
  if msgs:
1503 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
1504 afdc3985 Iustin Pop
1505 a8083063 Iustin Pop
1506 3f78eef2 Iustin Pop
def _RecursiveAssembleBD(disk, owner, as_primary):
1507 a8083063 Iustin Pop
  """Activate a block device for an instance.
1508 a8083063 Iustin Pop

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

1511 10c2650b Iustin Pop
  @note: this function is called recursively.
1512 a8083063 Iustin Pop

1513 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1514 10c2650b Iustin Pop
  @param disk: the disk we try to assemble
1515 10c2650b Iustin Pop
  @type owner: str
1516 10c2650b Iustin Pop
  @param owner: the name of the instance which owns the disk
1517 10c2650b Iustin Pop
  @type as_primary: boolean
1518 10c2650b Iustin Pop
  @param as_primary: if we should make the block device
1519 10c2650b Iustin Pop
      read/write
1520 a8083063 Iustin Pop

1521 10c2650b Iustin Pop
  @return: the assembled device or None (in case no device
1522 10c2650b Iustin Pop
      was assembled)
1523 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: in case there is an error
1524 10c2650b Iustin Pop
      during the activation of the children or the device
1525 10c2650b Iustin Pop
      itself
1526 a8083063 Iustin Pop

1527 a8083063 Iustin Pop
  """
1528 a8083063 Iustin Pop
  children = []
1529 a8083063 Iustin Pop
  if disk.children:
1530 fc1dc9d7 Iustin Pop
    mcn = disk.ChildrenNeeded()
1531 fc1dc9d7 Iustin Pop
    if mcn == -1:
1532 fc1dc9d7 Iustin Pop
      mcn = 0 # max number of Nones allowed
1533 fc1dc9d7 Iustin Pop
    else:
1534 fc1dc9d7 Iustin Pop
      mcn = len(disk.children) - mcn # max number of Nones
1535 a8083063 Iustin Pop
    for chld_disk in disk.children:
1536 fc1dc9d7 Iustin Pop
      try:
1537 fc1dc9d7 Iustin Pop
        cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary)
1538 fc1dc9d7 Iustin Pop
      except errors.BlockDeviceError, err:
1539 7803d4d3 Iustin Pop
        if children.count(None) >= mcn:
1540 fc1dc9d7 Iustin Pop
          raise
1541 fc1dc9d7 Iustin Pop
        cdev = None
1542 1063abd1 Iustin Pop
        logging.error("Error in child activation (but continuing): %s",
1543 1063abd1 Iustin Pop
                      str(err))
1544 fc1dc9d7 Iustin Pop
      children.append(cdev)
1545 a8083063 Iustin Pop
1546 a8083063 Iustin Pop
  if as_primary or disk.AssembleOnSecondary():
1547 464f8daf Iustin Pop
    r_dev = bdev.Assemble(disk.dev_type, disk.physical_id, children, disk.size)
1548 e31c43f7 Michael Hanselmann
    r_dev.SetSyncSpeed(constants.SYNC_SPEED)
1549 a8083063 Iustin Pop
    result = r_dev
1550 a8083063 Iustin Pop
    if as_primary or disk.OpenOnSecondary():
1551 a8083063 Iustin Pop
      r_dev.Open()
1552 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(r_dev.dev_path, owner,
1553 3f78eef2 Iustin Pop
                                as_primary, disk.iv_name)
1554 3f78eef2 Iustin Pop
1555 a8083063 Iustin Pop
  else:
1556 a8083063 Iustin Pop
    result = True
1557 a8083063 Iustin Pop
  return result
1558 a8083063 Iustin Pop
1559 a8083063 Iustin Pop
1560 c417e115 Iustin Pop
def BlockdevAssemble(disk, owner, as_primary, idx):
1561 a8083063 Iustin Pop
  """Activate a block device for an instance.
1562 a8083063 Iustin Pop

1563 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
1564 a8083063 Iustin Pop

1565 b1206984 Iustin Pop
  @rtype: str or boolean
1566 b1206984 Iustin Pop
  @return: a C{/dev/...} path for primary nodes, and
1567 b1206984 Iustin Pop
      C{True} for secondary nodes
1568 a8083063 Iustin Pop

1569 a8083063 Iustin Pop
  """
1570 53c14ef1 Iustin Pop
  try:
1571 53c14ef1 Iustin Pop
    result = _RecursiveAssembleBD(disk, owner, as_primary)
1572 53c14ef1 Iustin Pop
    if isinstance(result, bdev.BlockDev):
1573 b459a848 Andrea Spadaccini
      # pylint: disable=E1103
1574 53c14ef1 Iustin Pop
      result = result.dev_path
1575 c417e115 Iustin Pop
      if as_primary:
1576 c417e115 Iustin Pop
        _SymlinkBlockDev(owner, result, idx)
1577 53c14ef1 Iustin Pop
  except errors.BlockDeviceError, err:
1578 afdc3985 Iustin Pop
    _Fail("Error while assembling disk: %s", err, exc=True)
1579 c417e115 Iustin Pop
  except OSError, err:
1580 c417e115 Iustin Pop
    _Fail("Error while symlinking disk: %s", err, exc=True)
1581 afdc3985 Iustin Pop
1582 c26a6bd2 Iustin Pop
  return result
1583 a8083063 Iustin Pop
1584 a8083063 Iustin Pop
1585 821d1bd1 Iustin Pop
def BlockdevShutdown(disk):
1586 a8083063 Iustin Pop
  """Shut down a block device.
1587 a8083063 Iustin Pop

1588 5bbd3f7f Michael Hanselmann
  First, if the device is assembled (Attach() is successful), then
1589 c41eea6e Iustin Pop
  the device is shutdown. Then the children of the device are
1590 c41eea6e Iustin Pop
  shutdown.
1591 a8083063 Iustin Pop

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

1596 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1597 10c2650b Iustin Pop
  @param disk: the description of the disk we should
1598 10c2650b Iustin Pop
      shutdown
1599 c26a6bd2 Iustin Pop
  @rtype: None
1600 10c2650b Iustin Pop

1601 a8083063 Iustin Pop
  """
1602 cacfd1fd Iustin Pop
  msgs = []
1603 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
1604 a8083063 Iustin Pop
  if r_dev is not None:
1605 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
1606 cacfd1fd Iustin Pop
    try:
1607 746f7476 Iustin Pop
      r_dev.Shutdown()
1608 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
1609 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
1610 cacfd1fd Iustin Pop
      msgs.append(str(err))
1611 746f7476 Iustin Pop
1612 a8083063 Iustin Pop
  if disk.children:
1613 a8083063 Iustin Pop
    for child in disk.children:
1614 c26a6bd2 Iustin Pop
      try:
1615 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
1616 c26a6bd2 Iustin Pop
      except RPCFail, err:
1617 c26a6bd2 Iustin Pop
        msgs.append(str(err))
1618 746f7476 Iustin Pop
1619 c26a6bd2 Iustin Pop
  if msgs:
1620 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
1621 a8083063 Iustin Pop
1622 a8083063 Iustin Pop
1623 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
1624 153d9724 Iustin Pop
  """Extend a mirrored block device.
1625 a8083063 Iustin Pop

1626 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
1627 10c2650b Iustin Pop
  @param parent_cdev: the disk to which we should add children
1628 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
1629 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should add
1630 c26a6bd2 Iustin Pop
  @rtype: None
1631 10c2650b Iustin Pop

1632 a8083063 Iustin Pop
  """
1633 bca2e7f4 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
1634 153d9724 Iustin Pop
  if parent_bdev is None:
1635 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in add children", parent_cdev)
1636 153d9724 Iustin Pop
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
1637 153d9724 Iustin Pop
  if new_bdevs.count(None) > 0:
1638 2cc6781a Iustin Pop
    _Fail("Can't find new device(s) to add: %s:%s", new_bdevs, new_cdevs)
1639 153d9724 Iustin Pop
  parent_bdev.AddChildren(new_bdevs)
1640 a8083063 Iustin Pop
1641 a8083063 Iustin Pop
1642 821d1bd1 Iustin Pop
def BlockdevRemovechildren(parent_cdev, new_cdevs):
1643 153d9724 Iustin Pop
  """Shrink a mirrored block device.
1644 a8083063 Iustin Pop

1645 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
1646 10c2650b Iustin Pop
  @param parent_cdev: the disk from which we should remove children
1647 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
1648 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should remove
1649 c26a6bd2 Iustin Pop
  @rtype: None
1650 10c2650b Iustin Pop

1651 a8083063 Iustin Pop
  """
1652 153d9724 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
1653 153d9724 Iustin Pop
  if parent_bdev is None:
1654 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in remove children", parent_cdev)
1655 e739bd57 Iustin Pop
  devs = []
1656 e739bd57 Iustin Pop
  for disk in new_cdevs:
1657 e739bd57 Iustin Pop
    rpath = disk.StaticDevPath()
1658 e739bd57 Iustin Pop
    if rpath is None:
1659 e739bd57 Iustin Pop
      bd = _RecursiveFindBD(disk)
1660 e739bd57 Iustin Pop
      if bd is None:
1661 2cc6781a Iustin Pop
        _Fail("Can't find device %s while removing children", disk)
1662 e739bd57 Iustin Pop
      else:
1663 e739bd57 Iustin Pop
        devs.append(bd.dev_path)
1664 e739bd57 Iustin Pop
    else:
1665 e51db2a6 Iustin Pop
      if not utils.IsNormAbsPath(rpath):
1666 e51db2a6 Iustin Pop
        _Fail("Strange path returned from StaticDevPath: '%s'", rpath)
1667 e739bd57 Iustin Pop
      devs.append(rpath)
1668 e739bd57 Iustin Pop
  parent_bdev.RemoveChildren(devs)
1669 a8083063 Iustin Pop
1670 a8083063 Iustin Pop
1671 821d1bd1 Iustin Pop
def BlockdevGetmirrorstatus(disks):
1672 a8083063 Iustin Pop
  """Get the mirroring status of a list of devices.
1673 a8083063 Iustin Pop

1674 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
1675 10c2650b Iustin Pop
  @param disks: the list of disks which we should query
1676 10c2650b Iustin Pop
  @rtype: disk
1677 c6a9dffa Michael Hanselmann
  @return: List of L{objects.BlockDevStatus}, one for each disk
1678 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if any of the disks cannot be
1679 10c2650b Iustin Pop
      found
1680 a8083063 Iustin Pop

1681 a8083063 Iustin Pop
  """
1682 a8083063 Iustin Pop
  stats = []
1683 a8083063 Iustin Pop
  for dsk in disks:
1684 a8083063 Iustin Pop
    rbd = _RecursiveFindBD(dsk)
1685 a8083063 Iustin Pop
    if rbd is None:
1686 3efa9051 Iustin Pop
      _Fail("Can't find device %s", dsk)
1687 96acbc09 Michael Hanselmann
1688 36145b12 Michael Hanselmann
    stats.append(rbd.CombinedSyncStatus())
1689 96acbc09 Michael Hanselmann
1690 c26a6bd2 Iustin Pop
  return stats
1691 a8083063 Iustin Pop
1692 a8083063 Iustin Pop
1693 c6a9dffa Michael Hanselmann
def BlockdevGetmirrorstatusMulti(disks):
1694 c6a9dffa Michael Hanselmann
  """Get the mirroring status of a list of devices.
1695 c6a9dffa Michael Hanselmann

1696 c6a9dffa Michael Hanselmann
  @type disks: list of L{objects.Disk}
1697 c6a9dffa Michael Hanselmann
  @param disks: the list of disks which we should query
1698 c6a9dffa Michael Hanselmann
  @rtype: disk
1699 c6a9dffa Michael Hanselmann
  @return: List of tuples, (bool, status), one for each disk; bool denotes
1700 c6a9dffa Michael Hanselmann
    success/failure, status is L{objects.BlockDevStatus} on success, string
1701 c6a9dffa Michael Hanselmann
    otherwise
1702 c6a9dffa Michael Hanselmann

1703 c6a9dffa Michael Hanselmann
  """
1704 c6a9dffa Michael Hanselmann
  result = []
1705 c6a9dffa Michael Hanselmann
  for disk in disks:
1706 c6a9dffa Michael Hanselmann
    try:
1707 c6a9dffa Michael Hanselmann
      rbd = _RecursiveFindBD(disk)
1708 c6a9dffa Michael Hanselmann
      if rbd is None:
1709 c6a9dffa Michael Hanselmann
        result.append((False, "Can't find device %s" % disk))
1710 c6a9dffa Michael Hanselmann
        continue
1711 c6a9dffa Michael Hanselmann
1712 c6a9dffa Michael Hanselmann
      status = rbd.CombinedSyncStatus()
1713 c6a9dffa Michael Hanselmann
    except errors.BlockDeviceError, err:
1714 c6a9dffa Michael Hanselmann
      logging.exception("Error while getting disk status")
1715 c6a9dffa Michael Hanselmann
      result.append((False, str(err)))
1716 c6a9dffa Michael Hanselmann
    else:
1717 c6a9dffa Michael Hanselmann
      result.append((True, status))
1718 c6a9dffa Michael Hanselmann
1719 c6a9dffa Michael Hanselmann
  assert len(disks) == len(result)
1720 c6a9dffa Michael Hanselmann
1721 c6a9dffa Michael Hanselmann
  return result
1722 c6a9dffa Michael Hanselmann
1723 c6a9dffa Michael Hanselmann
1724 bca2e7f4 Iustin Pop
def _RecursiveFindBD(disk):
1725 a8083063 Iustin Pop
  """Check if a device is activated.
1726 a8083063 Iustin Pop

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

1729 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1730 10c2650b Iustin Pop
  @param disk: the disk object we need to find
1731 a8083063 Iustin Pop

1732 10c2650b Iustin Pop
  @return: None if the device can't be found,
1733 10c2650b Iustin Pop
      otherwise the device instance
1734 a8083063 Iustin Pop

1735 a8083063 Iustin Pop
  """
1736 a8083063 Iustin Pop
  children = []
1737 a8083063 Iustin Pop
  if disk.children:
1738 a8083063 Iustin Pop
    for chdisk in disk.children:
1739 a8083063 Iustin Pop
      children.append(_RecursiveFindBD(chdisk))
1740 a8083063 Iustin Pop
1741 464f8daf Iustin Pop
  return bdev.FindDevice(disk.dev_type, disk.physical_id, children, disk.size)
1742 a8083063 Iustin Pop
1743 a8083063 Iustin Pop
1744 f2e07bb4 Michael Hanselmann
def _OpenRealBD(disk):
1745 f2e07bb4 Michael Hanselmann
  """Opens the underlying block device of a disk.
1746 f2e07bb4 Michael Hanselmann

1747 f2e07bb4 Michael Hanselmann
  @type disk: L{objects.Disk}
1748 f2e07bb4 Michael Hanselmann
  @param disk: the disk object we want to open
1749 f2e07bb4 Michael Hanselmann

1750 f2e07bb4 Michael Hanselmann
  """
1751 f2e07bb4 Michael Hanselmann
  real_disk = _RecursiveFindBD(disk)
1752 f2e07bb4 Michael Hanselmann
  if real_disk is None:
1753 f2e07bb4 Michael Hanselmann
    _Fail("Block device '%s' is not set up", disk)
1754 f2e07bb4 Michael Hanselmann
1755 f2e07bb4 Michael Hanselmann
  real_disk.Open()
1756 f2e07bb4 Michael Hanselmann
1757 f2e07bb4 Michael Hanselmann
  return real_disk
1758 f2e07bb4 Michael Hanselmann
1759 f2e07bb4 Michael Hanselmann
1760 821d1bd1 Iustin Pop
def BlockdevFind(disk):
1761 a8083063 Iustin Pop
  """Check if a device is activated.
1762 a8083063 Iustin Pop

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

1765 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
1766 10c2650b Iustin Pop
  @param disk: the disk to find
1767 96acbc09 Michael Hanselmann
  @rtype: None or objects.BlockDevStatus
1768 96acbc09 Michael Hanselmann
  @return: None if the disk cannot be found, otherwise a the current
1769 96acbc09 Michael Hanselmann
           information
1770 a8083063 Iustin Pop

1771 a8083063 Iustin Pop
  """
1772 23829f6f Iustin Pop
  try:
1773 23829f6f Iustin Pop
    rbd = _RecursiveFindBD(disk)
1774 23829f6f Iustin Pop
  except errors.BlockDeviceError, err:
1775 2cc6781a Iustin Pop
    _Fail("Failed to find device: %s", err, exc=True)
1776 96acbc09 Michael Hanselmann
1777 a8083063 Iustin Pop
  if rbd is None:
1778 c26a6bd2 Iustin Pop
    return None
1779 96acbc09 Michael Hanselmann
1780 96acbc09 Michael Hanselmann
  return rbd.GetSyncStatus()
1781 a8083063 Iustin Pop
1782 a8083063 Iustin Pop
1783 968a7623 Iustin Pop
def BlockdevGetsize(disks):
1784 968a7623 Iustin Pop
  """Computes the size of the given disks.
1785 968a7623 Iustin Pop

1786 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
1787 968a7623 Iustin Pop

1788 968a7623 Iustin Pop
  @type disks: list of L{objects.Disk}
1789 968a7623 Iustin Pop
  @param disks: the list of disk to compute the size for
1790 968a7623 Iustin Pop
  @rtype: list
1791 968a7623 Iustin Pop
  @return: list with elements None if the disk cannot be found,
1792 968a7623 Iustin Pop
      otherwise the size
1793 968a7623 Iustin Pop

1794 968a7623 Iustin Pop
  """
1795 968a7623 Iustin Pop
  result = []
1796 968a7623 Iustin Pop
  for cf in disks:
1797 968a7623 Iustin Pop
    try:
1798 968a7623 Iustin Pop
      rbd = _RecursiveFindBD(cf)
1799 1122eb25 Iustin Pop
    except errors.BlockDeviceError:
1800 968a7623 Iustin Pop
      result.append(None)
1801 968a7623 Iustin Pop
      continue
1802 968a7623 Iustin Pop
    if rbd is None:
1803 968a7623 Iustin Pop
      result.append(None)
1804 968a7623 Iustin Pop
    else:
1805 968a7623 Iustin Pop
      result.append(rbd.GetActualSize())
1806 968a7623 Iustin Pop
  return result
1807 968a7623 Iustin Pop
1808 968a7623 Iustin Pop
1809 858f3d18 Iustin Pop
def BlockdevExport(disk, dest_node, dest_path, cluster_name):
1810 858f3d18 Iustin Pop
  """Export a block device to a remote node.
1811 858f3d18 Iustin Pop

1812 858f3d18 Iustin Pop
  @type disk: L{objects.Disk}
1813 858f3d18 Iustin Pop
  @param disk: the description of the disk to export
1814 858f3d18 Iustin Pop
  @type dest_node: str
1815 858f3d18 Iustin Pop
  @param dest_node: the destination node to export to
1816 858f3d18 Iustin Pop
  @type dest_path: str
1817 858f3d18 Iustin Pop
  @param dest_path: the destination path on the target node
1818 858f3d18 Iustin Pop
  @type cluster_name: str
1819 858f3d18 Iustin Pop
  @param cluster_name: the cluster name, needed for SSH hostalias
1820 858f3d18 Iustin Pop
  @rtype: None
1821 858f3d18 Iustin Pop

1822 858f3d18 Iustin Pop
  """
1823 f2e07bb4 Michael Hanselmann
  real_disk = _OpenRealBD(disk)
1824 858f3d18 Iustin Pop
1825 858f3d18 Iustin Pop
  # the block size on the read dd is 1MiB to match our units
1826 858f3d18 Iustin Pop
  expcmd = utils.BuildShellCmd("set -e; set -o pipefail; "
1827 858f3d18 Iustin Pop
                               "dd if=%s bs=1048576 count=%s",
1828 858f3d18 Iustin Pop
                               real_disk.dev_path, str(disk.size))
1829 858f3d18 Iustin Pop
1830 858f3d18 Iustin Pop
  # we set here a smaller block size as, due to ssh buffering, more
1831 858f3d18 Iustin Pop
  # than 64-128k will mostly ignored; we use nocreat to fail if the
1832 858f3d18 Iustin Pop
  # device is not already there or we pass a wrong path; we use
1833 858f3d18 Iustin Pop
  # notrunc to no attempt truncate on an LV device; we use oflag=dsync
1834 858f3d18 Iustin Pop
  # to not buffer too much memory; this means that at best, we flush
1835 858f3d18 Iustin Pop
  # every 64k, which will not be very fast
1836 858f3d18 Iustin Pop
  destcmd = utils.BuildShellCmd("dd of=%s conv=nocreat,notrunc bs=65536"
1837 858f3d18 Iustin Pop
                                " oflag=dsync", dest_path)
1838 858f3d18 Iustin Pop
1839 858f3d18 Iustin Pop
  remotecmd = _GetSshRunner(cluster_name).BuildCmd(dest_node,
1840 858f3d18 Iustin Pop
                                                   constants.GANETI_RUNAS,
1841 858f3d18 Iustin Pop
                                                   destcmd)
1842 858f3d18 Iustin Pop
1843 858f3d18 Iustin Pop
  # all commands have been checked, so we're safe to combine them
1844 d0c8c01d Iustin Pop
  command = "|".join([expcmd, utils.ShellQuoteArgs(remotecmd)])
1845 858f3d18 Iustin Pop
1846 858f3d18 Iustin Pop
  result = utils.RunCmd(["bash", "-c", command])
1847 858f3d18 Iustin Pop
1848 858f3d18 Iustin Pop
  if result.failed:
1849 858f3d18 Iustin Pop
    _Fail("Disk copy command '%s' returned error: %s"
1850 858f3d18 Iustin Pop
          " output: %s", command, result.fail_reason, result.output)
1851 858f3d18 Iustin Pop
1852 858f3d18 Iustin Pop
1853 a8083063 Iustin Pop
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
1854 a8083063 Iustin Pop
  """Write a file to the filesystem.
1855 a8083063 Iustin Pop

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

1859 10c2650b Iustin Pop
  @type file_name: str
1860 10c2650b Iustin Pop
  @param file_name: the target file name
1861 10c2650b Iustin Pop
  @type data: str
1862 10c2650b Iustin Pop
  @param data: the new contents of the file
1863 10c2650b Iustin Pop
  @type mode: int
1864 10c2650b Iustin Pop
  @param mode: the mode to give the file (can be None)
1865 9a914f7a René Nussbaumer
  @type uid: string
1866 9a914f7a René Nussbaumer
  @param uid: the owner of the file
1867 9a914f7a René Nussbaumer
  @type gid: string
1868 9a914f7a René Nussbaumer
  @param gid: the group of the file
1869 10c2650b Iustin Pop
  @type atime: float
1870 10c2650b Iustin Pop
  @param atime: the atime to set on the file (can be None)
1871 10c2650b Iustin Pop
  @type mtime: float
1872 10c2650b Iustin Pop
  @param mtime: the mtime to set on the file (can be None)
1873 c26a6bd2 Iustin Pop
  @rtype: None
1874 10c2650b Iustin Pop

1875 a8083063 Iustin Pop
  """
1876 a8083063 Iustin Pop
  if not os.path.isabs(file_name):
1877 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile is not absolute: '%s'", file_name)
1878 a8083063 Iustin Pop
1879 360b0dc2 Iustin Pop
  if file_name not in _ALLOWED_UPLOAD_FILES:
1880 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile not in allowed upload targets: '%s'",
1881 2cc6781a Iustin Pop
          file_name)
1882 a8083063 Iustin Pop
1883 12bce260 Michael Hanselmann
  raw_data = _Decompress(data)
1884 12bce260 Michael Hanselmann
1885 9a914f7a René Nussbaumer
  if not (isinstance(uid, basestring) and isinstance(gid, basestring)):
1886 9a914f7a René Nussbaumer
    _Fail("Invalid username/groupname type")
1887 9a914f7a René Nussbaumer
1888 9a914f7a René Nussbaumer
  getents = runtime.GetEnts()
1889 9a914f7a René Nussbaumer
  uid = getents.LookupUser(uid)
1890 9a914f7a René Nussbaumer
  gid = getents.LookupGroup(gid)
1891 9a914f7a René Nussbaumer
1892 8f065ae2 Iustin Pop
  utils.SafeWriteFile(file_name, None,
1893 8f065ae2 Iustin Pop
                      data=raw_data, mode=mode, uid=uid, gid=gid,
1894 8f065ae2 Iustin Pop
                      atime=atime, mtime=mtime)
1895 a8083063 Iustin Pop
1896 386b57af Iustin Pop
1897 b2f29800 René Nussbaumer
def RunOob(oob_program, command, node, timeout):
1898 b2f29800 René Nussbaumer
  """Executes oob_program with given command on given node.
1899 b2f29800 René Nussbaumer

1900 b2f29800 René Nussbaumer
  @param oob_program: The path to the executable oob_program
1901 b2f29800 René Nussbaumer
  @param command: The command to invoke on oob_program
1902 b2f29800 René Nussbaumer
  @param node: The node given as an argument to the program
1903 b2f29800 René Nussbaumer
  @param timeout: Timeout after which we kill the oob program
1904 b2f29800 René Nussbaumer

1905 b2f29800 René Nussbaumer
  @return: stdout
1906 b2f29800 René Nussbaumer
  @raise RPCFail: If execution fails for some reason
1907 b2f29800 René Nussbaumer

1908 b2f29800 René Nussbaumer
  """
1909 b2f29800 René Nussbaumer
  result = utils.RunCmd([oob_program, command, node], timeout=timeout)
1910 b2f29800 René Nussbaumer
1911 b2f29800 René Nussbaumer
  if result.failed:
1912 b2f29800 René Nussbaumer
    _Fail("'%s' failed with reason '%s'; output: %s", result.cmd,
1913 b2f29800 René Nussbaumer
          result.fail_reason, result.output)
1914 b2f29800 René Nussbaumer
1915 b2f29800 René Nussbaumer
  return result.stdout
1916 b2f29800 René Nussbaumer
1917 b2f29800 René Nussbaumer
1918 03d1dba2 Michael Hanselmann
def WriteSsconfFiles(values):
1919 89b14f05 Iustin Pop
  """Update all ssconf files.
1920 89b14f05 Iustin Pop

1921 89b14f05 Iustin Pop
  Wrapper around the SimpleStore.WriteFiles.
1922 89b14f05 Iustin Pop

1923 89b14f05 Iustin Pop
  """
1924 89b14f05 Iustin Pop
  ssconf.SimpleStore().WriteFiles(values)
1925 6ddc95ec Michael Hanselmann
1926 6ddc95ec Michael Hanselmann
1927 a8083063 Iustin Pop
def _ErrnoOrStr(err):
1928 a8083063 Iustin Pop
  """Format an EnvironmentError exception.
1929 a8083063 Iustin Pop

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

1934 10c2650b Iustin Pop
  @type err: L{EnvironmentError}
1935 10c2650b Iustin Pop
  @param err: the exception to format
1936 a8083063 Iustin Pop

1937 a8083063 Iustin Pop
  """
1938 d0c8c01d Iustin Pop
  if hasattr(err, "errno"):
1939 a8083063 Iustin Pop
    detail = errno.errorcode[err.errno]
1940 a8083063 Iustin Pop
  else:
1941 a8083063 Iustin Pop
    detail = str(err)
1942 a8083063 Iustin Pop
  return detail
1943 a8083063 Iustin Pop
1944 5d0fe286 Iustin Pop
1945 c19f9810 Iustin Pop
def _OSOndiskAPIVersion(os_dir):
1946 2f8598a5 Alexander Schreiber
  """Compute and return the API version of a given OS.
1947 a8083063 Iustin Pop

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

1951 10c2650b Iustin Pop
  @type os_dir: str
1952 c19f9810 Iustin Pop
  @param os_dir: the directory in which we should look for the OS
1953 8e70b181 Iustin Pop
  @rtype: tuple
1954 8e70b181 Iustin Pop
  @return: tuple (status, data) with status denoting the validity and
1955 8e70b181 Iustin Pop
      data holding either the vaid versions or an error message
1956 a8083063 Iustin Pop

1957 a8083063 Iustin Pop
  """
1958 e02b9114 Iustin Pop
  api_file = utils.PathJoin(os_dir, constants.OS_API_FILE)
1959 a8083063 Iustin Pop
1960 a8083063 Iustin Pop
  try:
1961 a8083063 Iustin Pop
    st = os.stat(api_file)
1962 a8083063 Iustin Pop
  except EnvironmentError, err:
1963 b6b45e0d Guido Trotter
    return False, ("Required file '%s' not found under path %s: %s" %
1964 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir, _ErrnoOrStr(err)))
1965 a8083063 Iustin Pop
1966 a8083063 Iustin Pop
  if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
1967 b6b45e0d Guido Trotter
    return False, ("File '%s' in %s is not a regular file" %
1968 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir))
1969 a8083063 Iustin Pop
1970 a8083063 Iustin Pop
  try:
1971 3374afa9 Guido Trotter
    api_versions = utils.ReadFile(api_file).splitlines()
1972 a8083063 Iustin Pop
  except EnvironmentError, err:
1973 255dcebd Iustin Pop
    return False, ("Error while reading the API version file at %s: %s" %
1974 255dcebd Iustin Pop
                   (api_file, _ErrnoOrStr(err)))
1975 a8083063 Iustin Pop
1976 a8083063 Iustin Pop
  try:
1977 63b9b186 Guido Trotter
    api_versions = [int(version.strip()) for version in api_versions]
1978 a8083063 Iustin Pop
  except (TypeError, ValueError), err:
1979 255dcebd Iustin Pop
    return False, ("API version(s) can't be converted to integer: %s" %
1980 255dcebd Iustin Pop
                   str(err))
1981 a8083063 Iustin Pop
1982 255dcebd Iustin Pop
  return True, api_versions
1983 a8083063 Iustin Pop
1984 386b57af Iustin Pop
1985 7c3d51d4 Guido Trotter
def DiagnoseOS(top_dirs=None):
1986 a8083063 Iustin Pop
  """Compute the validity for all OSes.
1987 a8083063 Iustin Pop

1988 10c2650b Iustin Pop
  @type top_dirs: list
1989 10c2650b Iustin Pop
  @param top_dirs: the list of directories in which to
1990 10c2650b Iustin Pop
      search (if not given defaults to
1991 10c2650b Iustin Pop
      L{constants.OS_SEARCH_PATH})
1992 10c2650b Iustin Pop
  @rtype: list of L{objects.OS}
1993 bad78e66 Iustin Pop
  @return: a list of tuples (name, path, status, diagnose, variants,
1994 bad78e66 Iustin Pop
      parameters, api_version) for all (potential) OSes under all
1995 bad78e66 Iustin Pop
      search paths, where:
1996 255dcebd Iustin Pop
          - name is the (potential) OS name
1997 255dcebd Iustin Pop
          - path is the full path to the OS
1998 255dcebd Iustin Pop
          - status True/False is the validity of the OS
1999 255dcebd Iustin Pop
          - diagnose is the error message for an invalid OS, otherwise empty
2000 ba00557a Guido Trotter
          - variants is a list of supported OS variants, if any
2001 c7d04a6b Iustin Pop
          - parameters is a list of (name, help) parameters, if any
2002 bad78e66 Iustin Pop
          - api_version is a list of support OS API versions
2003 a8083063 Iustin Pop

2004 a8083063 Iustin Pop
  """
2005 7c3d51d4 Guido Trotter
  if top_dirs is None:
2006 7c3d51d4 Guido Trotter
    top_dirs = constants.OS_SEARCH_PATH
2007 a8083063 Iustin Pop
2008 a8083063 Iustin Pop
  result = []
2009 65fe4693 Iustin Pop
  for dir_name in top_dirs:
2010 65fe4693 Iustin Pop
    if os.path.isdir(dir_name):
2011 7c3d51d4 Guido Trotter
      try:
2012 65fe4693 Iustin Pop
        f_names = utils.ListVisibleFiles(dir_name)
2013 7c3d51d4 Guido Trotter
      except EnvironmentError, err:
2014 29921401 Iustin Pop
        logging.exception("Can't list the OS directory %s: %s", dir_name, err)
2015 7c3d51d4 Guido Trotter
        break
2016 7c3d51d4 Guido Trotter
      for name in f_names:
2017 e02b9114 Iustin Pop
        os_path = utils.PathJoin(dir_name, name)
2018 255dcebd Iustin Pop
        status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
2019 255dcebd Iustin Pop
        if status:
2020 255dcebd Iustin Pop
          diagnose = ""
2021 ba00557a Guido Trotter
          variants = os_inst.supported_variants
2022 c7d04a6b Iustin Pop
          parameters = os_inst.supported_parameters
2023 bad78e66 Iustin Pop
          api_versions = os_inst.api_versions
2024 255dcebd Iustin Pop
        else:
2025 255dcebd Iustin Pop
          diagnose = os_inst
2026 bad78e66 Iustin Pop
          variants = parameters = api_versions = []
2027 bad78e66 Iustin Pop
        result.append((name, os_path, status, diagnose, variants,
2028 bad78e66 Iustin Pop
                       parameters, api_versions))
2029 a8083063 Iustin Pop
2030 c26a6bd2 Iustin Pop
  return result
2031 a8083063 Iustin Pop
2032 a8083063 Iustin Pop
2033 255dcebd Iustin Pop
def _TryOSFromDisk(name, base_dir=None):
2034 a8083063 Iustin Pop
  """Create an OS instance from disk.
2035 a8083063 Iustin Pop

2036 a8083063 Iustin Pop
  This function will return an OS instance if the given name is a
2037 8e70b181 Iustin Pop
  valid OS name.
2038 a8083063 Iustin Pop

2039 8ee4dc80 Guido Trotter
  @type base_dir: string
2040 8ee4dc80 Guido Trotter
  @keyword base_dir: Base directory containing OS installations.
2041 8ee4dc80 Guido Trotter
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2042 255dcebd Iustin Pop
  @rtype: tuple
2043 255dcebd Iustin Pop
  @return: success and either the OS instance if we find a valid one,
2044 255dcebd Iustin Pop
      or error message
2045 7c3d51d4 Guido Trotter

2046 a8083063 Iustin Pop
  """
2047 56bcd3f4 Guido Trotter
  if base_dir is None:
2048 57c177af Iustin Pop
    os_dir = utils.FindFile(name, constants.OS_SEARCH_PATH, os.path.isdir)
2049 c34c0cfd Iustin Pop
  else:
2050 f95c81bf Iustin Pop
    os_dir = utils.FindFile(name, [base_dir], os.path.isdir)
2051 f95c81bf Iustin Pop
2052 f95c81bf Iustin Pop
  if os_dir is None:
2053 5c0433d6 Iustin Pop
    return False, "Directory for OS %s not found in search path" % name
2054 a8083063 Iustin Pop
2055 c19f9810 Iustin Pop
  status, api_versions = _OSOndiskAPIVersion(os_dir)
2056 255dcebd Iustin Pop
  if not status:
2057 255dcebd Iustin Pop
    # push the error up
2058 255dcebd Iustin Pop
    return status, api_versions
2059 a8083063 Iustin Pop
2060 d1a7d66f Guido Trotter
  if not constants.OS_API_VERSIONS.intersection(api_versions):
2061 255dcebd Iustin Pop
    return False, ("API version mismatch for path '%s': found %s, want %s." %
2062 d1a7d66f Guido Trotter
                   (os_dir, api_versions, constants.OS_API_VERSIONS))
2063 a8083063 Iustin Pop
2064 35007011 Iustin Pop
  # OS Files dictionary, we will populate it with the absolute path
2065 35007011 Iustin Pop
  # names; if the value is True, then it is a required file, otherwise
2066 35007011 Iustin Pop
  # an optional one
2067 35007011 Iustin Pop
  os_files = dict.fromkeys(constants.OS_SCRIPTS, True)
2068 a8083063 Iustin Pop
2069 95075fba Guido Trotter
  if max(api_versions) >= constants.OS_API_V15:
2070 35007011 Iustin Pop
    os_files[constants.OS_VARIANTS_FILE] = False
2071 95075fba Guido Trotter
2072 c7d04a6b Iustin Pop
  if max(api_versions) >= constants.OS_API_V20:
2073 35007011 Iustin Pop
    os_files[constants.OS_PARAMETERS_FILE] = True
2074 c7d04a6b Iustin Pop
  else:
2075 c7d04a6b Iustin Pop
    del os_files[constants.OS_SCRIPT_VERIFY]
2076 c7d04a6b Iustin Pop
2077 35007011 Iustin Pop
  for (filename, required) in os_files.items():
2078 e02b9114 Iustin Pop
    os_files[filename] = utils.PathJoin(os_dir, filename)
2079 a8083063 Iustin Pop
2080 a8083063 Iustin Pop
    try:
2081 ea79fc15 Michael Hanselmann
      st = os.stat(os_files[filename])
2082 a8083063 Iustin Pop
    except EnvironmentError, err:
2083 35007011 Iustin Pop
      if err.errno == errno.ENOENT and not required:
2084 35007011 Iustin Pop
        del os_files[filename]
2085 35007011 Iustin Pop
        continue
2086 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is missing (%s)" %
2087 ea79fc15 Michael Hanselmann
                     (filename, os_dir, _ErrnoOrStr(err)))
2088 a8083063 Iustin Pop
2089 a8083063 Iustin Pop
    if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2090 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is not a regular file" %
2091 ea79fc15 Michael Hanselmann
                     (filename, os_dir))
2092 255dcebd Iustin Pop
2093 ea79fc15 Michael Hanselmann
    if filename in constants.OS_SCRIPTS:
2094 0757c107 Guido Trotter
      if stat.S_IMODE(st.st_mode) & stat.S_IXUSR != stat.S_IXUSR:
2095 0757c107 Guido Trotter
        return False, ("File '%s' under path '%s' is not executable" %
2096 ea79fc15 Michael Hanselmann
                       (filename, os_dir))
2097 0757c107 Guido Trotter
2098 845da3e8 Iustin Pop
  variants = []
2099 95075fba Guido Trotter
  if constants.OS_VARIANTS_FILE in os_files:
2100 95075fba Guido Trotter
    variants_file = os_files[constants.OS_VARIANTS_FILE]
2101 95075fba Guido Trotter
    try:
2102 95075fba Guido Trotter
      variants = utils.ReadFile(variants_file).splitlines()
2103 95075fba Guido Trotter
    except EnvironmentError, err:
2104 35007011 Iustin Pop
      # we accept missing files, but not other errors
2105 35007011 Iustin Pop
      if err.errno != errno.ENOENT:
2106 35007011 Iustin Pop
        return False, ("Error while reading the OS variants file at %s: %s" %
2107 35007011 Iustin Pop
                       (variants_file, _ErrnoOrStr(err)))
2108 0757c107 Guido Trotter
2109 c7d04a6b Iustin Pop
  parameters = []
2110 c7d04a6b Iustin Pop
  if constants.OS_PARAMETERS_FILE in os_files:
2111 c7d04a6b Iustin Pop
    parameters_file = os_files[constants.OS_PARAMETERS_FILE]
2112 c7d04a6b Iustin Pop
    try:
2113 c7d04a6b Iustin Pop
      parameters = utils.ReadFile(parameters_file).splitlines()
2114 c7d04a6b Iustin Pop
    except EnvironmentError, err:
2115 c7d04a6b Iustin Pop
      return False, ("Error while reading the OS parameters file at %s: %s" %
2116 c7d04a6b Iustin Pop
                     (parameters_file, _ErrnoOrStr(err)))
2117 c7d04a6b Iustin Pop
    parameters = [v.split(None, 1) for v in parameters]
2118 c7d04a6b Iustin Pop
2119 8e70b181 Iustin Pop
  os_obj = objects.OS(name=name, path=os_dir,
2120 41ba4061 Guido Trotter
                      create_script=os_files[constants.OS_SCRIPT_CREATE],
2121 41ba4061 Guido Trotter
                      export_script=os_files[constants.OS_SCRIPT_EXPORT],
2122 41ba4061 Guido Trotter
                      import_script=os_files[constants.OS_SCRIPT_IMPORT],
2123 41ba4061 Guido Trotter
                      rename_script=os_files[constants.OS_SCRIPT_RENAME],
2124 40684c3a Iustin Pop
                      verify_script=os_files.get(constants.OS_SCRIPT_VERIFY,
2125 40684c3a Iustin Pop
                                                 None),
2126 95075fba Guido Trotter
                      supported_variants=variants,
2127 c7d04a6b Iustin Pop
                      supported_parameters=parameters,
2128 255dcebd Iustin Pop
                      api_versions=api_versions)
2129 255dcebd Iustin Pop
  return True, os_obj
2130 255dcebd Iustin Pop
2131 255dcebd Iustin Pop
2132 255dcebd Iustin Pop
def OSFromDisk(name, base_dir=None):
2133 255dcebd Iustin Pop
  """Create an OS instance from disk.
2134 255dcebd Iustin Pop

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

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

2142 255dcebd Iustin Pop
  @type base_dir: string
2143 255dcebd Iustin Pop
  @keyword base_dir: Base directory containing OS installations.
2144 255dcebd Iustin Pop
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2145 255dcebd Iustin Pop
  @rtype: L{objects.OS}
2146 255dcebd Iustin Pop
  @return: the OS instance if we find a valid one
2147 255dcebd Iustin Pop
  @raise RPCFail: if we don't find a valid OS
2148 255dcebd Iustin Pop

2149 255dcebd Iustin Pop
  """
2150 870dc44c Iustin Pop
  name_only = objects.OS.GetName(name)
2151 6ee7102a Guido Trotter
  status, payload = _TryOSFromDisk(name_only, base_dir)
2152 255dcebd Iustin Pop
2153 255dcebd Iustin Pop
  if not status:
2154 255dcebd Iustin Pop
    _Fail(payload)
2155 a8083063 Iustin Pop
2156 255dcebd Iustin Pop
  return payload
2157 a8083063 Iustin Pop
2158 a8083063 Iustin Pop
2159 a025e535 Vitaly Kuznetsov
def OSCoreEnv(os_name, inst_os, os_params, debug=0):
2160 efaa9b06 Iustin Pop
  """Calculate the basic environment for an os script.
2161 2266edb2 Guido Trotter

2162 a025e535 Vitaly Kuznetsov
  @type os_name: str
2163 a025e535 Vitaly Kuznetsov
  @param os_name: full operating system name (including variant)
2164 099c52ad Iustin Pop
  @type inst_os: L{objects.OS}
2165 099c52ad Iustin Pop
  @param inst_os: operating system for which the environment is being built
2166 1bdcbbab Iustin Pop
  @type os_params: dict
2167 1bdcbbab Iustin Pop
  @param os_params: the OS parameters
2168 2266edb2 Guido Trotter
  @type debug: integer
2169 10c2650b Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2170 2266edb2 Guido Trotter
  @rtype: dict
2171 2266edb2 Guido Trotter
  @return: dict of environment variables
2172 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2173 10c2650b Iustin Pop
      cannot be found
2174 2266edb2 Guido Trotter

2175 2266edb2 Guido Trotter
  """
2176 2266edb2 Guido Trotter
  result = {}
2177 099c52ad Iustin Pop
  api_version = \
2178 099c52ad Iustin Pop
    max(constants.OS_API_VERSIONS.intersection(inst_os.api_versions))
2179 d0c8c01d Iustin Pop
  result["OS_API_VERSION"] = "%d" % api_version
2180 d0c8c01d Iustin Pop
  result["OS_NAME"] = inst_os.name
2181 d0c8c01d Iustin Pop
  result["DEBUG_LEVEL"] = "%d" % debug
2182 efaa9b06 Iustin Pop
2183 efaa9b06 Iustin Pop
  # OS variants
2184 35007011 Iustin Pop
  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
2185 870dc44c Iustin Pop
    variant = objects.OS.GetVariant(os_name)
2186 870dc44c Iustin Pop
    if not variant:
2187 099c52ad Iustin Pop
      variant = inst_os.supported_variants[0]
2188 35007011 Iustin Pop
  else:
2189 35007011 Iustin Pop
    variant = ""
2190 35007011 Iustin Pop
  result["OS_VARIANT"] = variant
2191 efaa9b06 Iustin Pop
2192 1bdcbbab Iustin Pop
  # OS params
2193 1bdcbbab Iustin Pop
  for pname, pvalue in os_params.items():
2194 d0c8c01d Iustin Pop
    result["OSP_%s" % pname.upper()] = pvalue
2195 1bdcbbab Iustin Pop
2196 efaa9b06 Iustin Pop
  return result
2197 efaa9b06 Iustin Pop
2198 efaa9b06 Iustin Pop
2199 efaa9b06 Iustin Pop
def OSEnvironment(instance, inst_os, debug=0):
2200 efaa9b06 Iustin Pop
  """Calculate the environment for an os script.
2201 efaa9b06 Iustin Pop

2202 efaa9b06 Iustin Pop
  @type instance: L{objects.Instance}
2203 efaa9b06 Iustin Pop
  @param instance: target instance for the os script run
2204 efaa9b06 Iustin Pop
  @type inst_os: L{objects.OS}
2205 efaa9b06 Iustin Pop
  @param inst_os: operating system for which the environment is being built
2206 efaa9b06 Iustin Pop
  @type debug: integer
2207 efaa9b06 Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2208 efaa9b06 Iustin Pop
  @rtype: dict
2209 efaa9b06 Iustin Pop
  @return: dict of environment variables
2210 efaa9b06 Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2211 efaa9b06 Iustin Pop
      cannot be found
2212 efaa9b06 Iustin Pop

2213 efaa9b06 Iustin Pop
  """
2214 a025e535 Vitaly Kuznetsov
  result = OSCoreEnv(instance.os, inst_os, instance.osparams, debug=debug)
2215 efaa9b06 Iustin Pop
2216 519719fd Marco Casavecchia
  for attr in ["name", "os", "uuid", "ctime", "mtime", "primary_node"]:
2217 f2165b8a Iustin Pop
    result["INSTANCE_%s" % attr.upper()] = str(getattr(instance, attr))
2218 f2165b8a Iustin Pop
2219 d0c8c01d Iustin Pop
  result["HYPERVISOR"] = instance.hypervisor
2220 d0c8c01d Iustin Pop
  result["DISK_COUNT"] = "%d" % len(instance.disks)
2221 d0c8c01d Iustin Pop
  result["NIC_COUNT"] = "%d" % len(instance.nics)
2222 d0c8c01d Iustin Pop
  result["INSTANCE_SECONDARY_NODES"] = \
2223 d0c8c01d Iustin Pop
      ("%s" % " ".join(instance.secondary_nodes))
2224 efaa9b06 Iustin Pop
2225 efaa9b06 Iustin Pop
  # Disks
2226 2266edb2 Guido Trotter
  for idx, disk in enumerate(instance.disks):
2227 f2e07bb4 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
2228 d0c8c01d Iustin Pop
    result["DISK_%d_PATH" % idx] = real_disk.dev_path
2229 d0c8c01d Iustin Pop
    result["DISK_%d_ACCESS" % idx] = disk.mode
2230 2266edb2 Guido Trotter
    if constants.HV_DISK_TYPE in instance.hvparams:
2231 d0c8c01d Iustin Pop
      result["DISK_%d_FRONTEND_TYPE" % idx] = \
2232 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_DISK_TYPE]
2233 2266edb2 Guido Trotter
    if disk.dev_type in constants.LDS_BLOCK:
2234 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = "block"
2235 2266edb2 Guido Trotter
    elif disk.dev_type == constants.LD_FILE:
2236 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = \
2237 d0c8c01d Iustin Pop
        "file:%s" % disk.physical_id[0]
2238 efaa9b06 Iustin Pop
2239 efaa9b06 Iustin Pop
  # NICs
2240 2266edb2 Guido Trotter
  for idx, nic in enumerate(instance.nics):
2241 d0c8c01d Iustin Pop
    result["NIC_%d_MAC" % idx] = nic.mac
2242 2266edb2 Guido Trotter
    if nic.ip:
2243 d0c8c01d Iustin Pop
      result["NIC_%d_IP" % idx] = nic.ip
2244 d0c8c01d Iustin Pop
    result["NIC_%d_MODE" % idx] = nic.nicparams[constants.NIC_MODE]
2245 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2246 d0c8c01d Iustin Pop
      result["NIC_%d_BRIDGE" % idx] = nic.nicparams[constants.NIC_LINK]
2247 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_LINK]:
2248 d0c8c01d Iustin Pop
      result["NIC_%d_LINK" % idx] = nic.nicparams[constants.NIC_LINK]
2249 2266edb2 Guido Trotter
    if constants.HV_NIC_TYPE in instance.hvparams:
2250 d0c8c01d Iustin Pop
      result["NIC_%d_FRONTEND_TYPE" % idx] = \
2251 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_NIC_TYPE]
2252 2266edb2 Guido Trotter
2253 efaa9b06 Iustin Pop
  # HV/BE params
2254 67fc3042 Iustin Pop
  for source, kind in [(instance.beparams, "BE"), (instance.hvparams, "HV")]:
2255 67fc3042 Iustin Pop
    for key, value in source.items():
2256 030b218a Iustin Pop
      result["INSTANCE_%s_%s" % (kind, key)] = str(value)
2257 67fc3042 Iustin Pop
2258 2266edb2 Guido Trotter
  return result
2259 a8083063 Iustin Pop
2260 f2e07bb4 Michael Hanselmann
2261 a59faf4b Iustin Pop
def BlockdevGrow(disk, amount, dryrun):
2262 594609c0 Iustin Pop
  """Grow a stack of block devices.
2263 594609c0 Iustin Pop

2264 594609c0 Iustin Pop
  This function is called recursively, with the childrens being the
2265 10c2650b Iustin Pop
  first ones to resize.
2266 594609c0 Iustin Pop

2267 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2268 10c2650b Iustin Pop
  @param disk: the disk to be grown
2269 a59faf4b Iustin Pop
  @type amount: integer
2270 a59faf4b Iustin Pop
  @param amount: the amount (in mebibytes) to grow with
2271 a59faf4b Iustin Pop
  @type dryrun: boolean
2272 a59faf4b Iustin Pop
  @param dryrun: whether to execute the operation in simulation mode
2273 a59faf4b Iustin Pop
      only, without actually increasing the size
2274 10c2650b Iustin Pop
  @rtype: (status, result)
2275 a59faf4b Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
2276 a59faf4b Iustin Pop
      the errors message if status is False
2277 594609c0 Iustin Pop

2278 594609c0 Iustin Pop
  """
2279 594609c0 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2280 594609c0 Iustin Pop
  if r_dev is None:
2281 afdc3985 Iustin Pop
    _Fail("Cannot find block device %s", disk)
2282 594609c0 Iustin Pop
2283 594609c0 Iustin Pop
  try:
2284 a59faf4b Iustin Pop
    r_dev.Grow(amount, dryrun)
2285 594609c0 Iustin Pop
  except errors.BlockDeviceError, err:
2286 2cc6781a Iustin Pop
    _Fail("Failed to grow block device: %s", err, exc=True)
2287 594609c0 Iustin Pop
2288 594609c0 Iustin Pop
2289 821d1bd1 Iustin Pop
def BlockdevSnapshot(disk):
2290 a8083063 Iustin Pop
  """Create a snapshot copy of a block device.
2291 a8083063 Iustin Pop

2292 a8083063 Iustin Pop
  This function is called recursively, and the snapshot is actually created
2293 a8083063 Iustin Pop
  just for the leaf lvm backend device.
2294 a8083063 Iustin Pop

2295 e9e9263d Guido Trotter
  @type disk: L{objects.Disk}
2296 e9e9263d Guido Trotter
  @param disk: the disk to be snapshotted
2297 e9e9263d Guido Trotter
  @rtype: string
2298 800ac399 Iustin Pop
  @return: snapshot disk ID as (vg, lv)
2299 a8083063 Iustin Pop

2300 098c0958 Michael Hanselmann
  """
2301 433c63aa Iustin Pop
  if disk.dev_type == constants.LD_DRBD8:
2302 433c63aa Iustin Pop
    if not disk.children:
2303 433c63aa Iustin Pop
      _Fail("DRBD device '%s' without backing storage cannot be snapshotted",
2304 433c63aa Iustin Pop
            disk.unique_id)
2305 433c63aa Iustin Pop
    return BlockdevSnapshot(disk.children[0])
2306 fe96220b Iustin Pop
  elif disk.dev_type == constants.LD_LV:
2307 a8083063 Iustin Pop
    r_dev = _RecursiveFindBD(disk)
2308 a8083063 Iustin Pop
    if r_dev is not None:
2309 433c63aa Iustin Pop
      # FIXME: choose a saner value for the snapshot size
2310 a8083063 Iustin Pop
      # let's stay on the safe side and ask for the full size, for now
2311 c26a6bd2 Iustin Pop
      return r_dev.Snapshot(disk.size)
2312 a8083063 Iustin Pop
    else:
2313 87812fd3 Iustin Pop
      _Fail("Cannot find block device %s", disk)
2314 a8083063 Iustin Pop
  else:
2315 87812fd3 Iustin Pop
    _Fail("Cannot snapshot non-lvm block device '%s' of type '%s'",
2316 87812fd3 Iustin Pop
          disk.unique_id, disk.dev_type)
2317 a8083063 Iustin Pop
2318 a8083063 Iustin Pop
2319 a8083063 Iustin Pop
def FinalizeExport(instance, snap_disks):
2320 a8083063 Iustin Pop
  """Write out the export configuration information.
2321 a8083063 Iustin Pop

2322 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
2323 10c2650b Iustin Pop
  @param instance: the instance which we export, used for
2324 10c2650b Iustin Pop
      saving configuration
2325 10c2650b Iustin Pop
  @type snap_disks: list of L{objects.Disk}
2326 10c2650b Iustin Pop
  @param snap_disks: list of snapshot block devices, which
2327 10c2650b Iustin Pop
      will be used to get the actual name of the dump file
2328 a8083063 Iustin Pop

2329 c26a6bd2 Iustin Pop
  @rtype: None
2330 a8083063 Iustin Pop

2331 098c0958 Michael Hanselmann
  """
2332 c4feafe8 Iustin Pop
  destdir = utils.PathJoin(constants.EXPORT_DIR, instance.name + ".new")
2333 c4feafe8 Iustin Pop
  finaldestdir = utils.PathJoin(constants.EXPORT_DIR, instance.name)
2334 a8083063 Iustin Pop
2335 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
2336 a8083063 Iustin Pop
2337 a8083063 Iustin Pop
  config.add_section(constants.INISECT_EXP)
2338 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "version", "0")
2339 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "timestamp", "%d" % int(time.time()))
2340 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "source", instance.primary_node)
2341 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "os", instance.os)
2342 775b8743 Michael Hanselmann
  config.set(constants.INISECT_EXP, "compression", "none")
2343 a8083063 Iustin Pop
2344 a8083063 Iustin Pop
  config.add_section(constants.INISECT_INS)
2345 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "name", instance.name)
2346 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "memory", "%d" %
2347 51de46bf Iustin Pop
             instance.beparams[constants.BE_MEMORY])
2348 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "vcpus", "%d" %
2349 51de46bf Iustin Pop
             instance.beparams[constants.BE_VCPUS])
2350 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "disk_template", instance.disk_template)
2351 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "hypervisor", instance.hypervisor)
2352 fbb2c636 Michael Hanselmann
  config.set(constants.INISECT_INS, "tags", " ".join(instance.GetTags()))
2353 66f93869 Manuel Franceschini
2354 95268cc3 Iustin Pop
  nic_total = 0
2355 a8083063 Iustin Pop
  for nic_count, nic in enumerate(instance.nics):
2356 95268cc3 Iustin Pop
    nic_total += 1
2357 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_mac" %
2358 d0c8c01d Iustin Pop
               nic_count, "%s" % nic.mac)
2359 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_ip" % nic_count, "%s" % nic.ip)
2360 6801eb5c Iustin Pop
    for param in constants.NICS_PARAMETER_TYPES:
2361 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "nic%d_%s" % (nic_count, param),
2362 d0c8c01d Iustin Pop
                 "%s" % nic.nicparams.get(param, None))
2363 a8083063 Iustin Pop
  # TODO: redundant: on load can read nics until it doesn't exist
2364 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "nic_count", "%d" % nic_total)
2365 a8083063 Iustin Pop
2366 726d7d68 Iustin Pop
  disk_total = 0
2367 a8083063 Iustin Pop
  for disk_count, disk in enumerate(snap_disks):
2368 19d7f90a Guido Trotter
    if disk:
2369 726d7d68 Iustin Pop
      disk_total += 1
2370 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_ivname" % disk_count,
2371 d0c8c01d Iustin Pop
                 ("%s" % disk.iv_name))
2372 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_dump" % disk_count,
2373 d0c8c01d Iustin Pop
                 ("%s" % disk.physical_id[1]))
2374 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_size" % disk_count,
2375 d0c8c01d Iustin Pop
                 ("%d" % disk.size))
2376 d0c8c01d Iustin Pop
2377 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "disk_count", "%d" % disk_total)
2378 a8083063 Iustin Pop
2379 3c8954ad Iustin Pop
  # New-style hypervisor/backend parameters
2380 3c8954ad Iustin Pop
2381 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_HYP)
2382 3c8954ad Iustin Pop
  for name, value in instance.hvparams.items():
2383 3c8954ad Iustin Pop
    if name not in constants.HVC_GLOBALS:
2384 3c8954ad Iustin Pop
      config.set(constants.INISECT_HYP, name, str(value))
2385 3c8954ad Iustin Pop
2386 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_BEP)
2387 3c8954ad Iustin Pop
  for name, value in instance.beparams.items():
2388 3c8954ad Iustin Pop
    config.set(constants.INISECT_BEP, name, str(value))
2389 3c8954ad Iustin Pop
2390 535b49cb Iustin Pop
  config.add_section(constants.INISECT_OSP)
2391 535b49cb Iustin Pop
  for name, value in instance.osparams.items():
2392 535b49cb Iustin Pop
    config.set(constants.INISECT_OSP, name, str(value))
2393 535b49cb Iustin Pop
2394 c4feafe8 Iustin Pop
  utils.WriteFile(utils.PathJoin(destdir, constants.EXPORT_CONF_FILE),
2395 726d7d68 Iustin Pop
                  data=config.Dumps())
2396 56569f4e Michael Hanselmann
  shutil.rmtree(finaldestdir, ignore_errors=True)
2397 a8083063 Iustin Pop
  shutil.move(destdir, finaldestdir)
2398 a8083063 Iustin Pop
2399 a8083063 Iustin Pop
2400 a8083063 Iustin Pop
def ExportInfo(dest):
2401 a8083063 Iustin Pop
  """Get export configuration information.
2402 a8083063 Iustin Pop

2403 10c2650b Iustin Pop
  @type dest: str
2404 10c2650b Iustin Pop
  @param dest: directory containing the export
2405 a8083063 Iustin Pop

2406 10c2650b Iustin Pop
  @rtype: L{objects.SerializableConfigParser}
2407 10c2650b Iustin Pop
  @return: a serializable config file containing the
2408 10c2650b Iustin Pop
      export info
2409 a8083063 Iustin Pop

2410 a8083063 Iustin Pop
  """
2411 c4feafe8 Iustin Pop
  cff = utils.PathJoin(dest, constants.EXPORT_CONF_FILE)
2412 a8083063 Iustin Pop
2413 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
2414 a8083063 Iustin Pop
  config.read(cff)
2415 a8083063 Iustin Pop
2416 a8083063 Iustin Pop
  if (not config.has_section(constants.INISECT_EXP) or
2417 a8083063 Iustin Pop
      not config.has_section(constants.INISECT_INS)):
2418 3eccac06 Iustin Pop
    _Fail("Export info file doesn't have the required fields")
2419 a8083063 Iustin Pop
2420 c26a6bd2 Iustin Pop
  return config.Dumps()
2421 a8083063 Iustin Pop
2422 a8083063 Iustin Pop
2423 a8083063 Iustin Pop
def ListExports():
2424 a8083063 Iustin Pop
  """Return a list of exports currently available on this machine.
2425 098c0958 Michael Hanselmann

2426 10c2650b Iustin Pop
  @rtype: list
2427 10c2650b Iustin Pop
  @return: list of the exports
2428 10c2650b Iustin Pop

2429 a8083063 Iustin Pop
  """
2430 a8083063 Iustin Pop
  if os.path.isdir(constants.EXPORT_DIR):
2431 b5b8309d Guido Trotter
    return sorted(utils.ListVisibleFiles(constants.EXPORT_DIR))
2432 a8083063 Iustin Pop
  else:
2433 afdc3985 Iustin Pop
    _Fail("No exports directory")
2434 a8083063 Iustin Pop
2435 a8083063 Iustin Pop
2436 a8083063 Iustin Pop
def RemoveExport(export):
2437 a8083063 Iustin Pop
  """Remove an existing export from the node.
2438 a8083063 Iustin Pop

2439 10c2650b Iustin Pop
  @type export: str
2440 10c2650b Iustin Pop
  @param export: the name of the export to remove
2441 c26a6bd2 Iustin Pop
  @rtype: None
2442 a8083063 Iustin Pop

2443 098c0958 Michael Hanselmann
  """
2444 c4feafe8 Iustin Pop
  target = utils.PathJoin(constants.EXPORT_DIR, export)
2445 a8083063 Iustin Pop
2446 35fbcd11 Iustin Pop
  try:
2447 35fbcd11 Iustin Pop
    shutil.rmtree(target)
2448 35fbcd11 Iustin Pop
  except EnvironmentError, err:
2449 35fbcd11 Iustin Pop
    _Fail("Error while removing the export: %s", err, exc=True)
2450 a8083063 Iustin Pop
2451 a8083063 Iustin Pop
2452 821d1bd1 Iustin Pop
def BlockdevRename(devlist):
2453 f3e513ad Iustin Pop
  """Rename a list of block devices.
2454 f3e513ad Iustin Pop

2455 10c2650b Iustin Pop
  @type devlist: list of tuples
2456 10c2650b Iustin Pop
  @param devlist: list of tuples of the form  (disk,
2457 10c2650b Iustin Pop
      new_logical_id, new_physical_id); disk is an
2458 10c2650b Iustin Pop
      L{objects.Disk} object describing the current disk,
2459 10c2650b Iustin Pop
      and new logical_id/physical_id is the name we
2460 10c2650b Iustin Pop
      rename it to
2461 10c2650b Iustin Pop
  @rtype: boolean
2462 10c2650b Iustin Pop
  @return: True if all renames succeeded, False otherwise
2463 f3e513ad Iustin Pop

2464 f3e513ad Iustin Pop
  """
2465 6b5e3f70 Iustin Pop
  msgs = []
2466 f3e513ad Iustin Pop
  result = True
2467 f3e513ad Iustin Pop
  for disk, unique_id in devlist:
2468 f3e513ad Iustin Pop
    dev = _RecursiveFindBD(disk)
2469 f3e513ad Iustin Pop
    if dev is None:
2470 6b5e3f70 Iustin Pop
      msgs.append("Can't find device %s in rename" % str(disk))
2471 f3e513ad Iustin Pop
      result = False
2472 f3e513ad Iustin Pop
      continue
2473 f3e513ad Iustin Pop
    try:
2474 3f78eef2 Iustin Pop
      old_rpath = dev.dev_path
2475 f3e513ad Iustin Pop
      dev.Rename(unique_id)
2476 3f78eef2 Iustin Pop
      new_rpath = dev.dev_path
2477 3f78eef2 Iustin Pop
      if old_rpath != new_rpath:
2478 3f78eef2 Iustin Pop
        DevCacheManager.RemoveCache(old_rpath)
2479 3f78eef2 Iustin Pop
        # FIXME: we should add the new cache information here, like:
2480 3f78eef2 Iustin Pop
        # DevCacheManager.UpdateCache(new_rpath, owner, ...)
2481 3f78eef2 Iustin Pop
        # but we don't have the owner here - maybe parse from existing
2482 3f78eef2 Iustin Pop
        # cache? for now, we only lose lvm data when we rename, which
2483 3f78eef2 Iustin Pop
        # is less critical than DRBD or MD
2484 f3e513ad Iustin Pop
    except errors.BlockDeviceError, err:
2485 6b5e3f70 Iustin Pop
      msgs.append("Can't rename device '%s' to '%s': %s" %
2486 6b5e3f70 Iustin Pop
                  (dev, unique_id, err))
2487 18682bca Iustin Pop
      logging.exception("Can't rename device '%s' to '%s'", dev, unique_id)
2488 f3e513ad Iustin Pop
      result = False
2489 afdc3985 Iustin Pop
  if not result:
2490 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2491 f3e513ad Iustin Pop
2492 f3e513ad Iustin Pop
2493 4b97f902 Apollon Oikonomopoulos
def _TransformFileStorageDir(fs_dir):
2494 778b75bb Manuel Franceschini
  """Checks whether given file_storage_dir is valid.
2495 778b75bb Manuel Franceschini

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

2500 4b97f902 Apollon Oikonomopoulos
  @type fs_dir: str
2501 4b97f902 Apollon Oikonomopoulos
  @param fs_dir: the path to check
2502 d61cbe76 Iustin Pop

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

2505 778b75bb Manuel Franceschini
  """
2506 cb7c0198 Iustin Pop
  if not constants.ENABLE_FILE_STORAGE:
2507 cb7c0198 Iustin Pop
    _Fail("File storage disabled at configure time")
2508 c657dcc9 Michael Hanselmann
  cfg = _GetConfig()
2509 4b97f902 Apollon Oikonomopoulos
  fs_dir = os.path.normpath(fs_dir)
2510 4b97f902 Apollon Oikonomopoulos
  base_fstore = cfg.GetFileStorageDir()
2511 4b97f902 Apollon Oikonomopoulos
  base_shared = cfg.GetSharedFileStorageDir()
2512 cf00dba0 René Nussbaumer
  if not (utils.IsBelowDir(base_fstore, fs_dir) or
2513 cf00dba0 René Nussbaumer
          utils.IsBelowDir(base_shared, fs_dir)):
2514 b2b8bcce Iustin Pop
    _Fail("File storage directory '%s' is not under base file"
2515 4b97f902 Apollon Oikonomopoulos
          " storage directory '%s' or shared storage directory '%s'",
2516 4b97f902 Apollon Oikonomopoulos
          fs_dir, base_fstore, base_shared)
2517 4b97f902 Apollon Oikonomopoulos
  return fs_dir
2518 778b75bb Manuel Franceschini
2519 778b75bb Manuel Franceschini
2520 778b75bb Manuel Franceschini
def CreateFileStorageDir(file_storage_dir):
2521 778b75bb Manuel Franceschini
  """Create file storage directory.
2522 778b75bb Manuel Franceschini

2523 b1206984 Iustin Pop
  @type file_storage_dir: str
2524 b1206984 Iustin Pop
  @param file_storage_dir: directory to create
2525 778b75bb Manuel Franceschini

2526 b1206984 Iustin Pop
  @rtype: tuple
2527 b1206984 Iustin Pop
  @return: tuple with first element a boolean indicating wheter dir
2528 b1206984 Iustin Pop
      creation was successful or not
2529 778b75bb Manuel Franceschini

2530 778b75bb Manuel Franceschini
  """
2531 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
2532 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
2533 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
2534 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
2535 b2b8bcce Iustin Pop
            file_storage_dir)
2536 778b75bb Manuel Franceschini
  else:
2537 b2b8bcce Iustin Pop
    try:
2538 b2b8bcce Iustin Pop
      os.makedirs(file_storage_dir, 0750)
2539 b2b8bcce Iustin Pop
    except OSError, err:
2540 b2b8bcce Iustin Pop
      _Fail("Cannot create file storage directory '%s': %s",
2541 b2b8bcce Iustin Pop
            file_storage_dir, err, exc=True)
2542 778b75bb Manuel Franceschini
2543 778b75bb Manuel Franceschini
2544 778b75bb Manuel Franceschini
def RemoveFileStorageDir(file_storage_dir):
2545 778b75bb Manuel Franceschini
  """Remove file storage directory.
2546 778b75bb Manuel Franceschini

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

2549 10c2650b Iustin Pop
  @type file_storage_dir: str
2550 10c2650b Iustin Pop
  @param file_storage_dir: the directory we should cleanup
2551 10c2650b Iustin Pop
  @rtype: tuple (success,)
2552 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
2553 5bbd3f7f Michael Hanselmann
      whether the operation was successful
2554 778b75bb Manuel Franceschini

2555 778b75bb Manuel Franceschini
  """
2556 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
2557 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
2558 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
2559 b2b8bcce Iustin Pop
      _Fail("Specified Storage directory '%s' is not a directory",
2560 b2b8bcce Iustin Pop
            file_storage_dir)
2561 afdc3985 Iustin Pop
    # deletes dir only if empty, otherwise we want to fail the rpc call
2562 b2b8bcce Iustin Pop
    try:
2563 b2b8bcce Iustin Pop
      os.rmdir(file_storage_dir)
2564 b2b8bcce Iustin Pop
    except OSError, err:
2565 b2b8bcce Iustin Pop
      _Fail("Cannot remove file storage directory '%s': %s",
2566 b2b8bcce Iustin Pop
            file_storage_dir, err)
2567 b2b8bcce Iustin Pop
2568 778b75bb Manuel Franceschini
2569 778b75bb Manuel Franceschini
def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir):
2570 778b75bb Manuel Franceschini
  """Rename the file storage directory.
2571 778b75bb Manuel Franceschini

2572 10c2650b Iustin Pop
  @type old_file_storage_dir: str
2573 10c2650b Iustin Pop
  @param old_file_storage_dir: the current path
2574 10c2650b Iustin Pop
  @type new_file_storage_dir: str
2575 10c2650b Iustin Pop
  @param new_file_storage_dir: the name we should rename to
2576 10c2650b Iustin Pop
  @rtype: tuple (success,)
2577 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
2578 10c2650b Iustin Pop
      whether the operation was successful
2579 778b75bb Manuel Franceschini

2580 778b75bb Manuel Franceschini
  """
2581 778b75bb Manuel Franceschini
  old_file_storage_dir = _TransformFileStorageDir(old_file_storage_dir)
2582 778b75bb Manuel Franceschini
  new_file_storage_dir = _TransformFileStorageDir(new_file_storage_dir)
2583 b2b8bcce Iustin Pop
  if not os.path.exists(new_file_storage_dir):
2584 b2b8bcce Iustin Pop
    if os.path.isdir(old_file_storage_dir):
2585 b2b8bcce Iustin Pop
      try:
2586 b2b8bcce Iustin Pop
        os.rename(old_file_storage_dir, new_file_storage_dir)
2587 b2b8bcce Iustin Pop
      except OSError, err:
2588 b2b8bcce Iustin Pop
        _Fail("Cannot rename '%s' to '%s': %s",
2589 b2b8bcce Iustin Pop
              old_file_storage_dir, new_file_storage_dir, err)
2590 778b75bb Manuel Franceschini
    else:
2591 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
2592 b2b8bcce Iustin Pop
            old_file_storage_dir)
2593 b2b8bcce Iustin Pop
  else:
2594 b2b8bcce Iustin Pop
    if os.path.exists(old_file_storage_dir):
2595 b2b8bcce Iustin Pop
      _Fail("Cannot rename '%s' to '%s': both locations exist",
2596 b2b8bcce Iustin Pop
            old_file_storage_dir, new_file_storage_dir)
2597 778b75bb Manuel Franceschini
2598 778b75bb Manuel Franceschini
2599 c8457ce7 Iustin Pop
def _EnsureJobQueueFile(file_name):
2600 dc31eae3 Michael Hanselmann
  """Checks whether the given filename is in the queue directory.
2601 ca52cdeb Michael Hanselmann

2602 10c2650b Iustin Pop
  @type file_name: str
2603 10c2650b Iustin Pop
  @param file_name: the file name we should check
2604 c8457ce7 Iustin Pop
  @rtype: None
2605 c8457ce7 Iustin Pop
  @raises RPCFail: if the file is not valid
2606 10c2650b Iustin Pop

2607 ca52cdeb Michael Hanselmann
  """
2608 ca52cdeb Michael Hanselmann
  queue_dir = os.path.normpath(constants.QUEUE_DIR)
2609 dc31eae3 Michael Hanselmann
  result = (os.path.commonprefix([queue_dir, file_name]) == queue_dir)
2610 dc31eae3 Michael Hanselmann
2611 dc31eae3 Michael Hanselmann
  if not result:
2612 c8457ce7 Iustin Pop
    _Fail("Passed job queue file '%s' does not belong to"
2613 c8457ce7 Iustin Pop
          " the queue directory '%s'", file_name, queue_dir)
2614 dc31eae3 Michael Hanselmann
2615 dc31eae3 Michael Hanselmann
2616 dc31eae3 Michael Hanselmann
def JobQueueUpdate(file_name, content):
2617 dc31eae3 Michael Hanselmann
  """Updates a file in the queue directory.
2618 dc31eae3 Michael Hanselmann

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

2622 10c2650b Iustin Pop
  @type file_name: str
2623 10c2650b Iustin Pop
  @param file_name: the job file name
2624 10c2650b Iustin Pop
  @type content: str
2625 10c2650b Iustin Pop
  @param content: the new job contents
2626 10c2650b Iustin Pop
  @rtype: boolean
2627 10c2650b Iustin Pop
  @return: the success of the operation
2628 10c2650b Iustin Pop

2629 dc31eae3 Michael Hanselmann
  """
2630 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(file_name)
2631 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
2632 ca52cdeb Michael Hanselmann
2633 ca52cdeb Michael Hanselmann
  # Write and replace the file atomically
2634 82b22e19 René Nussbaumer
  utils.WriteFile(file_name, data=_Decompress(content), uid=getents.masterd_uid,
2635 82b22e19 René Nussbaumer
                  gid=getents.masterd_gid)
2636 ca52cdeb Michael Hanselmann
2637 ca52cdeb Michael Hanselmann
2638 af5ebcb1 Michael Hanselmann
def JobQueueRename(old, new):
2639 af5ebcb1 Michael Hanselmann
  """Renames a job queue file.
2640 af5ebcb1 Michael Hanselmann

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

2643 10c2650b Iustin Pop
  @type old: str
2644 10c2650b Iustin Pop
  @param old: the old (actual) file name
2645 10c2650b Iustin Pop
  @type new: str
2646 10c2650b Iustin Pop
  @param new: the desired file name
2647 c8457ce7 Iustin Pop
  @rtype: tuple
2648 c8457ce7 Iustin Pop
  @return: the success of the operation and payload
2649 10c2650b Iustin Pop

2650 af5ebcb1 Michael Hanselmann
  """
2651 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(old)
2652 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(new)
2653 af5ebcb1 Michael Hanselmann
2654 58b22b6e Michael Hanselmann
  utils.RenameFile(old, new, mkdir=True)
2655 af5ebcb1 Michael Hanselmann
2656 af5ebcb1 Michael Hanselmann
2657 821d1bd1 Iustin Pop
def BlockdevClose(instance_name, disks):
2658 d61cbe76 Iustin Pop
  """Closes the given block devices.
2659 d61cbe76 Iustin Pop

2660 10c2650b Iustin Pop
  This means they will be switched to secondary mode (in case of
2661 10c2650b Iustin Pop
  DRBD).
2662 10c2650b Iustin Pop

2663 b2e7666a Iustin Pop
  @param instance_name: if the argument is not empty, the symlinks
2664 b2e7666a Iustin Pop
      of this instance will be removed
2665 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
2666 10c2650b Iustin Pop
  @param disks: the list of disks to be closed
2667 10c2650b Iustin Pop
  @rtype: tuple (success, message)
2668 10c2650b Iustin Pop
  @return: a tuple of success and message, where success
2669 10c2650b Iustin Pop
      indicates the succes of the operation, and message
2670 10c2650b Iustin Pop
      which will contain the error details in case we
2671 10c2650b Iustin Pop
      failed
2672 d61cbe76 Iustin Pop

2673 d61cbe76 Iustin Pop
  """
2674 d61cbe76 Iustin Pop
  bdevs = []
2675 d61cbe76 Iustin Pop
  for cf in disks:
2676 d61cbe76 Iustin Pop
    rd = _RecursiveFindBD(cf)
2677 d61cbe76 Iustin Pop
    if rd is None:
2678 2cc6781a Iustin Pop
      _Fail("Can't find device %s", cf)
2679 d61cbe76 Iustin Pop
    bdevs.append(rd)
2680 d61cbe76 Iustin Pop
2681 d61cbe76 Iustin Pop
  msg = []
2682 d61cbe76 Iustin Pop
  for rd in bdevs:
2683 d61cbe76 Iustin Pop
    try:
2684 d61cbe76 Iustin Pop
      rd.Close()
2685 d61cbe76 Iustin Pop
    except errors.BlockDeviceError, err:
2686 d61cbe76 Iustin Pop
      msg.append(str(err))
2687 d61cbe76 Iustin Pop
  if msg:
2688 afdc3985 Iustin Pop
    _Fail("Can't make devices secondary: %s", ",".join(msg))
2689 d61cbe76 Iustin Pop
  else:
2690 b2e7666a Iustin Pop
    if instance_name:
2691 5282084b Iustin Pop
      _RemoveBlockDevLinks(instance_name, disks)
2692 d61cbe76 Iustin Pop
2693 d61cbe76 Iustin Pop
2694 6217e295 Iustin Pop
def ValidateHVParams(hvname, hvparams):
2695 6217e295 Iustin Pop
  """Validates the given hypervisor parameters.
2696 6217e295 Iustin Pop

2697 6217e295 Iustin Pop
  @type hvname: string
2698 6217e295 Iustin Pop
  @param hvname: the hypervisor name
2699 6217e295 Iustin Pop
  @type hvparams: dict
2700 6217e295 Iustin Pop
  @param hvparams: the hypervisor parameters to be validated
2701 c26a6bd2 Iustin Pop
  @rtype: None
2702 6217e295 Iustin Pop

2703 6217e295 Iustin Pop
  """
2704 6217e295 Iustin Pop
  try:
2705 6217e295 Iustin Pop
    hv_type = hypervisor.GetHypervisor(hvname)
2706 6217e295 Iustin Pop
    hv_type.ValidateParameters(hvparams)
2707 6217e295 Iustin Pop
  except errors.HypervisorError, err:
2708 afdc3985 Iustin Pop
    _Fail(str(err), log=False)
2709 6217e295 Iustin Pop
2710 6217e295 Iustin Pop
2711 acd9ff9e Iustin Pop
def _CheckOSPList(os_obj, parameters):
2712 acd9ff9e Iustin Pop
  """Check whether a list of parameters is supported by the OS.
2713 acd9ff9e Iustin Pop

2714 acd9ff9e Iustin Pop
  @type os_obj: L{objects.OS}
2715 acd9ff9e Iustin Pop
  @param os_obj: OS object to check
2716 acd9ff9e Iustin Pop
  @type parameters: list
2717 acd9ff9e Iustin Pop
  @param parameters: the list of parameters to check
2718 acd9ff9e Iustin Pop

2719 acd9ff9e Iustin Pop
  """
2720 acd9ff9e Iustin Pop
  supported = [v[0] for v in os_obj.supported_parameters]
2721 acd9ff9e Iustin Pop
  delta = frozenset(parameters).difference(supported)
2722 acd9ff9e Iustin Pop
  if delta:
2723 acd9ff9e Iustin Pop
    _Fail("The following parameters are not supported"
2724 acd9ff9e Iustin Pop
          " by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
2725 acd9ff9e Iustin Pop
2726 acd9ff9e Iustin Pop
2727 acd9ff9e Iustin Pop
def ValidateOS(required, osname, checks, osparams):
2728 acd9ff9e Iustin Pop
  """Validate the given OS' parameters.
2729 acd9ff9e Iustin Pop

2730 acd9ff9e Iustin Pop
  @type required: boolean
2731 acd9ff9e Iustin Pop
  @param required: whether absence of the OS should translate into
2732 acd9ff9e Iustin Pop
      failure or not
2733 acd9ff9e Iustin Pop
  @type osname: string
2734 acd9ff9e Iustin Pop
  @param osname: the OS to be validated
2735 acd9ff9e Iustin Pop
  @type checks: list
2736 acd9ff9e Iustin Pop
  @param checks: list of the checks to run (currently only 'parameters')
2737 acd9ff9e Iustin Pop
  @type osparams: dict
2738 acd9ff9e Iustin Pop
  @param osparams: dictionary with OS parameters
2739 acd9ff9e Iustin Pop
  @rtype: boolean
2740 acd9ff9e Iustin Pop
  @return: True if the validation passed, or False if the OS was not
2741 acd9ff9e Iustin Pop
      found and L{required} was false
2742 acd9ff9e Iustin Pop

2743 acd9ff9e Iustin Pop
  """
2744 acd9ff9e Iustin Pop
  if not constants.OS_VALIDATE_CALLS.issuperset(checks):
2745 acd9ff9e Iustin Pop
    _Fail("Unknown checks required for OS %s: %s", osname,
2746 acd9ff9e Iustin Pop
          set(checks).difference(constants.OS_VALIDATE_CALLS))
2747 acd9ff9e Iustin Pop
2748 870dc44c Iustin Pop
  name_only = objects.OS.GetName(osname)
2749 acd9ff9e Iustin Pop
  status, tbv = _TryOSFromDisk(name_only, None)
2750 acd9ff9e Iustin Pop
2751 acd9ff9e Iustin Pop
  if not status:
2752 acd9ff9e Iustin Pop
    if required:
2753 acd9ff9e Iustin Pop
      _Fail(tbv)
2754 acd9ff9e Iustin Pop
    else:
2755 acd9ff9e Iustin Pop
      return False
2756 acd9ff9e Iustin Pop
2757 72db3fd7 Iustin Pop
  if max(tbv.api_versions) < constants.OS_API_V20:
2758 72db3fd7 Iustin Pop
    return True
2759 72db3fd7 Iustin Pop
2760 acd9ff9e Iustin Pop
  if constants.OS_VALIDATE_PARAMETERS in checks:
2761 acd9ff9e Iustin Pop
    _CheckOSPList(tbv, osparams.keys())
2762 acd9ff9e Iustin Pop
2763 a025e535 Vitaly Kuznetsov
  validate_env = OSCoreEnv(osname, tbv, osparams)
2764 acd9ff9e Iustin Pop
  result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
2765 896a03f6 Iustin Pop
                        cwd=tbv.path, reset_env=True)
2766 acd9ff9e Iustin Pop
  if result.failed:
2767 acd9ff9e Iustin Pop
    logging.error("os validate command '%s' returned error: %s output: %s",
2768 acd9ff9e Iustin Pop
                  result.cmd, result.fail_reason, result.output)
2769 acd9ff9e Iustin Pop
    _Fail("OS validation script failed (%s), output: %s",
2770 acd9ff9e Iustin Pop
          result.fail_reason, result.output, log=False)
2771 acd9ff9e Iustin Pop
2772 acd9ff9e Iustin Pop
  return True
2773 acd9ff9e Iustin Pop
2774 acd9ff9e Iustin Pop
2775 56aa9fd5 Iustin Pop
def DemoteFromMC():
2776 56aa9fd5 Iustin Pop
  """Demotes the current node from master candidate role.
2777 56aa9fd5 Iustin Pop

2778 56aa9fd5 Iustin Pop
  """
2779 56aa9fd5 Iustin Pop
  # try to ensure we're not the master by mistake
2780 56aa9fd5 Iustin Pop
  master, myself = ssconf.GetMasterAndMyself()
2781 56aa9fd5 Iustin Pop
  if master == myself:
2782 afdc3985 Iustin Pop
    _Fail("ssconf status shows I'm the master node, will not demote")
2783 f154a7a3 Michael Hanselmann
2784 f154a7a3 Michael Hanselmann
  result = utils.RunCmd([constants.DAEMON_UTIL, "check", constants.MASTERD])
2785 f154a7a3 Michael Hanselmann
  if not result.failed:
2786 afdc3985 Iustin Pop
    _Fail("The master daemon is running, will not demote")
2787 f154a7a3 Michael Hanselmann
2788 56aa9fd5 Iustin Pop
  try:
2789 9a5cb537 Iustin Pop
    if os.path.isfile(constants.CLUSTER_CONF_FILE):
2790 9a5cb537 Iustin Pop
      utils.CreateBackup(constants.CLUSTER_CONF_FILE)
2791 56aa9fd5 Iustin Pop
  except EnvironmentError, err:
2792 56aa9fd5 Iustin Pop
    if err.errno != errno.ENOENT:
2793 afdc3985 Iustin Pop
      _Fail("Error while backing up cluster file: %s", err, exc=True)
2794 f154a7a3 Michael Hanselmann
2795 56aa9fd5 Iustin Pop
  utils.RemoveFile(constants.CLUSTER_CONF_FILE)
2796 56aa9fd5 Iustin Pop
2797 56aa9fd5 Iustin Pop
2798 f942a838 Michael Hanselmann
def _GetX509Filenames(cryptodir, name):
2799 f942a838 Michael Hanselmann
  """Returns the full paths for the private key and certificate.
2800 f942a838 Michael Hanselmann

2801 f942a838 Michael Hanselmann
  """
2802 f942a838 Michael Hanselmann
  return (utils.PathJoin(cryptodir, name),
2803 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_KEY_FILE),
2804 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_CERT_FILE))
2805 f942a838 Michael Hanselmann
2806 f942a838 Michael Hanselmann
2807 f942a838 Michael Hanselmann
def CreateX509Certificate(validity, cryptodir=constants.CRYPTO_KEYS_DIR):
2808 f942a838 Michael Hanselmann
  """Creates a new X509 certificate for SSL/TLS.
2809 f942a838 Michael Hanselmann

2810 f942a838 Michael Hanselmann
  @type validity: int
2811 f942a838 Michael Hanselmann
  @param validity: Validity in seconds
2812 f942a838 Michael Hanselmann
  @rtype: tuple; (string, string)
2813 f942a838 Michael Hanselmann
  @return: Certificate name and public part
2814 f942a838 Michael Hanselmann

2815 f942a838 Michael Hanselmann
  """
2816 f942a838 Michael Hanselmann
  (key_pem, cert_pem) = \
2817 b705c7a6 Manuel Franceschini
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
2818 f942a838 Michael Hanselmann
                                     min(validity, _MAX_SSL_CERT_VALIDITY))
2819 f942a838 Michael Hanselmann
2820 f942a838 Michael Hanselmann
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
2821 f942a838 Michael Hanselmann
                              prefix="x509-%s-" % utils.TimestampForFilename())
2822 f942a838 Michael Hanselmann
  try:
2823 f942a838 Michael Hanselmann
    name = os.path.basename(cert_dir)
2824 f942a838 Michael Hanselmann
    assert len(name) > 5
2825 f942a838 Michael Hanselmann
2826 f942a838 Michael Hanselmann
    (_, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
2827 f942a838 Michael Hanselmann
2828 f942a838 Michael Hanselmann
    utils.WriteFile(key_file, mode=0400, data=key_pem)
2829 f942a838 Michael Hanselmann
    utils.WriteFile(cert_file, mode=0400, data=cert_pem)
2830 f942a838 Michael Hanselmann
2831 f942a838 Michael Hanselmann
    # Never return private key as it shouldn't leave the node
2832 f942a838 Michael Hanselmann
    return (name, cert_pem)
2833 f942a838 Michael Hanselmann
  except Exception:
2834 f942a838 Michael Hanselmann
    shutil.rmtree(cert_dir, ignore_errors=True)
2835 f942a838 Michael Hanselmann
    raise
2836 f942a838 Michael Hanselmann
2837 f942a838 Michael Hanselmann
2838 f942a838 Michael Hanselmann
def RemoveX509Certificate(name, cryptodir=constants.CRYPTO_KEYS_DIR):
2839 f942a838 Michael Hanselmann
  """Removes a X509 certificate.
2840 f942a838 Michael Hanselmann

2841 f942a838 Michael Hanselmann
  @type name: string
2842 f942a838 Michael Hanselmann
  @param name: Certificate name
2843 f942a838 Michael Hanselmann

2844 f942a838 Michael Hanselmann
  """
2845 f942a838 Michael Hanselmann
  (cert_dir, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
2846 f942a838 Michael Hanselmann
2847 f942a838 Michael Hanselmann
  utils.RemoveFile(key_file)
2848 f942a838 Michael Hanselmann
  utils.RemoveFile(cert_file)
2849 f942a838 Michael Hanselmann
2850 f942a838 Michael Hanselmann
  try:
2851 f942a838 Michael Hanselmann
    os.rmdir(cert_dir)
2852 f942a838 Michael Hanselmann
  except EnvironmentError, err:
2853 f942a838 Michael Hanselmann
    _Fail("Cannot remove certificate directory '%s': %s",
2854 f942a838 Michael Hanselmann
          cert_dir, err)
2855 f942a838 Michael Hanselmann
2856 f942a838 Michael Hanselmann
2857 1651d116 Michael Hanselmann
def _GetImportExportIoCommand(instance, mode, ieio, ieargs):
2858 1651d116 Michael Hanselmann
  """Returns the command for the requested input/output.
2859 1651d116 Michael Hanselmann

2860 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
2861 1651d116 Michael Hanselmann
  @param instance: The instance object
2862 1651d116 Michael Hanselmann
  @param mode: Import/export mode
2863 1651d116 Michael Hanselmann
  @param ieio: Input/output type
2864 1651d116 Michael Hanselmann
  @param ieargs: Input/output arguments
2865 1651d116 Michael Hanselmann

2866 1651d116 Michael Hanselmann
  """
2867 1651d116 Michael Hanselmann
  assert mode in (constants.IEM_IMPORT, constants.IEM_EXPORT)
2868 1651d116 Michael Hanselmann
2869 1651d116 Michael Hanselmann
  env = None
2870 1651d116 Michael Hanselmann
  prefix = None
2871 1651d116 Michael Hanselmann
  suffix = None
2872 2ad5550d Michael Hanselmann
  exp_size = None
2873 1651d116 Michael Hanselmann
2874 1651d116 Michael Hanselmann
  if ieio == constants.IEIO_FILE:
2875 1651d116 Michael Hanselmann
    (filename, ) = ieargs
2876 1651d116 Michael Hanselmann
2877 1651d116 Michael Hanselmann
    if not utils.IsNormAbsPath(filename):
2878 1651d116 Michael Hanselmann
      _Fail("Path '%s' is not normalized or absolute", filename)
2879 1651d116 Michael Hanselmann
2880 748c9884 René Nussbaumer
    real_filename = os.path.realpath(filename)
2881 748c9884 René Nussbaumer
    directory = os.path.dirname(real_filename)
2882 1651d116 Michael Hanselmann
2883 945859e0 René Nussbaumer
    if not utils.IsBelowDir(constants.EXPORT_DIR, real_filename):
2884 748c9884 René Nussbaumer
      _Fail("File '%s' is not under exports directory '%s': %s",
2885 748c9884 René Nussbaumer
            filename, constants.EXPORT_DIR, real_filename)
2886 1651d116 Michael Hanselmann
2887 1651d116 Michael Hanselmann
    # Create directory
2888 1651d116 Michael Hanselmann
    utils.Makedirs(directory, mode=0750)
2889 1651d116 Michael Hanselmann
2890 1651d116 Michael Hanselmann
    quoted_filename = utils.ShellQuote(filename)
2891 1651d116 Michael Hanselmann
2892 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2893 1651d116 Michael Hanselmann
      suffix = "> %s" % quoted_filename
2894 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2895 1651d116 Michael Hanselmann
      suffix = "< %s" % quoted_filename
2896 1651d116 Michael Hanselmann
2897 2ad5550d Michael Hanselmann
      # Retrieve file size
2898 2ad5550d Michael Hanselmann
      try:
2899 2ad5550d Michael Hanselmann
        st = os.stat(filename)
2900 2ad5550d Michael Hanselmann
      except EnvironmentError, err:
2901 2ad5550d Michael Hanselmann
        logging.error("Can't stat(2) %s: %s", filename, err)
2902 2ad5550d Michael Hanselmann
      else:
2903 2ad5550d Michael Hanselmann
        exp_size = utils.BytesToMebibyte(st.st_size)
2904 2ad5550d Michael Hanselmann
2905 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_RAW_DISK:
2906 1651d116 Michael Hanselmann
    (disk, ) = ieargs
2907 1651d116 Michael Hanselmann
2908 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
2909 1651d116 Michael Hanselmann
2910 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2911 1651d116 Michael Hanselmann
      # we set here a smaller block size as, due to transport buffering, more
2912 1651d116 Michael Hanselmann
      # than 64-128k will mostly ignored; we use nocreat to fail if the device
2913 1651d116 Michael Hanselmann
      # is not already there or we pass a wrong path; we use notrunc to no
2914 1651d116 Michael Hanselmann
      # attempt truncate on an LV device; we use oflag=dsync to not buffer too
2915 1651d116 Michael Hanselmann
      # much memory; this means that at best, we flush every 64k, which will
2916 1651d116 Michael Hanselmann
      # not be very fast
2917 1651d116 Michael Hanselmann
      suffix = utils.BuildShellCmd(("| dd of=%s conv=nocreat,notrunc"
2918 1651d116 Michael Hanselmann
                                    " bs=%s oflag=dsync"),
2919 1651d116 Michael Hanselmann
                                    real_disk.dev_path,
2920 1651d116 Michael Hanselmann
                                    str(64 * 1024))
2921 1651d116 Michael Hanselmann
2922 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2923 1651d116 Michael Hanselmann
      # the block size on the read dd is 1MiB to match our units
2924 1651d116 Michael Hanselmann
      prefix = utils.BuildShellCmd("dd if=%s bs=%s count=%s |",
2925 1651d116 Michael Hanselmann
                                   real_disk.dev_path,
2926 1651d116 Michael Hanselmann
                                   str(1024 * 1024), # 1 MB
2927 1651d116 Michael Hanselmann
                                   str(disk.size))
2928 2ad5550d Michael Hanselmann
      exp_size = disk.size
2929 1651d116 Michael Hanselmann
2930 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_SCRIPT:
2931 1651d116 Michael Hanselmann
    (disk, disk_index, ) = ieargs
2932 1651d116 Michael Hanselmann
2933 1651d116 Michael Hanselmann
    assert isinstance(disk_index, (int, long))
2934 1651d116 Michael Hanselmann
2935 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
2936 1651d116 Michael Hanselmann
2937 1651d116 Michael Hanselmann
    inst_os = OSFromDisk(instance.os)
2938 1651d116 Michael Hanselmann
    env = OSEnvironment(instance, inst_os)
2939 1651d116 Michael Hanselmann
2940 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2941 1651d116 Michael Hanselmann
      env["IMPORT_DEVICE"] = env["DISK_%d_PATH" % disk_index]
2942 1651d116 Michael Hanselmann
      env["IMPORT_INDEX"] = str(disk_index)
2943 1651d116 Michael Hanselmann
      script = inst_os.import_script
2944 1651d116 Michael Hanselmann
2945 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2946 1651d116 Michael Hanselmann
      env["EXPORT_DEVICE"] = real_disk.dev_path
2947 1651d116 Michael Hanselmann
      env["EXPORT_INDEX"] = str(disk_index)
2948 1651d116 Michael Hanselmann
      script = inst_os.export_script
2949 1651d116 Michael Hanselmann
2950 1651d116 Michael Hanselmann
    # TODO: Pass special environment only to script
2951 1651d116 Michael Hanselmann
    script_cmd = utils.BuildShellCmd("( cd %s && %s; )", inst_os.path, script)
2952 1651d116 Michael Hanselmann
2953 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
2954 1651d116 Michael Hanselmann
      suffix = "| %s" % script_cmd
2955 1651d116 Michael Hanselmann
2956 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
2957 1651d116 Michael Hanselmann
      prefix = "%s |" % script_cmd
2958 1651d116 Michael Hanselmann
2959 2ad5550d Michael Hanselmann
    # Let script predict size
2960 2ad5550d Michael Hanselmann
    exp_size = constants.IE_CUSTOM_SIZE
2961 2ad5550d Michael Hanselmann
2962 1651d116 Michael Hanselmann
  else:
2963 1651d116 Michael Hanselmann
    _Fail("Invalid %s I/O mode %r", mode, ieio)
2964 1651d116 Michael Hanselmann
2965 2ad5550d Michael Hanselmann
  return (env, prefix, suffix, exp_size)
2966 1651d116 Michael Hanselmann
2967 1651d116 Michael Hanselmann
2968 1651d116 Michael Hanselmann
def _CreateImportExportStatusDir(prefix):
2969 1651d116 Michael Hanselmann
  """Creates status directory for import/export.
2970 1651d116 Michael Hanselmann

2971 1651d116 Michael Hanselmann
  """
2972 1651d116 Michael Hanselmann
  return tempfile.mkdtemp(dir=constants.IMPORT_EXPORT_DIR,
2973 1651d116 Michael Hanselmann
                          prefix=("%s-%s-" %
2974 1651d116 Michael Hanselmann
                                  (prefix, utils.TimestampForFilename())))
2975 1651d116 Michael Hanselmann
2976 1651d116 Michael Hanselmann
2977 6613661a Iustin Pop
def StartImportExportDaemon(mode, opts, host, port, instance, component,
2978 6613661a Iustin Pop
                            ieio, ieioargs):
2979 1651d116 Michael Hanselmann
  """Starts an import or export daemon.
2980 1651d116 Michael Hanselmann

2981 1651d116 Michael Hanselmann
  @param mode: Import/output mode
2982 eb630f50 Michael Hanselmann
  @type opts: L{objects.ImportExportOptions}
2983 eb630f50 Michael Hanselmann
  @param opts: Daemon options
2984 1651d116 Michael Hanselmann
  @type host: string
2985 1651d116 Michael Hanselmann
  @param host: Remote host for export (None for import)
2986 1651d116 Michael Hanselmann
  @type port: int
2987 1651d116 Michael Hanselmann
  @param port: Remote port for export (None for import)
2988 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
2989 1651d116 Michael Hanselmann
  @param instance: Instance object
2990 6613661a Iustin Pop
  @type component: string
2991 6613661a Iustin Pop
  @param component: which part of the instance is transferred now,
2992 6613661a Iustin Pop
      e.g. 'disk/0'
2993 1651d116 Michael Hanselmann
  @param ieio: Input/output type
2994 1651d116 Michael Hanselmann
  @param ieioargs: Input/output arguments
2995 1651d116 Michael Hanselmann

2996 1651d116 Michael Hanselmann
  """
2997 1651d116 Michael Hanselmann
  if mode == constants.IEM_IMPORT:
2998 1651d116 Michael Hanselmann
    prefix = "import"
2999 1651d116 Michael Hanselmann
3000 1651d116 Michael Hanselmann
    if not (host is None and port is None):
3001 1651d116 Michael Hanselmann
      _Fail("Can not specify host or port on import")
3002 1651d116 Michael Hanselmann
3003 1651d116 Michael Hanselmann
  elif mode == constants.IEM_EXPORT:
3004 1651d116 Michael Hanselmann
    prefix = "export"
3005 1651d116 Michael Hanselmann
3006 1651d116 Michael Hanselmann
    if host is None or port is None:
3007 1651d116 Michael Hanselmann
      _Fail("Host and port must be specified for an export")
3008 1651d116 Michael Hanselmann
3009 1651d116 Michael Hanselmann
  else:
3010 1651d116 Michael Hanselmann
    _Fail("Invalid mode %r", mode)
3011 1651d116 Michael Hanselmann
3012 eb630f50 Michael Hanselmann
  if (opts.key_name is None) ^ (opts.ca_pem is None):
3013 1651d116 Michael Hanselmann
    _Fail("Cluster certificate can only be used for both key and CA")
3014 1651d116 Michael Hanselmann
3015 2ad5550d Michael Hanselmann
  (cmd_env, cmd_prefix, cmd_suffix, exp_size) = \
3016 1651d116 Michael Hanselmann
    _GetImportExportIoCommand(instance, mode, ieio, ieioargs)
3017 1651d116 Michael Hanselmann
3018 eb630f50 Michael Hanselmann
  if opts.key_name is None:
3019 1651d116 Michael Hanselmann
    # Use server.pem
3020 1651d116 Michael Hanselmann
    key_path = constants.NODED_CERT_FILE
3021 1651d116 Michael Hanselmann
    cert_path = constants.NODED_CERT_FILE
3022 eb630f50 Michael Hanselmann
    assert opts.ca_pem is None
3023 1651d116 Michael Hanselmann
  else:
3024 1651d116 Michael Hanselmann
    (_, key_path, cert_path) = _GetX509Filenames(constants.CRYPTO_KEYS_DIR,
3025 eb630f50 Michael Hanselmann
                                                 opts.key_name)
3026 eb630f50 Michael Hanselmann
    assert opts.ca_pem is not None
3027 1651d116 Michael Hanselmann
3028 63bcea2a Michael Hanselmann
  for i in [key_path, cert_path]:
3029 dcaabc4f Michael Hanselmann
    if not os.path.exists(i):
3030 63bcea2a Michael Hanselmann
      _Fail("File '%s' does not exist" % i)
3031 63bcea2a Michael Hanselmann
3032 6613661a Iustin Pop
  status_dir = _CreateImportExportStatusDir("%s-%s" % (prefix, component))
3033 1651d116 Michael Hanselmann
  try:
3034 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(status_dir, _IES_STATUS_FILE)
3035 1651d116 Michael Hanselmann
    pid_file = utils.PathJoin(status_dir, _IES_PID_FILE)
3036 63bcea2a Michael Hanselmann
    ca_file = utils.PathJoin(status_dir, _IES_CA_FILE)
3037 1651d116 Michael Hanselmann
3038 eb630f50 Michael Hanselmann
    if opts.ca_pem is None:
3039 1651d116 Michael Hanselmann
      # Use server.pem
3040 63bcea2a Michael Hanselmann
      ca = utils.ReadFile(constants.NODED_CERT_FILE)
3041 eb630f50 Michael Hanselmann
    else:
3042 eb630f50 Michael Hanselmann
      ca = opts.ca_pem
3043 63bcea2a Michael Hanselmann
3044 eb630f50 Michael Hanselmann
    # Write CA file
3045 63bcea2a Michael Hanselmann
    utils.WriteFile(ca_file, data=ca, mode=0400)
3046 1651d116 Michael Hanselmann
3047 1651d116 Michael Hanselmann
    cmd = [
3048 1651d116 Michael Hanselmann
      constants.IMPORT_EXPORT_DAEMON,
3049 1651d116 Michael Hanselmann
      status_file, mode,
3050 1651d116 Michael Hanselmann
      "--key=%s" % key_path,
3051 1651d116 Michael Hanselmann
      "--cert=%s" % cert_path,
3052 63bcea2a Michael Hanselmann
      "--ca=%s" % ca_file,
3053 1651d116 Michael Hanselmann
      ]
3054 1651d116 Michael Hanselmann
3055 1651d116 Michael Hanselmann
    if host:
3056 1651d116 Michael Hanselmann
      cmd.append("--host=%s" % host)
3057 1651d116 Michael Hanselmann
3058 1651d116 Michael Hanselmann
    if port:
3059 1651d116 Michael Hanselmann
      cmd.append("--port=%s" % port)
3060 1651d116 Michael Hanselmann
3061 855d2fc7 Michael Hanselmann
    if opts.ipv6:
3062 855d2fc7 Michael Hanselmann
      cmd.append("--ipv6")
3063 855d2fc7 Michael Hanselmann
    else:
3064 855d2fc7 Michael Hanselmann
      cmd.append("--ipv4")
3065 855d2fc7 Michael Hanselmann
3066 a5310c2a Michael Hanselmann
    if opts.compress:
3067 a5310c2a Michael Hanselmann
      cmd.append("--compress=%s" % opts.compress)
3068 a5310c2a Michael Hanselmann
3069 af1d39b1 Michael Hanselmann
    if opts.magic:
3070 af1d39b1 Michael Hanselmann
      cmd.append("--magic=%s" % opts.magic)
3071 af1d39b1 Michael Hanselmann
3072 2ad5550d Michael Hanselmann
    if exp_size is not None:
3073 2ad5550d Michael Hanselmann
      cmd.append("--expected-size=%s" % exp_size)
3074 2ad5550d Michael Hanselmann
3075 1651d116 Michael Hanselmann
    if cmd_prefix:
3076 1651d116 Michael Hanselmann
      cmd.append("--cmd-prefix=%s" % cmd_prefix)
3077 1651d116 Michael Hanselmann
3078 1651d116 Michael Hanselmann
    if cmd_suffix:
3079 1651d116 Michael Hanselmann
      cmd.append("--cmd-suffix=%s" % cmd_suffix)
3080 1651d116 Michael Hanselmann
3081 4478301b Michael Hanselmann
    if mode == constants.IEM_EXPORT:
3082 4478301b Michael Hanselmann
      # Retry connection a few times when connecting to remote peer
3083 4478301b Michael Hanselmann
      cmd.append("--connect-retries=%s" % constants.RIE_CONNECT_RETRIES)
3084 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % constants.RIE_CONNECT_ATTEMPT_TIMEOUT)
3085 4478301b Michael Hanselmann
    elif opts.connect_timeout is not None:
3086 4478301b Michael Hanselmann
      assert mode == constants.IEM_IMPORT
3087 4478301b Michael Hanselmann
      # Overall timeout for establishing connection while listening
3088 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % opts.connect_timeout)
3089 4478301b Michael Hanselmann
3090 6aa7a354 Iustin Pop
    logfile = _InstanceLogName(prefix, instance.os, instance.name, component)
3091 1651d116 Michael Hanselmann
3092 1651d116 Michael Hanselmann
    # TODO: Once _InstanceLogName uses tempfile.mkstemp, StartDaemon has
3093 1651d116 Michael Hanselmann
    # support for receiving a file descriptor for output
3094 1651d116 Michael Hanselmann
    utils.StartDaemon(cmd, env=cmd_env, pidfile=pid_file,
3095 1651d116 Michael Hanselmann
                      output=logfile)
3096 1651d116 Michael Hanselmann
3097 1651d116 Michael Hanselmann
    # The import/export name is simply the status directory name
3098 1651d116 Michael Hanselmann
    return os.path.basename(status_dir)
3099 1651d116 Michael Hanselmann
3100 1651d116 Michael Hanselmann
  except Exception:
3101 1651d116 Michael Hanselmann
    shutil.rmtree(status_dir, ignore_errors=True)
3102 1651d116 Michael Hanselmann
    raise
3103 1651d116 Michael Hanselmann
3104 1651d116 Michael Hanselmann
3105 1651d116 Michael Hanselmann
def GetImportExportStatus(names):
3106 1651d116 Michael Hanselmann
  """Returns import/export daemon status.
3107 1651d116 Michael Hanselmann

3108 1651d116 Michael Hanselmann
  @type names: sequence
3109 1651d116 Michael Hanselmann
  @param names: List of names
3110 1651d116 Michael Hanselmann
  @rtype: List of dicts
3111 1651d116 Michael Hanselmann
  @return: Returns a list of the state of each named import/export or None if a
3112 1651d116 Michael Hanselmann
           status couldn't be read
3113 1651d116 Michael Hanselmann

3114 1651d116 Michael Hanselmann
  """
3115 1651d116 Michael Hanselmann
  result = []
3116 1651d116 Michael Hanselmann
3117 1651d116 Michael Hanselmann
  for name in names:
3118 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name,
3119 1651d116 Michael Hanselmann
                                 _IES_STATUS_FILE)
3120 1651d116 Michael Hanselmann
3121 1651d116 Michael Hanselmann
    try:
3122 1651d116 Michael Hanselmann
      data = utils.ReadFile(status_file)
3123 1651d116 Michael Hanselmann
    except EnvironmentError, err:
3124 1651d116 Michael Hanselmann
      if err.errno != errno.ENOENT:
3125 1651d116 Michael Hanselmann
        raise
3126 1651d116 Michael Hanselmann
      data = None
3127 1651d116 Michael Hanselmann
3128 1651d116 Michael Hanselmann
    if not data:
3129 1651d116 Michael Hanselmann
      result.append(None)
3130 1651d116 Michael Hanselmann
      continue
3131 1651d116 Michael Hanselmann
3132 1651d116 Michael Hanselmann
    result.append(serializer.LoadJson(data))
3133 1651d116 Michael Hanselmann
3134 1651d116 Michael Hanselmann
  return result
3135 1651d116 Michael Hanselmann
3136 1651d116 Michael Hanselmann
3137 f81c4737 Michael Hanselmann
def AbortImportExport(name):
3138 f81c4737 Michael Hanselmann
  """Sends SIGTERM to a running import/export daemon.
3139 f81c4737 Michael Hanselmann

3140 f81c4737 Michael Hanselmann
  """
3141 f81c4737 Michael Hanselmann
  logging.info("Abort import/export %s", name)
3142 f81c4737 Michael Hanselmann
3143 f81c4737 Michael Hanselmann
  status_dir = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name)
3144 f81c4737 Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
3145 f81c4737 Michael Hanselmann
3146 f81c4737 Michael Hanselmann
  if pid:
3147 f81c4737 Michael Hanselmann
    logging.info("Import/export %s is running with PID %s, sending SIGTERM",
3148 f81c4737 Michael Hanselmann
                 name, pid)
3149 560cbec1 Michael Hanselmann
    utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
3150 f81c4737 Michael Hanselmann
3151 f81c4737 Michael Hanselmann
3152 1651d116 Michael Hanselmann
def CleanupImportExport(name):
3153 1651d116 Michael Hanselmann
  """Cleanup after an import or export.
3154 1651d116 Michael Hanselmann

3155 1651d116 Michael Hanselmann
  If the import/export daemon is still running it's killed. Afterwards the
3156 1651d116 Michael Hanselmann
  whole status directory is removed.
3157 1651d116 Michael Hanselmann

3158 1651d116 Michael Hanselmann
  """
3159 1651d116 Michael Hanselmann
  logging.info("Finalizing import/export %s", name)
3160 1651d116 Michael Hanselmann
3161 1651d116 Michael Hanselmann
  status_dir = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name)
3162 1651d116 Michael Hanselmann
3163 debed9ae Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
3164 1651d116 Michael Hanselmann
3165 1651d116 Michael Hanselmann
  if pid:
3166 1651d116 Michael Hanselmann
    logging.info("Import/export %s is still running with PID %s",
3167 1651d116 Michael Hanselmann
                 name, pid)
3168 1651d116 Michael Hanselmann
    utils.KillProcess(pid, waitpid=False)
3169 1651d116 Michael Hanselmann
3170 1651d116 Michael Hanselmann
  shutil.rmtree(status_dir, ignore_errors=True)
3171 1651d116 Michael Hanselmann
3172 1651d116 Michael Hanselmann
3173 6b93ec9d Iustin Pop
def _FindDisks(nodes_ip, disks):
3174 6b93ec9d Iustin Pop
  """Sets the physical ID on disks and returns the block devices.
3175 6b93ec9d Iustin Pop

3176 6b93ec9d Iustin Pop
  """
3177 6b93ec9d Iustin Pop
  # set the correct physical ID
3178 b705c7a6 Manuel Franceschini
  my_name = netutils.Hostname.GetSysName()
3179 6b93ec9d Iustin Pop
  for cf in disks:
3180 6b93ec9d Iustin Pop
    cf.SetPhysicalID(my_name, nodes_ip)
3181 6b93ec9d Iustin Pop
3182 6b93ec9d Iustin Pop
  bdevs = []
3183 6b93ec9d Iustin Pop
3184 6b93ec9d Iustin Pop
  for cf in disks:
3185 6b93ec9d Iustin Pop
    rd = _RecursiveFindBD(cf)
3186 6b93ec9d Iustin Pop
    if rd is None:
3187 5a533f8a Iustin Pop
      _Fail("Can't find device %s", cf)
3188 6b93ec9d Iustin Pop
    bdevs.append(rd)
3189 5a533f8a Iustin Pop
  return bdevs
3190 6b93ec9d Iustin Pop
3191 6b93ec9d Iustin Pop
3192 6b93ec9d Iustin Pop
def DrbdDisconnectNet(nodes_ip, disks):
3193 6b93ec9d Iustin Pop
  """Disconnects the network on a list of drbd devices.
3194 6b93ec9d Iustin Pop

3195 6b93ec9d Iustin Pop
  """
3196 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3197 6b93ec9d Iustin Pop
3198 6b93ec9d Iustin Pop
  # disconnect disks
3199 6b93ec9d Iustin Pop
  for rd in bdevs:
3200 6b93ec9d Iustin Pop
    try:
3201 6b93ec9d Iustin Pop
      rd.DisconnectNet()
3202 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
3203 2cc6781a Iustin Pop
      _Fail("Can't change network configuration to standalone mode: %s",
3204 2cc6781a Iustin Pop
            err, exc=True)
3205 6b93ec9d Iustin Pop
3206 6b93ec9d Iustin Pop
3207 6b93ec9d Iustin Pop
def DrbdAttachNet(nodes_ip, disks, instance_name, multimaster):
3208 6b93ec9d Iustin Pop
  """Attaches the network on a list of drbd devices.
3209 6b93ec9d Iustin Pop

3210 6b93ec9d Iustin Pop
  """
3211 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3212 6b93ec9d Iustin Pop
3213 6b93ec9d Iustin Pop
  if multimaster:
3214 53c776b5 Iustin Pop
    for idx, rd in enumerate(bdevs):
3215 6b93ec9d Iustin Pop
      try:
3216 53c776b5 Iustin Pop
        _SymlinkBlockDev(instance_name, rd.dev_path, idx)
3217 6b93ec9d Iustin Pop
      except EnvironmentError, err:
3218 2cc6781a Iustin Pop
        _Fail("Can't create symlink: %s", err)
3219 6b93ec9d Iustin Pop
  # reconnect disks, switch to new master configuration and if
3220 6b93ec9d Iustin Pop
  # needed primary mode
3221 6b93ec9d Iustin Pop
  for rd in bdevs:
3222 6b93ec9d Iustin Pop
    try:
3223 6b93ec9d Iustin Pop
      rd.AttachNet(multimaster)
3224 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
3225 2cc6781a Iustin Pop
      _Fail("Can't change network configuration: %s", err)
3226 3c0cdc83 Michael Hanselmann
3227 6b93ec9d Iustin Pop
  # wait until the disks are connected; we need to retry the re-attach
3228 6b93ec9d Iustin Pop
  # if the device becomes standalone, as this might happen if the one
3229 6b93ec9d Iustin Pop
  # node disconnects and reconnects in a different mode before the
3230 6b93ec9d Iustin Pop
  # other node reconnects; in this case, one or both of the nodes will
3231 6b93ec9d Iustin Pop
  # decide it has wrong configuration and switch to standalone
3232 3c0cdc83 Michael Hanselmann
3233 3c0cdc83 Michael Hanselmann
  def _Attach():
3234 6b93ec9d Iustin Pop
    all_connected = True
3235 3c0cdc83 Michael Hanselmann
3236 6b93ec9d Iustin Pop
    for rd in bdevs:
3237 6b93ec9d Iustin Pop
      stats = rd.GetProcStatus()
3238 3c0cdc83 Michael Hanselmann
3239 3c0cdc83 Michael Hanselmann
      all_connected = (all_connected and
3240 3c0cdc83 Michael Hanselmann
                       (stats.is_connected or stats.is_in_resync))
3241 3c0cdc83 Michael Hanselmann
3242 6b93ec9d Iustin Pop
      if stats.is_standalone:
3243 6b93ec9d Iustin Pop
        # peer had different config info and this node became
3244 6b93ec9d Iustin Pop
        # standalone, even though this should not happen with the
3245 6b93ec9d Iustin Pop
        # new staged way of changing disk configs
3246 6b93ec9d Iustin Pop
        try:
3247 c738375b Iustin Pop
          rd.AttachNet(multimaster)
3248 6b93ec9d Iustin Pop
        except errors.BlockDeviceError, err:
3249 2cc6781a Iustin Pop
          _Fail("Can't change network configuration: %s", err)
3250 3c0cdc83 Michael Hanselmann
3251 3c0cdc83 Michael Hanselmann
    if not all_connected:
3252 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
3253 3c0cdc83 Michael Hanselmann
3254 3c0cdc83 Michael Hanselmann
  try:
3255 3c0cdc83 Michael Hanselmann
    # Start with a delay of 100 miliseconds and go up to 5 seconds
3256 3c0cdc83 Michael Hanselmann
    utils.Retry(_Attach, (0.1, 1.5, 5.0), 2 * 60)
3257 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
3258 afdc3985 Iustin Pop
    _Fail("Timeout in disk reconnecting")
3259 3c0cdc83 Michael Hanselmann
3260 6b93ec9d Iustin Pop
  if multimaster:
3261 6b93ec9d Iustin Pop
    # change to primary mode
3262 6b93ec9d Iustin Pop
    for rd in bdevs:
3263 d3da87b8 Iustin Pop
      try:
3264 d3da87b8 Iustin Pop
        rd.Open()
3265 d3da87b8 Iustin Pop
      except errors.BlockDeviceError, err:
3266 2cc6781a Iustin Pop
        _Fail("Can't change to primary mode: %s", err)
3267 6b93ec9d Iustin Pop
3268 6b93ec9d Iustin Pop
3269 6b93ec9d Iustin Pop
def DrbdWaitSync(nodes_ip, disks):
3270 6b93ec9d Iustin Pop
  """Wait until DRBDs have synchronized.
3271 6b93ec9d Iustin Pop

3272 6b93ec9d Iustin Pop
  """
3273 db8667b7 Iustin Pop
  def _helper(rd):
3274 db8667b7 Iustin Pop
    stats = rd.GetProcStatus()
3275 db8667b7 Iustin Pop
    if not (stats.is_connected or stats.is_in_resync):
3276 db8667b7 Iustin Pop
      raise utils.RetryAgain()
3277 db8667b7 Iustin Pop
    return stats
3278 db8667b7 Iustin Pop
3279 5a533f8a Iustin Pop
  bdevs = _FindDisks(nodes_ip, disks)
3280 6b93ec9d Iustin Pop
3281 6b93ec9d Iustin Pop
  min_resync = 100
3282 6b93ec9d Iustin Pop
  alldone = True
3283 6b93ec9d Iustin Pop
  for rd in bdevs:
3284 db8667b7 Iustin Pop
    try:
3285 db8667b7 Iustin Pop
      # poll each second for 15 seconds
3286 db8667b7 Iustin Pop
      stats = utils.Retry(_helper, 1, 15, args=[rd])
3287 db8667b7 Iustin Pop
    except utils.RetryTimeout:
3288 db8667b7 Iustin Pop
      stats = rd.GetProcStatus()
3289 db8667b7 Iustin Pop
      # last check
3290 db8667b7 Iustin Pop
      if not (stats.is_connected or stats.is_in_resync):
3291 db8667b7 Iustin Pop
        _Fail("DRBD device %s is not in sync: stats=%s", rd, stats)
3292 6b93ec9d Iustin Pop
    alldone = alldone and (not stats.is_in_resync)
3293 6b93ec9d Iustin Pop
    if stats.sync_percent is not None:
3294 6b93ec9d Iustin Pop
      min_resync = min(min_resync, stats.sync_percent)
3295 afdc3985 Iustin Pop
3296 c26a6bd2 Iustin Pop
  return (alldone, min_resync)
3297 6b93ec9d Iustin Pop
3298 6b93ec9d Iustin Pop
3299 c46b9782 Luca Bigliardi
def GetDrbdUsermodeHelper():
3300 c46b9782 Luca Bigliardi
  """Returns DRBD usermode helper currently configured.
3301 c46b9782 Luca Bigliardi

3302 c46b9782 Luca Bigliardi
  """
3303 c46b9782 Luca Bigliardi
  try:
3304 c46b9782 Luca Bigliardi
    return bdev.BaseDRBD.GetUsermodeHelper()
3305 c46b9782 Luca Bigliardi
  except errors.BlockDeviceError, err:
3306 c46b9782 Luca Bigliardi
    _Fail(str(err))
3307 c46b9782 Luca Bigliardi
3308 c46b9782 Luca Bigliardi
3309 f5118ade Iustin Pop
def PowercycleNode(hypervisor_type):
3310 f5118ade Iustin Pop
  """Hard-powercycle the node.
3311 f5118ade Iustin Pop

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

3315 f5118ade Iustin Pop
  """
3316 f5118ade Iustin Pop
  hyper = hypervisor.GetHypervisor(hypervisor_type)
3317 f5118ade Iustin Pop
  try:
3318 f5118ade Iustin Pop
    pid = os.fork()
3319 29921401 Iustin Pop
  except OSError:
3320 f5118ade Iustin Pop
    # if we can't fork, we'll pretend that we're in the child process
3321 f5118ade Iustin Pop
    pid = 0
3322 f5118ade Iustin Pop
  if pid > 0:
3323 c26a6bd2 Iustin Pop
    return "Reboot scheduled in 5 seconds"
3324 1af6ac0f Luca Bigliardi
  # ensure the child is running on ram
3325 1af6ac0f Luca Bigliardi
  try:
3326 1af6ac0f Luca Bigliardi
    utils.Mlockall()
3327 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
3328 1af6ac0f Luca Bigliardi
    pass
3329 f5118ade Iustin Pop
  time.sleep(5)
3330 f5118ade Iustin Pop
  hyper.PowercycleNode()
3331 f5118ade Iustin Pop
3332 f5118ade Iustin Pop
3333 a8083063 Iustin Pop
class HooksRunner(object):
3334 a8083063 Iustin Pop
  """Hook runner.
3335 a8083063 Iustin Pop

3336 10c2650b Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not
3337 10c2650b Iustin Pop
  on the master side.
3338 a8083063 Iustin Pop

3339 a8083063 Iustin Pop
  """
3340 a8083063 Iustin Pop
  def __init__(self, hooks_base_dir=None):
3341 a8083063 Iustin Pop
    """Constructor for hooks runner.
3342 a8083063 Iustin Pop

3343 10c2650b Iustin Pop
    @type hooks_base_dir: str or None
3344 10c2650b Iustin Pop
    @param hooks_base_dir: if not None, this overrides the
3345 10c2650b Iustin Pop
        L{constants.HOOKS_BASE_DIR} (useful for unittests)
3346 a8083063 Iustin Pop

3347 a8083063 Iustin Pop
    """
3348 a8083063 Iustin Pop
    if hooks_base_dir is None:
3349 a8083063 Iustin Pop
      hooks_base_dir = constants.HOOKS_BASE_DIR
3350 fe267188 Iustin Pop
    # yeah, _BASE_DIR is not valid for attributes, we use it like a
3351 fe267188 Iustin Pop
    # constant
3352 b459a848 Andrea Spadaccini
    self._BASE_DIR = hooks_base_dir # pylint: disable=C0103
3353 a8083063 Iustin Pop
3354 a8083063 Iustin Pop
  def RunHooks(self, hpath, phase, env):
3355 a8083063 Iustin Pop
    """Run the scripts in the hooks directory.
3356 a8083063 Iustin Pop

3357 10c2650b Iustin Pop
    @type hpath: str
3358 10c2650b Iustin Pop
    @param hpath: the path to the hooks directory which
3359 10c2650b Iustin Pop
        holds the scripts
3360 10c2650b Iustin Pop
    @type phase: str
3361 10c2650b Iustin Pop
    @param phase: either L{constants.HOOKS_PHASE_PRE} or
3362 10c2650b Iustin Pop
        L{constants.HOOKS_PHASE_POST}
3363 10c2650b Iustin Pop
    @type env: dict
3364 10c2650b Iustin Pop
    @param env: dictionary with the environment for the hook
3365 10c2650b Iustin Pop
    @rtype: list
3366 10c2650b Iustin Pop
    @return: list of 3-element tuples:
3367 10c2650b Iustin Pop
      - script path
3368 10c2650b Iustin Pop
      - script result, either L{constants.HKR_SUCCESS} or
3369 10c2650b Iustin Pop
        L{constants.HKR_FAIL}
3370 10c2650b Iustin Pop
      - output of the script
3371 10c2650b Iustin Pop

3372 10c2650b Iustin Pop
    @raise errors.ProgrammerError: for invalid input
3373 10c2650b Iustin Pop
        parameters
3374 a8083063 Iustin Pop

3375 a8083063 Iustin Pop
    """
3376 a8083063 Iustin Pop
    if phase == constants.HOOKS_PHASE_PRE:
3377 a8083063 Iustin Pop
      suffix = "pre"
3378 a8083063 Iustin Pop
    elif phase == constants.HOOKS_PHASE_POST:
3379 a8083063 Iustin Pop
      suffix = "post"
3380 a8083063 Iustin Pop
    else:
3381 3fb4f740 Iustin Pop
      _Fail("Unknown hooks phase '%s'", phase)
3382 3fb4f740 Iustin Pop
3383 a8083063 Iustin Pop
    subdir = "%s-%s.d" % (hpath, suffix)
3384 0411c011 Iustin Pop
    dir_name = utils.PathJoin(self._BASE_DIR, subdir)
3385 6bb65e3a Guido Trotter
3386 6bb65e3a Guido Trotter
    results = []
3387 a9b7e346 Iustin Pop
3388 a9b7e346 Iustin Pop
    if not os.path.isdir(dir_name):
3389 a9b7e346 Iustin Pop
      # for non-existing/non-dirs, we simply exit instead of logging a
3390 a9b7e346 Iustin Pop
      # warning at every operation
3391 a9b7e346 Iustin Pop
      return results
3392 a9b7e346 Iustin Pop
3393 a9b7e346 Iustin Pop
    runparts_results = utils.RunParts(dir_name, env=env, reset_env=True)
3394 a9b7e346 Iustin Pop
3395 6bb65e3a Guido Trotter
    for (relname, relstatus, runresult)  in runparts_results:
3396 6bb65e3a Guido Trotter
      if relstatus == constants.RUNPARTS_SKIP:
3397 a8083063 Iustin Pop
        rrval = constants.HKR_SKIP
3398 a8083063 Iustin Pop
        output = ""
3399 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_ERR:
3400 6bb65e3a Guido Trotter
        rrval = constants.HKR_FAIL
3401 6bb65e3a Guido Trotter
        output = "Hook script execution error: %s" % runresult
3402 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_RUN:
3403 6bb65e3a Guido Trotter
        if runresult.failed:
3404 a8083063 Iustin Pop
          rrval = constants.HKR_FAIL
3405 a8083063 Iustin Pop
        else:
3406 6bb65e3a Guido Trotter
          rrval = constants.HKR_SUCCESS
3407 6bb65e3a Guido Trotter
        output = utils.SafeEncode(runresult.output.strip())
3408 6bb65e3a Guido Trotter
      results.append(("%s/%s" % (subdir, relname), rrval, output))
3409 6bb65e3a Guido Trotter
3410 6bb65e3a Guido Trotter
    return results
3411 3f78eef2 Iustin Pop
3412 3f78eef2 Iustin Pop
3413 8d528b7c Iustin Pop
class IAllocatorRunner(object):
3414 8d528b7c Iustin Pop
  """IAllocator runner.
3415 8d528b7c Iustin Pop

3416 8d528b7c Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not on
3417 8d528b7c Iustin Pop
  the master side.
3418 8d528b7c Iustin Pop

3419 8d528b7c Iustin Pop
  """
3420 7e950d31 Iustin Pop
  @staticmethod
3421 7e950d31 Iustin Pop
  def Run(name, idata):
3422 8d528b7c Iustin Pop
    """Run an iallocator script.
3423 8d528b7c Iustin Pop

3424 10c2650b Iustin Pop
    @type name: str
3425 10c2650b Iustin Pop
    @param name: the iallocator script name
3426 10c2650b Iustin Pop
    @type idata: str
3427 10c2650b Iustin Pop
    @param idata: the allocator input data
3428 10c2650b Iustin Pop

3429 10c2650b Iustin Pop
    @rtype: tuple
3430 87f5c298 Iustin Pop
    @return: two element tuple of:
3431 87f5c298 Iustin Pop
       - status
3432 87f5c298 Iustin Pop
       - either error message or stdout of allocator (for success)
3433 8d528b7c Iustin Pop

3434 8d528b7c Iustin Pop
    """
3435 8d528b7c Iustin Pop
    alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
3436 8d528b7c Iustin Pop
                                  os.path.isfile)
3437 8d528b7c Iustin Pop
    if alloc_script is None:
3438 87f5c298 Iustin Pop
      _Fail("iallocator module '%s' not found in the search path", name)
3439 8d528b7c Iustin Pop
3440 8d528b7c Iustin Pop
    fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
3441 8d528b7c Iustin Pop
    try:
3442 8d528b7c Iustin Pop
      os.write(fd, idata)
3443 8d528b7c Iustin Pop
      os.close(fd)
3444 8d528b7c Iustin Pop
      result = utils.RunCmd([alloc_script, fin_name])
3445 8d528b7c Iustin Pop
      if result.failed:
3446 87f5c298 Iustin Pop
        _Fail("iallocator module '%s' failed: %s, output '%s'",
3447 87f5c298 Iustin Pop
              name, result.fail_reason, result.output)
3448 8d528b7c Iustin Pop
    finally:
3449 8d528b7c Iustin Pop
      os.unlink(fin_name)
3450 8d528b7c Iustin Pop
3451 c26a6bd2 Iustin Pop
    return result.stdout
3452 8d528b7c Iustin Pop
3453 8d528b7c Iustin Pop
3454 3f78eef2 Iustin Pop
class DevCacheManager(object):
3455 c99a3cc0 Manuel Franceschini
  """Simple class for managing a cache of block device information.
3456 3f78eef2 Iustin Pop

3457 3f78eef2 Iustin Pop
  """
3458 3f78eef2 Iustin Pop
  _DEV_PREFIX = "/dev/"
3459 3f78eef2 Iustin Pop
  _ROOT_DIR = constants.BDEV_CACHE_DIR
3460 3f78eef2 Iustin Pop
3461 3f78eef2 Iustin Pop
  @classmethod
3462 3f78eef2 Iustin Pop
  def _ConvertPath(cls, dev_path):
3463 3f78eef2 Iustin Pop
    """Converts a /dev/name path to the cache file name.
3464 3f78eef2 Iustin Pop

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

3468 10c2650b Iustin Pop
    @type dev_path: str
3469 10c2650b Iustin Pop
    @param dev_path: the C{/dev/} path name
3470 10c2650b Iustin Pop
    @rtype: str
3471 10c2650b Iustin Pop
    @return: the converted path name
3472 3f78eef2 Iustin Pop

3473 3f78eef2 Iustin Pop
    """
3474 3f78eef2 Iustin Pop
    if dev_path.startswith(cls._DEV_PREFIX):
3475 3f78eef2 Iustin Pop
      dev_path = dev_path[len(cls._DEV_PREFIX):]
3476 3f78eef2 Iustin Pop
    dev_path = dev_path.replace("/", "_")
3477 0411c011 Iustin Pop
    fpath = utils.PathJoin(cls._ROOT_DIR, "bdev_%s" % dev_path)
3478 3f78eef2 Iustin Pop
    return fpath
3479 3f78eef2 Iustin Pop
3480 3f78eef2 Iustin Pop
  @classmethod
3481 3f78eef2 Iustin Pop
  def UpdateCache(cls, dev_path, owner, on_primary, iv_name):
3482 3f78eef2 Iustin Pop
    """Updates the cache information for a given device.
3483 3f78eef2 Iustin Pop

3484 10c2650b Iustin Pop
    @type dev_path: str
3485 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
3486 10c2650b Iustin Pop
    @type owner: str
3487 10c2650b Iustin Pop
    @param owner: the owner (instance name) of the device
3488 10c2650b Iustin Pop
    @type on_primary: bool
3489 10c2650b Iustin Pop
    @param on_primary: whether this is the primary
3490 10c2650b Iustin Pop
        node nor not
3491 10c2650b Iustin Pop
    @type iv_name: str
3492 10c2650b Iustin Pop
    @param iv_name: the instance-visible name of the
3493 c41eea6e Iustin Pop
        device, as in objects.Disk.iv_name
3494 10c2650b Iustin Pop

3495 10c2650b Iustin Pop
    @rtype: None
3496 10c2650b Iustin Pop

3497 3f78eef2 Iustin Pop
    """
3498 cf5a8306 Iustin Pop
    if dev_path is None:
3499 18682bca Iustin Pop
      logging.error("DevCacheManager.UpdateCache got a None dev_path")
3500 cf5a8306 Iustin Pop
      return
3501 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
3502 3f78eef2 Iustin Pop
    if on_primary:
3503 3f78eef2 Iustin Pop
      state = "primary"
3504 3f78eef2 Iustin Pop
    else:
3505 3f78eef2 Iustin Pop
      state = "secondary"
3506 3f78eef2 Iustin Pop
    if iv_name is None:
3507 3f78eef2 Iustin Pop
      iv_name = "not_visible"
3508 3f78eef2 Iustin Pop
    fdata = "%s %s %s\n" % (str(owner), state, iv_name)
3509 3f78eef2 Iustin Pop
    try:
3510 3f78eef2 Iustin Pop
      utils.WriteFile(fpath, data=fdata)
3511 3f78eef2 Iustin Pop
    except EnvironmentError, err:
3512 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)
3513 3f78eef2 Iustin Pop
3514 3f78eef2 Iustin Pop
  @classmethod
3515 3f78eef2 Iustin Pop
  def RemoveCache(cls, dev_path):
3516 3f78eef2 Iustin Pop
    """Remove data for a dev_path.
3517 3f78eef2 Iustin Pop

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

3521 10c2650b Iustin Pop
    @type dev_path: str
3522 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
3523 10c2650b Iustin Pop

3524 10c2650b Iustin Pop
    @rtype: None
3525 10c2650b Iustin Pop

3526 3f78eef2 Iustin Pop
    """
3527 cf5a8306 Iustin Pop
    if dev_path is None:
3528 18682bca Iustin Pop
      logging.error("DevCacheManager.RemoveCache got a None dev_path")
3529 cf5a8306 Iustin Pop
      return
3530 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
3531 3f78eef2 Iustin Pop
    try:
3532 3f78eef2 Iustin Pop
      utils.RemoveFile(fpath)
3533 3f78eef2 Iustin Pop
    except EnvironmentError, err:
3534 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)