Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ 808cb0ee

History | View | Annotate | Download (153.9 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 3cf06dd4 Jose A. Lopes
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 4daa5eb9 Sebastian Gebhard
# pylint: disable=E1103,C0302
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 4daa5eb9 Sebastian Gebhard
# C0302: This module has become too big and should be split up
38 4daa5eb9 Sebastian Gebhard
39 a8083063 Iustin Pop
40 229fb4ea Jose A. Lopes
import base64
41 229fb4ea Jose A. Lopes
import errno
42 229fb4ea Jose A. Lopes
import logging
43 a8083063 Iustin Pop
import os
44 a8083063 Iustin Pop
import os.path
45 c89622cd Jose A. Lopes
import pycurl
46 229fb4ea Jose A. Lopes
import random
47 229fb4ea Jose A. Lopes
import re
48 a8083063 Iustin Pop
import shutil
49 229fb4ea Jose A. Lopes
import signal
50 2fd4e86d Jose A. Lopes
import socket
51 a8083063 Iustin Pop
import stat
52 3b9e6a30 Iustin Pop
import tempfile
53 229fb4ea Jose A. Lopes
import time
54 12bce260 Michael Hanselmann
import zlib
55 a8083063 Iustin Pop
56 a8083063 Iustin Pop
from ganeti import errors
57 c89622cd Jose A. Lopes
from ganeti import http
58 a8083063 Iustin Pop
from ganeti import utils
59 a8083063 Iustin Pop
from ganeti import ssh
60 a8083063 Iustin Pop
from ganeti import hypervisor
61 a8083063 Iustin Pop
from ganeti import constants
62 cde49218 Helga Velroyen
from ganeti.storage import bdev
63 cde49218 Helga Velroyen
from ganeti.storage import drbd
64 13669ecd Helga Velroyen
from ganeti.storage import filestorage
65 a8083063 Iustin Pop
from ganeti import objects
66 880478f8 Iustin Pop
from ganeti import ssconf
67 1651d116 Michael Hanselmann
from ganeti import serializer
68 a744b676 Manuel Franceschini
from ganeti import netutils
69 82b22e19 René Nussbaumer
from ganeti import runtime
70 3ccd3243 Andrea Spadaccini
from ganeti import compat
71 710f30ec Michael Hanselmann
from ganeti import pathutils
72 cffbbae7 Michael Hanselmann
from ganeti import vcluster
73 99e222b1 Michael Hanselmann
from ganeti import ht
74 cde49218 Helga Velroyen
from ganeti.storage.base import BlockDev
75 cde49218 Helga Velroyen
from ganeti.storage.drbd import DRBD8
76 68d95757 Guido Trotter
from ganeti import hooksmaster
77 2fd4e86d Jose A. Lopes
from ganeti.rpc import transport
78 2fd4e86d Jose A. Lopes
from ganeti.rpc.errors import NoMasterError, TimeoutError
79 a8083063 Iustin Pop
80 a8083063 Iustin Pop
81 13998ef2 Michael Hanselmann
_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id"
82 b8028dcf Michael Hanselmann
_ALLOWED_CLEAN_DIRS = compat.UniqueFrozenset([
83 710f30ec Michael Hanselmann
  pathutils.DATA_DIR,
84 710f30ec Michael Hanselmann
  pathutils.JOB_QUEUE_ARCHIVE_DIR,
85 710f30ec Michael Hanselmann
  pathutils.QUEUE_DIR,
86 710f30ec Michael Hanselmann
  pathutils.CRYPTO_KEYS_DIR,
87 714ea7ca Iustin Pop
  ])
88 f942a838 Michael Hanselmann
_MAX_SSL_CERT_VALIDITY = 7 * 24 * 60 * 60
89 f942a838 Michael Hanselmann
_X509_KEY_FILE = "key"
90 f942a838 Michael Hanselmann
_X509_CERT_FILE = "cert"
91 1651d116 Michael Hanselmann
_IES_STATUS_FILE = "status"
92 1651d116 Michael Hanselmann
_IES_PID_FILE = "pid"
93 1651d116 Michael Hanselmann
_IES_CA_FILE = "ca"
94 13998ef2 Michael Hanselmann
95 0b5303da Iustin Pop
#: Valid LVS output line regex
96 78f99abb Michele Tartara
_LVSLINE_REGEX = re.compile(r"^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6,})\|?$")
97 0b5303da Iustin Pop
98 702eff21 Andrea Spadaccini
# Actions for the master setup script
99 702eff21 Andrea Spadaccini
_MASTER_START = "start"
100 702eff21 Andrea Spadaccini
_MASTER_STOP = "stop"
101 702eff21 Andrea Spadaccini
102 45bc4635 Iustin Pop
#: Maximum file permissions for restricted command directory and executables
103 1a2eb2dc Michael Hanselmann
_RCMD_MAX_MODE = (stat.S_IRWXU |
104 1a2eb2dc Michael Hanselmann
                  stat.S_IRGRP | stat.S_IXGRP |
105 1a2eb2dc Michael Hanselmann
                  stat.S_IROTH | stat.S_IXOTH)
106 1a2eb2dc Michael Hanselmann
107 45bc4635 Iustin Pop
#: Delay before returning an error for restricted commands
108 1a2eb2dc Michael Hanselmann
_RCMD_INVALID_DELAY = 10
109 1a2eb2dc Michael Hanselmann
110 45bc4635 Iustin Pop
#: How long to wait to acquire lock for restricted commands (shorter than
111 1a2eb2dc Michael Hanselmann
#: L{_RCMD_INVALID_DELAY}) to reduce blockage of noded forks when many
112 1a2eb2dc Michael Hanselmann
#: command requests arrive
113 1a2eb2dc Michael Hanselmann
_RCMD_LOCK_TIMEOUT = _RCMD_INVALID_DELAY * 0.8
114 1a2eb2dc Michael Hanselmann
115 13998ef2 Michael Hanselmann
116 2cc6781a Iustin Pop
class RPCFail(Exception):
117 2cc6781a Iustin Pop
  """Class denoting RPC failure.
118 2cc6781a Iustin Pop

119 2cc6781a Iustin Pop
  Its argument is the error message.
120 2cc6781a Iustin Pop

121 2cc6781a Iustin Pop
  """
122 2cc6781a Iustin Pop
123 13998ef2 Michael Hanselmann
124 584ea340 Michele Tartara
def _GetInstReasonFilename(instance_name):
125 a59d5fa1 Michele Tartara
  """Path of the file containing the reason of the instance status change.
126 a59d5fa1 Michele Tartara

127 a59d5fa1 Michele Tartara
  @type instance_name: string
128 a59d5fa1 Michele Tartara
  @param instance_name: The name of the instance
129 a59d5fa1 Michele Tartara
  @rtype: string
130 a59d5fa1 Michele Tartara
  @return: The path of the file
131 a59d5fa1 Michele Tartara

132 a59d5fa1 Michele Tartara
  """
133 a59d5fa1 Michele Tartara
  return utils.PathJoin(pathutils.INSTANCE_REASON_DIR, instance_name)
134 a59d5fa1 Michele Tartara
135 a59d5fa1 Michele Tartara
136 584ea340 Michele Tartara
def _StoreInstReasonTrail(instance_name, trail):
137 584ea340 Michele Tartara
  """Serialize a reason trail related to an instance change of state to file.
138 584ea340 Michele Tartara

139 584ea340 Michele Tartara
  The exact location of the file depends on the name of the instance and on
140 584ea340 Michele Tartara
  the configuration of the Ganeti cluster defined at deploy time.
141 584ea340 Michele Tartara

142 584ea340 Michele Tartara
  @type instance_name: string
143 584ea340 Michele Tartara
  @param instance_name: The name of the instance
144 3cf06dd4 Jose A. Lopes

145 3cf06dd4 Jose A. Lopes
  @type trail: list of reasons
146 3cf06dd4 Jose A. Lopes
  @param trail: reason trail
147 3cf06dd4 Jose A. Lopes

148 584ea340 Michele Tartara
  @rtype: None
149 584ea340 Michele Tartara

150 584ea340 Michele Tartara
  """
151 584ea340 Michele Tartara
  json = serializer.DumpJson(trail)
152 584ea340 Michele Tartara
  filename = _GetInstReasonFilename(instance_name)
153 584ea340 Michele Tartara
  utils.WriteFile(filename, data=json)
154 584ea340 Michele Tartara
155 584ea340 Michele Tartara
156 2cc6781a Iustin Pop
def _Fail(msg, *args, **kwargs):
157 2cc6781a Iustin Pop
  """Log an error and the raise an RPCFail exception.
158 2cc6781a Iustin Pop

159 2cc6781a Iustin Pop
  This exception is then handled specially in the ganeti daemon and
160 2cc6781a Iustin Pop
  turned into a 'failed' return type. As such, this function is a
161 2cc6781a Iustin Pop
  useful shortcut for logging the error and returning it to the master
162 2cc6781a Iustin Pop
  daemon.
163 2cc6781a Iustin Pop

164 2cc6781a Iustin Pop
  @type msg: string
165 2cc6781a Iustin Pop
  @param msg: the text of the exception
166 2cc6781a Iustin Pop
  @raise RPCFail
167 2cc6781a Iustin Pop

168 2cc6781a Iustin Pop
  """
169 2cc6781a Iustin Pop
  if args:
170 2cc6781a Iustin Pop
    msg = msg % args
171 afdc3985 Iustin Pop
  if "log" not in kwargs or kwargs["log"]: # if we should log this error
172 afdc3985 Iustin Pop
    if "exc" in kwargs and kwargs["exc"]:
173 afdc3985 Iustin Pop
      logging.exception(msg)
174 afdc3985 Iustin Pop
    else:
175 afdc3985 Iustin Pop
      logging.error(msg)
176 2cc6781a Iustin Pop
  raise RPCFail(msg)
177 2cc6781a Iustin Pop
178 2cc6781a Iustin Pop
179 c657dcc9 Michael Hanselmann
def _GetConfig():
180 93384844 Iustin Pop
  """Simple wrapper to return a SimpleStore.
181 10c2650b Iustin Pop

182 93384844 Iustin Pop
  @rtype: L{ssconf.SimpleStore}
183 93384844 Iustin Pop
  @return: a SimpleStore instance
184 10c2650b Iustin Pop

185 10c2650b Iustin Pop
  """
186 93384844 Iustin Pop
  return ssconf.SimpleStore()
187 c657dcc9 Michael Hanselmann
188 c657dcc9 Michael Hanselmann
189 62c9ec92 Iustin Pop
def _GetSshRunner(cluster_name):
190 10c2650b Iustin Pop
  """Simple wrapper to return an SshRunner.
191 10c2650b Iustin Pop

192 10c2650b Iustin Pop
  @type cluster_name: str
193 10c2650b Iustin Pop
  @param cluster_name: the cluster name, which is needed
194 10c2650b Iustin Pop
      by the SshRunner constructor
195 10c2650b Iustin Pop
  @rtype: L{ssh.SshRunner}
196 10c2650b Iustin Pop
  @return: an SshRunner instance
197 10c2650b Iustin Pop

198 10c2650b Iustin Pop
  """
199 62c9ec92 Iustin Pop
  return ssh.SshRunner(cluster_name)
200 c92b310a Michael Hanselmann
201 c92b310a Michael Hanselmann
202 12bce260 Michael Hanselmann
def _Decompress(data):
203 12bce260 Michael Hanselmann
  """Unpacks data compressed by the RPC client.
204 12bce260 Michael Hanselmann

205 12bce260 Michael Hanselmann
  @type data: list or tuple
206 12bce260 Michael Hanselmann
  @param data: Data sent by RPC client
207 12bce260 Michael Hanselmann
  @rtype: str
208 12bce260 Michael Hanselmann
  @return: Decompressed data
209 12bce260 Michael Hanselmann

210 12bce260 Michael Hanselmann
  """
211 52e2f66e Michael Hanselmann
  assert isinstance(data, (list, tuple))
212 12bce260 Michael Hanselmann
  assert len(data) == 2
213 12bce260 Michael Hanselmann
  (encoding, content) = data
214 12bce260 Michael Hanselmann
  if encoding == constants.RPC_ENCODING_NONE:
215 12bce260 Michael Hanselmann
    return content
216 12bce260 Michael Hanselmann
  elif encoding == constants.RPC_ENCODING_ZLIB_BASE64:
217 12bce260 Michael Hanselmann
    return zlib.decompress(base64.b64decode(content))
218 12bce260 Michael Hanselmann
  else:
219 12bce260 Michael Hanselmann
    raise AssertionError("Unknown data encoding")
220 12bce260 Michael Hanselmann
221 12bce260 Michael Hanselmann
222 3bc6be5c Iustin Pop
def _CleanDirectory(path, exclude=None):
223 76ab5558 Michael Hanselmann
  """Removes all regular files in a directory.
224 76ab5558 Michael Hanselmann

225 10c2650b Iustin Pop
  @type path: str
226 10c2650b Iustin Pop
  @param path: the directory to clean
227 76ab5558 Michael Hanselmann
  @type exclude: list
228 10c2650b Iustin Pop
  @param exclude: list of files to be excluded, defaults
229 10c2650b Iustin Pop
      to the empty list
230 76ab5558 Michael Hanselmann

231 76ab5558 Michael Hanselmann
  """
232 714ea7ca Iustin Pop
  if path not in _ALLOWED_CLEAN_DIRS:
233 714ea7ca Iustin Pop
    _Fail("Path passed to _CleanDirectory not in allowed clean targets: '%s'",
234 714ea7ca Iustin Pop
          path)
235 714ea7ca Iustin Pop
236 3956cee1 Michael Hanselmann
  if not os.path.isdir(path):
237 3956cee1 Michael Hanselmann
    return
238 3bc6be5c Iustin Pop
  if exclude is None:
239 3bc6be5c Iustin Pop
    exclude = []
240 3bc6be5c Iustin Pop
  else:
241 3bc6be5c Iustin Pop
    # Normalize excluded paths
242 3bc6be5c Iustin Pop
    exclude = [os.path.normpath(i) for i in exclude]
243 76ab5558 Michael Hanselmann
244 3956cee1 Michael Hanselmann
  for rel_name in utils.ListVisibleFiles(path):
245 c4feafe8 Iustin Pop
    full_name = utils.PathJoin(path, rel_name)
246 76ab5558 Michael Hanselmann
    if full_name in exclude:
247 76ab5558 Michael Hanselmann
      continue
248 3956cee1 Michael Hanselmann
    if os.path.isfile(full_name) and not os.path.islink(full_name):
249 3956cee1 Michael Hanselmann
      utils.RemoveFile(full_name)
250 3956cee1 Michael Hanselmann
251 3956cee1 Michael Hanselmann
252 360b0dc2 Iustin Pop
def _BuildUploadFileList():
253 360b0dc2 Iustin Pop
  """Build the list of allowed upload files.
254 360b0dc2 Iustin Pop

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

257 360b0dc2 Iustin Pop
  """
258 b397a7d2 Iustin Pop
  allowed_files = set([
259 710f30ec Michael Hanselmann
    pathutils.CLUSTER_CONF_FILE,
260 ee045466 Michael Hanselmann
    pathutils.ETC_HOSTS,
261 710f30ec Michael Hanselmann
    pathutils.SSH_KNOWN_HOSTS_FILE,
262 710f30ec Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
263 710f30ec Michael Hanselmann
    pathutils.RAPI_CERT_FILE,
264 710f30ec Michael Hanselmann
    pathutils.SPICE_CERT_FILE,
265 710f30ec Michael Hanselmann
    pathutils.SPICE_CACERT_FILE,
266 710f30ec Michael Hanselmann
    pathutils.RAPI_USERS_FILE,
267 710f30ec Michael Hanselmann
    pathutils.CONFD_HMAC_KEY,
268 710f30ec Michael Hanselmann
    pathutils.CLUSTER_DOMAIN_SECRET_FILE,
269 b397a7d2 Iustin Pop
    ])
270 b397a7d2 Iustin Pop
271 b397a7d2 Iustin Pop
  for hv_name in constants.HYPER_TYPES:
272 e5a45a16 Iustin Pop
    hv_class = hypervisor.GetHypervisorClass(hv_name)
273 69ab2e12 Guido Trotter
    allowed_files.update(hv_class.GetAncillaryFiles()[0])
274 b397a7d2 Iustin Pop
275 3439fd6b Michael Hanselmann
  assert pathutils.FILE_STORAGE_PATHS_FILE not in allowed_files, \
276 3439fd6b Michael Hanselmann
    "Allowed file storage paths should never be uploaded via RPC"
277 3439fd6b Michael Hanselmann
278 b397a7d2 Iustin Pop
  return frozenset(allowed_files)
279 360b0dc2 Iustin Pop
280 360b0dc2 Iustin Pop
281 360b0dc2 Iustin Pop
_ALLOWED_UPLOAD_FILES = _BuildUploadFileList()
282 360b0dc2 Iustin Pop
283 360b0dc2 Iustin Pop
284 1bc59f76 Michael Hanselmann
def JobQueuePurge():
285 10c2650b Iustin Pop
  """Removes job queue files and archived jobs.
286 10c2650b Iustin Pop

287 c8457ce7 Iustin Pop
  @rtype: tuple
288 c8457ce7 Iustin Pop
  @return: True, None
289 24fc781f Michael Hanselmann

290 24fc781f Michael Hanselmann
  """
291 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.QUEUE_DIR, exclude=[pathutils.JOB_QUEUE_LOCK_FILE])
292 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.JOB_QUEUE_ARCHIVE_DIR)
293 24fc781f Michael Hanselmann
294 24fc781f Michael Hanselmann
295 cb8028f3 Jose A. Lopes
def GetMasterNodeName():
296 cb8028f3 Jose A. Lopes
  """Returns the master node name.
297 bd1e4562 Iustin Pop

298 cb8028f3 Jose A. Lopes
  @rtype: string
299 cb8028f3 Jose A. Lopes
  @return: name of the master node
300 2a52a064 Iustin Pop
  @raise RPCFail: in case of errors
301 b1b6ea87 Iustin Pop

302 b1b6ea87 Iustin Pop
  """
303 b1b6ea87 Iustin Pop
  try:
304 cb8028f3 Jose A. Lopes
    return _GetConfig().GetMasterNode()
305 b1b6ea87 Iustin Pop
  except errors.ConfigurationError, err:
306 29921401 Iustin Pop
    _Fail("Cluster configuration incomplete: %s", err, exc=True)
307 b1b6ea87 Iustin Pop
308 b1b6ea87 Iustin Pop
309 0fa481f5 Andrea Spadaccini
def RunLocalHooks(hook_opcode, hooks_path, env_builder_fn):
310 0fa481f5 Andrea Spadaccini
  """Decorator that runs hooks before and after the decorated function.
311 0fa481f5 Andrea Spadaccini

312 0fa481f5 Andrea Spadaccini
  @type hook_opcode: string
313 0fa481f5 Andrea Spadaccini
  @param hook_opcode: opcode of the hook
314 0fa481f5 Andrea Spadaccini
  @type hooks_path: string
315 0fa481f5 Andrea Spadaccini
  @param hooks_path: path of the hooks
316 0fa481f5 Andrea Spadaccini
  @type env_builder_fn: function
317 0fa481f5 Andrea Spadaccini
  @param env_builder_fn: function that returns a dictionary containing the
318 3ccd3243 Andrea Spadaccini
    environment variables for the hooks. Will get all the parameters of the
319 3ccd3243 Andrea Spadaccini
    decorated function.
320 0fa481f5 Andrea Spadaccini
  @raise RPCFail: in case of pre-hook failure
321 0fa481f5 Andrea Spadaccini

322 0fa481f5 Andrea Spadaccini
  """
323 0fa481f5 Andrea Spadaccini
  def decorator(fn):
324 0fa481f5 Andrea Spadaccini
    def wrapper(*args, **kwargs):
325 0fa481f5 Andrea Spadaccini
      _, myself = ssconf.GetMasterAndMyself()
326 0fa481f5 Andrea Spadaccini
      nodes = ([myself], [myself])  # these hooks run locally
327 0fa481f5 Andrea Spadaccini
328 3ccd3243 Andrea Spadaccini
      env_fn = compat.partial(env_builder_fn, *args, **kwargs)
329 3ccd3243 Andrea Spadaccini
330 0fa481f5 Andrea Spadaccini
      cfg = _GetConfig()
331 0fa481f5 Andrea Spadaccini
      hr = HooksRunner()
332 68d95757 Guido Trotter
      hm = hooksmaster.HooksMaster(hook_opcode, hooks_path, nodes,
333 237a833c Thomas Thrainer
                                   hr.RunLocalHooks, None, env_fn, None,
334 68d95757 Guido Trotter
                                   logging.warning, cfg.GetClusterName(),
335 68d95757 Guido Trotter
                                   cfg.GetMasterNode())
336 0fa481f5 Andrea Spadaccini
      hm.RunPhase(constants.HOOKS_PHASE_PRE)
337 0fa481f5 Andrea Spadaccini
      result = fn(*args, **kwargs)
338 0fa481f5 Andrea Spadaccini
      hm.RunPhase(constants.HOOKS_PHASE_POST)
339 0fa481f5 Andrea Spadaccini
340 0fa481f5 Andrea Spadaccini
      return result
341 0fa481f5 Andrea Spadaccini
    return wrapper
342 0fa481f5 Andrea Spadaccini
  return decorator
343 0fa481f5 Andrea Spadaccini
344 0fa481f5 Andrea Spadaccini
345 57c7bc57 Andrea Spadaccini
def _BuildMasterIpEnv(master_params, use_external_mip_script=None):
346 2d88fdd3 Andrea Spadaccini
  """Builds environment variables for master IP hooks.
347 2d88fdd3 Andrea Spadaccini

348 3ccd3243 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
349 3ccd3243 Andrea Spadaccini
  @param master_params: network parameters of the master
350 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
351 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
352 57c7bc57 Andrea Spadaccini
    address setup script (unused, but necessary per the implementation of the
353 57c7bc57 Andrea Spadaccini
    _RunLocalHooks decorator)
354 3ccd3243 Andrea Spadaccini

355 2d88fdd3 Andrea Spadaccini
  """
356 57c7bc57 Andrea Spadaccini
  # pylint: disable=W0613
357 3ccd3243 Andrea Spadaccini
  ver = netutils.IPAddress.GetVersionFromAddressFamily(master_params.ip_family)
358 2d88fdd3 Andrea Spadaccini
  env = {
359 3ccd3243 Andrea Spadaccini
    "MASTER_NETDEV": master_params.netdev,
360 3ccd3243 Andrea Spadaccini
    "MASTER_IP": master_params.ip,
361 702eff21 Andrea Spadaccini
    "MASTER_NETMASK": str(master_params.netmask),
362 3ccd3243 Andrea Spadaccini
    "CLUSTER_IP_VERSION": str(ver),
363 2d88fdd3 Andrea Spadaccini
  }
364 2d88fdd3 Andrea Spadaccini
365 2d88fdd3 Andrea Spadaccini
  return env
366 2d88fdd3 Andrea Spadaccini
367 2d88fdd3 Andrea Spadaccini
368 702eff21 Andrea Spadaccini
def _RunMasterSetupScript(master_params, action, use_external_mip_script):
369 702eff21 Andrea Spadaccini
  """Execute the master IP address setup script.
370 702eff21 Andrea Spadaccini

371 702eff21 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
372 702eff21 Andrea Spadaccini
  @param master_params: network parameters of the master
373 702eff21 Andrea Spadaccini
  @type action: string
374 702eff21 Andrea Spadaccini
  @param action: action to pass to the script. Must be one of
375 702eff21 Andrea Spadaccini
    L{backend._MASTER_START} or L{backend._MASTER_STOP}
376 702eff21 Andrea Spadaccini
  @type use_external_mip_script: boolean
377 702eff21 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
378 702eff21 Andrea Spadaccini
    address setup script
379 702eff21 Andrea Spadaccini
  @raise backend.RPCFail: if there are errors during the execution of the
380 702eff21 Andrea Spadaccini
    script
381 702eff21 Andrea Spadaccini

382 702eff21 Andrea Spadaccini
  """
383 702eff21 Andrea Spadaccini
  env = _BuildMasterIpEnv(master_params)
384 702eff21 Andrea Spadaccini
385 702eff21 Andrea Spadaccini
  if use_external_mip_script:
386 710f30ec Michael Hanselmann
    setup_script = pathutils.EXTERNAL_MASTER_SETUP_SCRIPT
387 702eff21 Andrea Spadaccini
  else:
388 710f30ec Michael Hanselmann
    setup_script = pathutils.DEFAULT_MASTER_SETUP_SCRIPT
389 702eff21 Andrea Spadaccini
390 702eff21 Andrea Spadaccini
  result = utils.RunCmd([setup_script, action], env=env, reset_env=True)
391 702eff21 Andrea Spadaccini
392 702eff21 Andrea Spadaccini
  if result.failed:
393 19e1b715 Iustin Pop
    _Fail("Failed to %s the master IP. Script return value: %s, output: '%s'" %
394 19e1b715 Iustin Pop
          (action, result.exit_code, result.output), log=True)
395 702eff21 Andrea Spadaccini
396 702eff21 Andrea Spadaccini
397 2d88fdd3 Andrea Spadaccini
@RunLocalHooks(constants.FAKE_OP_MASTER_TURNUP, "master-ip-turnup",
398 3a3e4f1e Andrea Spadaccini
               _BuildMasterIpEnv)
399 57c7bc57 Andrea Spadaccini
def ActivateMasterIp(master_params, use_external_mip_script):
400 fb460cf7 Andrea Spadaccini
  """Activate the IP address of the master daemon.
401 fb460cf7 Andrea Spadaccini

402 c79198a0 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
403 c79198a0 Andrea Spadaccini
  @param master_params: network parameters of the master
404 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
405 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
406 57c7bc57 Andrea Spadaccini
    address setup script
407 702eff21 Andrea Spadaccini
  @raise RPCFail: in case of errors during the IP startup
408 8da2bd43 Andrea Spadaccini

409 fb460cf7 Andrea Spadaccini
  """
410 702eff21 Andrea Spadaccini
  _RunMasterSetupScript(master_params, _MASTER_START,
411 702eff21 Andrea Spadaccini
                        use_external_mip_script)
412 fb460cf7 Andrea Spadaccini
413 fb460cf7 Andrea Spadaccini
414 fb460cf7 Andrea Spadaccini
def StartMasterDaemons(no_voting):
415 a8083063 Iustin Pop
  """Activate local node as master node.
416 a8083063 Iustin Pop

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

419 3583908a Guido Trotter
  @type no_voting: boolean
420 3583908a Guido Trotter
  @param no_voting: whether to start ganeti-masterd without a node vote
421 fb460cf7 Andrea Spadaccini
      but still non-interactively
422 10c2650b Iustin Pop
  @rtype: None
423 a8083063 Iustin Pop

424 a8083063 Iustin Pop
  """
425 a8083063 Iustin Pop
426 fb460cf7 Andrea Spadaccini
  if no_voting:
427 fb460cf7 Andrea Spadaccini
    masterd_args = "--no-voting --yes-do-it"
428 fb460cf7 Andrea Spadaccini
  else:
429 fb460cf7 Andrea Spadaccini
    masterd_args = ""
430 f154a7a3 Michael Hanselmann
431 fb460cf7 Andrea Spadaccini
  env = {
432 fb460cf7 Andrea Spadaccini
    "EXTRA_MASTERD_ARGS": masterd_args,
433 fb460cf7 Andrea Spadaccini
    }
434 fb460cf7 Andrea Spadaccini
435 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "start-master"], env=env)
436 fb460cf7 Andrea Spadaccini
  if result.failed:
437 fb460cf7 Andrea Spadaccini
    msg = "Can't start Ganeti master: %s" % result.output
438 fb460cf7 Andrea Spadaccini
    logging.error(msg)
439 fb460cf7 Andrea Spadaccini
    _Fail(msg)
440 f154a7a3 Michael Hanselmann
441 fb460cf7 Andrea Spadaccini
442 2d88fdd3 Andrea Spadaccini
@RunLocalHooks(constants.FAKE_OP_MASTER_TURNDOWN, "master-ip-turndown",
443 3a3e4f1e Andrea Spadaccini
               _BuildMasterIpEnv)
444 57c7bc57 Andrea Spadaccini
def DeactivateMasterIp(master_params, use_external_mip_script):
445 fb460cf7 Andrea Spadaccini
  """Deactivate the master IP on this node.
446 a8083063 Iustin Pop

447 c79198a0 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
448 c79198a0 Andrea Spadaccini
  @param master_params: network parameters of the master
449 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
450 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
451 57c7bc57 Andrea Spadaccini
    address setup script
452 702eff21 Andrea Spadaccini
  @raise RPCFail: in case of errors during the IP turndown
453 96e0d5cc Andrea Spadaccini

454 a8083063 Iustin Pop
  """
455 702eff21 Andrea Spadaccini
  _RunMasterSetupScript(master_params, _MASTER_STOP,
456 702eff21 Andrea Spadaccini
                        use_external_mip_script)
457 b1b6ea87 Iustin Pop
458 fb460cf7 Andrea Spadaccini
459 fb460cf7 Andrea Spadaccini
def StopMasterDaemons():
460 fb460cf7 Andrea Spadaccini
  """Stop the master daemons on this node.
461 fb460cf7 Andrea Spadaccini

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

464 fb460cf7 Andrea Spadaccini
  @rtype: None
465 fb460cf7 Andrea Spadaccini

466 fb460cf7 Andrea Spadaccini
  """
467 fb460cf7 Andrea Spadaccini
  # TODO: log and report back to the caller the error failures; we
468 fb460cf7 Andrea Spadaccini
  # need to decide in which case we fail the RPC for this
469 fb460cf7 Andrea Spadaccini
470 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop-master"])
471 fb460cf7 Andrea Spadaccini
  if result.failed:
472 fb460cf7 Andrea Spadaccini
    logging.error("Could not stop Ganeti master, command %s had exitcode %s"
473 fb460cf7 Andrea Spadaccini
                  " and error %s",
474 fb460cf7 Andrea Spadaccini
                  result.cmd, result.exit_code, result.output)
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
477 41e079ce Andrea Spadaccini
def ChangeMasterNetmask(old_netmask, netmask, master_ip, master_netdev):
478 5a8648eb Andrea Spadaccini
  """Change the netmask of the master IP.
479 5a8648eb Andrea Spadaccini

480 41e079ce Andrea Spadaccini
  @param old_netmask: the old value of the netmask
481 41e079ce Andrea Spadaccini
  @param netmask: the new value of the netmask
482 41e079ce Andrea Spadaccini
  @param master_ip: the master IP
483 41e079ce Andrea Spadaccini
  @param master_netdev: the master network device
484 41e079ce Andrea Spadaccini

485 5a8648eb Andrea Spadaccini
  """
486 5a8648eb Andrea Spadaccini
  if old_netmask == netmask:
487 5a8648eb Andrea Spadaccini
    return
488 5a8648eb Andrea Spadaccini
489 9e6014b9 Andrea Spadaccini
  if not netutils.IPAddress.Own(master_ip):
490 9e6014b9 Andrea Spadaccini
    _Fail("The master IP address is not up, not attempting to change its"
491 9e6014b9 Andrea Spadaccini
          " netmask")
492 9e6014b9 Andrea Spadaccini
493 5a8648eb Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
494 5a8648eb Andrea Spadaccini
                         "%s/%s" % (master_ip, netmask),
495 5a8648eb Andrea Spadaccini
                         "dev", master_netdev, "label",
496 5a8648eb Andrea Spadaccini
                         "%s:0" % master_netdev])
497 5a8648eb Andrea Spadaccini
  if result.failed:
498 9e6014b9 Andrea Spadaccini
    _Fail("Could not set the new netmask on the master IP address")
499 5a8648eb Andrea Spadaccini
500 5a8648eb Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
501 5a8648eb Andrea Spadaccini
                         "%s/%s" % (master_ip, old_netmask),
502 5a8648eb Andrea Spadaccini
                         "dev", master_netdev, "label",
503 5a8648eb Andrea Spadaccini
                         "%s:0" % master_netdev])
504 5a8648eb Andrea Spadaccini
  if result.failed:
505 9e6014b9 Andrea Spadaccini
    _Fail("Could not bring down the master IP address with the old netmask")
506 5a8648eb Andrea Spadaccini
507 5a8648eb Andrea Spadaccini
508 19ddc57a René Nussbaumer
def EtcHostsModify(mode, host, ip):
509 19ddc57a René Nussbaumer
  """Modify a host entry in /etc/hosts.
510 19ddc57a René Nussbaumer

511 19ddc57a René Nussbaumer
  @param mode: The mode to operate. Either add or remove entry
512 19ddc57a René Nussbaumer
  @param host: The host to operate on
513 19ddc57a René Nussbaumer
  @param ip: The ip associated with the entry
514 19ddc57a René Nussbaumer

515 19ddc57a René Nussbaumer
  """
516 19ddc57a René Nussbaumer
  if mode == constants.ETC_HOSTS_ADD:
517 19ddc57a René Nussbaumer
    if not ip:
518 19ddc57a René Nussbaumer
      RPCFail("Mode 'add' needs 'ip' parameter, but parameter not"
519 19ddc57a René Nussbaumer
              " present")
520 19ddc57a René Nussbaumer
    utils.AddHostToEtcHosts(host, ip)
521 19ddc57a René Nussbaumer
  elif mode == constants.ETC_HOSTS_REMOVE:
522 19ddc57a René Nussbaumer
    if ip:
523 19ddc57a René Nussbaumer
      RPCFail("Mode 'remove' does not allow 'ip' parameter, but"
524 19ddc57a René Nussbaumer
              " parameter is present")
525 19ddc57a René Nussbaumer
    utils.RemoveHostFromEtcHosts(host)
526 19ddc57a René Nussbaumer
  else:
527 19ddc57a René Nussbaumer
    RPCFail("Mode not supported")
528 19ddc57a René Nussbaumer
529 19ddc57a René Nussbaumer
530 b989b9d9 Ken Wehr
def LeaveCluster(modify_ssh_setup):
531 10c2650b Iustin Pop
  """Cleans up and remove the current node.
532 10c2650b Iustin Pop

533 10c2650b Iustin Pop
  This function cleans up and prepares the current node to be removed
534 10c2650b Iustin Pop
  from the cluster.
535 10c2650b Iustin Pop

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

540 b989b9d9 Ken Wehr
  @param modify_ssh_setup: boolean
541 b989b9d9 Ken Wehr

542 a8083063 Iustin Pop
  """
543 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.DATA_DIR)
544 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.CRYPTO_KEYS_DIR)
545 1bc59f76 Michael Hanselmann
  JobQueuePurge()
546 f78346f5 Michael Hanselmann
547 b989b9d9 Ken Wehr
  if modify_ssh_setup:
548 b989b9d9 Ken Wehr
    try:
549 052783ff Michael Hanselmann
      priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.SSH_LOGIN_USER)
550 7900ed01 Iustin Pop
551 b989b9d9 Ken Wehr
      utils.RemoveAuthorizedKey(auth_keys, utils.ReadFile(pub_key))
552 a8083063 Iustin Pop
553 b989b9d9 Ken Wehr
      utils.RemoveFile(priv_key)
554 b989b9d9 Ken Wehr
      utils.RemoveFile(pub_key)
555 b989b9d9 Ken Wehr
    except errors.OpExecError:
556 b989b9d9 Ken Wehr
      logging.exception("Error while processing ssh files")
557 a8083063 Iustin Pop
558 ed008420 Guido Trotter
  try:
559 710f30ec Michael Hanselmann
    utils.RemoveFile(pathutils.CONFD_HMAC_KEY)
560 710f30ec Michael Hanselmann
    utils.RemoveFile(pathutils.RAPI_CERT_FILE)
561 710f30ec Michael Hanselmann
    utils.RemoveFile(pathutils.SPICE_CERT_FILE)
562 710f30ec Michael Hanselmann
    utils.RemoveFile(pathutils.SPICE_CACERT_FILE)
563 710f30ec Michael Hanselmann
    utils.RemoveFile(pathutils.NODED_CERT_FILE)
564 b459a848 Andrea Spadaccini
  except: # pylint: disable=W0702
565 ed008420 Guido Trotter
    logging.exception("Error while removing cluster secrets")
566 ed008420 Guido Trotter
567 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "stop", constants.CONFD])
568 f154a7a3 Michael Hanselmann
  if result.failed:
569 f154a7a3 Michael Hanselmann
    logging.error("Command %s failed with exitcode %s and error %s",
570 f154a7a3 Michael Hanselmann
                  result.cmd, result.exit_code, result.output)
571 ed008420 Guido Trotter
572 0623d351 Iustin Pop
  # Raise a custom exception (handled in ganeti-noded)
573 d0c8c01d Iustin Pop
  raise errors.QuitGanetiException(True, "Shutdown scheduled")
574 6d8b6238 Guido Trotter
575 a8083063 Iustin Pop
576 b01b7a50 Helga Velroyen
def _CheckStorageParams(params, num_params):
577 b01b7a50 Helga Velroyen
  """Performs sanity checks for storage parameters.
578 b01b7a50 Helga Velroyen

579 b01b7a50 Helga Velroyen
  @type params: list
580 b01b7a50 Helga Velroyen
  @param params: list of storage parameters
581 b01b7a50 Helga Velroyen
  @type num_params: int
582 b01b7a50 Helga Velroyen
  @param num_params: expected number of parameters
583 b01b7a50 Helga Velroyen

584 b01b7a50 Helga Velroyen
  """
585 b01b7a50 Helga Velroyen
  if params is None:
586 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("No storage parameters for storage"
587 b01b7a50 Helga Velroyen
                                 " reporting is provided.")
588 b01b7a50 Helga Velroyen
  if not isinstance(params, list):
589 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("The storage parameters are not of type"
590 b01b7a50 Helga Velroyen
                                 " list: '%s'" % params)
591 b01b7a50 Helga Velroyen
  if not len(params) == num_params:
592 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("Did not receive the expected number of"
593 b01b7a50 Helga Velroyen
                                 "storage parameters: expected %s,"
594 b01b7a50 Helga Velroyen
                                 " received '%s'" % (num_params, len(params)))
595 b01b7a50 Helga Velroyen
596 b01b7a50 Helga Velroyen
597 3c8a599a Helga Velroyen
def _CheckLvmStorageParams(params):
598 3c8a599a Helga Velroyen
  """Performs sanity check for the 'exclusive storage' flag.
599 3c8a599a Helga Velroyen

600 3c8a599a Helga Velroyen
  @see: C{_CheckStorageParams}
601 3c8a599a Helga Velroyen

602 3c8a599a Helga Velroyen
  """
603 3c8a599a Helga Velroyen
  _CheckStorageParams(params, 1)
604 3c8a599a Helga Velroyen
  excl_stor = params[0]
605 3c8a599a Helga Velroyen
  if not isinstance(params[0], bool):
606 3c8a599a Helga Velroyen
    raise errors.ProgrammerError("Exclusive storage parameter is not"
607 3c8a599a Helga Velroyen
                                 " boolean: '%s'." % excl_stor)
608 3c8a599a Helga Velroyen
  return excl_stor
609 3c8a599a Helga Velroyen
610 3c8a599a Helga Velroyen
611 52a8a6ae Helga Velroyen
def _GetLvmVgSpaceInfo(name, params):
612 52a8a6ae Helga Velroyen
  """Wrapper around C{_GetVgInfo} which checks the storage parameters.
613 52a8a6ae Helga Velroyen

614 52a8a6ae Helga Velroyen
  @type name: string
615 52a8a6ae Helga Velroyen
  @param name: name of the volume group
616 52a8a6ae Helga Velroyen
  @type params: list
617 52a8a6ae Helga Velroyen
  @param params: list of storage parameters, which in this case should be
618 52a8a6ae Helga Velroyen
    containing only one for exclusive storage
619 52a8a6ae Helga Velroyen

620 52a8a6ae Helga Velroyen
  """
621 3c8a599a Helga Velroyen
  excl_stor = _CheckLvmStorageParams(params)
622 52a8a6ae Helga Velroyen
  return _GetVgInfo(name, excl_stor)
623 52a8a6ae Helga Velroyen
624 52a8a6ae Helga Velroyen
625 3f73b3ae Helga Velroyen
def _GetVgInfo(
626 3f73b3ae Helga Velroyen
    name, excl_stor, info_fn=bdev.LogicalVolume.GetVGInfo):
627 78519c10 Michael Hanselmann
  """Retrieves information about a LVM volume group.
628 78519c10 Michael Hanselmann

629 78519c10 Michael Hanselmann
  """
630 78519c10 Michael Hanselmann
  # TODO: GetVGInfo supports returning information for multiple VGs at once
631 3f73b3ae Helga Velroyen
  vginfo = info_fn([name], excl_stor)
632 78519c10 Michael Hanselmann
  if vginfo:
633 78519c10 Michael Hanselmann
    vg_free = int(round(vginfo[0][0], 0))
634 78519c10 Michael Hanselmann
    vg_size = int(round(vginfo[0][1], 0))
635 78519c10 Michael Hanselmann
  else:
636 78519c10 Michael Hanselmann
    vg_free = None
637 78519c10 Michael Hanselmann
    vg_size = None
638 78519c10 Michael Hanselmann
639 78519c10 Michael Hanselmann
  return {
640 0f0f6d7d Helga Velroyen
    "type": constants.ST_LVM_VG,
641 78519c10 Michael Hanselmann
    "name": name,
642 32389d91 Helga Velroyen
    "storage_free": vg_free,
643 32389d91 Helga Velroyen
    "storage_size": vg_size,
644 78519c10 Michael Hanselmann
    }
645 78519c10 Michael Hanselmann
646 78519c10 Michael Hanselmann
647 3c8a599a Helga Velroyen
def _GetLvmPvSpaceInfo(name, params):
648 3c8a599a Helga Velroyen
  """Wrapper around C{_GetVgSpindlesInfo} with sanity checks.
649 3c8a599a Helga Velroyen

650 a18ab868 Helga Velroyen
  @see: C{_GetLvmVgSpaceInfo}
651 3c8a599a Helga Velroyen

652 3c8a599a Helga Velroyen
  """
653 3c8a599a Helga Velroyen
  excl_stor = _CheckLvmStorageParams(params)
654 3c8a599a Helga Velroyen
  return _GetVgSpindlesInfo(name, excl_stor)
655 3f73b3ae Helga Velroyen
656 3c8a599a Helga Velroyen
657 a18ab868 Helga Velroyen
def _GetVgSpindlesInfo(
658 a18ab868 Helga Velroyen
    name, excl_stor, info_fn=bdev.LogicalVolume.GetVgSpindlesInfo):
659 a1860404 Bernardo Dal Seno
  """Retrieves information about spindles in an LVM volume group.
660 a1860404 Bernardo Dal Seno

661 a1860404 Bernardo Dal Seno
  @type name: string
662 a1860404 Bernardo Dal Seno
  @param name: VG name
663 a1860404 Bernardo Dal Seno
  @type excl_stor: bool
664 a1860404 Bernardo Dal Seno
  @param excl_stor: exclusive storage
665 a1860404 Bernardo Dal Seno
  @rtype: dict
666 a1860404 Bernardo Dal Seno
  @return: dictionary whose keys are "name", "vg_free", "vg_size" for VG name,
667 a1860404 Bernardo Dal Seno
      free spindles, total spindles respectively
668 a1860404 Bernardo Dal Seno

669 a1860404 Bernardo Dal Seno
  """
670 a1860404 Bernardo Dal Seno
  if excl_stor:
671 a18ab868 Helga Velroyen
    (vg_free, vg_size) = info_fn(name)
672 a1860404 Bernardo Dal Seno
  else:
673 a1860404 Bernardo Dal Seno
    vg_free = 0
674 a1860404 Bernardo Dal Seno
    vg_size = 0
675 a1860404 Bernardo Dal Seno
  return {
676 0f0f6d7d Helga Velroyen
    "type": constants.ST_LVM_PV,
677 a1860404 Bernardo Dal Seno
    "name": name,
678 32389d91 Helga Velroyen
    "storage_free": vg_free,
679 32389d91 Helga Velroyen
    "storage_size": vg_size,
680 a1860404 Bernardo Dal Seno
    }
681 a1860404 Bernardo Dal Seno
682 a1860404 Bernardo Dal Seno
683 439e1d3f Helga Velroyen
def _GetHvInfo(name, hvparams, get_hv_fn=hypervisor.GetHypervisor):
684 78519c10 Michael Hanselmann
  """Retrieves node information from a hypervisor.
685 78519c10 Michael Hanselmann

686 78519c10 Michael Hanselmann
  The information returned depends on the hypervisor. Common items:
687 78519c10 Michael Hanselmann

688 78519c10 Michael Hanselmann
    - vg_size is the size of the configured volume group in MiB
689 78519c10 Michael Hanselmann
    - vg_free is the free size of the volume group in MiB
690 78519c10 Michael Hanselmann
    - memory_dom0 is the memory allocated for domain0 in MiB
691 78519c10 Michael Hanselmann
    - memory_free is the currently available (free) ram in MiB
692 78519c10 Michael Hanselmann
    - memory_total is the total number of ram in MiB
693 78519c10 Michael Hanselmann
    - hv_version: the hypervisor version, if available
694 78519c10 Michael Hanselmann

695 439e1d3f Helga Velroyen
  @type hvparams: dict of string
696 439e1d3f Helga Velroyen
  @param hvparams: the hypervisor's hvparams
697 439e1d3f Helga Velroyen

698 78519c10 Michael Hanselmann
  """
699 439e1d3f Helga Velroyen
  return get_hv_fn(name).GetNodeInfo(hvparams=hvparams)
700 439e1d3f Helga Velroyen
701 439e1d3f Helga Velroyen
702 439e1d3f Helga Velroyen
def _GetHvInfoAll(hv_specs, get_hv_fn=hypervisor.GetHypervisor):
703 439e1d3f Helga Velroyen
  """Retrieves node information for all hypervisors.
704 439e1d3f Helga Velroyen

705 439e1d3f Helga Velroyen
  See C{_GetHvInfo} for information on the output.
706 439e1d3f Helga Velroyen

707 439e1d3f Helga Velroyen
  @type hv_specs: list of pairs (string, dict of strings)
708 439e1d3f Helga Velroyen
  @param hv_specs: list of pairs of a hypervisor's name and its hvparams
709 439e1d3f Helga Velroyen

710 439e1d3f Helga Velroyen
  """
711 439e1d3f Helga Velroyen
  if hv_specs is None:
712 439e1d3f Helga Velroyen
    return None
713 439e1d3f Helga Velroyen
714 439e1d3f Helga Velroyen
  result = []
715 439e1d3f Helga Velroyen
  for hvname, hvparams in hv_specs:
716 439e1d3f Helga Velroyen
    result.append(_GetHvInfo(hvname, hvparams, get_hv_fn))
717 439e1d3f Helga Velroyen
  return result
718 78519c10 Michael Hanselmann
719 78519c10 Michael Hanselmann
720 78519c10 Michael Hanselmann
def _GetNamedNodeInfo(names, fn):
721 78519c10 Michael Hanselmann
  """Calls C{fn} for all names in C{names} and returns a dictionary.
722 78519c10 Michael Hanselmann

723 78519c10 Michael Hanselmann
  @rtype: None or dict
724 78519c10 Michael Hanselmann

725 78519c10 Michael Hanselmann
  """
726 78519c10 Michael Hanselmann
  if names is None:
727 78519c10 Michael Hanselmann
    return None
728 78519c10 Michael Hanselmann
  else:
729 ff3be305 Michael Hanselmann
    return map(fn, names)
730 78519c10 Michael Hanselmann
731 78519c10 Michael Hanselmann
732 152759e4 Helga Velroyen
def GetNodeInfo(storage_units, hv_specs):
733 5bbd3f7f Michael Hanselmann
  """Gives back a hash with different information about the node.
734 a8083063 Iustin Pop

735 152759e4 Helga Velroyen
  @type storage_units: list of tuples (string, string, list)
736 152759e4 Helga Velroyen
  @param storage_units: List of tuples (storage unit, identifier, parameters) to
737 152759e4 Helga Velroyen
    ask for disk space information. In case of lvm-vg, the identifier is
738 152759e4 Helga Velroyen
    the VG name. The parameters can contain additional, storage-type-specific
739 152759e4 Helga Velroyen
    parameters, for example exclusive storage for lvm storage.
740 439e1d3f Helga Velroyen
  @type hv_specs: list of pairs (string, dict of strings)
741 439e1d3f Helga Velroyen
  @param hv_specs: list of pairs of a hypervisor's name and its hvparams
742 78519c10 Michael Hanselmann
  @rtype: tuple; (string, None/dict, None/dict)
743 78519c10 Michael Hanselmann
  @return: Tuple containing boot ID, volume group information and hypervisor
744 78519c10 Michael Hanselmann
    information
745 a8083063 Iustin Pop

746 098c0958 Michael Hanselmann
  """
747 78519c10 Michael Hanselmann
  bootid = utils.ReadFile(_BOOT_ID_PATH, size=128).rstrip("\n")
748 4b92e992 Helga Velroyen
  storage_info = _GetNamedNodeInfo(
749 4b92e992 Helga Velroyen
    storage_units,
750 152759e4 Helga Velroyen
    (lambda (storage_type, storage_key, storage_params):
751 152759e4 Helga Velroyen
        _ApplyStorageInfoFunction(storage_type, storage_key, storage_params)))
752 439e1d3f Helga Velroyen
  hv_info = _GetHvInfoAll(hv_specs)
753 4b92e992 Helga Velroyen
  return (bootid, storage_info, hv_info)
754 4b92e992 Helga Velroyen
755 4b92e992 Helga Velroyen
756 b01b7a50 Helga Velroyen
def _GetFileStorageSpaceInfo(path, params):
757 13669ecd Helga Velroyen
  """Wrapper around filestorage.GetSpaceInfo.
758 13669ecd Helga Velroyen

759 13669ecd Helga Velroyen
  The purpose of this wrapper is to call filestorage.GetFileStorageSpaceInfo
760 13669ecd Helga Velroyen
  and ignore the *args parameter to not leak it into the filestorage
761 13669ecd Helga Velroyen
  module's code.
762 13669ecd Helga Velroyen

763 13669ecd Helga Velroyen
  @see: C{filestorage.GetFileStorageSpaceInfo} for description of the
764 13669ecd Helga Velroyen
    parameters.
765 13669ecd Helga Velroyen

766 13669ecd Helga Velroyen
  """
767 b01b7a50 Helga Velroyen
  _CheckStorageParams(params, 0)
768 13669ecd Helga Velroyen
  return filestorage.GetFileStorageSpaceInfo(path)
769 13669ecd Helga Velroyen
770 13669ecd Helga Velroyen
771 4b92e992 Helga Velroyen
# FIXME: implement storage reporting for all missing storage types.
772 4b92e992 Helga Velroyen
_STORAGE_TYPE_INFO_FN = {
773 4b92e992 Helga Velroyen
  constants.ST_BLOCK: None,
774 4b92e992 Helga Velroyen
  constants.ST_DISKLESS: None,
775 4b92e992 Helga Velroyen
  constants.ST_EXT: None,
776 13669ecd Helga Velroyen
  constants.ST_FILE: _GetFileStorageSpaceInfo,
777 3c8a599a Helga Velroyen
  constants.ST_LVM_PV: _GetLvmPvSpaceInfo,
778 52a8a6ae Helga Velroyen
  constants.ST_LVM_VG: _GetLvmVgSpaceInfo,
779 5a904197 Santi Raffa
  constants.ST_SHARED_FILE: None,
780 4b92e992 Helga Velroyen
  constants.ST_RADOS: None,
781 4b92e992 Helga Velroyen
}
782 4b92e992 Helga Velroyen
783 4b92e992 Helga Velroyen
784 4b92e992 Helga Velroyen
def _ApplyStorageInfoFunction(storage_type, storage_key, *args):
785 4b92e992 Helga Velroyen
  """Looks up and applies the correct function to calculate free and total
786 4b92e992 Helga Velroyen
  storage for the given storage type.
787 4b92e992 Helga Velroyen

788 4b92e992 Helga Velroyen
  @type storage_type: string
789 4b92e992 Helga Velroyen
  @param storage_type: the storage type for which the storage shall be reported.
790 4b92e992 Helga Velroyen
  @type storage_key: string
791 4b92e992 Helga Velroyen
  @param storage_key: identifier of a storage unit, e.g. the volume group name
792 4b92e992 Helga Velroyen
    of an LVM storage unit
793 4b92e992 Helga Velroyen
  @type args: any
794 4b92e992 Helga Velroyen
  @param args: various parameters that can be used for storage reporting. These
795 4b92e992 Helga Velroyen
    parameters and their semantics vary from storage type to storage type and
796 4b92e992 Helga Velroyen
    are just propagated in this function.
797 4b92e992 Helga Velroyen
  @return: the results of the application of the storage space function (see
798 4b92e992 Helga Velroyen
    _STORAGE_TYPE_INFO_FN) if storage space reporting is implemented for that
799 4b92e992 Helga Velroyen
    storage type
800 4b92e992 Helga Velroyen
  @raises NotImplementedError: for storage types who don't support space
801 4b92e992 Helga Velroyen
    reporting yet
802 4b92e992 Helga Velroyen
  """
803 4b92e992 Helga Velroyen
  fn = _STORAGE_TYPE_INFO_FN[storage_type]
804 4b92e992 Helga Velroyen
  if fn is not None:
805 4b92e992 Helga Velroyen
    return fn(storage_key, *args)
806 4b92e992 Helga Velroyen
  else:
807 4b92e992 Helga Velroyen
    raise NotImplementedError
808 a8083063 Iustin Pop
809 a8083063 Iustin Pop
810 d5a690cb Bernardo Dal Seno
def _CheckExclusivePvs(pvi_list):
811 d5a690cb Bernardo Dal Seno
  """Check that PVs are not shared among LVs
812 d5a690cb Bernardo Dal Seno

813 d5a690cb Bernardo Dal Seno
  @type pvi_list: list of L{objects.LvmPvInfo} objects
814 d5a690cb Bernardo Dal Seno
  @param pvi_list: information about the PVs
815 d5a690cb Bernardo Dal Seno

816 d5a690cb Bernardo Dal Seno
  @rtype: list of tuples (string, list of strings)
817 d5a690cb Bernardo Dal Seno
  @return: offending volumes, as tuples: (pv_name, [lv1_name, lv2_name...])
818 d5a690cb Bernardo Dal Seno

819 d5a690cb Bernardo Dal Seno
  """
820 d5a690cb Bernardo Dal Seno
  res = []
821 d5a690cb Bernardo Dal Seno
  for pvi in pvi_list:
822 d5a690cb Bernardo Dal Seno
    if len(pvi.lv_list) > 1:
823 d5a690cb Bernardo Dal Seno
      res.append((pvi.name, pvi.lv_list))
824 d5a690cb Bernardo Dal Seno
  return res
825 d5a690cb Bernardo Dal Seno
826 d5a690cb Bernardo Dal Seno
827 75bf3149 Helga Velroyen
def _VerifyHypervisors(what, vm_capable, result, all_hvparams,
828 75bf3149 Helga Velroyen
                       get_hv_fn=hypervisor.GetHypervisor):
829 75bf3149 Helga Velroyen
  """Verifies the hypervisor. Appends the results to the 'results' list.
830 75bf3149 Helga Velroyen

831 75bf3149 Helga Velroyen
  @type what: C{dict}
832 75bf3149 Helga Velroyen
  @param what: a dictionary of things to check
833 75bf3149 Helga Velroyen
  @type vm_capable: boolean
834 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
835 75bf3149 Helga Velroyen
  @type result: dict
836 75bf3149 Helga Velroyen
  @param result: dictionary of verification results; results of the
837 75bf3149 Helga Velroyen
    verifications in this function will be added here
838 75bf3149 Helga Velroyen
  @type all_hvparams: dict of dict of string
839 75bf3149 Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
840 75bf3149 Helga Velroyen
  @type get_hv_fn: function
841 75bf3149 Helga Velroyen
  @param get_hv_fn: function to retrieve the hypervisor, to improve testability
842 75bf3149 Helga Velroyen

843 75bf3149 Helga Velroyen
  """
844 75bf3149 Helga Velroyen
  if not vm_capable:
845 75bf3149 Helga Velroyen
    return
846 75bf3149 Helga Velroyen
847 75bf3149 Helga Velroyen
  if constants.NV_HYPERVISOR in what:
848 75bf3149 Helga Velroyen
    result[constants.NV_HYPERVISOR] = {}
849 75bf3149 Helga Velroyen
    for hv_name in what[constants.NV_HYPERVISOR]:
850 75bf3149 Helga Velroyen
      hvparams = all_hvparams[hv_name]
851 75bf3149 Helga Velroyen
      try:
852 75bf3149 Helga Velroyen
        val = get_hv_fn(hv_name).Verify(hvparams=hvparams)
853 75bf3149 Helga Velroyen
      except errors.HypervisorError, err:
854 75bf3149 Helga Velroyen
        val = "Error while checking hypervisor: %s" % str(err)
855 75bf3149 Helga Velroyen
      result[constants.NV_HYPERVISOR][hv_name] = val
856 75bf3149 Helga Velroyen
857 75bf3149 Helga Velroyen
858 75bf3149 Helga Velroyen
def _VerifyHvparams(what, vm_capable, result,
859 75bf3149 Helga Velroyen
                    get_hv_fn=hypervisor.GetHypervisor):
860 75bf3149 Helga Velroyen
  """Verifies the hvparams. Appends the results to the 'results' list.
861 75bf3149 Helga Velroyen

862 75bf3149 Helga Velroyen
  @type what: C{dict}
863 75bf3149 Helga Velroyen
  @param what: a dictionary of things to check
864 75bf3149 Helga Velroyen
  @type vm_capable: boolean
865 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
866 75bf3149 Helga Velroyen
  @type result: dict
867 75bf3149 Helga Velroyen
  @param result: dictionary of verification results; results of the
868 75bf3149 Helga Velroyen
    verifications in this function will be added here
869 75bf3149 Helga Velroyen
  @type get_hv_fn: function
870 75bf3149 Helga Velroyen
  @param get_hv_fn: function to retrieve the hypervisor, to improve testability
871 75bf3149 Helga Velroyen

872 75bf3149 Helga Velroyen
  """
873 75bf3149 Helga Velroyen
  if not vm_capable:
874 75bf3149 Helga Velroyen
    return
875 75bf3149 Helga Velroyen
876 75bf3149 Helga Velroyen
  if constants.NV_HVPARAMS in what:
877 75bf3149 Helga Velroyen
    result[constants.NV_HVPARAMS] = []
878 75bf3149 Helga Velroyen
    for source, hv_name, hvparms in what[constants.NV_HVPARAMS]:
879 75bf3149 Helga Velroyen
      try:
880 75bf3149 Helga Velroyen
        logging.info("Validating hv %s, %s", hv_name, hvparms)
881 75bf3149 Helga Velroyen
        get_hv_fn(hv_name).ValidateParameters(hvparms)
882 75bf3149 Helga Velroyen
      except errors.HypervisorError, err:
883 75bf3149 Helga Velroyen
        result[constants.NV_HVPARAMS].append((source, hv_name, str(err)))
884 75bf3149 Helga Velroyen
885 75bf3149 Helga Velroyen
886 5b0dfcef Helga Velroyen
def _VerifyInstanceList(what, vm_capable, result, all_hvparams):
887 5b0dfcef Helga Velroyen
  """Verifies the instance list.
888 5b0dfcef Helga Velroyen

889 5b0dfcef Helga Velroyen
  @type what: C{dict}
890 5b0dfcef Helga Velroyen
  @param what: a dictionary of things to check
891 5b0dfcef Helga Velroyen
  @type vm_capable: boolean
892 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
893 5b0dfcef Helga Velroyen
  @type result: dict
894 5b0dfcef Helga Velroyen
  @param result: dictionary of verification results; results of the
895 5b0dfcef Helga Velroyen
    verifications in this function will be added here
896 5b0dfcef Helga Velroyen
  @type all_hvparams: dict of dict of string
897 5b0dfcef Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
898 5b0dfcef Helga Velroyen

899 5b0dfcef Helga Velroyen
  """
900 5b0dfcef Helga Velroyen
  if constants.NV_INSTANCELIST in what and vm_capable:
901 5b0dfcef Helga Velroyen
    # GetInstanceList can fail
902 5b0dfcef Helga Velroyen
    try:
903 5b0dfcef Helga Velroyen
      val = GetInstanceList(what[constants.NV_INSTANCELIST],
904 5b0dfcef Helga Velroyen
                            all_hvparams=all_hvparams)
905 5b0dfcef Helga Velroyen
    except RPCFail, err:
906 5b0dfcef Helga Velroyen
      val = str(err)
907 5b0dfcef Helga Velroyen
    result[constants.NV_INSTANCELIST] = val
908 5b0dfcef Helga Velroyen
909 5b0dfcef Helga Velroyen
910 5b0dfcef Helga Velroyen
def _VerifyNodeInfo(what, vm_capable, result, all_hvparams):
911 5b0dfcef Helga Velroyen
  """Verifies the node info.
912 5b0dfcef Helga Velroyen

913 5b0dfcef Helga Velroyen
  @type what: C{dict}
914 5b0dfcef Helga Velroyen
  @param what: a dictionary of things to check
915 5b0dfcef Helga Velroyen
  @type vm_capable: boolean
916 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
917 5b0dfcef Helga Velroyen
  @type result: dict
918 5b0dfcef Helga Velroyen
  @param result: dictionary of verification results; results of the
919 5b0dfcef Helga Velroyen
    verifications in this function will be added here
920 5b0dfcef Helga Velroyen
  @type all_hvparams: dict of dict of string
921 5b0dfcef Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
922 5b0dfcef Helga Velroyen

923 5b0dfcef Helga Velroyen
  """
924 5b0dfcef Helga Velroyen
  if constants.NV_HVINFO in what and vm_capable:
925 5b0dfcef Helga Velroyen
    hvname = what[constants.NV_HVINFO]
926 5b0dfcef Helga Velroyen
    hyper = hypervisor.GetHypervisor(hvname)
927 5b0dfcef Helga Velroyen
    hvparams = all_hvparams[hvname]
928 5b0dfcef Helga Velroyen
    result[constants.NV_HVINFO] = hyper.GetNodeInfo(hvparams=hvparams)
929 5b0dfcef Helga Velroyen
930 5b0dfcef Helga Velroyen
931 a6c43c02 Helga Velroyen
def _VerifyClientCertificate(cert_file=pathutils.NODED_CLIENT_CERT_FILE):
932 a6c43c02 Helga Velroyen
  """Verify the existance and validity of the client SSL certificate.
933 a6c43c02 Helga Velroyen

934 a6c43c02 Helga Velroyen
  """
935 a6c43c02 Helga Velroyen
  create_cert_cmd = "gnt-cluster renew-crypto --new-node-certificates"
936 a6c43c02 Helga Velroyen
  if not os.path.exists(cert_file):
937 a6c43c02 Helga Velroyen
    return (constants.CV_ERROR,
938 a6c43c02 Helga Velroyen
            "The client certificate does not exist. Run '%s' to create"
939 46ae85de Helga Velroyen
            " client certificates for all nodes." % create_cert_cmd)
940 a6c43c02 Helga Velroyen
941 a6c43c02 Helga Velroyen
  (errcode, msg) = utils.VerifyCertificate(cert_file)
942 a6c43c02 Helga Velroyen
  if errcode is not None:
943 a6c43c02 Helga Velroyen
    return (errcode, msg)
944 a6c43c02 Helga Velroyen
  else:
945 a6c43c02 Helga Velroyen
    # if everything is fine, we return the digest to be compared to the config
946 a6c43c02 Helga Velroyen
    return (None, utils.GetCertificateDigest(cert_filename=cert_file))
947 a6c43c02 Helga Velroyen
948 a6c43c02 Helga Velroyen
949 a9f33339 Petr Pudlak
def VerifyNode(what, cluster_name, all_hvparams, node_groups, groups_cfg):
950 a8083063 Iustin Pop
  """Verify the status of the local node.
951 a8083063 Iustin Pop

952 e69d05fd Iustin Pop
  Based on the input L{what} parameter, various checks are done on the
953 e69d05fd Iustin Pop
  local node.
954 e69d05fd Iustin Pop

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

958 e69d05fd Iustin Pop
  If the I{nodelist} key is present, we check that we have
959 e69d05fd Iustin Pop
  connectivity via ssh with the target nodes (and check the hostname
960 e69d05fd Iustin Pop
  report).
961 a8083063 Iustin Pop

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

966 e69d05fd Iustin Pop
  @type what: C{dict}
967 e69d05fd Iustin Pop
  @param what: a dictionary of things to check:
968 e69d05fd Iustin Pop
      - filelist: list of files for which to compute checksums
969 e69d05fd Iustin Pop
      - nodelist: list of nodes we should check ssh communication with
970 e69d05fd Iustin Pop
      - node-net-test: list of nodes we should check node daemon port
971 e69d05fd Iustin Pop
        connectivity with
972 e69d05fd Iustin Pop
      - hypervisor: list with hypervisors to run the verify for
973 5b0dfcef Helga Velroyen
  @type cluster_name: string
974 5b0dfcef Helga Velroyen
  @param cluster_name: the cluster's name
975 5b0dfcef Helga Velroyen
  @type all_hvparams: dict of dict of strings
976 5b0dfcef Helga Velroyen
  @param all_hvparams: a dictionary mapping hypervisor names to hvparams
977 a9f33339 Petr Pudlak
  @type node_groups: a dict of strings
978 a9f33339 Petr Pudlak
  @param node_groups: node _names_ mapped to their group uuids (it's enough to
979 a9f33339 Petr Pudlak
      have only those nodes that are in `what["nodelist"]`)
980 a9f33339 Petr Pudlak
  @type groups_cfg: a dict of dict of strings
981 a9f33339 Petr Pudlak
  @param groups_cfg: a dictionary mapping group uuids to their configuration
982 10c2650b Iustin Pop
  @rtype: dict
983 10c2650b Iustin Pop
  @return: a dictionary with the same keys as the input dict, and
984 10c2650b Iustin Pop
      values representing the result of the checks
985 a8083063 Iustin Pop

986 a8083063 Iustin Pop
  """
987 a8083063 Iustin Pop
  result = {}
988 b705c7a6 Manuel Franceschini
  my_name = netutils.Hostname.GetSysName()
989 a744b676 Manuel Franceschini
  port = netutils.GetDaemonPort(constants.NODED)
990 8964ee14 Iustin Pop
  vm_capable = my_name not in what.get(constants.NV_VMNODES, [])
991 a8083063 Iustin Pop
992 75bf3149 Helga Velroyen
  _VerifyHypervisors(what, vm_capable, result, all_hvparams)
993 75bf3149 Helga Velroyen
  _VerifyHvparams(what, vm_capable, result)
994 58a59652 Iustin Pop
995 25361b9a Iustin Pop
  if constants.NV_FILELIST in what:
996 47130d50 Michael Hanselmann
    fingerprints = utils.FingerprintFiles(map(vcluster.LocalizeVirtualPath,
997 47130d50 Michael Hanselmann
                                              what[constants.NV_FILELIST]))
998 47130d50 Michael Hanselmann
    result[constants.NV_FILELIST] = \
999 47130d50 Michael Hanselmann
      dict((vcluster.MakeVirtualPath(key), value)
1000 47130d50 Michael Hanselmann
           for (key, value) in fingerprints.items())
1001 25361b9a Iustin Pop
1002 a6c43c02 Helga Velroyen
  if constants.NV_CLIENT_CERT in what:
1003 a6c43c02 Helga Velroyen
    result[constants.NV_CLIENT_CERT] = _VerifyClientCertificate()
1004 a6c43c02 Helga Velroyen
1005 25361b9a Iustin Pop
  if constants.NV_NODELIST in what:
1006 64c7b383 Michael Hanselmann
    (nodes, bynode) = what[constants.NV_NODELIST]
1007 64c7b383 Michael Hanselmann
1008 64c7b383 Michael Hanselmann
    # Add nodes from other groups (different for each node)
1009 64c7b383 Michael Hanselmann
    try:
1010 64c7b383 Michael Hanselmann
      nodes.extend(bynode[my_name])
1011 64c7b383 Michael Hanselmann
    except KeyError:
1012 64c7b383 Michael Hanselmann
      pass
1013 64c7b383 Michael Hanselmann
1014 64c7b383 Michael Hanselmann
    # Use a random order
1015 64c7b383 Michael Hanselmann
    random.shuffle(nodes)
1016 64c7b383 Michael Hanselmann
1017 64c7b383 Michael Hanselmann
    # Try to contact all nodes
1018 64c7b383 Michael Hanselmann
    val = {}
1019 64c7b383 Michael Hanselmann
    for node in nodes:
1020 a9f33339 Petr Pudlak
      params = groups_cfg.get(node_groups.get(node))
1021 a9f33339 Petr Pudlak
      ssh_port = params["ndparams"].get(constants.ND_SSH_PORT)
1022 a9f33339 Petr Pudlak
      logging.debug("Ssh port %s (None = default) for node %s",
1023 a9f33339 Petr Pudlak
                    str(ssh_port), node)
1024 a9f33339 Petr Pudlak
      success, message = _GetSshRunner(cluster_name). \
1025 a9f33339 Petr Pudlak
                            VerifyNodeHostname(node, ssh_port)
1026 a8083063 Iustin Pop
      if not success:
1027 64c7b383 Michael Hanselmann
        val[node] = message
1028 64c7b383 Michael Hanselmann
1029 64c7b383 Michael Hanselmann
    result[constants.NV_NODELIST] = val
1030 25361b9a Iustin Pop
1031 25361b9a Iustin Pop
  if constants.NV_NODENETTEST in what:
1032 25361b9a Iustin Pop
    result[constants.NV_NODENETTEST] = tmp = {}
1033 9d4bfc96 Iustin Pop
    my_pip = my_sip = None
1034 25361b9a Iustin Pop
    for name, pip, sip in what[constants.NV_NODENETTEST]:
1035 9d4bfc96 Iustin Pop
      if name == my_name:
1036 9d4bfc96 Iustin Pop
        my_pip = pip
1037 9d4bfc96 Iustin Pop
        my_sip = sip
1038 9d4bfc96 Iustin Pop
        break
1039 9d4bfc96 Iustin Pop
    if not my_pip:
1040 25361b9a Iustin Pop
      tmp[my_name] = ("Can't find my own primary/secondary IP"
1041 25361b9a Iustin Pop
                      " in the node list")
1042 9d4bfc96 Iustin Pop
    else:
1043 25361b9a Iustin Pop
      for name, pip, sip in what[constants.NV_NODENETTEST]:
1044 9d4bfc96 Iustin Pop
        fail = []
1045 a744b676 Manuel Franceschini
        if not netutils.TcpPing(pip, port, source=my_pip):
1046 9d4bfc96 Iustin Pop
          fail.append("primary")
1047 9d4bfc96 Iustin Pop
        if sip != pip:
1048 a744b676 Manuel Franceschini
          if not netutils.TcpPing(sip, port, source=my_sip):
1049 9d4bfc96 Iustin Pop
            fail.append("secondary")
1050 9d4bfc96 Iustin Pop
        if fail:
1051 25361b9a Iustin Pop
          tmp[name] = ("failure using the %s interface(s)" %
1052 25361b9a Iustin Pop
                       " and ".join(fail))
1053 25361b9a Iustin Pop
1054 a3a5f850 Iustin Pop
  if constants.NV_MASTERIP in what:
1055 a3a5f850 Iustin Pop
    # FIXME: add checks on incoming data structures (here and in the
1056 a3a5f850 Iustin Pop
    # rest of the function)
1057 a3a5f850 Iustin Pop
    master_name, master_ip = what[constants.NV_MASTERIP]
1058 a3a5f850 Iustin Pop
    if master_name == my_name:
1059 9769bb78 Manuel Franceschini
      source = constants.IP4_ADDRESS_LOCALHOST
1060 a3a5f850 Iustin Pop
    else:
1061 a3a5f850 Iustin Pop
      source = None
1062 a744b676 Manuel Franceschini
    result[constants.NV_MASTERIP] = netutils.TcpPing(master_ip, port,
1063 5ae4945a Iustin Pop
                                                     source=source)
1064 a3a5f850 Iustin Pop
1065 17b0b812 Andrea Spadaccini
  if constants.NV_USERSCRIPTS in what:
1066 17b0b812 Andrea Spadaccini
    result[constants.NV_USERSCRIPTS] = \
1067 17b0b812 Andrea Spadaccini
      [script for script in what[constants.NV_USERSCRIPTS]
1068 10b86782 Michael Hanselmann
       if not utils.IsExecutable(script)]
1069 17b0b812 Andrea Spadaccini
1070 16f41f24 René Nussbaumer
  if constants.NV_OOB_PATHS in what:
1071 16f41f24 René Nussbaumer
    result[constants.NV_OOB_PATHS] = tmp = []
1072 16f41f24 René Nussbaumer
    for path in what[constants.NV_OOB_PATHS]:
1073 16f41f24 René Nussbaumer
      try:
1074 16f41f24 René Nussbaumer
        st = os.stat(path)
1075 16f41f24 René Nussbaumer
      except OSError, err:
1076 16f41f24 René Nussbaumer
        tmp.append("error stating out of band helper: %s" % err)
1077 16f41f24 René Nussbaumer
      else:
1078 16f41f24 René Nussbaumer
        if stat.S_ISREG(st.st_mode):
1079 16f41f24 René Nussbaumer
          if stat.S_IMODE(st.st_mode) & stat.S_IXUSR:
1080 16f41f24 René Nussbaumer
            tmp.append(None)
1081 16f41f24 René Nussbaumer
          else:
1082 16f41f24 René Nussbaumer
            tmp.append("out of band helper %s is not executable" % path)
1083 16f41f24 René Nussbaumer
        else:
1084 16f41f24 René Nussbaumer
          tmp.append("out of band helper %s is not a file" % path)
1085 16f41f24 René Nussbaumer
1086 8964ee14 Iustin Pop
  if constants.NV_LVLIST in what and vm_capable:
1087 ed904904 Iustin Pop
    try:
1088 84d7e26b Dmitry Chernyak
      val = GetVolumeList(utils.ListVolumeGroups().keys())
1089 ed904904 Iustin Pop
    except RPCFail, err:
1090 ed904904 Iustin Pop
      val = str(err)
1091 ed904904 Iustin Pop
    result[constants.NV_LVLIST] = val
1092 25361b9a Iustin Pop
1093 5b0dfcef Helga Velroyen
  _VerifyInstanceList(what, vm_capable, result, all_hvparams)
1094 25361b9a Iustin Pop
1095 8964ee14 Iustin Pop
  if constants.NV_VGLIST in what and vm_capable:
1096 e480923b Iustin Pop
    result[constants.NV_VGLIST] = utils.ListVolumeGroups()
1097 25361b9a Iustin Pop
1098 8964ee14 Iustin Pop
  if constants.NV_PVLIST in what and vm_capable:
1099 d5a690cb Bernardo Dal Seno
    check_exclusive_pvs = constants.NV_EXCLUSIVEPVS in what
1100 59726e15 Bernardo Dal Seno
    val = bdev.LogicalVolume.GetPVInfo(what[constants.NV_PVLIST],
1101 d5a690cb Bernardo Dal Seno
                                       filter_allocatable=False,
1102 d5a690cb Bernardo Dal Seno
                                       include_lvs=check_exclusive_pvs)
1103 d5a690cb Bernardo Dal Seno
    if check_exclusive_pvs:
1104 d5a690cb Bernardo Dal Seno
      result[constants.NV_EXCLUSIVEPVS] = _CheckExclusivePvs(val)
1105 d5a690cb Bernardo Dal Seno
      for pvi in val:
1106 d5a690cb Bernardo Dal Seno
        # Avoid sending useless data on the wire
1107 d5a690cb Bernardo Dal Seno
        pvi.lv_list = []
1108 59726e15 Bernardo Dal Seno
    result[constants.NV_PVLIST] = map(objects.LvmPvInfo.ToDict, val)
1109 d091393e Iustin Pop
1110 25361b9a Iustin Pop
  if constants.NV_VERSION in what:
1111 e9ce0a64 Iustin Pop
    result[constants.NV_VERSION] = (constants.PROTOCOL_VERSION,
1112 e9ce0a64 Iustin Pop
                                    constants.RELEASE_VERSION)
1113 25361b9a Iustin Pop
1114 5b0dfcef Helga Velroyen
  _VerifyNodeInfo(what, vm_capable, result, all_hvparams)
1115 9d4bfc96 Iustin Pop
1116 5bb0a1cb Thomas Thrainer
  if constants.NV_DRBDVERSION in what and vm_capable:
1117 5bb0a1cb Thomas Thrainer
    try:
1118 47e0abee Thomas Thrainer
      drbd_version = DRBD8.GetProcInfo().GetVersionString()
1119 5bb0a1cb Thomas Thrainer
    except errors.BlockDeviceError, err:
1120 5bb0a1cb Thomas Thrainer
      logging.warning("Can't get DRBD version", exc_info=True)
1121 5bb0a1cb Thomas Thrainer
      drbd_version = str(err)
1122 5bb0a1cb Thomas Thrainer
    result[constants.NV_DRBDVERSION] = drbd_version
1123 5bb0a1cb Thomas Thrainer
1124 8964ee14 Iustin Pop
  if constants.NV_DRBDLIST in what and vm_capable:
1125 6d2e83d5 Iustin Pop
    try:
1126 47e0abee Thomas Thrainer
      used_minors = drbd.DRBD8.GetUsedDevs()
1127 f6eaed12 Iustin Pop
    except errors.BlockDeviceError, err:
1128 6d2e83d5 Iustin Pop
      logging.warning("Can't get used minors list", exc_info=True)
1129 f6eaed12 Iustin Pop
      used_minors = str(err)
1130 6d2e83d5 Iustin Pop
    result[constants.NV_DRBDLIST] = used_minors
1131 6d2e83d5 Iustin Pop
1132 8964ee14 Iustin Pop
  if constants.NV_DRBDHELPER in what and vm_capable:
1133 7ef40fbe Luca Bigliardi
    status = True
1134 7ef40fbe Luca Bigliardi
    try:
1135 47e0abee Thomas Thrainer
      payload = drbd.DRBD8.GetUsermodeHelper()
1136 7ef40fbe Luca Bigliardi
    except errors.BlockDeviceError, err:
1137 7ef40fbe Luca Bigliardi
      logging.error("Can't get DRBD usermode helper: %s", str(err))
1138 7ef40fbe Luca Bigliardi
      status = False
1139 7ef40fbe Luca Bigliardi
      payload = str(err)
1140 7ef40fbe Luca Bigliardi
    result[constants.NV_DRBDHELPER] = (status, payload)
1141 7ef40fbe Luca Bigliardi
1142 7c0aa8e9 Iustin Pop
  if constants.NV_NODESETUP in what:
1143 7c0aa8e9 Iustin Pop
    result[constants.NV_NODESETUP] = tmpr = []
1144 7c0aa8e9 Iustin Pop
    if not os.path.isdir("/sys/block") or not os.path.isdir("/sys/class/net"):
1145 7c0aa8e9 Iustin Pop
      tmpr.append("The sysfs filesytem doesn't seem to be mounted"
1146 7c0aa8e9 Iustin Pop
                  " under /sys, missing required directories /sys/block"
1147 7c0aa8e9 Iustin Pop
                  " and /sys/class/net")
1148 7c0aa8e9 Iustin Pop
    if (not os.path.isdir("/proc/sys") or
1149 7c0aa8e9 Iustin Pop
        not os.path.isfile("/proc/sysrq-trigger")):
1150 7c0aa8e9 Iustin Pop
      tmpr.append("The procfs filesystem doesn't seem to be mounted"
1151 7c0aa8e9 Iustin Pop
                  " under /proc, missing required directory /proc/sys and"
1152 7c0aa8e9 Iustin Pop
                  " the file /proc/sysrq-trigger")
1153 313b2dd4 Michael Hanselmann
1154 313b2dd4 Michael Hanselmann
  if constants.NV_TIME in what:
1155 313b2dd4 Michael Hanselmann
    result[constants.NV_TIME] = utils.SplitTime(time.time())
1156 313b2dd4 Michael Hanselmann
1157 8964ee14 Iustin Pop
  if constants.NV_OSLIST in what and vm_capable:
1158 b0d85178 Iustin Pop
    result[constants.NV_OSLIST] = DiagnoseOS()
1159 b0d85178 Iustin Pop
1160 20d317d4 Iustin Pop
  if constants.NV_BRIDGES in what and vm_capable:
1161 20d317d4 Iustin Pop
    result[constants.NV_BRIDGES] = [bridge
1162 20d317d4 Iustin Pop
                                    for bridge in what[constants.NV_BRIDGES]
1163 20d317d4 Iustin Pop
                                    if not utils.BridgeExists(bridge)]
1164 23e3c9b7 Michael Hanselmann
1165 13a6c760 Helga Velroyen
  if what.get(constants.NV_ACCEPTED_STORAGE_PATHS) == my_name:
1166 13a6c760 Helga Velroyen
    result[constants.NV_ACCEPTED_STORAGE_PATHS] = \
1167 13a6c760 Helga Velroyen
        filestorage.ComputeWrongFileStoragePaths()
1168 72b35807 Michael Hanselmann
1169 9c1c3c19 Helga Velroyen
  if what.get(constants.NV_FILE_STORAGE_PATH):
1170 9c1c3c19 Helga Velroyen
    pathresult = filestorage.CheckFileStoragePath(
1171 9c1c3c19 Helga Velroyen
        what[constants.NV_FILE_STORAGE_PATH])
1172 9c1c3c19 Helga Velroyen
    if pathresult:
1173 9c1c3c19 Helga Velroyen
      result[constants.NV_FILE_STORAGE_PATH] = pathresult
1174 9c1c3c19 Helga Velroyen
1175 4b322a76 Helga Velroyen
  if what.get(constants.NV_SHARED_FILE_STORAGE_PATH):
1176 4b322a76 Helga Velroyen
    pathresult = filestorage.CheckFileStoragePath(
1177 4b322a76 Helga Velroyen
        what[constants.NV_SHARED_FILE_STORAGE_PATH])
1178 4b322a76 Helga Velroyen
    if pathresult:
1179 4b322a76 Helga Velroyen
      result[constants.NV_SHARED_FILE_STORAGE_PATH] = pathresult
1180 4b322a76 Helga Velroyen
1181 c26a6bd2 Iustin Pop
  return result
1182 a8083063 Iustin Pop
1183 a8083063 Iustin Pop
1184 d722af8b Helga Velroyen
def GetCryptoTokens(token_requests):
1185 d722af8b Helga Velroyen
  """Perform actions on the node's cryptographic tokens.
1186 d722af8b Helga Velroyen

1187 d722af8b Helga Velroyen
  Token types can be 'ssl' or 'ssh'. So far only some actions are implemented
1188 d722af8b Helga Velroyen
  for 'ssl'. Action 'get' returns the digest of the public client ssl
1189 d722af8b Helga Velroyen
  certificate. Action 'create' creates a new client certificate and private key
1190 d722af8b Helga Velroyen
  and also returns the digest of the certificate. The third parameter of a
1191 d722af8b Helga Velroyen
  token request are optional parameters for the actions, so far only the
1192 d722af8b Helga Velroyen
  filename is supported.
1193 d722af8b Helga Velroyen

1194 d722af8b Helga Velroyen
  @type token_requests: list of tuples of (string, string, dict), where the
1195 d722af8b Helga Velroyen
    first string is in constants.CRYPTO_TYPES, the second in
1196 d722af8b Helga Velroyen
    constants.CRYPTO_ACTIONS. The third parameter is a dictionary of string
1197 d722af8b Helga Velroyen
    to string.
1198 d722af8b Helga Velroyen
  @param token_requests: list of requests of cryptographic tokens and actions
1199 d722af8b Helga Velroyen
    to perform on them. The actions come with a dictionary of options.
1200 b544a3c2 Helga Velroyen
  @rtype: list of tuples (string, string)
1201 b544a3c2 Helga Velroyen
  @return: list of tuples of the token type and the public crypto token
1202 b544a3c2 Helga Velroyen

1203 b544a3c2 Helga Velroyen
  """
1204 22114677 Helga Velroyen
  getents = runtime.GetEnts()
1205 d722af8b Helga Velroyen
  _VALID_CERT_FILES = [pathutils.NODED_CERT_FILE,
1206 d722af8b Helga Velroyen
                       pathutils.NODED_CLIENT_CERT_FILE,
1207 d722af8b Helga Velroyen
                       pathutils.NODED_CLIENT_CERT_FILE_TMP]
1208 d722af8b Helga Velroyen
  _DEFAULT_CERT_FILE = pathutils.NODED_CLIENT_CERT_FILE
1209 b544a3c2 Helga Velroyen
  tokens = []
1210 d722af8b Helga Velroyen
  for (token_type, action, options) in token_requests:
1211 b544a3c2 Helga Velroyen
    if token_type not in constants.CRYPTO_TYPES:
1212 d722af8b Helga Velroyen
      raise errors.ProgrammerError("Token type '%s' not supported." %
1213 b544a3c2 Helga Velroyen
                                   token_type)
1214 d722af8b Helga Velroyen
    if action not in constants.CRYPTO_ACTIONS:
1215 d722af8b Helga Velroyen
      raise errors.ProgrammerError("Action '%s' is not supported." %
1216 d722af8b Helga Velroyen
                                   action)
1217 b544a3c2 Helga Velroyen
    if token_type == constants.CRYPTO_TYPE_SSL_DIGEST:
1218 d722af8b Helga Velroyen
      if action == constants.CRYPTO_ACTION_CREATE:
1219 ab4b1cf2 Helga Velroyen
1220 ab4b1cf2 Helga Velroyen
        # extract file name from options
1221 d722af8b Helga Velroyen
        cert_filename = None
1222 d722af8b Helga Velroyen
        if options:
1223 d722af8b Helga Velroyen
          cert_filename = options.get(constants.CRYPTO_OPTION_CERT_FILE)
1224 d722af8b Helga Velroyen
        if not cert_filename:
1225 d722af8b Helga Velroyen
          cert_filename = _DEFAULT_CERT_FILE
1226 d722af8b Helga Velroyen
        # For security reason, we don't allow arbitrary filenames
1227 d722af8b Helga Velroyen
        if not cert_filename in _VALID_CERT_FILES:
1228 d722af8b Helga Velroyen
          raise errors.ProgrammerError(
1229 d722af8b Helga Velroyen
            "The certificate file name path '%s' is not allowed." %
1230 d722af8b Helga Velroyen
            cert_filename)
1231 ab4b1cf2 Helga Velroyen
1232 ab4b1cf2 Helga Velroyen
        # extract serial number from options
1233 ab4b1cf2 Helga Velroyen
        serial_no = None
1234 ab4b1cf2 Helga Velroyen
        if options:
1235 ab4b1cf2 Helga Velroyen
          try:
1236 ab4b1cf2 Helga Velroyen
            serial_no = int(options[constants.CRYPTO_OPTION_SERIAL_NO])
1237 ab4b1cf2 Helga Velroyen
          except ValueError:
1238 ab4b1cf2 Helga Velroyen
            raise errors.ProgrammerError(
1239 ab4b1cf2 Helga Velroyen
              "The given serial number is not an intenger: %s." %
1240 ab4b1cf2 Helga Velroyen
              options.get(constants.CRYPTO_OPTION_SERIAL_NO))
1241 ab4b1cf2 Helga Velroyen
          except KeyError:
1242 ab4b1cf2 Helga Velroyen
            raise errors.ProgrammerError("No serial number was provided.")
1243 ab4b1cf2 Helga Velroyen
1244 ab4b1cf2 Helga Velroyen
        if not serial_no:
1245 ab4b1cf2 Helga Velroyen
          raise errors.ProgrammerError(
1246 ab4b1cf2 Helga Velroyen
            "Cannot create an SSL certificate without a serial no.")
1247 ab4b1cf2 Helga Velroyen
1248 d722af8b Helga Velroyen
        utils.GenerateNewSslCert(
1249 ab4b1cf2 Helga Velroyen
          True, cert_filename, serial_no,
1250 22114677 Helga Velroyen
          "Create new client SSL certificate in %s." % cert_filename,
1251 22114677 Helga Velroyen
          uid=getents.masterd_uid, gid=getents.masterd_gid)
1252 d722af8b Helga Velroyen
        tokens.append((token_type,
1253 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest(
1254 d722af8b Helga Velroyen
                         cert_filename=cert_filename)))
1255 d722af8b Helga Velroyen
      elif action == constants.CRYPTO_ACTION_GET:
1256 d722af8b Helga Velroyen
        tokens.append((token_type,
1257 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest()))
1258 b544a3c2 Helga Velroyen
  return tokens
1259 b544a3c2 Helga Velroyen
1260 b544a3c2 Helga Velroyen
1261 2be7273c Apollon Oikonomopoulos
def GetBlockDevSizes(devices):
1262 2be7273c Apollon Oikonomopoulos
  """Return the size of the given block devices
1263 2be7273c Apollon Oikonomopoulos

1264 2be7273c Apollon Oikonomopoulos
  @type devices: list
1265 2be7273c Apollon Oikonomopoulos
  @param devices: list of block device nodes to query
1266 2be7273c Apollon Oikonomopoulos
  @rtype: dict
1267 2be7273c Apollon Oikonomopoulos
  @return:
1268 2be7273c Apollon Oikonomopoulos
    dictionary of all block devices under /dev (key). The value is their
1269 2be7273c Apollon Oikonomopoulos
    size in MiB.
1270 2be7273c Apollon Oikonomopoulos

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

1273 2be7273c Apollon Oikonomopoulos
  """
1274 2be7273c Apollon Oikonomopoulos
  DEV_PREFIX = "/dev/"
1275 2be7273c Apollon Oikonomopoulos
  blockdevs = {}
1276 2be7273c Apollon Oikonomopoulos
1277 2be7273c Apollon Oikonomopoulos
  for devpath in devices:
1278 cf00dba0 René Nussbaumer
    if not utils.IsBelowDir(DEV_PREFIX, devpath):
1279 2be7273c Apollon Oikonomopoulos
      continue
1280 2be7273c Apollon Oikonomopoulos
1281 2be7273c Apollon Oikonomopoulos
    try:
1282 2be7273c Apollon Oikonomopoulos
      st = os.stat(devpath)
1283 2be7273c Apollon Oikonomopoulos
    except EnvironmentError, err:
1284 2be7273c Apollon Oikonomopoulos
      logging.warning("Error stat()'ing device %s: %s", devpath, str(err))
1285 2be7273c Apollon Oikonomopoulos
      continue
1286 2be7273c Apollon Oikonomopoulos
1287 2be7273c Apollon Oikonomopoulos
    if stat.S_ISBLK(st.st_mode):
1288 2be7273c Apollon Oikonomopoulos
      result = utils.RunCmd(["blockdev", "--getsize64", devpath])
1289 2be7273c Apollon Oikonomopoulos
      if result.failed:
1290 2be7273c Apollon Oikonomopoulos
        # We don't want to fail, just do not list this device as available
1291 2be7273c Apollon Oikonomopoulos
        logging.warning("Cannot get size for block device %s", devpath)
1292 2be7273c Apollon Oikonomopoulos
        continue
1293 2be7273c Apollon Oikonomopoulos
1294 2be7273c Apollon Oikonomopoulos
      size = int(result.stdout) / (1024 * 1024)
1295 2be7273c Apollon Oikonomopoulos
      blockdevs[devpath] = size
1296 2be7273c Apollon Oikonomopoulos
  return blockdevs
1297 2be7273c Apollon Oikonomopoulos
1298 2be7273c Apollon Oikonomopoulos
1299 84d7e26b Dmitry Chernyak
def GetVolumeList(vg_names):
1300 a8083063 Iustin Pop
  """Compute list of logical volumes and their size.
1301 a8083063 Iustin Pop

1302 84d7e26b Dmitry Chernyak
  @type vg_names: list
1303 397693d3 Iustin Pop
  @param vg_names: the volume groups whose LVs we should list, or
1304 397693d3 Iustin Pop
      empty for all volume groups
1305 10c2650b Iustin Pop
  @rtype: dict
1306 10c2650b Iustin Pop
  @return:
1307 10c2650b Iustin Pop
      dictionary of all partions (key) with value being a tuple of
1308 10c2650b Iustin Pop
      their size (in MiB), inactive and online status::
1309 10c2650b Iustin Pop

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

1312 10c2650b Iustin Pop
      in case of errors, a string is returned with the error
1313 10c2650b Iustin Pop
      details.
1314 a8083063 Iustin Pop

1315 a8083063 Iustin Pop
  """
1316 cb2037a2 Iustin Pop
  lvs = {}
1317 d0c8c01d Iustin Pop
  sep = "|"
1318 397693d3 Iustin Pop
  if not vg_names:
1319 397693d3 Iustin Pop
    vg_names = []
1320 cb2037a2 Iustin Pop
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
1321 cb2037a2 Iustin Pop
                         "--separator=%s" % sep,
1322 84d7e26b Dmitry Chernyak
                         "-ovg_name,lv_name,lv_size,lv_attr"] + vg_names)
1323 a8083063 Iustin Pop
  if result.failed:
1324 29d376ec Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s", result.output)
1325 cb2037a2 Iustin Pop
1326 cb2037a2 Iustin Pop
  for line in result.stdout.splitlines():
1327 df4c2628 Iustin Pop
    line = line.strip()
1328 0b5303da Iustin Pop
    match = _LVSLINE_REGEX.match(line)
1329 df4c2628 Iustin Pop
    if not match:
1330 18682bca Iustin Pop
      logging.error("Invalid line returned from lvs output: '%s'", line)
1331 df4c2628 Iustin Pop
      continue
1332 84d7e26b Dmitry Chernyak
    vg_name, name, size, attr = match.groups()
1333 d0c8c01d Iustin Pop
    inactive = attr[4] == "-"
1334 d0c8c01d Iustin Pop
    online = attr[5] == "o"
1335 d0c8c01d Iustin Pop
    virtual = attr[0] == "v"
1336 33f2a81a Iustin Pop
    if virtual:
1337 33f2a81a Iustin Pop
      # we don't want to report such volumes as existing, since they
1338 33f2a81a Iustin Pop
      # don't really hold data
1339 33f2a81a Iustin Pop
      continue
1340 e687ec01 Michael Hanselmann
    lvs[vg_name + "/" + name] = (size, inactive, online)
1341 cb2037a2 Iustin Pop
1342 cb2037a2 Iustin Pop
  return lvs
1343 a8083063 Iustin Pop
1344 a8083063 Iustin Pop
1345 a8083063 Iustin Pop
def ListVolumeGroups():
1346 2f8598a5 Alexander Schreiber
  """List the volume groups and their size.
1347 a8083063 Iustin Pop

1348 10c2650b Iustin Pop
  @rtype: dict
1349 10c2650b Iustin Pop
  @return: dictionary with keys volume name and values the
1350 10c2650b Iustin Pop
      size of the volume
1351 a8083063 Iustin Pop

1352 a8083063 Iustin Pop
  """
1353 c26a6bd2 Iustin Pop
  return utils.ListVolumeGroups()
1354 a8083063 Iustin Pop
1355 a8083063 Iustin Pop
1356 dcb93971 Michael Hanselmann
def NodeVolumes():
1357 dcb93971 Michael Hanselmann
  """List all volumes on this node.
1358 dcb93971 Michael Hanselmann

1359 10c2650b Iustin Pop
  @rtype: list
1360 10c2650b Iustin Pop
  @return:
1361 10c2650b Iustin Pop
    A list of dictionaries, each having four keys:
1362 10c2650b Iustin Pop
      - name: the logical volume name,
1363 10c2650b Iustin Pop
      - size: the size of the logical volume
1364 10c2650b Iustin Pop
      - dev: the physical device on which the LV lives
1365 10c2650b Iustin Pop
      - vg: the volume group to which it belongs
1366 10c2650b Iustin Pop

1367 10c2650b Iustin Pop
    In case of errors, we return an empty list and log the
1368 10c2650b Iustin Pop
    error.
1369 10c2650b Iustin Pop

1370 10c2650b Iustin Pop
    Note that since a logical volume can live on multiple physical
1371 10c2650b Iustin Pop
    volumes, the resulting list might include a logical volume
1372 10c2650b Iustin Pop
    multiple times.
1373 10c2650b Iustin Pop

1374 dcb93971 Michael Hanselmann
  """
1375 dcb93971 Michael Hanselmann
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
1376 dcb93971 Michael Hanselmann
                         "--separator=|",
1377 dcb93971 Michael Hanselmann
                         "--options=lv_name,lv_size,devices,vg_name"])
1378 dcb93971 Michael Hanselmann
  if result.failed:
1379 10bfe6cb Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s",
1380 10bfe6cb Iustin Pop
          result.output)
1381 dcb93971 Michael Hanselmann
1382 dcb93971 Michael Hanselmann
  def parse_dev(dev):
1383 d0c8c01d Iustin Pop
    return dev.split("(")[0]
1384 89e5ab02 Iustin Pop
1385 89e5ab02 Iustin Pop
  def handle_dev(dev):
1386 89e5ab02 Iustin Pop
    return [parse_dev(x) for x in dev.split(",")]
1387 dcb93971 Michael Hanselmann
1388 dcb93971 Michael Hanselmann
  def map_line(line):
1389 89e5ab02 Iustin Pop
    line = [v.strip() for v in line]
1390 d0c8c01d Iustin Pop
    return [{"name": line[0], "size": line[1],
1391 d0c8c01d Iustin Pop
             "dev": dev, "vg": line[3]} for dev in handle_dev(line[2])]
1392 89e5ab02 Iustin Pop
1393 89e5ab02 Iustin Pop
  all_devs = []
1394 89e5ab02 Iustin Pop
  for line in result.stdout.splitlines():
1395 d0c8c01d Iustin Pop
    if line.count("|") >= 3:
1396 d0c8c01d Iustin Pop
      all_devs.extend(map_line(line.split("|")))
1397 89e5ab02 Iustin Pop
    else:
1398 89e5ab02 Iustin Pop
      logging.warning("Strange line in the output from lvs: '%s'", line)
1399 89e5ab02 Iustin Pop
  return all_devs
1400 dcb93971 Michael Hanselmann
1401 dcb93971 Michael Hanselmann
1402 a8083063 Iustin Pop
def BridgesExist(bridges_list):
1403 2f8598a5 Alexander Schreiber
  """Check if a list of bridges exist on the current node.
1404 a8083063 Iustin Pop

1405 b1206984 Iustin Pop
  @rtype: boolean
1406 b1206984 Iustin Pop
  @return: C{True} if all of them exist, C{False} otherwise
1407 a8083063 Iustin Pop

1408 a8083063 Iustin Pop
  """
1409 35c0c8da Iustin Pop
  missing = []
1410 a8083063 Iustin Pop
  for bridge in bridges_list:
1411 a8083063 Iustin Pop
    if not utils.BridgeExists(bridge):
1412 35c0c8da Iustin Pop
      missing.append(bridge)
1413 a8083063 Iustin Pop
1414 35c0c8da Iustin Pop
  if missing:
1415 1f864b60 Iustin Pop
    _Fail("Missing bridges %s", utils.CommaJoin(missing))
1416 35c0c8da Iustin Pop
1417 a8083063 Iustin Pop
1418 2bff1928 Helga Velroyen
def GetInstanceListForHypervisor(hname, hvparams=None,
1419 2bff1928 Helga Velroyen
                                 get_hv_fn=hypervisor.GetHypervisor):
1420 2bff1928 Helga Velroyen
  """Provides a list of instances of the given hypervisor.
1421 2bff1928 Helga Velroyen

1422 2bff1928 Helga Velroyen
  @type hname: string
1423 2bff1928 Helga Velroyen
  @param hname: name of the hypervisor
1424 2bff1928 Helga Velroyen
  @type hvparams: dict of strings
1425 2bff1928 Helga Velroyen
  @param hvparams: hypervisor parameters for the given hypervisor
1426 2bff1928 Helga Velroyen
  @type get_hv_fn: function
1427 2bff1928 Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1428 2bff1928 Helga Velroyen
    name; optional parameter to increase testability
1429 2bff1928 Helga Velroyen

1430 2bff1928 Helga Velroyen
  @rtype: list
1431 2bff1928 Helga Velroyen
  @return: a list of all running instances on the current node
1432 2bff1928 Helga Velroyen
    - instance1.example.com
1433 2bff1928 Helga Velroyen
    - instance2.example.com
1434 2bff1928 Helga Velroyen

1435 2bff1928 Helga Velroyen
  """
1436 2bff1928 Helga Velroyen
  results = []
1437 2bff1928 Helga Velroyen
  try:
1438 2bff1928 Helga Velroyen
    hv = get_hv_fn(hname)
1439 5b0dfcef Helga Velroyen
    names = hv.ListInstances(hvparams=hvparams)
1440 2bff1928 Helga Velroyen
    results.extend(names)
1441 2bff1928 Helga Velroyen
  except errors.HypervisorError, err:
1442 2bff1928 Helga Velroyen
    _Fail("Error enumerating instances (hypervisor %s): %s",
1443 2bff1928 Helga Velroyen
          hname, err, exc=True)
1444 2bff1928 Helga Velroyen
  return results
1445 2bff1928 Helga Velroyen
1446 2bff1928 Helga Velroyen
1447 fac83f8a Helga Velroyen
def GetInstanceList(hypervisor_list, all_hvparams=None,
1448 fac83f8a Helga Velroyen
                    get_hv_fn=hypervisor.GetHypervisor):
1449 2f8598a5 Alexander Schreiber
  """Provides a list of instances.
1450 a8083063 Iustin Pop

1451 e69d05fd Iustin Pop
  @type hypervisor_list: list
1452 e69d05fd Iustin Pop
  @param hypervisor_list: the list of hypervisors to query information
1453 fac83f8a Helga Velroyen
  @type all_hvparams: dict of dict of strings
1454 fac83f8a Helga Velroyen
  @param all_hvparams: a dictionary mapping hypervisor types to respective
1455 fac83f8a Helga Velroyen
    cluster-wide hypervisor parameters
1456 fac83f8a Helga Velroyen
  @type get_hv_fn: function
1457 fac83f8a Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1458 fac83f8a Helga Velroyen
    name; optional parameter to increase testability
1459 e69d05fd Iustin Pop

1460 e69d05fd Iustin Pop
  @rtype: list
1461 e69d05fd Iustin Pop
  @return: a list of all running instances on the current node
1462 10c2650b Iustin Pop
    - instance1.example.com
1463 10c2650b Iustin Pop
    - instance2.example.com
1464 a8083063 Iustin Pop

1465 098c0958 Michael Hanselmann
  """
1466 e69d05fd Iustin Pop
  results = []
1467 e69d05fd Iustin Pop
  for hname in hypervisor_list:
1468 5b0dfcef Helga Velroyen
    hvparams = all_hvparams[hname]
1469 5b0dfcef Helga Velroyen
    results.extend(GetInstanceListForHypervisor(hname, hvparams=hvparams,
1470 2bff1928 Helga Velroyen
                                                get_hv_fn=get_hv_fn))
1471 e69d05fd Iustin Pop
  return results
1472 a8083063 Iustin Pop
1473 a8083063 Iustin Pop
1474 0bbec3af Helga Velroyen
def GetInstanceInfo(instance, hname, hvparams=None):
1475 5bbd3f7f Michael Hanselmann
  """Gives back the information about an instance as a dictionary.
1476 a8083063 Iustin Pop

1477 e69d05fd Iustin Pop
  @type instance: string
1478 e69d05fd Iustin Pop
  @param instance: the instance name
1479 e69d05fd Iustin Pop
  @type hname: string
1480 e69d05fd Iustin Pop
  @param hname: the hypervisor type of the instance
1481 0bbec3af Helga Velroyen
  @type hvparams: dict of strings
1482 0bbec3af Helga Velroyen
  @param hvparams: the instance's hvparams
1483 a8083063 Iustin Pop

1484 e69d05fd Iustin Pop
  @rtype: dict
1485 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
1486 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1487 a3f0f306 Jose A. Lopes
      - state: state of instance (HvInstanceState)
1488 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1489 1cb97324 Agata Murawska
      - vcpus: the number of vcpus (int)
1490 a8083063 Iustin Pop

1491 098c0958 Michael Hanselmann
  """
1492 a8083063 Iustin Pop
  output = {}
1493 a8083063 Iustin Pop
1494 0bbec3af Helga Velroyen
  iinfo = hypervisor.GetHypervisor(hname).GetInstanceInfo(instance,
1495 0bbec3af Helga Velroyen
                                                          hvparams=hvparams)
1496 a8083063 Iustin Pop
  if iinfo is not None:
1497 d0c8c01d Iustin Pop
    output["memory"] = iinfo[2]
1498 1cb97324 Agata Murawska
    output["vcpus"] = iinfo[3]
1499 d0c8c01d Iustin Pop
    output["state"] = iinfo[4]
1500 d0c8c01d Iustin Pop
    output["time"] = iinfo[5]
1501 a8083063 Iustin Pop
1502 c26a6bd2 Iustin Pop
  return output
1503 a8083063 Iustin Pop
1504 a8083063 Iustin Pop
1505 56e7640c Iustin Pop
def GetInstanceMigratable(instance):
1506 3361ab37 Helga Velroyen
  """Computes whether an instance can be migrated.
1507 56e7640c Iustin Pop

1508 56e7640c Iustin Pop
  @type instance: L{objects.Instance}
1509 56e7640c Iustin Pop
  @param instance: object representing the instance to be checked.
1510 56e7640c Iustin Pop

1511 56e7640c Iustin Pop
  @rtype: tuple
1512 56e7640c Iustin Pop
  @return: tuple of (result, description) where:
1513 56e7640c Iustin Pop
      - result: whether the instance can be migrated or not
1514 56e7640c Iustin Pop
      - description: a description of the issue, if relevant
1515 56e7640c Iustin Pop

1516 56e7640c Iustin Pop
  """
1517 56e7640c Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1518 afdc3985 Iustin Pop
  iname = instance.name
1519 3361ab37 Helga Velroyen
  if iname not in hyper.ListInstances(instance.hvparams):
1520 afdc3985 Iustin Pop
    _Fail("Instance %s is not running", iname)
1521 56e7640c Iustin Pop
1522 e9ebf2d7 Ilias Tsitsimpis
  for idx in range(len(instance.disks_info)):
1523 afdc3985 Iustin Pop
    link_name = _GetBlockDevSymlinkPath(iname, idx)
1524 56e7640c Iustin Pop
    if not os.path.islink(link_name):
1525 b8ebd37b Iustin Pop
      logging.warning("Instance %s is missing symlink %s for disk %d",
1526 b8ebd37b Iustin Pop
                      iname, link_name, idx)
1527 56e7640c Iustin Pop
1528 56e7640c Iustin Pop
1529 0200a1af Helga Velroyen
def GetAllInstancesInfo(hypervisor_list, all_hvparams):
1530 a8083063 Iustin Pop
  """Gather data about all instances.
1531 a8083063 Iustin Pop

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

1536 e69d05fd Iustin Pop
  @type hypervisor_list: list
1537 e69d05fd Iustin Pop
  @param hypervisor_list: list of hypervisors to query for instance data
1538 0200a1af Helga Velroyen
  @type all_hvparams: dict of dict of strings
1539 0200a1af Helga Velroyen
  @param all_hvparams: mapping of hypervisor names to hvparams
1540 e69d05fd Iustin Pop

1541 955db481 Guido Trotter
  @rtype: dict
1542 e69d05fd Iustin Pop
  @return: dictionary of instance: data, with data having the following keys:
1543 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1544 e69d05fd Iustin Pop
      - state: xen state of instance (string)
1545 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1546 10c2650b Iustin Pop
      - vcpus: the number of vcpus
1547 a8083063 Iustin Pop

1548 098c0958 Michael Hanselmann
  """
1549 a8083063 Iustin Pop
  output = {}
1550 e69d05fd Iustin Pop
  for hname in hypervisor_list:
1551 0200a1af Helga Velroyen
    hvparams = all_hvparams[hname]
1552 0200a1af Helga Velroyen
    iinfo = hypervisor.GetHypervisor(hname).GetAllInstancesInfo(hvparams)
1553 e69d05fd Iustin Pop
    if iinfo:
1554 29921401 Iustin Pop
      for name, _, memory, vcpus, state, times in iinfo:
1555 f23b5ae8 Iustin Pop
        value = {
1556 d0c8c01d Iustin Pop
          "memory": memory,
1557 d0c8c01d Iustin Pop
          "vcpus": vcpus,
1558 d0c8c01d Iustin Pop
          "state": state,
1559 d0c8c01d Iustin Pop
          "time": times,
1560 e69d05fd Iustin Pop
          }
1561 b33b6f55 Iustin Pop
        if name in output:
1562 b33b6f55 Iustin Pop
          # we only check static parameters, like memory and vcpus,
1563 b33b6f55 Iustin Pop
          # and not state and time which can change between the
1564 b33b6f55 Iustin Pop
          # invocations of the different hypervisors
1565 d0c8c01d Iustin Pop
          for key in "memory", "vcpus":
1566 b33b6f55 Iustin Pop
            if value[key] != output[name][key]:
1567 2fa74ef4 Iustin Pop
              _Fail("Instance %s is running twice"
1568 2fa74ef4 Iustin Pop
                    " with different parameters", name)
1569 f23b5ae8 Iustin Pop
        output[name] = value
1570 a8083063 Iustin Pop
1571 c26a6bd2 Iustin Pop
  return output
1572 a8083063 Iustin Pop
1573 a8083063 Iustin Pop
1574 b9e12624 Hrvoje Ribicic
def GetInstanceConsoleInfo(instance_param_dict,
1575 b9e12624 Hrvoje Ribicic
                           get_hv_fn=hypervisor.GetHypervisor):
1576 b9e12624 Hrvoje Ribicic
  """Gather data about the console access of a set of instances of this node.
1577 b9e12624 Hrvoje Ribicic

1578 b9e12624 Hrvoje Ribicic
  This function assumes that the caller already knows which instances are on
1579 b9e12624 Hrvoje Ribicic
  this node, by calling a function such as L{GetAllInstancesInfo} or
1580 b9e12624 Hrvoje Ribicic
  L{GetInstanceList}.
1581 b9e12624 Hrvoje Ribicic

1582 b9e12624 Hrvoje Ribicic
  For every instance, a large amount of configuration data needs to be
1583 b9e12624 Hrvoje Ribicic
  provided to the hypervisor interface in order to receive the console
1584 b9e12624 Hrvoje Ribicic
  information. Whether this could or should be cut down can be discussed.
1585 b9e12624 Hrvoje Ribicic
  The information is provided in a dictionary indexed by instance name,
1586 b9e12624 Hrvoje Ribicic
  allowing any number of instance queries to be done.
1587 b9e12624 Hrvoje Ribicic

1588 b9e12624 Hrvoje Ribicic
  @type instance_param_dict: dict of string to tuple of dictionaries, where the
1589 c42be2c0 Petr Pudlak
    dictionaries represent: L{objects.Instance}, L{objects.Node},
1590 c42be2c0 Petr Pudlak
    L{objects.NodeGroup}, HvParams, BeParams
1591 b9e12624 Hrvoje Ribicic
  @param instance_param_dict: mapping of instance name to parameters necessary
1592 b9e12624 Hrvoje Ribicic
    for console information retrieval
1593 b9e12624 Hrvoje Ribicic

1594 b9e12624 Hrvoje Ribicic
  @rtype: dict
1595 b9e12624 Hrvoje Ribicic
  @return: dictionary of instance: data, with data having the following keys:
1596 b9e12624 Hrvoje Ribicic
      - instance: instance name
1597 b9e12624 Hrvoje Ribicic
      - kind: console kind
1598 b9e12624 Hrvoje Ribicic
      - message: used with kind == CONS_MESSAGE, indicates console to be
1599 b9e12624 Hrvoje Ribicic
                 unavailable, supplies error message
1600 b9e12624 Hrvoje Ribicic
      - host: host to connect to
1601 b9e12624 Hrvoje Ribicic
      - port: port to use
1602 b9e12624 Hrvoje Ribicic
      - user: user for login
1603 b9e12624 Hrvoje Ribicic
      - command: the command, broken into parts as an array
1604 b9e12624 Hrvoje Ribicic
      - display: unknown, potentially unused?
1605 b9e12624 Hrvoje Ribicic

1606 b9e12624 Hrvoje Ribicic
  """
1607 b9e12624 Hrvoje Ribicic
1608 b9e12624 Hrvoje Ribicic
  output = {}
1609 b9e12624 Hrvoje Ribicic
  for inst_name in instance_param_dict:
1610 b9e12624 Hrvoje Ribicic
    instance = instance_param_dict[inst_name]["instance"]
1611 b9e12624 Hrvoje Ribicic
    pnode = instance_param_dict[inst_name]["node"]
1612 c42be2c0 Petr Pudlak
    group = instance_param_dict[inst_name]["group"]
1613 b9e12624 Hrvoje Ribicic
    hvparams = instance_param_dict[inst_name]["hvParams"]
1614 b9e12624 Hrvoje Ribicic
    beparams = instance_param_dict[inst_name]["beParams"]
1615 b9e12624 Hrvoje Ribicic
1616 b9e12624 Hrvoje Ribicic
    instance = objects.Instance.FromDict(instance)
1617 b9e12624 Hrvoje Ribicic
    pnode = objects.Node.FromDict(pnode)
1618 c42be2c0 Petr Pudlak
    group = objects.NodeGroup.FromDict(group)
1619 b9e12624 Hrvoje Ribicic
1620 b9e12624 Hrvoje Ribicic
    h = get_hv_fn(instance.hypervisor)
1621 c42be2c0 Petr Pudlak
    output[inst_name] = h.GetInstanceConsole(instance, pnode, group,
1622 c42be2c0 Petr Pudlak
                                             hvparams, beparams).ToDict()
1623 b9e12624 Hrvoje Ribicic
1624 b9e12624 Hrvoje Ribicic
  return output
1625 b9e12624 Hrvoje Ribicic
1626 b9e12624 Hrvoje Ribicic
1627 6aa7a354 Iustin Pop
def _InstanceLogName(kind, os_name, instance, component):
1628 81a3406c Iustin Pop
  """Compute the OS log filename for a given instance and operation.
1629 81a3406c Iustin Pop

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

1633 81a3406c Iustin Pop
  @type kind: string
1634 81a3406c Iustin Pop
  @param kind: the operation type (e.g. add, import, etc.)
1635 81a3406c Iustin Pop
  @type os_name: string
1636 81a3406c Iustin Pop
  @param os_name: the os name
1637 81a3406c Iustin Pop
  @type instance: string
1638 81a3406c Iustin Pop
  @param instance: the name of the instance being imported/added/etc.
1639 6aa7a354 Iustin Pop
  @type component: string or None
1640 6aa7a354 Iustin Pop
  @param component: the name of the component of the instance being
1641 6aa7a354 Iustin Pop
      transferred
1642 81a3406c Iustin Pop

1643 81a3406c Iustin Pop
  """
1644 1651d116 Michael Hanselmann
  # TODO: Use tempfile.mkstemp to create unique filename
1645 6aa7a354 Iustin Pop
  if component:
1646 6aa7a354 Iustin Pop
    assert "/" not in component
1647 6aa7a354 Iustin Pop
    c_msg = "-%s" % component
1648 6aa7a354 Iustin Pop
  else:
1649 6aa7a354 Iustin Pop
    c_msg = ""
1650 6aa7a354 Iustin Pop
  base = ("%s-%s-%s%s-%s.log" %
1651 6aa7a354 Iustin Pop
          (kind, os_name, instance, c_msg, utils.TimestampForFilename()))
1652 710f30ec Michael Hanselmann
  return utils.PathJoin(pathutils.LOG_OS_DIR, base)
1653 81a3406c Iustin Pop
1654 81a3406c Iustin Pop
1655 4a0e011f Iustin Pop
def InstanceOsAdd(instance, reinstall, debug):
1656 2f8598a5 Alexander Schreiber
  """Add an OS to an instance.
1657 a8083063 Iustin Pop

1658 d15a9ad3 Guido Trotter
  @type instance: L{objects.Instance}
1659 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1660 e557bae9 Guido Trotter
  @type reinstall: boolean
1661 e557bae9 Guido Trotter
  @param reinstall: whether this is an instance reinstall
1662 4a0e011f Iustin Pop
  @type debug: integer
1663 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1664 c26a6bd2 Iustin Pop
  @rtype: None
1665 a8083063 Iustin Pop

1666 a8083063 Iustin Pop
  """
1667 255dcebd Iustin Pop
  inst_os = OSFromDisk(instance.os)
1668 255dcebd Iustin Pop
1669 4a0e011f Iustin Pop
  create_env = OSEnvironment(instance, inst_os, debug)
1670 e557bae9 Guido Trotter
  if reinstall:
1671 d0c8c01d Iustin Pop
    create_env["INSTANCE_REINSTALL"] = "1"
1672 a8083063 Iustin Pop
1673 6aa7a354 Iustin Pop
  logfile = _InstanceLogName("add", instance.os, instance.name, None)
1674 decd5f45 Iustin Pop
1675 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.create_script], env=create_env,
1676 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1677 decd5f45 Iustin Pop
  if result.failed:
1678 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s, logfile: %s,"
1679 d868edb4 Iustin Pop
                  " output: %s", result.cmd, result.fail_reason, logfile,
1680 18682bca Iustin Pop
                  result.output)
1681 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1682 20e01edd Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1683 afdc3985 Iustin Pop
    _Fail("OS create script failed (%s), last lines in the"
1684 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1685 decd5f45 Iustin Pop
1686 decd5f45 Iustin Pop
1687 4a0e011f Iustin Pop
def RunRenameInstance(instance, old_name, debug):
1688 decd5f45 Iustin Pop
  """Run the OS rename script for an instance.
1689 decd5f45 Iustin Pop

1690 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1691 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1692 d15a9ad3 Guido Trotter
  @type old_name: string
1693 d15a9ad3 Guido Trotter
  @param old_name: previous instance name
1694 4a0e011f Iustin Pop
  @type debug: integer
1695 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1696 10c2650b Iustin Pop
  @rtype: boolean
1697 10c2650b Iustin Pop
  @return: the success of the operation
1698 decd5f45 Iustin Pop

1699 decd5f45 Iustin Pop
  """
1700 decd5f45 Iustin Pop
  inst_os = OSFromDisk(instance.os)
1701 decd5f45 Iustin Pop
1702 4a0e011f Iustin Pop
  rename_env = OSEnvironment(instance, inst_os, debug)
1703 d0c8c01d Iustin Pop
  rename_env["OLD_INSTANCE_NAME"] = old_name
1704 decd5f45 Iustin Pop
1705 81a3406c Iustin Pop
  logfile = _InstanceLogName("rename", instance.os,
1706 6aa7a354 Iustin Pop
                             "%s-%s" % (old_name, instance.name), None)
1707 a8083063 Iustin Pop
1708 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.rename_script], env=rename_env,
1709 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1710 a8083063 Iustin Pop
1711 a8083063 Iustin Pop
  if result.failed:
1712 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s output: %s",
1713 d868edb4 Iustin Pop
                  result.cmd, result.fail_reason, result.output)
1714 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1715 96841384 Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1716 afdc3985 Iustin Pop
    _Fail("OS rename script failed (%s), last lines in the"
1717 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1718 a8083063 Iustin Pop
1719 a8083063 Iustin Pop
1720 3b721842 Michael Hanselmann
def _GetBlockDevSymlinkPath(instance_name, idx, _dir=None):
1721 3b721842 Michael Hanselmann
  """Returns symlink path for block device.
1722 3b721842 Michael Hanselmann

1723 3b721842 Michael Hanselmann
  """
1724 3b721842 Michael Hanselmann
  if _dir is None:
1725 3b721842 Michael Hanselmann
    _dir = pathutils.DISK_LINKS_DIR
1726 3b721842 Michael Hanselmann
1727 3b721842 Michael Hanselmann
  return utils.PathJoin(_dir,
1728 3b721842 Michael Hanselmann
                        ("%s%s%s" %
1729 3b721842 Michael Hanselmann
                         (instance_name, constants.DISK_SEPARATOR, idx)))
1730 5282084b Iustin Pop
1731 5282084b Iustin Pop
1732 5282084b Iustin Pop
def _SymlinkBlockDev(instance_name, device_path, idx):
1733 9332fd8a Iustin Pop
  """Set up symlinks to a instance's block device.
1734 9332fd8a Iustin Pop

1735 9332fd8a Iustin Pop
  This is an auxiliary function run when an instance is start (on the primary
1736 9332fd8a Iustin Pop
  node) or when an instance is migrated (on the target node).
1737 9332fd8a Iustin Pop

1738 9332fd8a Iustin Pop

1739 5282084b Iustin Pop
  @param instance_name: the name of the target instance
1740 5282084b Iustin Pop
  @param device_path: path of the physical block device, on the node
1741 5282084b Iustin Pop
  @param idx: the disk index
1742 5282084b Iustin Pop
  @return: absolute path to the disk's symlink
1743 9332fd8a Iustin Pop

1744 9332fd8a Iustin Pop
  """
1745 5282084b Iustin Pop
  link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1746 9332fd8a Iustin Pop
  try:
1747 9332fd8a Iustin Pop
    os.symlink(device_path, link_name)
1748 5282084b Iustin Pop
  except OSError, err:
1749 5282084b Iustin Pop
    if err.errno == errno.EEXIST:
1750 9332fd8a Iustin Pop
      if (not os.path.islink(link_name) or
1751 9332fd8a Iustin Pop
          os.readlink(link_name) != device_path):
1752 9332fd8a Iustin Pop
        os.remove(link_name)
1753 9332fd8a Iustin Pop
        os.symlink(device_path, link_name)
1754 9332fd8a Iustin Pop
    else:
1755 9332fd8a Iustin Pop
      raise
1756 9332fd8a Iustin Pop
1757 9332fd8a Iustin Pop
  return link_name
1758 9332fd8a Iustin Pop
1759 9332fd8a Iustin Pop
1760 5282084b Iustin Pop
def _RemoveBlockDevLinks(instance_name, disks):
1761 3c9c571d Iustin Pop
  """Remove the block device symlinks belonging to the given instance.
1762 3c9c571d Iustin Pop

1763 3c9c571d Iustin Pop
  """
1764 29921401 Iustin Pop
  for idx, _ in enumerate(disks):
1765 5282084b Iustin Pop
    link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1766 5282084b Iustin Pop
    if os.path.islink(link_name):
1767 3c9c571d Iustin Pop
      try:
1768 03dfa658 Iustin Pop
        os.remove(link_name)
1769 03dfa658 Iustin Pop
      except OSError:
1770 03dfa658 Iustin Pop
        logging.exception("Can't remove symlink '%s'", link_name)
1771 3c9c571d Iustin Pop
1772 3c9c571d Iustin Pop
1773 66d3d195 Dimitris Aragiorgis
def _CalculateDeviceURI(instance, disk, device):
1774 66d3d195 Dimitris Aragiorgis
  """Get the URI for the device.
1775 66d3d195 Dimitris Aragiorgis

1776 66d3d195 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
1777 66d3d195 Dimitris Aragiorgis
  @param instance: the instance which disk belongs to
1778 66d3d195 Dimitris Aragiorgis
  @type disk: L{objects.Disk}
1779 66d3d195 Dimitris Aragiorgis
  @param disk: the target disk object
1780 66d3d195 Dimitris Aragiorgis
  @type device: L{bdev.BlockDev}
1781 66d3d195 Dimitris Aragiorgis
  @param device: the corresponding BlockDevice
1782 66d3d195 Dimitris Aragiorgis
  @rtype: string
1783 66d3d195 Dimitris Aragiorgis
  @return: the device uri if any else None
1784 66d3d195 Dimitris Aragiorgis

1785 66d3d195 Dimitris Aragiorgis
  """
1786 66d3d195 Dimitris Aragiorgis
  access_mode = disk.params.get(constants.LDP_ACCESS,
1787 66d3d195 Dimitris Aragiorgis
                                constants.DISK_KERNELSPACE)
1788 66d3d195 Dimitris Aragiorgis
  if access_mode == constants.DISK_USERSPACE:
1789 66d3d195 Dimitris Aragiorgis
    # This can raise errors.BlockDeviceError
1790 66d3d195 Dimitris Aragiorgis
    return device.GetUserspaceAccessUri(instance.hypervisor)
1791 66d3d195 Dimitris Aragiorgis
  else:
1792 66d3d195 Dimitris Aragiorgis
    return None
1793 66d3d195 Dimitris Aragiorgis
1794 66d3d195 Dimitris Aragiorgis
1795 9332fd8a Iustin Pop
def _GatherAndLinkBlockDevs(instance):
1796 a8083063 Iustin Pop
  """Set up an instance's block device(s).
1797 a8083063 Iustin Pop

1798 a8083063 Iustin Pop
  This is run on the primary node at instance startup. The block
1799 a8083063 Iustin Pop
  devices must be already assembled.
1800 a8083063 Iustin Pop

1801 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1802 5bd52dab Thomas Thrainer
  @param instance: the instance whose disks we should assemble
1803 069cfbf1 Iustin Pop
  @rtype: list
1804 66d3d195 Dimitris Aragiorgis
  @return: list of (disk_object, link_name, drive_uri)
1805 10c2650b Iustin Pop

1806 a8083063 Iustin Pop
  """
1807 a8083063 Iustin Pop
  block_devices = []
1808 e9ebf2d7 Ilias Tsitsimpis
  for idx, disk in enumerate(instance.disks_info):
1809 a8083063 Iustin Pop
    device = _RecursiveFindBD(disk)
1810 a8083063 Iustin Pop
    if device is None:
1811 a8083063 Iustin Pop
      raise errors.BlockDeviceError("Block device '%s' is not set up." %
1812 a8083063 Iustin Pop
                                    str(disk))
1813 a8083063 Iustin Pop
    device.Open()
1814 9332fd8a Iustin Pop
    try:
1815 5282084b Iustin Pop
      link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
1816 9332fd8a Iustin Pop
    except OSError, e:
1817 9332fd8a Iustin Pop
      raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
1818 9332fd8a Iustin Pop
                                    e.strerror)
1819 66d3d195 Dimitris Aragiorgis
    uri = _CalculateDeviceURI(instance, disk, device)
1820 9332fd8a Iustin Pop
1821 66d3d195 Dimitris Aragiorgis
    block_devices.append((disk, link_name, uri))
1822 9332fd8a Iustin Pop
1823 a8083063 Iustin Pop
  return block_devices
1824 a8083063 Iustin Pop
1825 a8083063 Iustin Pop
1826 1fa6fcba Michele Tartara
def StartInstance(instance, startup_paused, reason, store_reason=True):
1827 a8083063 Iustin Pop
  """Start an instance.
1828 a8083063 Iustin Pop

1829 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1830 e69d05fd Iustin Pop
  @param instance: the instance object
1831 323f9095 Stephen Shirley
  @type startup_paused: bool
1832 323f9095 Stephen Shirley
  @param instance: pause instance at startup?
1833 1fa6fcba Michele Tartara
  @type reason: list of reasons
1834 1fa6fcba Michele Tartara
  @param reason: the reason trail for this startup
1835 1fa6fcba Michele Tartara
  @type store_reason: boolean
1836 1fa6fcba Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1837 c26a6bd2 Iustin Pop
  @rtype: None
1838 a8083063 Iustin Pop

1839 098c0958 Michael Hanselmann
  """
1840 3361ab37 Helga Velroyen
  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
1841 3361ab37 Helga Velroyen
                                                   instance.hvparams)
1842 a8083063 Iustin Pop
1843 a8083063 Iustin Pop
  if instance.name in running_instances:
1844 c26a6bd2 Iustin Pop
    logging.info("Instance %s already running, not starting", instance.name)
1845 c26a6bd2 Iustin Pop
    return
1846 a8083063 Iustin Pop
1847 a8083063 Iustin Pop
  try:
1848 ec596c24 Iustin Pop
    block_devices = _GatherAndLinkBlockDevs(instance)
1849 ec596c24 Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
1850 323f9095 Stephen Shirley
    hyper.StartInstance(instance, block_devices, startup_paused)
1851 1fa6fcba Michele Tartara
    if store_reason:
1852 1fa6fcba Michele Tartara
      _StoreInstReasonTrail(instance.name, reason)
1853 ec596c24 Iustin Pop
  except errors.BlockDeviceError, err:
1854 2cc6781a Iustin Pop
    _Fail("Block device error: %s", err, exc=True)
1855 a8083063 Iustin Pop
  except errors.HypervisorError, err:
1856 e9ebf2d7 Ilias Tsitsimpis
    _RemoveBlockDevLinks(instance.name, instance.disks_info)
1857 2cc6781a Iustin Pop
    _Fail("Hypervisor error: %s", err, exc=True)
1858 a8083063 Iustin Pop
1859 a8083063 Iustin Pop
1860 1f350e0f Michele Tartara
def InstanceShutdown(instance, timeout, reason, store_reason=True):
1861 a8083063 Iustin Pop
  """Shut an instance down.
1862 a8083063 Iustin Pop

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

1865 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1866 e69d05fd Iustin Pop
  @param instance: the instance object
1867 6263189c Guido Trotter
  @type timeout: integer
1868 6263189c Guido Trotter
  @param timeout: maximum timeout for soft shutdown
1869 1f350e0f Michele Tartara
  @type reason: list of reasons
1870 1f350e0f Michele Tartara
  @param reason: the reason trail for this shutdown
1871 1f350e0f Michele Tartara
  @type store_reason: boolean
1872 1f350e0f Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1873 c26a6bd2 Iustin Pop
  @rtype: None
1874 a8083063 Iustin Pop

1875 098c0958 Michael Hanselmann
  """
1876 e69d05fd Iustin Pop
  hv_name = instance.hypervisor
1877 e4e9b806 Guido Trotter
  hyper = hypervisor.GetHypervisor(hv_name)
1878 c26a6bd2 Iustin Pop
  iname = instance.name
1879 a8083063 Iustin Pop
1880 3361ab37 Helga Velroyen
  if instance.name not in hyper.ListInstances(instance.hvparams):
1881 c26a6bd2 Iustin Pop
    logging.info("Instance %s not running, doing nothing", iname)
1882 c26a6bd2 Iustin Pop
    return
1883 a8083063 Iustin Pop
1884 876fb142 Helga Velroyen
  class _TryShutdown(object):
1885 3c0cdc83 Michael Hanselmann
    def __init__(self):
1886 3c0cdc83 Michael Hanselmann
      self.tried_once = False
1887 a8083063 Iustin Pop
1888 3c0cdc83 Michael Hanselmann
    def __call__(self):
1889 3361ab37 Helga Velroyen
      if iname not in hyper.ListInstances(instance.hvparams):
1890 3c0cdc83 Michael Hanselmann
        return
1891 3c0cdc83 Michael Hanselmann
1892 3c0cdc83 Michael Hanselmann
      try:
1893 874f6148 Michele Tartara
        hyper.StopInstance(instance, retry=self.tried_once, timeout=timeout)
1894 1f350e0f Michele Tartara
        if store_reason:
1895 1f350e0f Michele Tartara
          _StoreInstReasonTrail(instance.name, reason)
1896 3c0cdc83 Michael Hanselmann
      except errors.HypervisorError, err:
1897 3361ab37 Helga Velroyen
        if iname not in hyper.ListInstances(instance.hvparams):
1898 3c0cdc83 Michael Hanselmann
          # if the instance is no longer existing, consider this a
1899 3c0cdc83 Michael Hanselmann
          # success and go to cleanup
1900 3c0cdc83 Michael Hanselmann
          return
1901 3c0cdc83 Michael Hanselmann
1902 3c0cdc83 Michael Hanselmann
        _Fail("Failed to stop instance %s: %s", iname, err)
1903 3c0cdc83 Michael Hanselmann
1904 3c0cdc83 Michael Hanselmann
      self.tried_once = True
1905 3c0cdc83 Michael Hanselmann
1906 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
1907 3c0cdc83 Michael Hanselmann
1908 3c0cdc83 Michael Hanselmann
  try:
1909 3c0cdc83 Michael Hanselmann
    utils.Retry(_TryShutdown(), 5, timeout)
1910 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
1911 a8083063 Iustin Pop
    # the shutdown did not succeed
1912 e4e9b806 Guido Trotter
    logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
1913 a8083063 Iustin Pop
1914 a8083063 Iustin Pop
    try:
1915 a8083063 Iustin Pop
      hyper.StopInstance(instance, force=True)
1916 a8083063 Iustin Pop
    except errors.HypervisorError, err:
1917 3361ab37 Helga Velroyen
      if iname in hyper.ListInstances(instance.hvparams):
1918 3782acd7 Iustin Pop
        # only raise an error if the instance still exists, otherwise
1919 3782acd7 Iustin Pop
        # the error could simply be "instance ... unknown"!
1920 3782acd7 Iustin Pop
        _Fail("Failed to force stop instance %s: %s", iname, err)
1921 a8083063 Iustin Pop
1922 a8083063 Iustin Pop
    time.sleep(1)
1923 3c0cdc83 Michael Hanselmann
1924 3361ab37 Helga Velroyen
    if iname in hyper.ListInstances(instance.hvparams):
1925 c26a6bd2 Iustin Pop
      _Fail("Could not shutdown instance %s even by destroy", iname)
1926 3c9c571d Iustin Pop
1927 f28ec899 Guido Trotter
  try:
1928 f28ec899 Guido Trotter
    hyper.CleanupInstance(instance.name)
1929 f28ec899 Guido Trotter
  except errors.HypervisorError, err:
1930 f28ec899 Guido Trotter
    logging.warning("Failed to execute post-shutdown cleanup step: %s", err)
1931 f28ec899 Guido Trotter
1932 e9ebf2d7 Ilias Tsitsimpis
  _RemoveBlockDevLinks(iname, instance.disks_info)
1933 a8083063 Iustin Pop
1934 a8083063 Iustin Pop
1935 55cec070 Michele Tartara
def InstanceReboot(instance, reboot_type, shutdown_timeout, reason):
1936 007a2f3e Alexander Schreiber
  """Reboot an instance.
1937 007a2f3e Alexander Schreiber

1938 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1939 10c2650b Iustin Pop
  @param instance: the instance object to reboot
1940 10c2650b Iustin Pop
  @type reboot_type: str
1941 10c2650b Iustin Pop
  @param reboot_type: the type of reboot, one the following
1942 10c2650b Iustin Pop
    constants:
1943 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_SOFT}: only reboot the
1944 10c2650b Iustin Pop
        instance OS, do not recreate the VM
1945 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_HARD}: tear down and
1946 10c2650b Iustin Pop
        restart the VM (at the hypervisor level)
1947 73e5a4f4 Iustin Pop
      - the other reboot type (L{constants.INSTANCE_REBOOT_FULL}) is
1948 73e5a4f4 Iustin Pop
        not accepted here, since that mode is handled differently, in
1949 73e5a4f4 Iustin Pop
        cmdlib, and translates into full stop and start of the
1950 73e5a4f4 Iustin Pop
        instance (instead of a call_instance_reboot RPC)
1951 23057d29 Michael Hanselmann
  @type shutdown_timeout: integer
1952 23057d29 Michael Hanselmann
  @param shutdown_timeout: maximum timeout for soft shutdown
1953 55cec070 Michele Tartara
  @type reason: list of reasons
1954 55cec070 Michele Tartara
  @param reason: the reason trail for this reboot
1955 c26a6bd2 Iustin Pop
  @rtype: None
1956 007a2f3e Alexander Schreiber

1957 007a2f3e Alexander Schreiber
  """
1958 3361ab37 Helga Velroyen
  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
1959 3361ab37 Helga Velroyen
                                                   instance.hvparams)
1960 007a2f3e Alexander Schreiber
1961 007a2f3e Alexander Schreiber
  if instance.name not in running_instances:
1962 2cc6781a Iustin Pop
    _Fail("Cannot reboot instance %s that is not running", instance.name)
1963 007a2f3e Alexander Schreiber
1964 e69d05fd Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1965 007a2f3e Alexander Schreiber
  if reboot_type == constants.INSTANCE_REBOOT_SOFT:
1966 007a2f3e Alexander Schreiber
    try:
1967 007a2f3e Alexander Schreiber
      hyper.RebootInstance(instance)
1968 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1969 2cc6781a Iustin Pop
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1970 007a2f3e Alexander Schreiber
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1971 007a2f3e Alexander Schreiber
    try:
1972 1f350e0f Michele Tartara
      InstanceShutdown(instance, shutdown_timeout, reason, store_reason=False)
1973 1fa6fcba Michele Tartara
      result = StartInstance(instance, False, reason, store_reason=False)
1974 55cec070 Michele Tartara
      _StoreInstReasonTrail(instance.name, reason)
1975 4a90bd4f Michele Tartara
      return result
1976 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1977 2cc6781a Iustin Pop
      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
1978 007a2f3e Alexander Schreiber
  else:
1979 2cc6781a Iustin Pop
    _Fail("Invalid reboot_type received: %s", reboot_type)
1980 007a2f3e Alexander Schreiber
1981 007a2f3e Alexander Schreiber
1982 ebe466d8 Guido Trotter
def InstanceBalloonMemory(instance, memory):
1983 ebe466d8 Guido Trotter
  """Resize an instance's memory.
1984 ebe466d8 Guido Trotter

1985 ebe466d8 Guido Trotter
  @type instance: L{objects.Instance}
1986 ebe466d8 Guido Trotter
  @param instance: the instance object
1987 ebe466d8 Guido Trotter
  @type memory: int
1988 ebe466d8 Guido Trotter
  @param memory: new memory amount in MB
1989 ebe466d8 Guido Trotter
  @rtype: None
1990 ebe466d8 Guido Trotter

1991 ebe466d8 Guido Trotter
  """
1992 ebe466d8 Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1993 3361ab37 Helga Velroyen
  running = hyper.ListInstances(instance.hvparams)
1994 ebe466d8 Guido Trotter
  if instance.name not in running:
1995 ebe466d8 Guido Trotter
    logging.info("Instance %s is not running, cannot balloon", instance.name)
1996 ebe466d8 Guido Trotter
    return
1997 ebe466d8 Guido Trotter
  try:
1998 ebe466d8 Guido Trotter
    hyper.BalloonInstanceMemory(instance, memory)
1999 ebe466d8 Guido Trotter
  except errors.HypervisorError, err:
2000 ebe466d8 Guido Trotter
    _Fail("Failed to balloon instance memory: %s", err, exc=True)
2001 ebe466d8 Guido Trotter
2002 ebe466d8 Guido Trotter
2003 6906a9d8 Guido Trotter
def MigrationInfo(instance):
2004 6906a9d8 Guido Trotter
  """Gather information about an instance to be migrated.
2005 6906a9d8 Guido Trotter

2006 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2007 6906a9d8 Guido Trotter
  @param instance: the instance definition
2008 6906a9d8 Guido Trotter

2009 6906a9d8 Guido Trotter
  """
2010 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2011 cd42d0ad Guido Trotter
  try:
2012 cd42d0ad Guido Trotter
    info = hyper.MigrationInfo(instance)
2013 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2014 2cc6781a Iustin Pop
    _Fail("Failed to fetch migration information: %s", err, exc=True)
2015 c26a6bd2 Iustin Pop
  return info
2016 6906a9d8 Guido Trotter
2017 6906a9d8 Guido Trotter
2018 6906a9d8 Guido Trotter
def AcceptInstance(instance, info, target):
2019 6906a9d8 Guido Trotter
  """Prepare the node to accept an instance.
2020 6906a9d8 Guido Trotter

2021 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2022 6906a9d8 Guido Trotter
  @param instance: the instance definition
2023 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
2024 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
2025 6906a9d8 Guido Trotter
  @type target: string
2026 6906a9d8 Guido Trotter
  @param target: target host (usually ip), on this node
2027 6906a9d8 Guido Trotter

2028 6906a9d8 Guido Trotter
  """
2029 77fcff4a Apollon Oikonomopoulos
  # TODO: why is this required only for DTS_EXT_MIRROR?
2030 77fcff4a Apollon Oikonomopoulos
  if instance.disk_template in constants.DTS_EXT_MIRROR:
2031 77fcff4a Apollon Oikonomopoulos
    # Create the symlinks, as the disks are not active
2032 77fcff4a Apollon Oikonomopoulos
    # in any way
2033 77fcff4a Apollon Oikonomopoulos
    try:
2034 77fcff4a Apollon Oikonomopoulos
      _GatherAndLinkBlockDevs(instance)
2035 77fcff4a Apollon Oikonomopoulos
    except errors.BlockDeviceError, err:
2036 77fcff4a Apollon Oikonomopoulos
      _Fail("Block device error: %s", err, exc=True)
2037 77fcff4a Apollon Oikonomopoulos
2038 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2039 cd42d0ad Guido Trotter
  try:
2040 cd42d0ad Guido Trotter
    hyper.AcceptInstance(instance, info, target)
2041 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2042 77fcff4a Apollon Oikonomopoulos
    if instance.disk_template in constants.DTS_EXT_MIRROR:
2043 e9ebf2d7 Ilias Tsitsimpis
      _RemoveBlockDevLinks(instance.name, instance.disks_info)
2044 2cc6781a Iustin Pop
    _Fail("Failed to accept instance: %s", err, exc=True)
2045 6906a9d8 Guido Trotter
2046 6906a9d8 Guido Trotter
2047 6a1434d7 Andrea Spadaccini
def FinalizeMigrationDst(instance, info, success):
2048 6906a9d8 Guido Trotter
  """Finalize any preparation to accept an instance.
2049 6906a9d8 Guido Trotter

2050 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2051 6906a9d8 Guido Trotter
  @param instance: the instance definition
2052 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
2053 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
2054 6906a9d8 Guido Trotter
  @type success: boolean
2055 6906a9d8 Guido Trotter
  @param success: whether the migration was a success or a failure
2056 6906a9d8 Guido Trotter

2057 6906a9d8 Guido Trotter
  """
2058 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2059 cd42d0ad Guido Trotter
  try:
2060 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationDst(instance, info, success)
2061 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2062 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize migration on the target node: %s", err, exc=True)
2063 6906a9d8 Guido Trotter
2064 6906a9d8 Guido Trotter
2065 bc0a2284 Helga Velroyen
def MigrateInstance(cluster_name, instance, target, live):
2066 2a10865c Iustin Pop
  """Migrates an instance to another node.
2067 2a10865c Iustin Pop

2068 bc0a2284 Helga Velroyen
  @type cluster_name: string
2069 bc0a2284 Helga Velroyen
  @param cluster_name: name of the cluster
2070 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
2071 9f0e6b37 Iustin Pop
  @param instance: the instance definition
2072 9f0e6b37 Iustin Pop
  @type target: string
2073 9f0e6b37 Iustin Pop
  @param target: the target node name
2074 9f0e6b37 Iustin Pop
  @type live: boolean
2075 9f0e6b37 Iustin Pop
  @param live: whether the migration should be done live or not (the
2076 9f0e6b37 Iustin Pop
      interpretation of this parameter is left to the hypervisor)
2077 c03fe62b Andrea Spadaccini
  @raise RPCFail: if migration fails for some reason
2078 9f0e6b37 Iustin Pop

2079 2a10865c Iustin Pop
  """
2080 53c776b5 Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2081 2a10865c Iustin Pop
2082 2a10865c Iustin Pop
  try:
2083 bc0a2284 Helga Velroyen
    hyper.MigrateInstance(cluster_name, instance, target, live)
2084 2a10865c Iustin Pop
  except errors.HypervisorError, err:
2085 2cc6781a Iustin Pop
    _Fail("Failed to migrate instance: %s", err, exc=True)
2086 2a10865c Iustin Pop
2087 2a10865c Iustin Pop
2088 6a1434d7 Andrea Spadaccini
def FinalizeMigrationSource(instance, success, live):
2089 6a1434d7 Andrea Spadaccini
  """Finalize the instance migration on the source node.
2090 6a1434d7 Andrea Spadaccini

2091 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2092 6a1434d7 Andrea Spadaccini
  @param instance: the instance definition of the migrated instance
2093 6a1434d7 Andrea Spadaccini
  @type success: bool
2094 6a1434d7 Andrea Spadaccini
  @param success: whether the migration succeeded or not
2095 6a1434d7 Andrea Spadaccini
  @type live: bool
2096 6a1434d7 Andrea Spadaccini
  @param live: whether the user requested a live migration or not
2097 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the execution fails for some reason
2098 6a1434d7 Andrea Spadaccini

2099 6a1434d7 Andrea Spadaccini
  """
2100 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2101 6a1434d7 Andrea Spadaccini
2102 6a1434d7 Andrea Spadaccini
  try:
2103 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationSource(instance, success, live)
2104 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2105 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize the migration on the source node: %s", err,
2106 6a1434d7 Andrea Spadaccini
          exc=True)
2107 6a1434d7 Andrea Spadaccini
2108 6a1434d7 Andrea Spadaccini
2109 6a1434d7 Andrea Spadaccini
def GetMigrationStatus(instance):
2110 6a1434d7 Andrea Spadaccini
  """Get the migration status
2111 6a1434d7 Andrea Spadaccini

2112 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2113 6a1434d7 Andrea Spadaccini
  @param instance: the instance that is being migrated
2114 6a1434d7 Andrea Spadaccini
  @rtype: L{objects.MigrationStatus}
2115 6a1434d7 Andrea Spadaccini
  @return: the status of the current migration (one of
2116 6a1434d7 Andrea Spadaccini
           L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2117 6a1434d7 Andrea Spadaccini
           progress info that can be retrieved from the hypervisor
2118 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the migration status cannot be retrieved
2119 6a1434d7 Andrea Spadaccini

2120 6a1434d7 Andrea Spadaccini
  """
2121 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2122 6a1434d7 Andrea Spadaccini
  try:
2123 6a1434d7 Andrea Spadaccini
    return hyper.GetMigrationStatus(instance)
2124 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2125 6a1434d7 Andrea Spadaccini
    _Fail("Failed to get migration status: %s", err, exc=True)
2126 6a1434d7 Andrea Spadaccini
2127 6a1434d7 Andrea Spadaccini
2128 c5708931 Dimitris Aragiorgis
def HotplugDevice(instance, action, dev_type, device, extra, seq):
2129 c5708931 Dimitris Aragiorgis
  """Hotplug a device
2130 c5708931 Dimitris Aragiorgis

2131 c5708931 Dimitris Aragiorgis
  Hotplug is currently supported only for KVM Hypervisor.
2132 c5708931 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
2133 c5708931 Dimitris Aragiorgis
  @param instance: the instance to which we hotplug a device
2134 c5708931 Dimitris Aragiorgis
  @type action: string
2135 c5708931 Dimitris Aragiorgis
  @param action: the hotplug action to perform
2136 c5708931 Dimitris Aragiorgis
  @type dev_type: string
2137 c5708931 Dimitris Aragiorgis
  @param dev_type: the device type to hotplug
2138 c5708931 Dimitris Aragiorgis
  @type device: either L{objects.NIC} or L{objects.Disk}
2139 c5708931 Dimitris Aragiorgis
  @param device: the device object to hotplug
2140 c5708931 Dimitris Aragiorgis
  @type extra: string
2141 c5708931 Dimitris Aragiorgis
  @param extra: extra info used by hotplug code (e.g. disk link)
2142 c5708931 Dimitris Aragiorgis
  @type seq: int
2143 c5708931 Dimitris Aragiorgis
  @param seq: the index of the device from master perspective
2144 c5708931 Dimitris Aragiorgis
  @raise RPCFail: in case instance does not have KVM hypervisor
2145 c5708931 Dimitris Aragiorgis

2146 c5708931 Dimitris Aragiorgis
  """
2147 c5708931 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2148 c5708931 Dimitris Aragiorgis
  try:
2149 50e0f1d9 Dimitris Aragiorgis
    hyper.VerifyHotplugSupport(instance, action, dev_type)
2150 50e0f1d9 Dimitris Aragiorgis
  except errors.HotplugError, err:
2151 c5708931 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2152 c5708931 Dimitris Aragiorgis
2153 c5708931 Dimitris Aragiorgis
  if action == constants.HOTPLUG_ACTION_ADD:
2154 c5708931 Dimitris Aragiorgis
    fn = hyper.HotAddDevice
2155 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_REMOVE:
2156 c5708931 Dimitris Aragiorgis
    fn = hyper.HotDelDevice
2157 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_MODIFY:
2158 c5708931 Dimitris Aragiorgis
    fn = hyper.HotModDevice
2159 c5708931 Dimitris Aragiorgis
  else:
2160 c5708931 Dimitris Aragiorgis
    assert action in constants.HOTPLUG_ALL_ACTIONS
2161 c5708931 Dimitris Aragiorgis
2162 c5708931 Dimitris Aragiorgis
  return fn(instance, dev_type, device, extra, seq)
2163 c5708931 Dimitris Aragiorgis
2164 c5708931 Dimitris Aragiorgis
2165 24711492 Dimitris Aragiorgis
def HotplugSupported(instance):
2166 24711492 Dimitris Aragiorgis
  """Checks if hotplug is generally supported.
2167 24711492 Dimitris Aragiorgis

2168 24711492 Dimitris Aragiorgis
  """
2169 24711492 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2170 24711492 Dimitris Aragiorgis
  try:
2171 24711492 Dimitris Aragiorgis
    hyper.HotplugSupported(instance)
2172 24711492 Dimitris Aragiorgis
  except errors.HotplugError, err:
2173 24711492 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2174 24711492 Dimitris Aragiorgis
2175 24711492 Dimitris Aragiorgis
2176 2fd4e86d Jose A. Lopes
def ModifyInstanceMetadata(metadata):
2177 2fd4e86d Jose A. Lopes
  """Sends instance data to the metadata daemon.
2178 2fd4e86d Jose A. Lopes

2179 2fd4e86d Jose A. Lopes
  Uses the Luxi transport layer to communicate with the metadata
2180 2fd4e86d Jose A. Lopes
  daemon configuration server.  It starts the metadata daemon if it is
2181 2fd4e86d Jose A. Lopes
  not running.
2182 2fd4e86d Jose A. Lopes

2183 2fd4e86d Jose A. Lopes
  @type metadata: dict
2184 2fd4e86d Jose A. Lopes
  @param metadata: instance metadata obtained by calling
2185 2fd4e86d Jose A. Lopes
                   L{objects.Instance.ToDict} on an instance object
2186 2fd4e86d Jose A. Lopes

2187 2fd4e86d Jose A. Lopes
  """
2188 2fd4e86d Jose A. Lopes
  if not utils.IsDaemonAlive(constants.METAD):
2189 bac957e5 Apollon Oikonomopoulos
    result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.METAD])
2190 2fd4e86d Jose A. Lopes
    if result.failed:
2191 2fd4e86d Jose A. Lopes
      raise errors.HypervisorError("Failed to start metadata daemon")
2192 2fd4e86d Jose A. Lopes
2193 2fd4e86d Jose A. Lopes
  def _Connect():
2194 2fd4e86d Jose A. Lopes
    return transport.Transport(pathutils.SOCKET_DIR + "/ganeti-metad")
2195 2fd4e86d Jose A. Lopes
2196 2fd4e86d Jose A. Lopes
  retries = 5
2197 2fd4e86d Jose A. Lopes
2198 2fd4e86d Jose A. Lopes
  while True:
2199 2fd4e86d Jose A. Lopes
    try:
2200 2fd4e86d Jose A. Lopes
      trans = utils.Retry(_Connect, 1.0, constants.LUXI_DEF_CTMO)
2201 2fd4e86d Jose A. Lopes
      break
2202 2fd4e86d Jose A. Lopes
    except utils.RetryTimeout:
2203 2fd4e86d Jose A. Lopes
      raise TimeoutError("Connection to metadata daemon timed out")
2204 2fd4e86d Jose A. Lopes
    except (socket.error, NoMasterError), err:
2205 2fd4e86d Jose A. Lopes
      if retries == 0:
2206 2fd4e86d Jose A. Lopes
        raise TimeoutError("Failed to connect to metadata daemon: %s" % err)
2207 2fd4e86d Jose A. Lopes
      else:
2208 2fd4e86d Jose A. Lopes
        retries -= 1
2209 2fd4e86d Jose A. Lopes
2210 2fd4e86d Jose A. Lopes
  data = serializer.DumpJson(metadata,
2211 2fd4e86d Jose A. Lopes
                             private_encoder=serializer.EncodeWithPrivateFields)
2212 2fd4e86d Jose A. Lopes
2213 2fd4e86d Jose A. Lopes
  trans.Send(data)
2214 2fd4e86d Jose A. Lopes
  trans.Close()
2215 2fd4e86d Jose A. Lopes
2216 2fd4e86d Jose A. Lopes
2217 ee1478e5 Bernardo Dal Seno
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
2218 a8083063 Iustin Pop
  """Creates a block device for an instance.
2219 a8083063 Iustin Pop

2220 b1206984 Iustin Pop
  @type disk: L{objects.Disk}
2221 b1206984 Iustin Pop
  @param disk: the object describing the disk we should create
2222 b1206984 Iustin Pop
  @type size: int
2223 b1206984 Iustin Pop
  @param size: the size of the physical underlying device, in MiB
2224 b1206984 Iustin Pop
  @type owner: str
2225 b1206984 Iustin Pop
  @param owner: the name of the instance for which disk is created,
2226 b1206984 Iustin Pop
      used for device cache data
2227 b1206984 Iustin Pop
  @type on_primary: boolean
2228 b1206984 Iustin Pop
  @param on_primary:  indicates if it is the primary node or not
2229 b1206984 Iustin Pop
  @type info: string
2230 b1206984 Iustin Pop
  @param info: string that will be sent to the physical device
2231 b1206984 Iustin Pop
      creation, used for example to set (LVM) tags on LVs
2232 ee1478e5 Bernardo Dal Seno
  @type excl_stor: boolean
2233 ee1478e5 Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
2234 b1206984 Iustin Pop

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

2239 a8083063 Iustin Pop
  """
2240 d0c8c01d Iustin Pop
  # TODO: remove the obsolete "size" argument
2241 b459a848 Andrea Spadaccini
  # pylint: disable=W0613
2242 a8083063 Iustin Pop
  clist = []
2243 a8083063 Iustin Pop
  if disk.children:
2244 a8083063 Iustin Pop
    for child in disk.children:
2245 1063abd1 Iustin Pop
      try:
2246 1063abd1 Iustin Pop
        crdev = _RecursiveAssembleBD(child, owner, on_primary)
2247 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2248 2cc6781a Iustin Pop
        _Fail("Can't assemble device %s: %s", child, err)
2249 a8083063 Iustin Pop
      if on_primary or disk.AssembleOnSecondary():
2250 a8083063 Iustin Pop
        # we need the children open in case the device itself has to
2251 a8083063 Iustin Pop
        # be assembled
2252 1063abd1 Iustin Pop
        try:
2253 b459a848 Andrea Spadaccini
          # pylint: disable=E1103
2254 1063abd1 Iustin Pop
          crdev.Open()
2255 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
2256 2cc6781a Iustin Pop
          _Fail("Can't make child '%s' read-write: %s", child, err)
2257 a8083063 Iustin Pop
      clist.append(crdev)
2258 a8083063 Iustin Pop
2259 dab69e97 Iustin Pop
  try:
2260 ee1478e5 Bernardo Dal Seno
    device = bdev.Create(disk, clist, excl_stor)
2261 1063abd1 Iustin Pop
  except errors.BlockDeviceError, err:
2262 2cc6781a Iustin Pop
    _Fail("Can't create block device: %s", err)
2263 6c626518 Iustin Pop
2264 a8083063 Iustin Pop
  if on_primary or disk.AssembleOnSecondary():
2265 1063abd1 Iustin Pop
    try:
2266 1063abd1 Iustin Pop
      device.Assemble()
2267 1063abd1 Iustin Pop
    except errors.BlockDeviceError, err:
2268 2cc6781a Iustin Pop
      _Fail("Can't assemble device after creation, unusual event: %s", err)
2269 a8083063 Iustin Pop
    if on_primary or disk.OpenOnSecondary():
2270 1063abd1 Iustin Pop
      try:
2271 1063abd1 Iustin Pop
        device.Open(force=True)
2272 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2273 2cc6781a Iustin Pop
        _Fail("Can't make device r/w after creation, unusual event: %s", err)
2274 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(device.dev_path, owner,
2275 3f78eef2 Iustin Pop
                                on_primary, disk.iv_name)
2276 a0c3fea1 Michael Hanselmann
2277 a0c3fea1 Michael Hanselmann
  device.SetInfo(info)
2278 a0c3fea1 Michael Hanselmann
2279 c26a6bd2 Iustin Pop
  return device.unique_id
2280 a8083063 Iustin Pop
2281 a8083063 Iustin Pop
2282 326e0925 Jose A. Lopes
def _DumpDevice(source_path, target_path, offset, size, truncate):
2283 229fb4ea Jose A. Lopes
  """This function images/wipes the device using a local file.
2284 69dd363f René Nussbaumer

2285 229fb4ea Jose A. Lopes
  @type source_path: string
2286 229fb4ea Jose A. Lopes
  @param source_path: path of the image or data source (e.g., "/dev/zero")
2287 229fb4ea Jose A. Lopes

2288 229fb4ea Jose A. Lopes
  @type target_path: string
2289 229fb4ea Jose A. Lopes
  @param target_path: path of the device to image/wipe
2290 229fb4ea Jose A. Lopes

2291 229fb4ea Jose A. Lopes
  @type offset: int
2292 229fb4ea Jose A. Lopes
  @param offset: offset in MiB in the output file
2293 229fb4ea Jose A. Lopes

2294 229fb4ea Jose A. Lopes
  @type size: int
2295 229fb4ea Jose A. Lopes
  @param size: maximum size in MiB to write (data source might be smaller)
2296 229fb4ea Jose A. Lopes

2297 326e0925 Jose A. Lopes
  @type truncate: bool
2298 326e0925 Jose A. Lopes
  @param truncate: whether the file should be truncated
2299 326e0925 Jose A. Lopes

2300 229fb4ea Jose A. Lopes
  @return: None
2301 229fb4ea Jose A. Lopes
  @raise RPCFail: in case of failure
2302 69dd363f René Nussbaumer

2303 69dd363f René Nussbaumer
  """
2304 0188611b Michael Hanselmann
  # Internal sizes are always in Mebibytes; if the following "dd" command
2305 0188611b Michael Hanselmann
  # should use a different block size the offset and size given to this
2306 0188611b Michael Hanselmann
  # function must be adjusted accordingly before being passed to "dd".
2307 0188611b Michael Hanselmann
  block_size = 1024 * 1024
2308 0188611b Michael Hanselmann
2309 229fb4ea Jose A. Lopes
  cmd = [constants.DD_CMD, "if=%s" % source_path, "seek=%d" % offset,
2310 229fb4ea Jose A. Lopes
         "bs=%s" % block_size, "oflag=direct", "of=%s" % target_path,
2311 da63bb4e René Nussbaumer
         "count=%d" % size]
2312 326e0925 Jose A. Lopes
2313 326e0925 Jose A. Lopes
  if not truncate:
2314 326e0925 Jose A. Lopes
    cmd.append("conv=notrunc")
2315 326e0925 Jose A. Lopes
2316 da63bb4e René Nussbaumer
  result = utils.RunCmd(cmd)
2317 69dd363f René Nussbaumer
2318 69dd363f René Nussbaumer
  if result.failed:
2319 229fb4ea Jose A. Lopes
    _Fail("Dump command '%s' exited with error: %s; output: %s", result.cmd,
2320 69dd363f René Nussbaumer
          result.fail_reason, result.output)
2321 69dd363f René Nussbaumer
2322 69dd363f René Nussbaumer
2323 c89622cd Jose A. Lopes
def _DownloadAndDumpDevice(source_url, target_path, size):
2324 c89622cd Jose A. Lopes
  """This function images a device using a downloaded image file.
2325 c89622cd Jose A. Lopes

2326 c89622cd Jose A. Lopes
  @type source_url: string
2327 c89622cd Jose A. Lopes
  @param source_url: URL of image to dump to disk
2328 c89622cd Jose A. Lopes

2329 c89622cd Jose A. Lopes
  @type target_path: string
2330 c89622cd Jose A. Lopes
  @param target_path: path of the device to image
2331 c89622cd Jose A. Lopes

2332 c89622cd Jose A. Lopes
  @type size: int
2333 c89622cd Jose A. Lopes
  @param size: maximum size in MiB to write (data source might be smaller)
2334 c89622cd Jose A. Lopes

2335 c89622cd Jose A. Lopes
  @rtype: NoneType
2336 c89622cd Jose A. Lopes
  @return: None
2337 c89622cd Jose A. Lopes
  @raise RPCFail: in case of download or write failures
2338 c89622cd Jose A. Lopes

2339 c89622cd Jose A. Lopes
  """
2340 c89622cd Jose A. Lopes
  class DDParams(object):
2341 c89622cd Jose A. Lopes
    def __init__(self, current_size, total_size):
2342 c89622cd Jose A. Lopes
      self.current_size = current_size
2343 c89622cd Jose A. Lopes
      self.total_size = total_size
2344 c89622cd Jose A. Lopes
      self.image_size_error = False
2345 c89622cd Jose A. Lopes
2346 c89622cd Jose A. Lopes
  def dd_write(ddparams, out):
2347 c89622cd Jose A. Lopes
    if ddparams.current_size < ddparams.total_size:
2348 c89622cd Jose A. Lopes
      ddparams.current_size += len(out)
2349 c89622cd Jose A. Lopes
      target_file.write(out)
2350 c89622cd Jose A. Lopes
    else:
2351 c89622cd Jose A. Lopes
      ddparams.image_size_error = True
2352 c89622cd Jose A. Lopes
      return -1
2353 c89622cd Jose A. Lopes
2354 ee6106f0 Jose A. Lopes
  target_file = open(target_path, "r+")
2355 c89622cd Jose A. Lopes
  ddparams = DDParams(0, 1024 * 1024 * size)
2356 c89622cd Jose A. Lopes
2357 c89622cd Jose A. Lopes
  curl = pycurl.Curl()
2358 c89622cd Jose A. Lopes
  curl.setopt(pycurl.VERBOSE, True)
2359 c89622cd Jose A. Lopes
  curl.setopt(pycurl.NOSIGNAL, True)
2360 c89622cd Jose A. Lopes
  curl.setopt(pycurl.USERAGENT, http.HTTP_GANETI_VERSION)
2361 c89622cd Jose A. Lopes
  curl.setopt(pycurl.URL, source_url)
2362 c89622cd Jose A. Lopes
  curl.setopt(pycurl.WRITEFUNCTION, lambda out: dd_write(ddparams, out))
2363 c89622cd Jose A. Lopes
2364 c89622cd Jose A. Lopes
  try:
2365 c89622cd Jose A. Lopes
    curl.perform()
2366 c89622cd Jose A. Lopes
  except pycurl.error:
2367 c89622cd Jose A. Lopes
    if ddparams.image_size_error:
2368 c89622cd Jose A. Lopes
      _Fail("Disk image larger than the disk")
2369 c89622cd Jose A. Lopes
    else:
2370 c89622cd Jose A. Lopes
      raise
2371 c89622cd Jose A. Lopes
2372 c89622cd Jose A. Lopes
  target_file.close()
2373 c89622cd Jose A. Lopes
2374 c89622cd Jose A. Lopes
2375 da63bb4e René Nussbaumer
def BlockdevWipe(disk, offset, size):
2376 69dd363f René Nussbaumer
  """Wipes a block device.
2377 69dd363f René Nussbaumer

2378 69dd363f René Nussbaumer
  @type disk: L{objects.Disk}
2379 69dd363f René Nussbaumer
  @param disk: the disk object we want to wipe
2380 da63bb4e René Nussbaumer
  @type offset: int
2381 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
2382 da63bb4e René Nussbaumer
  @type size: int
2383 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
2384 69dd363f René Nussbaumer

2385 69dd363f René Nussbaumer
  """
2386 69dd363f René Nussbaumer
  try:
2387 69dd363f René Nussbaumer
    rdev = _RecursiveFindBD(disk)
2388 da63bb4e René Nussbaumer
  except errors.BlockDeviceError:
2389 da63bb4e René Nussbaumer
    rdev = None
2390 da63bb4e René Nussbaumer
2391 da63bb4e René Nussbaumer
  if not rdev:
2392 229fb4ea Jose A. Lopes
    _Fail("Cannot wipe device %s: device not found", disk.iv_name)
2393 0188611b Michael Hanselmann
  if offset < 0:
2394 0188611b Michael Hanselmann
    _Fail("Negative offset")
2395 0188611b Michael Hanselmann
  if size < 0:
2396 0188611b Michael Hanselmann
    _Fail("Negative size")
2397 da63bb4e René Nussbaumer
  if offset > rdev.size:
2398 229fb4ea Jose A. Lopes
    _Fail("Wipe offset is bigger than device size")
2399 da63bb4e René Nussbaumer
  if (offset + size) > rdev.size:
2400 229fb4ea Jose A. Lopes
    _Fail("Wipe offset and size are bigger than device size")
2401 229fb4ea Jose A. Lopes
2402 326e0925 Jose A. Lopes
  _DumpDevice("/dev/zero", rdev.dev_path, offset, size, True)
2403 69dd363f René Nussbaumer
2404 69dd363f René Nussbaumer
2405 2b8322f7 Jose A. Lopes
def BlockdevImage(disk, image, size):
2406 2b8322f7 Jose A. Lopes
  """Images a block device either by dumping a local file or
2407 2b8322f7 Jose A. Lopes
  downloading a URL.
2408 2b8322f7 Jose A. Lopes

2409 2b8322f7 Jose A. Lopes
  @type disk: L{objects.Disk}
2410 2b8322f7 Jose A. Lopes
  @param disk: the disk object we want to image
2411 2b8322f7 Jose A. Lopes

2412 2b8322f7 Jose A. Lopes
  @type image: string
2413 2b8322f7 Jose A. Lopes
  @param image: file path to the disk image be dumped
2414 2b8322f7 Jose A. Lopes

2415 2b8322f7 Jose A. Lopes
  @type size: int
2416 2b8322f7 Jose A. Lopes
  @param size: The size in MiB to write
2417 2b8322f7 Jose A. Lopes

2418 2b8322f7 Jose A. Lopes
  @rtype: NoneType
2419 2b8322f7 Jose A. Lopes
  @return: None
2420 2b8322f7 Jose A. Lopes
  @raise RPCFail: in case of failure
2421 2b8322f7 Jose A. Lopes

2422 2b8322f7 Jose A. Lopes
  """
2423 d00e49f6 Jose A. Lopes
  if not (utils.IsUrl(image) or os.path.exists(image)):
2424 d00e49f6 Jose A. Lopes
    _Fail("Image '%s' not found", image)
2425 d00e49f6 Jose A. Lopes
2426 2b8322f7 Jose A. Lopes
  try:
2427 2b8322f7 Jose A. Lopes
    rdev = _RecursiveFindBD(disk)
2428 2b8322f7 Jose A. Lopes
  except errors.BlockDeviceError:
2429 2b8322f7 Jose A. Lopes
    rdev = None
2430 2b8322f7 Jose A. Lopes
2431 2b8322f7 Jose A. Lopes
  if not rdev:
2432 2b8322f7 Jose A. Lopes
    _Fail("Cannot image device %s: device not found", disk.iv_name)
2433 2b8322f7 Jose A. Lopes
  if size < 0:
2434 2b8322f7 Jose A. Lopes
    _Fail("Negative size")
2435 2b8322f7 Jose A. Lopes
  if size > rdev.size:
2436 2b8322f7 Jose A. Lopes
    _Fail("Image size is bigger than device size")
2437 2b8322f7 Jose A. Lopes
2438 2b8322f7 Jose A. Lopes
  if utils.IsUrl(image):
2439 2b8322f7 Jose A. Lopes
    _DownloadAndDumpDevice(image, rdev.dev_path, size)
2440 2b8322f7 Jose A. Lopes
  else:
2441 326e0925 Jose A. Lopes
    _DumpDevice(image, rdev.dev_path, 0, size, False)
2442 2b8322f7 Jose A. Lopes
2443 69dd363f René Nussbaumer
2444 5119c79e René Nussbaumer
def BlockdevPauseResumeSync(disks, pause):
2445 5119c79e René Nussbaumer
  """Pause or resume the sync of the block device.
2446 5119c79e René Nussbaumer

2447 0f39886a René Nussbaumer
  @type disks: list of L{objects.Disk}
2448 0f39886a René Nussbaumer
  @param disks: the disks object we want to pause/resume
2449 5119c79e René Nussbaumer
  @type pause: bool
2450 5119c79e René Nussbaumer
  @param pause: Wheater to pause or resume
2451 5119c79e René Nussbaumer

2452 5119c79e René Nussbaumer
  """
2453 5119c79e René Nussbaumer
  success = []
2454 5119c79e René Nussbaumer
  for disk in disks:
2455 5119c79e René Nussbaumer
    try:
2456 5119c79e René Nussbaumer
      rdev = _RecursiveFindBD(disk)
2457 5119c79e René Nussbaumer
    except errors.BlockDeviceError:
2458 5119c79e René Nussbaumer
      rdev = None
2459 5119c79e René Nussbaumer
2460 5119c79e René Nussbaumer
    if not rdev:
2461 5119c79e René Nussbaumer
      success.append((False, ("Cannot change sync for device %s:"
2462 5119c79e René Nussbaumer
                              " device not found" % disk.iv_name)))
2463 5119c79e René Nussbaumer
      continue
2464 5119c79e René Nussbaumer
2465 5119c79e René Nussbaumer
    result = rdev.PauseResumeSync(pause)
2466 5119c79e René Nussbaumer
2467 5119c79e René Nussbaumer
    if result:
2468 5119c79e René Nussbaumer
      success.append((result, None))
2469 5119c79e René Nussbaumer
    else:
2470 5119c79e René Nussbaumer
      if pause:
2471 5119c79e René Nussbaumer
        msg = "Pause"
2472 5119c79e René Nussbaumer
      else:
2473 5119c79e René Nussbaumer
        msg = "Resume"
2474 5119c79e René Nussbaumer
      success.append((result, "%s for device %s failed" % (msg, disk.iv_name)))
2475 5119c79e René Nussbaumer
2476 5119c79e René Nussbaumer
  return success
2477 5119c79e René Nussbaumer
2478 5119c79e René Nussbaumer
2479 821d1bd1 Iustin Pop
def BlockdevRemove(disk):
2480 a8083063 Iustin Pop
  """Remove a block device.
2481 a8083063 Iustin Pop

2482 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
2483 10c2650b Iustin Pop

2484 c41eea6e Iustin Pop
  @type disk: L{objects.Disk}
2485 10c2650b Iustin Pop
  @param disk: the disk object we should remove
2486 10c2650b Iustin Pop
  @rtype: boolean
2487 10c2650b Iustin Pop
  @return: the success of the operation
2488 a8083063 Iustin Pop

2489 a8083063 Iustin Pop
  """
2490 e1bc0878 Iustin Pop
  msgs = []
2491 a8083063 Iustin Pop
  try:
2492 bca2e7f4 Iustin Pop
    rdev = _RecursiveFindBD(disk)
2493 a8083063 Iustin Pop
  except errors.BlockDeviceError, err:
2494 a8083063 Iustin Pop
    # probably can't attach
2495 18682bca Iustin Pop
    logging.info("Can't attach to device %s in remove", disk)
2496 a8083063 Iustin Pop
    rdev = None
2497 a8083063 Iustin Pop
  if rdev is not None:
2498 3f78eef2 Iustin Pop
    r_path = rdev.dev_path
2499 b3ae67d7 Dimitris Aragiorgis
2500 b3ae67d7 Dimitris Aragiorgis
    def _TryRemove():
2501 b3ae67d7 Dimitris Aragiorgis
      try:
2502 b3ae67d7 Dimitris Aragiorgis
        rdev.Remove()
2503 b3ae67d7 Dimitris Aragiorgis
        return []
2504 b3ae67d7 Dimitris Aragiorgis
      except errors.BlockDeviceError, err:
2505 b3ae67d7 Dimitris Aragiorgis
        return [str(err)]
2506 b3ae67d7 Dimitris Aragiorgis
2507 b3ae67d7 Dimitris Aragiorgis
    msgs.extend(utils.SimpleRetry([], _TryRemove,
2508 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_INTERVAL,
2509 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_TIMEOUT))
2510 b3ae67d7 Dimitris Aragiorgis
2511 c26a6bd2 Iustin Pop
    if not msgs:
2512 3f78eef2 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2513 e1bc0878 Iustin Pop
2514 a8083063 Iustin Pop
  if disk.children:
2515 a8083063 Iustin Pop
    for child in disk.children:
2516 c26a6bd2 Iustin Pop
      try:
2517 c26a6bd2 Iustin Pop
        BlockdevRemove(child)
2518 c26a6bd2 Iustin Pop
      except RPCFail, err:
2519 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2520 e1bc0878 Iustin Pop
2521 c26a6bd2 Iustin Pop
  if msgs:
2522 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2523 afdc3985 Iustin Pop
2524 a8083063 Iustin Pop
2525 3f78eef2 Iustin Pop
def _RecursiveAssembleBD(disk, owner, as_primary):
2526 a8083063 Iustin Pop
  """Activate a block device for an instance.
2527 a8083063 Iustin Pop

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

2530 10c2650b Iustin Pop
  @note: this function is called recursively.
2531 a8083063 Iustin Pop

2532 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2533 10c2650b Iustin Pop
  @param disk: the disk we try to assemble
2534 10c2650b Iustin Pop
  @type owner: str
2535 10c2650b Iustin Pop
  @param owner: the name of the instance which owns the disk
2536 10c2650b Iustin Pop
  @type as_primary: boolean
2537 10c2650b Iustin Pop
  @param as_primary: if we should make the block device
2538 10c2650b Iustin Pop
      read/write
2539 a8083063 Iustin Pop

2540 10c2650b Iustin Pop
  @return: the assembled device or None (in case no device
2541 10c2650b Iustin Pop
      was assembled)
2542 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: in case there is an error
2543 10c2650b Iustin Pop
      during the activation of the children or the device
2544 10c2650b Iustin Pop
      itself
2545 a8083063 Iustin Pop

2546 a8083063 Iustin Pop
  """
2547 a8083063 Iustin Pop
  children = []
2548 a8083063 Iustin Pop
  if disk.children:
2549 fc1dc9d7 Iustin Pop
    mcn = disk.ChildrenNeeded()
2550 fc1dc9d7 Iustin Pop
    if mcn == -1:
2551 fc1dc9d7 Iustin Pop
      mcn = 0 # max number of Nones allowed
2552 fc1dc9d7 Iustin Pop
    else:
2553 fc1dc9d7 Iustin Pop
      mcn = len(disk.children) - mcn # max number of Nones
2554 a8083063 Iustin Pop
    for chld_disk in disk.children:
2555 fc1dc9d7 Iustin Pop
      try:
2556 fc1dc9d7 Iustin Pop
        cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary)
2557 fc1dc9d7 Iustin Pop
      except errors.BlockDeviceError, err:
2558 7803d4d3 Iustin Pop
        if children.count(None) >= mcn:
2559 fc1dc9d7 Iustin Pop
          raise
2560 fc1dc9d7 Iustin Pop
        cdev = None
2561 1063abd1 Iustin Pop
        logging.error("Error in child activation (but continuing): %s",
2562 1063abd1 Iustin Pop
                      str(err))
2563 fc1dc9d7 Iustin Pop
      children.append(cdev)
2564 a8083063 Iustin Pop
2565 a8083063 Iustin Pop
  if as_primary or disk.AssembleOnSecondary():
2566 94dcbdb0 Andrea Spadaccini
    r_dev = bdev.Assemble(disk, children)
2567 a8083063 Iustin Pop
    result = r_dev
2568 a8083063 Iustin Pop
    if as_primary or disk.OpenOnSecondary():
2569 a8083063 Iustin Pop
      r_dev.Open()
2570 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(r_dev.dev_path, owner,
2571 3f78eef2 Iustin Pop
                                as_primary, disk.iv_name)
2572 3f78eef2 Iustin Pop
2573 a8083063 Iustin Pop
  else:
2574 a8083063 Iustin Pop
    result = True
2575 a8083063 Iustin Pop
  return result
2576 a8083063 Iustin Pop
2577 a8083063 Iustin Pop
2578 c417e115 Iustin Pop
def BlockdevAssemble(disk, owner, as_primary, idx):
2579 a8083063 Iustin Pop
  """Activate a block device for an instance.
2580 a8083063 Iustin Pop

2581 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
2582 a8083063 Iustin Pop

2583 b1206984 Iustin Pop
  @rtype: str or boolean
2584 ff5def9b Dimitris Aragiorgis
  @return: a tuple with the C{/dev/...} path and the created symlink
2585 ff5def9b Dimitris Aragiorgis
      for primary nodes, and (C{True}, C{True}) for secondary nodes
2586 a8083063 Iustin Pop

2587 a8083063 Iustin Pop
  """
2588 53c14ef1 Iustin Pop
  try:
2589 53c14ef1 Iustin Pop
    result = _RecursiveAssembleBD(disk, owner, as_primary)
2590 89ff748d Thomas Thrainer
    if isinstance(result, BlockDev):
2591 b459a848 Andrea Spadaccini
      # pylint: disable=E1103
2592 ff5def9b Dimitris Aragiorgis
      dev_path = result.dev_path
2593 ff5def9b Dimitris Aragiorgis
      link_name = None
2594 c417e115 Iustin Pop
      if as_primary:
2595 ff5def9b Dimitris Aragiorgis
        link_name = _SymlinkBlockDev(owner, dev_path, idx)
2596 ff5def9b Dimitris Aragiorgis
    elif result:
2597 ff5def9b Dimitris Aragiorgis
      return result, result
2598 ff5def9b Dimitris Aragiorgis
    else:
2599 ff5def9b Dimitris Aragiorgis
      _Fail("Unexpected result from _RecursiveAssembleBD")
2600 53c14ef1 Iustin Pop
  except errors.BlockDeviceError, err:
2601 afdc3985 Iustin Pop
    _Fail("Error while assembling disk: %s", err, exc=True)
2602 c417e115 Iustin Pop
  except OSError, err:
2603 c417e115 Iustin Pop
    _Fail("Error while symlinking disk: %s", err, exc=True)
2604 afdc3985 Iustin Pop
2605 ff5def9b Dimitris Aragiorgis
  return dev_path, link_name
2606 a8083063 Iustin Pop
2607 a8083063 Iustin Pop
2608 821d1bd1 Iustin Pop
def BlockdevShutdown(disk):
2609 a8083063 Iustin Pop
  """Shut down a block device.
2610 a8083063 Iustin Pop

2611 5bbd3f7f Michael Hanselmann
  First, if the device is assembled (Attach() is successful), then
2612 c41eea6e Iustin Pop
  the device is shutdown. Then the children of the device are
2613 c41eea6e Iustin Pop
  shutdown.
2614 a8083063 Iustin Pop

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

2619 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2620 10c2650b Iustin Pop
  @param disk: the description of the disk we should
2621 10c2650b Iustin Pop
      shutdown
2622 c26a6bd2 Iustin Pop
  @rtype: None
2623 10c2650b Iustin Pop

2624 a8083063 Iustin Pop
  """
2625 cacfd1fd Iustin Pop
  msgs = []
2626 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2627 a8083063 Iustin Pop
  if r_dev is not None:
2628 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
2629 cacfd1fd Iustin Pop
    try:
2630 746f7476 Iustin Pop
      r_dev.Shutdown()
2631 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2632 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
2633 cacfd1fd Iustin Pop
      msgs.append(str(err))
2634 746f7476 Iustin Pop
2635 a8083063 Iustin Pop
  if disk.children:
2636 a8083063 Iustin Pop
    for child in disk.children:
2637 c26a6bd2 Iustin Pop
      try:
2638 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
2639 c26a6bd2 Iustin Pop
      except RPCFail, err:
2640 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2641 746f7476 Iustin Pop
2642 c26a6bd2 Iustin Pop
  if msgs:
2643 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2644 a8083063 Iustin Pop
2645 a8083063 Iustin Pop
2646 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
2647 153d9724 Iustin Pop
  """Extend a mirrored block device.
2648 a8083063 Iustin Pop

2649 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2650 10c2650b Iustin Pop
  @param parent_cdev: the disk to which we should add children
2651 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2652 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should add
2653 c26a6bd2 Iustin Pop
  @rtype: None
2654 10c2650b Iustin Pop

2655 a8083063 Iustin Pop
  """
2656 bca2e7f4 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
2657 153d9724 Iustin Pop
  if parent_bdev is None:
2658 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in add children", parent_cdev)
2659 153d9724 Iustin Pop
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
2660 153d9724 Iustin Pop
  if new_bdevs.count(None) > 0:
2661 2cc6781a Iustin Pop
    _Fail("Can't find new device(s) to add: %s:%s", new_bdevs, new_cdevs)
2662 153d9724 Iustin Pop
  parent_bdev.AddChildren(new_bdevs)
2663 a8083063 Iustin Pop
2664 a8083063 Iustin Pop
2665 821d1bd1 Iustin Pop
def BlockdevRemovechildren(parent_cdev, new_cdevs):
2666 153d9724 Iustin Pop
  """Shrink a mirrored block device.
2667 a8083063 Iustin Pop

2668 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2669 10c2650b Iustin Pop
  @param parent_cdev: the disk from which we should remove children
2670 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2671 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should remove
2672 c26a6bd2 Iustin Pop
  @rtype: None
2673 10c2650b Iustin Pop

2674 a8083063 Iustin Pop
  """
2675 153d9724 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
2676 153d9724 Iustin Pop
  if parent_bdev is None:
2677 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in remove children", parent_cdev)
2678 e739bd57 Iustin Pop
  devs = []
2679 e739bd57 Iustin Pop
  for disk in new_cdevs:
2680 e739bd57 Iustin Pop
    rpath = disk.StaticDevPath()
2681 e739bd57 Iustin Pop
    if rpath is None:
2682 e739bd57 Iustin Pop
      bd = _RecursiveFindBD(disk)
2683 e739bd57 Iustin Pop
      if bd is None:
2684 2cc6781a Iustin Pop
        _Fail("Can't find device %s while removing children", disk)
2685 e739bd57 Iustin Pop
      else:
2686 e739bd57 Iustin Pop
        devs.append(bd.dev_path)
2687 e739bd57 Iustin Pop
    else:
2688 e51db2a6 Iustin Pop
      if not utils.IsNormAbsPath(rpath):
2689 e51db2a6 Iustin Pop
        _Fail("Strange path returned from StaticDevPath: '%s'", rpath)
2690 e739bd57 Iustin Pop
      devs.append(rpath)
2691 e739bd57 Iustin Pop
  parent_bdev.RemoveChildren(devs)
2692 a8083063 Iustin Pop
2693 a8083063 Iustin Pop
2694 821d1bd1 Iustin Pop
def BlockdevGetmirrorstatus(disks):
2695 a8083063 Iustin Pop
  """Get the mirroring status of a list of devices.
2696 a8083063 Iustin Pop

2697 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
2698 10c2650b Iustin Pop
  @param disks: the list of disks which we should query
2699 10c2650b Iustin Pop
  @rtype: disk
2700 c6a9dffa Michael Hanselmann
  @return: List of L{objects.BlockDevStatus}, one for each disk
2701 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if any of the disks cannot be
2702 10c2650b Iustin Pop
      found
2703 a8083063 Iustin Pop

2704 a8083063 Iustin Pop
  """
2705 a8083063 Iustin Pop
  stats = []
2706 a8083063 Iustin Pop
  for dsk in disks:
2707 a8083063 Iustin Pop
    rbd = _RecursiveFindBD(dsk)
2708 a8083063 Iustin Pop
    if rbd is None:
2709 3efa9051 Iustin Pop
      _Fail("Can't find device %s", dsk)
2710 96acbc09 Michael Hanselmann
2711 36145b12 Michael Hanselmann
    stats.append(rbd.CombinedSyncStatus())
2712 96acbc09 Michael Hanselmann
2713 c26a6bd2 Iustin Pop
  return stats
2714 a8083063 Iustin Pop
2715 a8083063 Iustin Pop
2716 c6a9dffa Michael Hanselmann
def BlockdevGetmirrorstatusMulti(disks):
2717 c6a9dffa Michael Hanselmann
  """Get the mirroring status of a list of devices.
2718 c6a9dffa Michael Hanselmann

2719 c6a9dffa Michael Hanselmann
  @type disks: list of L{objects.Disk}
2720 c6a9dffa Michael Hanselmann
  @param disks: the list of disks which we should query
2721 c6a9dffa Michael Hanselmann
  @rtype: disk
2722 c6a9dffa Michael Hanselmann
  @return: List of tuples, (bool, status), one for each disk; bool denotes
2723 c6a9dffa Michael Hanselmann
    success/failure, status is L{objects.BlockDevStatus} on success, string
2724 c6a9dffa Michael Hanselmann
    otherwise
2725 c6a9dffa Michael Hanselmann

2726 c6a9dffa Michael Hanselmann
  """
2727 c6a9dffa Michael Hanselmann
  result = []
2728 c6a9dffa Michael Hanselmann
  for disk in disks:
2729 c6a9dffa Michael Hanselmann
    try:
2730 c6a9dffa Michael Hanselmann
      rbd = _RecursiveFindBD(disk)
2731 c6a9dffa Michael Hanselmann
      if rbd is None:
2732 c6a9dffa Michael Hanselmann
        result.append((False, "Can't find device %s" % disk))
2733 c6a9dffa Michael Hanselmann
        continue
2734 c6a9dffa Michael Hanselmann
2735 c6a9dffa Michael Hanselmann
      status = rbd.CombinedSyncStatus()
2736 c6a9dffa Michael Hanselmann
    except errors.BlockDeviceError, err:
2737 c6a9dffa Michael Hanselmann
      logging.exception("Error while getting disk status")
2738 c6a9dffa Michael Hanselmann
      result.append((False, str(err)))
2739 c6a9dffa Michael Hanselmann
    else:
2740 c6a9dffa Michael Hanselmann
      result.append((True, status))
2741 c6a9dffa Michael Hanselmann
2742 c6a9dffa Michael Hanselmann
  assert len(disks) == len(result)
2743 c6a9dffa Michael Hanselmann
2744 c6a9dffa Michael Hanselmann
  return result
2745 c6a9dffa Michael Hanselmann
2746 c6a9dffa Michael Hanselmann
2747 bca2e7f4 Iustin Pop
def _RecursiveFindBD(disk):
2748 a8083063 Iustin Pop
  """Check if a device is activated.
2749 a8083063 Iustin Pop

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

2752 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2753 10c2650b Iustin Pop
  @param disk: the disk object we need to find
2754 a8083063 Iustin Pop

2755 10c2650b Iustin Pop
  @return: None if the device can't be found,
2756 10c2650b Iustin Pop
      otherwise the device instance
2757 a8083063 Iustin Pop

2758 a8083063 Iustin Pop
  """
2759 a8083063 Iustin Pop
  children = []
2760 a8083063 Iustin Pop
  if disk.children:
2761 a8083063 Iustin Pop
    for chdisk in disk.children:
2762 a8083063 Iustin Pop
      children.append(_RecursiveFindBD(chdisk))
2763 a8083063 Iustin Pop
2764 94dcbdb0 Andrea Spadaccini
  return bdev.FindDevice(disk, children)
2765 a8083063 Iustin Pop
2766 a8083063 Iustin Pop
2767 f2e07bb4 Michael Hanselmann
def _OpenRealBD(disk):
2768 f2e07bb4 Michael Hanselmann
  """Opens the underlying block device of a disk.
2769 f2e07bb4 Michael Hanselmann

2770 f2e07bb4 Michael Hanselmann
  @type disk: L{objects.Disk}
2771 f2e07bb4 Michael Hanselmann
  @param disk: the disk object we want to open
2772 f2e07bb4 Michael Hanselmann

2773 f2e07bb4 Michael Hanselmann
  """
2774 f2e07bb4 Michael Hanselmann
  real_disk = _RecursiveFindBD(disk)
2775 f2e07bb4 Michael Hanselmann
  if real_disk is None:
2776 f2e07bb4 Michael Hanselmann
    _Fail("Block device '%s' is not set up", disk)
2777 f2e07bb4 Michael Hanselmann
2778 f2e07bb4 Michael Hanselmann
  real_disk.Open()
2779 f2e07bb4 Michael Hanselmann
2780 f2e07bb4 Michael Hanselmann
  return real_disk
2781 f2e07bb4 Michael Hanselmann
2782 f2e07bb4 Michael Hanselmann
2783 821d1bd1 Iustin Pop
def BlockdevFind(disk):
2784 a8083063 Iustin Pop
  """Check if a device is activated.
2785 a8083063 Iustin Pop

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

2788 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2789 10c2650b Iustin Pop
  @param disk: the disk to find
2790 96acbc09 Michael Hanselmann
  @rtype: None or objects.BlockDevStatus
2791 96acbc09 Michael Hanselmann
  @return: None if the disk cannot be found, otherwise a the current
2792 96acbc09 Michael Hanselmann
           information
2793 a8083063 Iustin Pop

2794 a8083063 Iustin Pop
  """
2795 23829f6f Iustin Pop
  try:
2796 23829f6f Iustin Pop
    rbd = _RecursiveFindBD(disk)
2797 23829f6f Iustin Pop
  except errors.BlockDeviceError, err:
2798 2cc6781a Iustin Pop
    _Fail("Failed to find device: %s", err, exc=True)
2799 96acbc09 Michael Hanselmann
2800 a8083063 Iustin Pop
  if rbd is None:
2801 c26a6bd2 Iustin Pop
    return None
2802 96acbc09 Michael Hanselmann
2803 96acbc09 Michael Hanselmann
  return rbd.GetSyncStatus()
2804 a8083063 Iustin Pop
2805 a8083063 Iustin Pop
2806 6ef8077e Bernardo Dal Seno
def BlockdevGetdimensions(disks):
2807 968a7623 Iustin Pop
  """Computes the size of the given disks.
2808 968a7623 Iustin Pop

2809 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
2810 968a7623 Iustin Pop

2811 968a7623 Iustin Pop
  @type disks: list of L{objects.Disk}
2812 968a7623 Iustin Pop
  @param disks: the list of disk to compute the size for
2813 968a7623 Iustin Pop
  @rtype: list
2814 968a7623 Iustin Pop
  @return: list with elements None if the disk cannot be found,
2815 6ef8077e Bernardo Dal Seno
      otherwise the pair (size, spindles), where spindles is None if the
2816 6ef8077e Bernardo Dal Seno
      device doesn't support that
2817 968a7623 Iustin Pop

2818 968a7623 Iustin Pop
  """
2819 968a7623 Iustin Pop
  result = []
2820 968a7623 Iustin Pop
  for cf in disks:
2821 968a7623 Iustin Pop
    try:
2822 968a7623 Iustin Pop
      rbd = _RecursiveFindBD(cf)
2823 1122eb25 Iustin Pop
    except errors.BlockDeviceError:
2824 968a7623 Iustin Pop
      result.append(None)
2825 968a7623 Iustin Pop
      continue
2826 968a7623 Iustin Pop
    if rbd is None:
2827 968a7623 Iustin Pop
      result.append(None)
2828 968a7623 Iustin Pop
    else:
2829 6ef8077e Bernardo Dal Seno
      result.append(rbd.GetActualDimensions())
2830 968a7623 Iustin Pop
  return result
2831 968a7623 Iustin Pop
2832 968a7623 Iustin Pop
2833 a8083063 Iustin Pop
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
2834 a8083063 Iustin Pop
  """Write a file to the filesystem.
2835 a8083063 Iustin Pop

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

2839 10c2650b Iustin Pop
  @type file_name: str
2840 10c2650b Iustin Pop
  @param file_name: the target file name
2841 10c2650b Iustin Pop
  @type data: str
2842 10c2650b Iustin Pop
  @param data: the new contents of the file
2843 10c2650b Iustin Pop
  @type mode: int
2844 10c2650b Iustin Pop
  @param mode: the mode to give the file (can be None)
2845 9a914f7a René Nussbaumer
  @type uid: string
2846 9a914f7a René Nussbaumer
  @param uid: the owner of the file
2847 9a914f7a René Nussbaumer
  @type gid: string
2848 9a914f7a René Nussbaumer
  @param gid: the group of the file
2849 10c2650b Iustin Pop
  @type atime: float
2850 10c2650b Iustin Pop
  @param atime: the atime to set on the file (can be None)
2851 10c2650b Iustin Pop
  @type mtime: float
2852 10c2650b Iustin Pop
  @param mtime: the mtime to set on the file (can be None)
2853 c26a6bd2 Iustin Pop
  @rtype: None
2854 10c2650b Iustin Pop

2855 a8083063 Iustin Pop
  """
2856 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
2857 cffbbae7 Michael Hanselmann
2858 a8083063 Iustin Pop
  if not os.path.isabs(file_name):
2859 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile is not absolute: '%s'", file_name)
2860 a8083063 Iustin Pop
2861 360b0dc2 Iustin Pop
  if file_name not in _ALLOWED_UPLOAD_FILES:
2862 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile not in allowed upload targets: '%s'",
2863 2cc6781a Iustin Pop
          file_name)
2864 a8083063 Iustin Pop
2865 12bce260 Michael Hanselmann
  raw_data = _Decompress(data)
2866 12bce260 Michael Hanselmann
2867 9a914f7a René Nussbaumer
  if not (isinstance(uid, basestring) and isinstance(gid, basestring)):
2868 9a914f7a René Nussbaumer
    _Fail("Invalid username/groupname type")
2869 9a914f7a René Nussbaumer
2870 9a914f7a René Nussbaumer
  getents = runtime.GetEnts()
2871 9a914f7a René Nussbaumer
  uid = getents.LookupUser(uid)
2872 9a914f7a René Nussbaumer
  gid = getents.LookupGroup(gid)
2873 9a914f7a René Nussbaumer
2874 8f065ae2 Iustin Pop
  utils.SafeWriteFile(file_name, None,
2875 8f065ae2 Iustin Pop
                      data=raw_data, mode=mode, uid=uid, gid=gid,
2876 8f065ae2 Iustin Pop
                      atime=atime, mtime=mtime)
2877 a8083063 Iustin Pop
2878 386b57af Iustin Pop
2879 b2f29800 René Nussbaumer
def RunOob(oob_program, command, node, timeout):
2880 b2f29800 René Nussbaumer
  """Executes oob_program with given command on given node.
2881 b2f29800 René Nussbaumer

2882 b2f29800 René Nussbaumer
  @param oob_program: The path to the executable oob_program
2883 b2f29800 René Nussbaumer
  @param command: The command to invoke on oob_program
2884 b2f29800 René Nussbaumer
  @param node: The node given as an argument to the program
2885 b2f29800 René Nussbaumer
  @param timeout: Timeout after which we kill the oob program
2886 b2f29800 René Nussbaumer

2887 b2f29800 René Nussbaumer
  @return: stdout
2888 b2f29800 René Nussbaumer
  @raise RPCFail: If execution fails for some reason
2889 b2f29800 René Nussbaumer

2890 b2f29800 René Nussbaumer
  """
2891 b2f29800 René Nussbaumer
  result = utils.RunCmd([oob_program, command, node], timeout=timeout)
2892 b2f29800 René Nussbaumer
2893 b2f29800 René Nussbaumer
  if result.failed:
2894 b2f29800 René Nussbaumer
    _Fail("'%s' failed with reason '%s'; output: %s", result.cmd,
2895 b2f29800 René Nussbaumer
          result.fail_reason, result.output)
2896 b2f29800 René Nussbaumer
2897 b2f29800 René Nussbaumer
  return result.stdout
2898 b2f29800 René Nussbaumer
2899 b2f29800 René Nussbaumer
2900 c19f9810 Iustin Pop
def _OSOndiskAPIVersion(os_dir):
2901 2f8598a5 Alexander Schreiber
  """Compute and return the API version of a given OS.
2902 a8083063 Iustin Pop

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

2906 10c2650b Iustin Pop
  @type os_dir: str
2907 c19f9810 Iustin Pop
  @param os_dir: the directory in which we should look for the OS
2908 8e70b181 Iustin Pop
  @rtype: tuple
2909 8e70b181 Iustin Pop
  @return: tuple (status, data) with status denoting the validity and
2910 c42facd9 Jose A. Lopes
      data holding either the valid versions or an error message
2911 a8083063 Iustin Pop

2912 a8083063 Iustin Pop
  """
2913 e02b9114 Iustin Pop
  api_file = utils.PathJoin(os_dir, constants.OS_API_FILE)
2914 a8083063 Iustin Pop
2915 a8083063 Iustin Pop
  try:
2916 a8083063 Iustin Pop
    st = os.stat(api_file)
2917 a8083063 Iustin Pop
  except EnvironmentError, err:
2918 b6b45e0d Guido Trotter
    return False, ("Required file '%s' not found under path %s: %s" %
2919 eb93b673 Guido Trotter
                   (constants.OS_API_FILE, os_dir, utils.ErrnoOrStr(err)))
2920 a8083063 Iustin Pop
2921 a8083063 Iustin Pop
  if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2922 b6b45e0d Guido Trotter
    return False, ("File '%s' in %s is not a regular file" %
2923 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir))
2924 a8083063 Iustin Pop
2925 a8083063 Iustin Pop
  try:
2926 3374afa9 Guido Trotter
    api_versions = utils.ReadFile(api_file).splitlines()
2927 a8083063 Iustin Pop
  except EnvironmentError, err:
2928 255dcebd Iustin Pop
    return False, ("Error while reading the API version file at %s: %s" %
2929 eb93b673 Guido Trotter
                   (api_file, utils.ErrnoOrStr(err)))
2930 a8083063 Iustin Pop
2931 a8083063 Iustin Pop
  try:
2932 63b9b186 Guido Trotter
    api_versions = [int(version.strip()) for version in api_versions]
2933 a8083063 Iustin Pop
  except (TypeError, ValueError), err:
2934 255dcebd Iustin Pop
    return False, ("API version(s) can't be converted to integer: %s" %
2935 255dcebd Iustin Pop
                   str(err))
2936 a8083063 Iustin Pop
2937 255dcebd Iustin Pop
  return True, api_versions
2938 a8083063 Iustin Pop
2939 386b57af Iustin Pop
2940 7c3d51d4 Guido Trotter
def DiagnoseOS(top_dirs=None):
2941 a8083063 Iustin Pop
  """Compute the validity for all OSes.
2942 a8083063 Iustin Pop

2943 10c2650b Iustin Pop
  @type top_dirs: list
2944 10c2650b Iustin Pop
  @param top_dirs: the list of directories in which to
2945 10c2650b Iustin Pop
      search (if not given defaults to
2946 3329f4de Michael Hanselmann
      L{pathutils.OS_SEARCH_PATH})
2947 10c2650b Iustin Pop
  @rtype: list of L{objects.OS}
2948 bad78e66 Iustin Pop
  @return: a list of tuples (name, path, status, diagnose, variants,
2949 bad78e66 Iustin Pop
      parameters, api_version) for all (potential) OSes under all
2950 bad78e66 Iustin Pop
      search paths, where:
2951 255dcebd Iustin Pop
          - name is the (potential) OS name
2952 255dcebd Iustin Pop
          - path is the full path to the OS
2953 255dcebd Iustin Pop
          - status True/False is the validity of the OS
2954 255dcebd Iustin Pop
          - diagnose is the error message for an invalid OS, otherwise empty
2955 ba00557a Guido Trotter
          - variants is a list of supported OS variants, if any
2956 c7d04a6b Iustin Pop
          - parameters is a list of (name, help) parameters, if any
2957 bad78e66 Iustin Pop
          - api_version is a list of support OS API versions
2958 a8083063 Iustin Pop

2959 a8083063 Iustin Pop
  """
2960 7c3d51d4 Guido Trotter
  if top_dirs is None:
2961 710f30ec Michael Hanselmann
    top_dirs = pathutils.OS_SEARCH_PATH
2962 a8083063 Iustin Pop
2963 a8083063 Iustin Pop
  result = []
2964 65fe4693 Iustin Pop
  for dir_name in top_dirs:
2965 65fe4693 Iustin Pop
    if os.path.isdir(dir_name):
2966 7c3d51d4 Guido Trotter
      try:
2967 65fe4693 Iustin Pop
        f_names = utils.ListVisibleFiles(dir_name)
2968 7c3d51d4 Guido Trotter
      except EnvironmentError, err:
2969 29921401 Iustin Pop
        logging.exception("Can't list the OS directory %s: %s", dir_name, err)
2970 7c3d51d4 Guido Trotter
        break
2971 7c3d51d4 Guido Trotter
      for name in f_names:
2972 e02b9114 Iustin Pop
        os_path = utils.PathJoin(dir_name, name)
2973 255dcebd Iustin Pop
        status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
2974 255dcebd Iustin Pop
        if status:
2975 255dcebd Iustin Pop
          diagnose = ""
2976 ba00557a Guido Trotter
          variants = os_inst.supported_variants
2977 c7d04a6b Iustin Pop
          parameters = os_inst.supported_parameters
2978 bad78e66 Iustin Pop
          api_versions = os_inst.api_versions
2979 a44114c9 Jose A. Lopes
          trusted = False if os_inst.create_script_untrusted else True
2980 255dcebd Iustin Pop
        else:
2981 255dcebd Iustin Pop
          diagnose = os_inst
2982 bad78e66 Iustin Pop
          variants = parameters = api_versions = []
2983 a44114c9 Jose A. Lopes
          trusted = True
2984 bad78e66 Iustin Pop
        result.append((name, os_path, status, diagnose, variants,
2985 a44114c9 Jose A. Lopes
                       parameters, api_versions, trusted))
2986 a8083063 Iustin Pop
2987 c26a6bd2 Iustin Pop
  return result
2988 a8083063 Iustin Pop
2989 a8083063 Iustin Pop
2990 255dcebd Iustin Pop
def _TryOSFromDisk(name, base_dir=None):
2991 a8083063 Iustin Pop
  """Create an OS instance from disk.
2992 a8083063 Iustin Pop

2993 a8083063 Iustin Pop
  This function will return an OS instance if the given name is a
2994 8e70b181 Iustin Pop
  valid OS name.
2995 a8083063 Iustin Pop

2996 8ee4dc80 Guido Trotter
  @type base_dir: string
2997 8ee4dc80 Guido Trotter
  @keyword base_dir: Base directory containing OS installations.
2998 8ee4dc80 Guido Trotter
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2999 255dcebd Iustin Pop
  @rtype: tuple
3000 255dcebd Iustin Pop
  @return: success and either the OS instance if we find a valid one,
3001 255dcebd Iustin Pop
      or error message
3002 7c3d51d4 Guido Trotter

3003 a8083063 Iustin Pop
  """
3004 56bcd3f4 Guido Trotter
  if base_dir is None:
3005 710f30ec Michael Hanselmann
    os_dir = utils.FindFile(name, pathutils.OS_SEARCH_PATH, os.path.isdir)
3006 c34c0cfd Iustin Pop
  else:
3007 f95c81bf Iustin Pop
    os_dir = utils.FindFile(name, [base_dir], os.path.isdir)
3008 f95c81bf Iustin Pop
3009 f95c81bf Iustin Pop
  if os_dir is None:
3010 5c0433d6 Iustin Pop
    return False, "Directory for OS %s not found in search path" % name
3011 a8083063 Iustin Pop
3012 c19f9810 Iustin Pop
  status, api_versions = _OSOndiskAPIVersion(os_dir)
3013 255dcebd Iustin Pop
  if not status:
3014 255dcebd Iustin Pop
    # push the error up
3015 255dcebd Iustin Pop
    return status, api_versions
3016 a8083063 Iustin Pop
3017 d1a7d66f Guido Trotter
  if not constants.OS_API_VERSIONS.intersection(api_versions):
3018 255dcebd Iustin Pop
    return False, ("API version mismatch for path '%s': found %s, want %s." %
3019 d1a7d66f Guido Trotter
                   (os_dir, api_versions, constants.OS_API_VERSIONS))
3020 a8083063 Iustin Pop
3021 35007011 Iustin Pop
  # OS Files dictionary, we will populate it with the absolute path
3022 35007011 Iustin Pop
  # names; if the value is True, then it is a required file, otherwise
3023 35007011 Iustin Pop
  # an optional one
3024 35007011 Iustin Pop
  os_files = dict.fromkeys(constants.OS_SCRIPTS, True)
3025 a8083063 Iustin Pop
3026 a44114c9 Jose A. Lopes
  os_files[constants.OS_SCRIPT_CREATE] = False
3027 a44114c9 Jose A. Lopes
  os_files[constants.OS_SCRIPT_CREATE_UNTRUSTED] = False
3028 a44114c9 Jose A. Lopes
3029 95075fba Guido Trotter
  if max(api_versions) >= constants.OS_API_V15:
3030 35007011 Iustin Pop
    os_files[constants.OS_VARIANTS_FILE] = False
3031 95075fba Guido Trotter
3032 c7d04a6b Iustin Pop
  if max(api_versions) >= constants.OS_API_V20:
3033 35007011 Iustin Pop
    os_files[constants.OS_PARAMETERS_FILE] = True
3034 c7d04a6b Iustin Pop
  else:
3035 c7d04a6b Iustin Pop
    del os_files[constants.OS_SCRIPT_VERIFY]
3036 c7d04a6b Iustin Pop
3037 35007011 Iustin Pop
  for (filename, required) in os_files.items():
3038 e02b9114 Iustin Pop
    os_files[filename] = utils.PathJoin(os_dir, filename)
3039 a8083063 Iustin Pop
3040 a8083063 Iustin Pop
    try:
3041 ea79fc15 Michael Hanselmann
      st = os.stat(os_files[filename])
3042 a8083063 Iustin Pop
    except EnvironmentError, err:
3043 35007011 Iustin Pop
      if err.errno == errno.ENOENT and not required:
3044 35007011 Iustin Pop
        del os_files[filename]
3045 35007011 Iustin Pop
        continue
3046 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is missing (%s)" %
3047 eb93b673 Guido Trotter
                     (filename, os_dir, utils.ErrnoOrStr(err)))
3048 a8083063 Iustin Pop
3049 a8083063 Iustin Pop
    if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
3050 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is not a regular file" %
3051 ea79fc15 Michael Hanselmann
                     (filename, os_dir))
3052 255dcebd Iustin Pop
3053 ea79fc15 Michael Hanselmann
    if filename in constants.OS_SCRIPTS:
3054 0757c107 Guido Trotter
      if stat.S_IMODE(st.st_mode) & stat.S_IXUSR != stat.S_IXUSR:
3055 0757c107 Guido Trotter
        return False, ("File '%s' under path '%s' is not executable" %
3056 ea79fc15 Michael Hanselmann
                       (filename, os_dir))
3057 0757c107 Guido Trotter
3058 a44114c9 Jose A. Lopes
  if not constants.OS_SCRIPT_CREATE in os_files and \
3059 a44114c9 Jose A. Lopes
        not constants.OS_SCRIPT_CREATE_UNTRUSTED in os_files:
3060 a44114c9 Jose A. Lopes
    return False, ("A create script (trusted or untrusted) under path '%s'"
3061 a44114c9 Jose A. Lopes
                   " must exist" % os_dir)
3062 a44114c9 Jose A. Lopes
3063 a44114c9 Jose A. Lopes
  create_script = os_files.get(constants.OS_SCRIPT_CREATE, None)
3064 a44114c9 Jose A. Lopes
  create_script_untrusted = os_files.get(constants.OS_SCRIPT_CREATE_UNTRUSTED,
3065 a44114c9 Jose A. Lopes
                                         None)
3066 a44114c9 Jose A. Lopes
3067 845da3e8 Iustin Pop
  variants = []
3068 95075fba Guido Trotter
  if constants.OS_VARIANTS_FILE in os_files:
3069 95075fba Guido Trotter
    variants_file = os_files[constants.OS_VARIANTS_FILE]
3070 95075fba Guido Trotter
    try:
3071 5a7cb9d3 Iustin Pop
      variants = \
3072 5a7cb9d3 Iustin Pop
        utils.FilterEmptyLinesAndComments(utils.ReadFile(variants_file))
3073 95075fba Guido Trotter
    except EnvironmentError, err:
3074 35007011 Iustin Pop
      # we accept missing files, but not other errors
3075 35007011 Iustin Pop
      if err.errno != errno.ENOENT:
3076 35007011 Iustin Pop
        return False, ("Error while reading the OS variants file at %s: %s" %
3077 eb93b673 Guido Trotter
                       (variants_file, utils.ErrnoOrStr(err)))
3078 0757c107 Guido Trotter
3079 c7d04a6b Iustin Pop
  parameters = []
3080 c7d04a6b Iustin Pop
  if constants.OS_PARAMETERS_FILE in os_files:
3081 c7d04a6b Iustin Pop
    parameters_file = os_files[constants.OS_PARAMETERS_FILE]
3082 c7d04a6b Iustin Pop
    try:
3083 c7d04a6b Iustin Pop
      parameters = utils.ReadFile(parameters_file).splitlines()
3084 c7d04a6b Iustin Pop
    except EnvironmentError, err:
3085 c7d04a6b Iustin Pop
      return False, ("Error while reading the OS parameters file at %s: %s" %
3086 eb93b673 Guido Trotter
                     (parameters_file, utils.ErrnoOrStr(err)))
3087 c7d04a6b Iustin Pop
    parameters = [v.split(None, 1) for v in parameters]
3088 c7d04a6b Iustin Pop
3089 8e70b181 Iustin Pop
  os_obj = objects.OS(name=name, path=os_dir,
3090 a44114c9 Jose A. Lopes
                      create_script=create_script,
3091 a44114c9 Jose A. Lopes
                      create_script_untrusted=create_script_untrusted,
3092 41ba4061 Guido Trotter
                      export_script=os_files[constants.OS_SCRIPT_EXPORT],
3093 41ba4061 Guido Trotter
                      import_script=os_files[constants.OS_SCRIPT_IMPORT],
3094 41ba4061 Guido Trotter
                      rename_script=os_files[constants.OS_SCRIPT_RENAME],
3095 40684c3a Iustin Pop
                      verify_script=os_files.get(constants.OS_SCRIPT_VERIFY,
3096 40684c3a Iustin Pop
                                                 None),
3097 95075fba Guido Trotter
                      supported_variants=variants,
3098 c7d04a6b Iustin Pop
                      supported_parameters=parameters,
3099 255dcebd Iustin Pop
                      api_versions=api_versions)
3100 255dcebd Iustin Pop
  return True, os_obj
3101 255dcebd Iustin Pop
3102 255dcebd Iustin Pop
3103 255dcebd Iustin Pop
def OSFromDisk(name, base_dir=None):
3104 255dcebd Iustin Pop
  """Create an OS instance from disk.
3105 255dcebd Iustin Pop

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

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

3113 255dcebd Iustin Pop
  @type base_dir: string
3114 255dcebd Iustin Pop
  @keyword base_dir: Base directory containing OS installations.
3115 255dcebd Iustin Pop
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
3116 255dcebd Iustin Pop
  @rtype: L{objects.OS}
3117 255dcebd Iustin Pop
  @return: the OS instance if we find a valid one
3118 255dcebd Iustin Pop
  @raise RPCFail: if we don't find a valid OS
3119 255dcebd Iustin Pop

3120 255dcebd Iustin Pop
  """
3121 870dc44c Iustin Pop
  name_only = objects.OS.GetName(name)
3122 6ee7102a Guido Trotter
  status, payload = _TryOSFromDisk(name_only, base_dir)
3123 255dcebd Iustin Pop
3124 255dcebd Iustin Pop
  if not status:
3125 255dcebd Iustin Pop
    _Fail(payload)
3126 a8083063 Iustin Pop
3127 255dcebd Iustin Pop
  return payload
3128 a8083063 Iustin Pop
3129 a8083063 Iustin Pop
3130 a025e535 Vitaly Kuznetsov
def OSCoreEnv(os_name, inst_os, os_params, debug=0):
3131 efaa9b06 Iustin Pop
  """Calculate the basic environment for an os script.
3132 2266edb2 Guido Trotter

3133 a025e535 Vitaly Kuznetsov
  @type os_name: str
3134 a025e535 Vitaly Kuznetsov
  @param os_name: full operating system name (including variant)
3135 099c52ad Iustin Pop
  @type inst_os: L{objects.OS}
3136 099c52ad Iustin Pop
  @param inst_os: operating system for which the environment is being built
3137 1bdcbbab Iustin Pop
  @type os_params: dict
3138 1bdcbbab Iustin Pop
  @param os_params: the OS parameters
3139 2266edb2 Guido Trotter
  @type debug: integer
3140 10c2650b Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
3141 2266edb2 Guido Trotter
  @rtype: dict
3142 2266edb2 Guido Trotter
  @return: dict of environment variables
3143 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if the block device
3144 10c2650b Iustin Pop
      cannot be found
3145 2266edb2 Guido Trotter

3146 2266edb2 Guido Trotter
  """
3147 2266edb2 Guido Trotter
  result = {}
3148 099c52ad Iustin Pop
  api_version = \
3149 099c52ad Iustin Pop
    max(constants.OS_API_VERSIONS.intersection(inst_os.api_versions))
3150 d0c8c01d Iustin Pop
  result["OS_API_VERSION"] = "%d" % api_version
3151 d0c8c01d Iustin Pop
  result["OS_NAME"] = inst_os.name
3152 d0c8c01d Iustin Pop
  result["DEBUG_LEVEL"] = "%d" % debug
3153 efaa9b06 Iustin Pop
3154 efaa9b06 Iustin Pop
  # OS variants
3155 35007011 Iustin Pop
  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
3156 870dc44c Iustin Pop
    variant = objects.OS.GetVariant(os_name)
3157 870dc44c Iustin Pop
    if not variant:
3158 099c52ad Iustin Pop
      variant = inst_os.supported_variants[0]
3159 35007011 Iustin Pop
  else:
3160 35007011 Iustin Pop
    variant = ""
3161 35007011 Iustin Pop
  result["OS_VARIANT"] = variant
3162 efaa9b06 Iustin Pop
3163 1bdcbbab Iustin Pop
  # OS params
3164 1bdcbbab Iustin Pop
  for pname, pvalue in os_params.items():
3165 a971cfee Jose A. Lopes
    result["OSP_%s" % pname.upper().replace("-", "_")] = pvalue
3166 1bdcbbab Iustin Pop
3167 9a6ade06 Iustin Pop
  # Set a default path otherwise programs called by OS scripts (or
3168 9a6ade06 Iustin Pop
  # even hooks called from OS scripts) might break, and we don't want
3169 9a6ade06 Iustin Pop
  # to have each script require setting a PATH variable
3170 9a6ade06 Iustin Pop
  result["PATH"] = constants.HOOKS_PATH
3171 9a6ade06 Iustin Pop
3172 efaa9b06 Iustin Pop
  return result
3173 efaa9b06 Iustin Pop
3174 efaa9b06 Iustin Pop
3175 efaa9b06 Iustin Pop
def OSEnvironment(instance, inst_os, debug=0):
3176 efaa9b06 Iustin Pop
  """Calculate the environment for an os script.
3177 efaa9b06 Iustin Pop

3178 efaa9b06 Iustin Pop
  @type instance: L{objects.Instance}
3179 efaa9b06 Iustin Pop
  @param instance: target instance for the os script run
3180 efaa9b06 Iustin Pop
  @type inst_os: L{objects.OS}
3181 efaa9b06 Iustin Pop
  @param inst_os: operating system for which the environment is being built
3182 efaa9b06 Iustin Pop
  @type debug: integer
3183 efaa9b06 Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
3184 efaa9b06 Iustin Pop
  @rtype: dict
3185 efaa9b06 Iustin Pop
  @return: dict of environment variables
3186 efaa9b06 Iustin Pop
  @raise errors.BlockDeviceError: if the block device
3187 efaa9b06 Iustin Pop
      cannot be found
3188 efaa9b06 Iustin Pop

3189 efaa9b06 Iustin Pop
  """
3190 a025e535 Vitaly Kuznetsov
  result = OSCoreEnv(instance.os, inst_os, instance.osparams, debug=debug)
3191 efaa9b06 Iustin Pop
3192 519719fd Marco Casavecchia
  for attr in ["name", "os", "uuid", "ctime", "mtime", "primary_node"]:
3193 f2165b8a Iustin Pop
    result["INSTANCE_%s" % attr.upper()] = str(getattr(instance, attr))
3194 f2165b8a Iustin Pop
3195 d0c8c01d Iustin Pop
  result["HYPERVISOR"] = instance.hypervisor
3196 e9ebf2d7 Ilias Tsitsimpis
  result["DISK_COUNT"] = "%d" % len(instance.disks_info)
3197 d0c8c01d Iustin Pop
  result["NIC_COUNT"] = "%d" % len(instance.nics)
3198 d0c8c01d Iustin Pop
  result["INSTANCE_SECONDARY_NODES"] = \
3199 d0c8c01d Iustin Pop
      ("%s" % " ".join(instance.secondary_nodes))
3200 efaa9b06 Iustin Pop
3201 efaa9b06 Iustin Pop
  # Disks
3202 e9ebf2d7 Ilias Tsitsimpis
  for idx, disk in enumerate(instance.disks_info):
3203 f2e07bb4 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
3204 d0c8c01d Iustin Pop
    result["DISK_%d_PATH" % idx] = real_disk.dev_path
3205 d0c8c01d Iustin Pop
    result["DISK_%d_ACCESS" % idx] = disk.mode
3206 8a348b15 Christos Stavrakakis
    result["DISK_%d_UUID" % idx] = disk.uuid
3207 8a348b15 Christos Stavrakakis
    if disk.name:
3208 8a348b15 Christos Stavrakakis
      result["DISK_%d_NAME" % idx] = disk.name
3209 2266edb2 Guido Trotter
    if constants.HV_DISK_TYPE in instance.hvparams:
3210 d0c8c01d Iustin Pop
      result["DISK_%d_FRONTEND_TYPE" % idx] = \
3211 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_DISK_TYPE]
3212 cd3b4ff4 Helga Velroyen
    if disk.dev_type in constants.DTS_BLOCK:
3213 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = "block"
3214 a09639d1 Santi Raffa
    elif disk.dev_type in constants.DTS_FILEBASED:
3215 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = \
3216 a57e502a Thomas Thrainer
        "file:%s" % disk.logical_id[0]
3217 efaa9b06 Iustin Pop
3218 efaa9b06 Iustin Pop
  # NICs
3219 2266edb2 Guido Trotter
  for idx, nic in enumerate(instance.nics):
3220 d0c8c01d Iustin Pop
    result["NIC_%d_MAC" % idx] = nic.mac
3221 8a348b15 Christos Stavrakakis
    result["NIC_%d_UUID" % idx] = nic.uuid
3222 8a348b15 Christos Stavrakakis
    if nic.name:
3223 8a348b15 Christos Stavrakakis
      result["NIC_%d_NAME" % idx] = nic.name
3224 2266edb2 Guido Trotter
    if nic.ip:
3225 d0c8c01d Iustin Pop
      result["NIC_%d_IP" % idx] = nic.ip
3226 d0c8c01d Iustin Pop
    result["NIC_%d_MODE" % idx] = nic.nicparams[constants.NIC_MODE]
3227 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
3228 d0c8c01d Iustin Pop
      result["NIC_%d_BRIDGE" % idx] = nic.nicparams[constants.NIC_LINK]
3229 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_LINK]:
3230 d0c8c01d Iustin Pop
      result["NIC_%d_LINK" % idx] = nic.nicparams[constants.NIC_LINK]
3231 d89168ff Guido Trotter
    if nic.netinfo:
3232 d89168ff Guido Trotter
      nobj = objects.Network.FromDict(nic.netinfo)
3233 d89168ff Guido Trotter
      result.update(nobj.HooksDict("NIC_%d_" % idx))
3234 2266edb2 Guido Trotter
    if constants.HV_NIC_TYPE in instance.hvparams:
3235 d0c8c01d Iustin Pop
      result["NIC_%d_FRONTEND_TYPE" % idx] = \
3236 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_NIC_TYPE]
3237 2266edb2 Guido Trotter
3238 efaa9b06 Iustin Pop
  # HV/BE params
3239 67fc3042 Iustin Pop
  for source, kind in [(instance.beparams, "BE"), (instance.hvparams, "HV")]:
3240 67fc3042 Iustin Pop
    for key, value in source.items():
3241 030b218a Iustin Pop
      result["INSTANCE_%s_%s" % (kind, key)] = str(value)
3242 67fc3042 Iustin Pop
3243 2266edb2 Guido Trotter
  return result
3244 a8083063 Iustin Pop
3245 f2e07bb4 Michael Hanselmann
3246 b954f097 Constantinos Venetsanopoulos
def DiagnoseExtStorage(top_dirs=None):
3247 b954f097 Constantinos Venetsanopoulos
  """Compute the validity for all ExtStorage Providers.
3248 b954f097 Constantinos Venetsanopoulos

3249 b954f097 Constantinos Venetsanopoulos
  @type top_dirs: list
3250 b954f097 Constantinos Venetsanopoulos
  @param top_dirs: the list of directories in which to
3251 b954f097 Constantinos Venetsanopoulos
      search (if not given defaults to
3252 b954f097 Constantinos Venetsanopoulos
      L{pathutils.ES_SEARCH_PATH})
3253 b954f097 Constantinos Venetsanopoulos
  @rtype: list of L{objects.ExtStorage}
3254 b954f097 Constantinos Venetsanopoulos
  @return: a list of tuples (name, path, status, diagnose, parameters)
3255 b954f097 Constantinos Venetsanopoulos
      for all (potential) ExtStorage Providers under all
3256 b954f097 Constantinos Venetsanopoulos
      search paths, where:
3257 b954f097 Constantinos Venetsanopoulos
          - name is the (potential) ExtStorage Provider
3258 b954f097 Constantinos Venetsanopoulos
          - path is the full path to the ExtStorage Provider
3259 b954f097 Constantinos Venetsanopoulos
          - status True/False is the validity of the ExtStorage Provider
3260 b954f097 Constantinos Venetsanopoulos
          - diagnose is the error message for an invalid ExtStorage Provider,
3261 b954f097 Constantinos Venetsanopoulos
            otherwise empty
3262 b954f097 Constantinos Venetsanopoulos
          - parameters is a list of (name, help) parameters, if any
3263 b954f097 Constantinos Venetsanopoulos

3264 b954f097 Constantinos Venetsanopoulos
  """
3265 b954f097 Constantinos Venetsanopoulos
  if top_dirs is None:
3266 b954f097 Constantinos Venetsanopoulos
    top_dirs = pathutils.ES_SEARCH_PATH
3267 b954f097 Constantinos Venetsanopoulos
3268 b954f097 Constantinos Venetsanopoulos
  result = []
3269 b954f097 Constantinos Venetsanopoulos
  for dir_name in top_dirs:
3270 b954f097 Constantinos Venetsanopoulos
    if os.path.isdir(dir_name):
3271 b954f097 Constantinos Venetsanopoulos
      try:
3272 b954f097 Constantinos Venetsanopoulos
        f_names = utils.ListVisibleFiles(dir_name)
3273 b954f097 Constantinos Venetsanopoulos
      except EnvironmentError, err:
3274 b954f097 Constantinos Venetsanopoulos
        logging.exception("Can't list the ExtStorage directory %s: %s",
3275 b954f097 Constantinos Venetsanopoulos
                          dir_name, err)
3276 b954f097 Constantinos Venetsanopoulos
        break
3277 b954f097 Constantinos Venetsanopoulos
      for name in f_names:
3278 b954f097 Constantinos Venetsanopoulos
        es_path = utils.PathJoin(dir_name, name)
3279 b954f097 Constantinos Venetsanopoulos
        status, es_inst = bdev.ExtStorageFromDisk(name, base_dir=dir_name)
3280 b954f097 Constantinos Venetsanopoulos
        if status:
3281 b954f097 Constantinos Venetsanopoulos
          diagnose = ""
3282 b954f097 Constantinos Venetsanopoulos
          parameters = es_inst.supported_parameters
3283 b954f097 Constantinos Venetsanopoulos
        else:
3284 b954f097 Constantinos Venetsanopoulos
          diagnose = es_inst
3285 b954f097 Constantinos Venetsanopoulos
          parameters = []
3286 b954f097 Constantinos Venetsanopoulos
        result.append((name, es_path, status, diagnose, parameters))
3287 b954f097 Constantinos Venetsanopoulos
3288 b954f097 Constantinos Venetsanopoulos
  return result
3289 b954f097 Constantinos Venetsanopoulos
3290 b954f097 Constantinos Venetsanopoulos
3291 be9150ea Bernardo Dal Seno
def BlockdevGrow(disk, amount, dryrun, backingstore, excl_stor):
3292 594609c0 Iustin Pop
  """Grow a stack of block devices.
3293 594609c0 Iustin Pop

3294 594609c0 Iustin Pop
  This function is called recursively, with the childrens being the
3295 10c2650b Iustin Pop
  first ones to resize.
3296 594609c0 Iustin Pop

3297 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
3298 10c2650b Iustin Pop
  @param disk: the disk to be grown
3299 a59faf4b Iustin Pop
  @type amount: integer
3300 a59faf4b Iustin Pop
  @param amount: the amount (in mebibytes) to grow with
3301 a59faf4b Iustin Pop
  @type dryrun: boolean
3302 a59faf4b Iustin Pop
  @param dryrun: whether to execute the operation in simulation mode
3303 a59faf4b Iustin Pop
      only, without actually increasing the size
3304 cad0723b Iustin Pop
  @param backingstore: whether to execute the operation on backing storage
3305 cad0723b Iustin Pop
      only, or on "logical" storage only; e.g. DRBD is logical storage,
3306 cad0723b Iustin Pop
      whereas LVM, file, RBD are backing storage
3307 10c2650b Iustin Pop
  @rtype: (status, result)
3308 be9150ea Bernardo Dal Seno
  @type excl_stor: boolean
3309 be9150ea Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
3310 a59faf4b Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3311 a59faf4b Iustin Pop
      the errors message if status is False
3312 594609c0 Iustin Pop

3313 594609c0 Iustin Pop
  """
3314 594609c0 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3315 594609c0 Iustin Pop
  if r_dev is None:
3316 afdc3985 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3317 594609c0 Iustin Pop
3318 594609c0 Iustin Pop
  try:
3319 be9150ea Bernardo Dal Seno
    r_dev.Grow(amount, dryrun, backingstore, excl_stor)
3320 594609c0 Iustin Pop
  except errors.BlockDeviceError, err:
3321 2cc6781a Iustin Pop
    _Fail("Failed to grow block device: %s", err, exc=True)
3322 594609c0 Iustin Pop
3323 594609c0 Iustin Pop
3324 821d1bd1 Iustin Pop
def BlockdevSnapshot(disk):
3325 a8083063 Iustin Pop
  """Create a snapshot copy of a block device.
3326 a8083063 Iustin Pop

3327 a8083063 Iustin Pop
  This function is called recursively, and the snapshot is actually created
3328 a8083063 Iustin Pop
  just for the leaf lvm backend device.
3329 a8083063 Iustin Pop

3330 e9e9263d Guido Trotter
  @type disk: L{objects.Disk}
3331 e9e9263d Guido Trotter
  @param disk: the disk to be snapshotted
3332 e9e9263d Guido Trotter
  @rtype: string
3333 800ac399 Iustin Pop
  @return: snapshot disk ID as (vg, lv)
3334 a8083063 Iustin Pop

3335 098c0958 Michael Hanselmann
  """
3336 cd3b4ff4 Helga Velroyen
  if disk.dev_type == constants.DT_DRBD8:
3337 433c63aa Iustin Pop
    if not disk.children:
3338 433c63aa Iustin Pop
      _Fail("DRBD device '%s' without backing storage cannot be snapshotted",
3339 433c63aa Iustin Pop
            disk.unique_id)
3340 433c63aa Iustin Pop
    return BlockdevSnapshot(disk.children[0])
3341 cd3b4ff4 Helga Velroyen
  elif disk.dev_type == constants.DT_PLAIN:
3342 a8083063 Iustin Pop
    r_dev = _RecursiveFindBD(disk)
3343 a8083063 Iustin Pop
    if r_dev is not None:
3344 433c63aa Iustin Pop
      # FIXME: choose a saner value for the snapshot size
3345 a8083063 Iustin Pop
      # let's stay on the safe side and ask for the full size, for now
3346 c26a6bd2 Iustin Pop
      return r_dev.Snapshot(disk.size)
3347 a8083063 Iustin Pop
    else:
3348 87812fd3 Iustin Pop
      _Fail("Cannot find block device %s", disk)
3349 a8083063 Iustin Pop
  else:
3350 87812fd3 Iustin Pop
    _Fail("Cannot snapshot non-lvm block device '%s' of type '%s'",
3351 87812fd3 Iustin Pop
          disk.unique_id, disk.dev_type)
3352 a8083063 Iustin Pop
3353 a8083063 Iustin Pop
3354 48e175a2 Iustin Pop
def BlockdevSetInfo(disk, info):
3355 48e175a2 Iustin Pop
  """Sets 'metadata' information on block devices.
3356 48e175a2 Iustin Pop

3357 48e175a2 Iustin Pop
  This function sets 'info' metadata on block devices. Initial
3358 48e175a2 Iustin Pop
  information is set at device creation; this function should be used
3359 48e175a2 Iustin Pop
  for example after renames.
3360 48e175a2 Iustin Pop

3361 48e175a2 Iustin Pop
  @type disk: L{objects.Disk}
3362 48e175a2 Iustin Pop
  @param disk: the disk to be grown
3363 48e175a2 Iustin Pop
  @type info: string
3364 48e175a2 Iustin Pop
  @param info: new 'info' metadata
3365 48e175a2 Iustin Pop
  @rtype: (status, result)
3366 48e175a2 Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3367 48e175a2 Iustin Pop
      the errors message if status is False
3368 48e175a2 Iustin Pop

3369 48e175a2 Iustin Pop
  """
3370 48e175a2 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3371 48e175a2 Iustin Pop
  if r_dev is None:
3372 48e175a2 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3373 48e175a2 Iustin Pop
3374 48e175a2 Iustin Pop
  try:
3375 48e175a2 Iustin Pop
    r_dev.SetInfo(info)
3376 48e175a2 Iustin Pop
  except errors.BlockDeviceError, err:
3377 48e175a2 Iustin Pop
    _Fail("Failed to set information on block device: %s", err, exc=True)
3378 48e175a2 Iustin Pop
3379 48e175a2 Iustin Pop
3380 a8083063 Iustin Pop
def FinalizeExport(instance, snap_disks):
3381 a8083063 Iustin Pop
  """Write out the export configuration information.
3382 a8083063 Iustin Pop

3383 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
3384 10c2650b Iustin Pop
  @param instance: the instance which we export, used for
3385 10c2650b Iustin Pop
      saving configuration
3386 10c2650b Iustin Pop
  @type snap_disks: list of L{objects.Disk}
3387 10c2650b Iustin Pop
  @param snap_disks: list of snapshot block devices, which
3388 10c2650b Iustin Pop
      will be used to get the actual name of the dump file
3389 a8083063 Iustin Pop

3390 c26a6bd2 Iustin Pop
  @rtype: None
3391 a8083063 Iustin Pop

3392 098c0958 Michael Hanselmann
  """
3393 710f30ec Michael Hanselmann
  destdir = utils.PathJoin(pathutils.EXPORT_DIR, instance.name + ".new")
3394 710f30ec Michael Hanselmann
  finaldestdir = utils.PathJoin(pathutils.EXPORT_DIR, instance.name)
3395 a8083063 Iustin Pop
3396 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
3397 a8083063 Iustin Pop
3398 a8083063 Iustin Pop
  config.add_section(constants.INISECT_EXP)
3399 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "version", "0")
3400 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "timestamp", "%d" % int(time.time()))
3401 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "source", instance.primary_node)
3402 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "os", instance.os)
3403 775b8743 Michael Hanselmann
  config.set(constants.INISECT_EXP, "compression", "none")
3404 a8083063 Iustin Pop
3405 a8083063 Iustin Pop
  config.add_section(constants.INISECT_INS)
3406 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "name", instance.name)
3407 1db993d5 Guido Trotter
  config.set(constants.INISECT_INS, "maxmem", "%d" %
3408 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MAXMEM])
3409 1db993d5 Guido Trotter
  config.set(constants.INISECT_INS, "minmem", "%d" %
3410 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MINMEM])
3411 1db993d5 Guido Trotter
  # "memory" is deprecated, but useful for exporting to old ganeti versions
3412 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "memory", "%d" %
3413 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MAXMEM])
3414 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "vcpus", "%d" %
3415 51de46bf Iustin Pop
             instance.beparams[constants.BE_VCPUS])
3416 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "disk_template", instance.disk_template)
3417 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "hypervisor", instance.hypervisor)
3418 fbb2c636 Michael Hanselmann
  config.set(constants.INISECT_INS, "tags", " ".join(instance.GetTags()))
3419 66f93869 Manuel Franceschini
3420 95268cc3 Iustin Pop
  nic_total = 0
3421 a8083063 Iustin Pop
  for nic_count, nic in enumerate(instance.nics):
3422 95268cc3 Iustin Pop
    nic_total += 1
3423 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_mac" %
3424 d0c8c01d Iustin Pop
               nic_count, "%s" % nic.mac)
3425 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_ip" % nic_count, "%s" % nic.ip)
3426 7a476bb5 Dimitris Aragiorgis
    config.set(constants.INISECT_INS, "nic%d_network" % nic_count,
3427 7a476bb5 Dimitris Aragiorgis
               "%s" % nic.network)
3428 0f68f7fa Dimitris Aragiorgis
    config.set(constants.INISECT_INS, "nic%d_name" % nic_count,
3429 0f68f7fa Dimitris Aragiorgis
               "%s" % nic.name)
3430 6801eb5c Iustin Pop
    for param in constants.NICS_PARAMETER_TYPES:
3431 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "nic%d_%s" % (nic_count, param),
3432 d0c8c01d Iustin Pop
                 "%s" % nic.nicparams.get(param, None))
3433 a8083063 Iustin Pop
  # TODO: redundant: on load can read nics until it doesn't exist
3434 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "nic_count", "%d" % nic_total)
3435 a8083063 Iustin Pop
3436 726d7d68 Iustin Pop
  disk_total = 0
3437 a8083063 Iustin Pop
  for disk_count, disk in enumerate(snap_disks):
3438 19d7f90a Guido Trotter
    if disk:
3439 726d7d68 Iustin Pop
      disk_total += 1
3440 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_ivname" % disk_count,
3441 d0c8c01d Iustin Pop
                 ("%s" % disk.iv_name))
3442 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_dump" % disk_count,
3443 a57e502a Thomas Thrainer
                 ("%s" % disk.logical_id[1]))
3444 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_size" % disk_count,
3445 d0c8c01d Iustin Pop
                 ("%d" % disk.size))
3446 0f68f7fa Dimitris Aragiorgis
      config.set(constants.INISECT_INS, "disk%d_name" % disk_count,
3447 0f68f7fa Dimitris Aragiorgis
                 "%s" % disk.name)
3448 d0c8c01d Iustin Pop
3449 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "disk_count", "%d" % disk_total)
3450 a8083063 Iustin Pop
3451 3c8954ad Iustin Pop
  # New-style hypervisor/backend parameters
3452 3c8954ad Iustin Pop
3453 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_HYP)
3454 3c8954ad Iustin Pop
  for name, value in instance.hvparams.items():
3455 3c8954ad Iustin Pop
    if name not in constants.HVC_GLOBALS:
3456 3c8954ad Iustin Pop
      config.set(constants.INISECT_HYP, name, str(value))
3457 3c8954ad Iustin Pop
3458 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_BEP)
3459 3c8954ad Iustin Pop
  for name, value in instance.beparams.items():
3460 3c8954ad Iustin Pop
    config.set(constants.INISECT_BEP, name, str(value))
3461 3c8954ad Iustin Pop
3462 535b49cb Iustin Pop
  config.add_section(constants.INISECT_OSP)
3463 535b49cb Iustin Pop
  for name, value in instance.osparams.items():
3464 535b49cb Iustin Pop
    config.set(constants.INISECT_OSP, name, str(value))
3465 535b49cb Iustin Pop
3466 6bce7ba2 Santi Raffa
  config.add_section(constants.INISECT_OSP_PRIVATE)
3467 6bce7ba2 Santi Raffa
  for name, value in instance.osparams_private.items():
3468 6bce7ba2 Santi Raffa
    config.set(constants.INISECT_OSP_PRIVATE, name, str(value.Get()))
3469 6bce7ba2 Santi Raffa
3470 c4feafe8 Iustin Pop
  utils.WriteFile(utils.PathJoin(destdir, constants.EXPORT_CONF_FILE),
3471 726d7d68 Iustin Pop
                  data=config.Dumps())
3472 56569f4e Michael Hanselmann
  shutil.rmtree(finaldestdir, ignore_errors=True)
3473 a8083063 Iustin Pop
  shutil.move(destdir, finaldestdir)
3474 a8083063 Iustin Pop
3475 a8083063 Iustin Pop
3476 a8083063 Iustin Pop
def ExportInfo(dest):
3477 a8083063 Iustin Pop
  """Get export configuration information.
3478 a8083063 Iustin Pop

3479 10c2650b Iustin Pop
  @type dest: str
3480 10c2650b Iustin Pop
  @param dest: directory containing the export
3481 a8083063 Iustin Pop

3482 10c2650b Iustin Pop
  @rtype: L{objects.SerializableConfigParser}
3483 10c2650b Iustin Pop
  @return: a serializable config file containing the
3484 10c2650b Iustin Pop
      export info
3485 a8083063 Iustin Pop

3486 a8083063 Iustin Pop
  """
3487 c4feafe8 Iustin Pop
  cff = utils.PathJoin(dest, constants.EXPORT_CONF_FILE)
3488 a8083063 Iustin Pop
3489 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
3490 a8083063 Iustin Pop
  config.read(cff)
3491 a8083063 Iustin Pop
3492 a8083063 Iustin Pop
  if (not config.has_section(constants.INISECT_EXP) or
3493 a8083063 Iustin Pop
      not config.has_section(constants.INISECT_INS)):
3494 3eccac06 Iustin Pop
    _Fail("Export info file doesn't have the required fields")
3495 a8083063 Iustin Pop
3496 c26a6bd2 Iustin Pop
  return config.Dumps()
3497 a8083063 Iustin Pop
3498 a8083063 Iustin Pop
3499 a8083063 Iustin Pop
def ListExports():
3500 a8083063 Iustin Pop
  """Return a list of exports currently available on this machine.
3501 098c0958 Michael Hanselmann

3502 10c2650b Iustin Pop
  @rtype: list
3503 10c2650b Iustin Pop
  @return: list of the exports
3504 10c2650b Iustin Pop

3505 a8083063 Iustin Pop
  """
3506 710f30ec Michael Hanselmann
  if os.path.isdir(pathutils.EXPORT_DIR):
3507 710f30ec Michael Hanselmann
    return sorted(utils.ListVisibleFiles(pathutils.EXPORT_DIR))
3508 a8083063 Iustin Pop
  else:
3509 afdc3985 Iustin Pop
    _Fail("No exports directory")
3510 a8083063 Iustin Pop
3511 a8083063 Iustin Pop
3512 a8083063 Iustin Pop
def RemoveExport(export):
3513 a8083063 Iustin Pop
  """Remove an existing export from the node.
3514 a8083063 Iustin Pop

3515 10c2650b Iustin Pop
  @type export: str
3516 10c2650b Iustin Pop
  @param export: the name of the export to remove
3517 c26a6bd2 Iustin Pop
  @rtype: None
3518 a8083063 Iustin Pop

3519 098c0958 Michael Hanselmann
  """
3520 710f30ec Michael Hanselmann
  target = utils.PathJoin(pathutils.EXPORT_DIR, export)
3521 a8083063 Iustin Pop
3522 35fbcd11 Iustin Pop
  try:
3523 35fbcd11 Iustin Pop
    shutil.rmtree(target)
3524 35fbcd11 Iustin Pop
  except EnvironmentError, err:
3525 35fbcd11 Iustin Pop
    _Fail("Error while removing the export: %s", err, exc=True)
3526 a8083063 Iustin Pop
3527 a8083063 Iustin Pop
3528 821d1bd1 Iustin Pop
def BlockdevRename(devlist):
3529 f3e513ad Iustin Pop
  """Rename a list of block devices.
3530 f3e513ad Iustin Pop

3531 10c2650b Iustin Pop
  @type devlist: list of tuples
3532 a57e502a Thomas Thrainer
  @param devlist: list of tuples of the form  (disk, new_unique_id); disk is
3533 a57e502a Thomas Thrainer
      an L{objects.Disk} object describing the current disk, and new
3534 a57e502a Thomas Thrainer
      unique_id is the name we rename it to
3535 10c2650b Iustin Pop
  @rtype: boolean
3536 10c2650b Iustin Pop
  @return: True if all renames succeeded, False otherwise
3537 f3e513ad Iustin Pop

3538 f3e513ad Iustin Pop
  """
3539 6b5e3f70 Iustin Pop
  msgs = []
3540 f3e513ad Iustin Pop
  result = True
3541 f3e513ad Iustin Pop
  for disk, unique_id in devlist:
3542 f3e513ad Iustin Pop
    dev = _RecursiveFindBD(disk)
3543 f3e513ad Iustin Pop
    if dev is None:
3544 6b5e3f70 Iustin Pop
      msgs.append("Can't find device %s in rename" % str(disk))
3545 f3e513ad Iustin Pop
      result = False
3546 f3e513ad Iustin Pop
      continue
3547 f3e513ad Iustin Pop
    try:
3548 3f78eef2 Iustin Pop
      old_rpath = dev.dev_path
3549 f3e513ad Iustin Pop
      dev.Rename(unique_id)
3550 3f78eef2 Iustin Pop
      new_rpath = dev.dev_path
3551 3f78eef2 Iustin Pop
      if old_rpath != new_rpath:
3552 3f78eef2 Iustin Pop
        DevCacheManager.RemoveCache(old_rpath)
3553 3f78eef2 Iustin Pop
        # FIXME: we should add the new cache information here, like:
3554 3f78eef2 Iustin Pop
        # DevCacheManager.UpdateCache(new_rpath, owner, ...)
3555 3f78eef2 Iustin Pop
        # but we don't have the owner here - maybe parse from existing
3556 3f78eef2 Iustin Pop
        # cache? for now, we only lose lvm data when we rename, which
3557 3f78eef2 Iustin Pop
        # is less critical than DRBD or MD
3558 f3e513ad Iustin Pop
    except errors.BlockDeviceError, err:
3559 6b5e3f70 Iustin Pop
      msgs.append("Can't rename device '%s' to '%s': %s" %
3560 6b5e3f70 Iustin Pop
                  (dev, unique_id, err))
3561 18682bca Iustin Pop
      logging.exception("Can't rename device '%s' to '%s'", dev, unique_id)
3562 f3e513ad Iustin Pop
      result = False
3563 afdc3985 Iustin Pop
  if not result:
3564 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
3565 f3e513ad Iustin Pop
3566 f3e513ad Iustin Pop
3567 4b97f902 Apollon Oikonomopoulos
def _TransformFileStorageDir(fs_dir):
3568 778b75bb Manuel Franceschini
  """Checks whether given file_storage_dir is valid.
3569 778b75bb Manuel Franceschini

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

3574 4b97f902 Apollon Oikonomopoulos
  @type fs_dir: str
3575 4b97f902 Apollon Oikonomopoulos
  @param fs_dir: the path to check
3576 d61cbe76 Iustin Pop

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

3579 778b75bb Manuel Franceschini
  """
3580 13a6c760 Helga Velroyen
  filestorage.CheckFileStoragePath(fs_dir)
3581 5e09a309 Michael Hanselmann
3582 5e09a309 Michael Hanselmann
  return os.path.normpath(fs_dir)
3583 778b75bb Manuel Franceschini
3584 778b75bb Manuel Franceschini
3585 778b75bb Manuel Franceschini
def CreateFileStorageDir(file_storage_dir):
3586 778b75bb Manuel Franceschini
  """Create file storage directory.
3587 778b75bb Manuel Franceschini

3588 b1206984 Iustin Pop
  @type file_storage_dir: str
3589 b1206984 Iustin Pop
  @param file_storage_dir: directory to create
3590 778b75bb Manuel Franceschini

3591 b1206984 Iustin Pop
  @rtype: tuple
3592 b1206984 Iustin Pop
  @return: tuple with first element a boolean indicating wheter dir
3593 b1206984 Iustin Pop
      creation was successful or not
3594 778b75bb Manuel Franceschini

3595 778b75bb Manuel Franceschini
  """
3596 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3597 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3598 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3599 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3600 b2b8bcce Iustin Pop
            file_storage_dir)
3601 778b75bb Manuel Franceschini
  else:
3602 b2b8bcce Iustin Pop
    try:
3603 b2b8bcce Iustin Pop
      os.makedirs(file_storage_dir, 0750)
3604 b2b8bcce Iustin Pop
    except OSError, err:
3605 b2b8bcce Iustin Pop
      _Fail("Cannot create file storage directory '%s': %s",
3606 b2b8bcce Iustin Pop
            file_storage_dir, err, exc=True)
3607 778b75bb Manuel Franceschini
3608 778b75bb Manuel Franceschini
3609 778b75bb Manuel Franceschini
def RemoveFileStorageDir(file_storage_dir):
3610 778b75bb Manuel Franceschini
  """Remove file storage directory.
3611 778b75bb Manuel Franceschini

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

3614 10c2650b Iustin Pop
  @type file_storage_dir: str
3615 10c2650b Iustin Pop
  @param file_storage_dir: the directory we should cleanup
3616 10c2650b Iustin Pop
  @rtype: tuple (success,)
3617 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3618 5bbd3f7f Michael Hanselmann
      whether the operation was successful
3619 778b75bb Manuel Franceschini

3620 778b75bb Manuel Franceschini
  """
3621 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3622 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3623 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3624 b2b8bcce Iustin Pop
      _Fail("Specified Storage directory '%s' is not a directory",
3625 b2b8bcce Iustin Pop
            file_storage_dir)
3626 afdc3985 Iustin Pop
    # deletes dir only if empty, otherwise we want to fail the rpc call
3627 b2b8bcce Iustin Pop
    try:
3628 b2b8bcce Iustin Pop
      os.rmdir(file_storage_dir)
3629 b2b8bcce Iustin Pop
    except OSError, err:
3630 b2b8bcce Iustin Pop
      _Fail("Cannot remove file storage directory '%s': %s",
3631 b2b8bcce Iustin Pop
            file_storage_dir, err)
3632 b2b8bcce Iustin Pop
3633 778b75bb Manuel Franceschini
3634 778b75bb Manuel Franceschini
def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir):
3635 778b75bb Manuel Franceschini
  """Rename the file storage directory.
3636 778b75bb Manuel Franceschini

3637 10c2650b Iustin Pop
  @type old_file_storage_dir: str
3638 10c2650b Iustin Pop
  @param old_file_storage_dir: the current path
3639 10c2650b Iustin Pop
  @type new_file_storage_dir: str
3640 10c2650b Iustin Pop
  @param new_file_storage_dir: the name we should rename to
3641 10c2650b Iustin Pop
  @rtype: tuple (success,)
3642 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3643 10c2650b Iustin Pop
      whether the operation was successful
3644 778b75bb Manuel Franceschini

3645 778b75bb Manuel Franceschini
  """
3646 778b75bb Manuel Franceschini
  old_file_storage_dir = _TransformFileStorageDir(old_file_storage_dir)
3647 778b75bb Manuel Franceschini
  new_file_storage_dir = _TransformFileStorageDir(new_file_storage_dir)
3648 b2b8bcce Iustin Pop
  if not os.path.exists(new_file_storage_dir):
3649 b2b8bcce Iustin Pop
    if os.path.isdir(old_file_storage_dir):
3650 b2b8bcce Iustin Pop
      try:
3651 b2b8bcce Iustin Pop
        os.rename(old_file_storage_dir, new_file_storage_dir)
3652 b2b8bcce Iustin Pop
      except OSError, err:
3653 b2b8bcce Iustin Pop
        _Fail("Cannot rename '%s' to '%s': %s",
3654 b2b8bcce Iustin Pop
              old_file_storage_dir, new_file_storage_dir, err)
3655 778b75bb Manuel Franceschini
    else:
3656 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3657 b2b8bcce Iustin Pop
            old_file_storage_dir)
3658 b2b8bcce Iustin Pop
  else:
3659 b2b8bcce Iustin Pop
    if os.path.exists(old_file_storage_dir):
3660 b2b8bcce Iustin Pop
      _Fail("Cannot rename '%s' to '%s': both locations exist",
3661 b2b8bcce Iustin Pop
            old_file_storage_dir, new_file_storage_dir)
3662 778b75bb Manuel Franceschini
3663 778b75bb Manuel Franceschini
3664 c8457ce7 Iustin Pop
def _EnsureJobQueueFile(file_name):
3665 dc31eae3 Michael Hanselmann
  """Checks whether the given filename is in the queue directory.
3666 ca52cdeb Michael Hanselmann

3667 10c2650b Iustin Pop
  @type file_name: str
3668 10c2650b Iustin Pop
  @param file_name: the file name we should check
3669 c8457ce7 Iustin Pop
  @rtype: None
3670 c8457ce7 Iustin Pop
  @raises RPCFail: if the file is not valid
3671 10c2650b Iustin Pop

3672 ca52cdeb Michael Hanselmann
  """
3673 b3589802 Michael Hanselmann
  if not utils.IsBelowDir(pathutils.QUEUE_DIR, file_name):
3674 c8457ce7 Iustin Pop
    _Fail("Passed job queue file '%s' does not belong to"
3675 b3589802 Michael Hanselmann
          " the queue directory '%s'", file_name, pathutils.QUEUE_DIR)
3676 dc31eae3 Michael Hanselmann
3677 dc31eae3 Michael Hanselmann
3678 dc31eae3 Michael Hanselmann
def JobQueueUpdate(file_name, content):
3679 dc31eae3 Michael Hanselmann
  """Updates a file in the queue directory.
3680 dc31eae3 Michael Hanselmann

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

3684 10c2650b Iustin Pop
  @type file_name: str
3685 10c2650b Iustin Pop
  @param file_name: the job file name
3686 10c2650b Iustin Pop
  @type content: str
3687 10c2650b Iustin Pop
  @param content: the new job contents
3688 10c2650b Iustin Pop
  @rtype: boolean
3689 10c2650b Iustin Pop
  @return: the success of the operation
3690 10c2650b Iustin Pop

3691 dc31eae3 Michael Hanselmann
  """
3692 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
3693 cffbbae7 Michael Hanselmann
3694 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(file_name)
3695 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
3696 ca52cdeb Michael Hanselmann
3697 ca52cdeb Michael Hanselmann
  # Write and replace the file atomically
3698 82b22e19 René Nussbaumer
  utils.WriteFile(file_name, data=_Decompress(content), uid=getents.masterd_uid,
3699 fe05a931 Michele Tartara
                  gid=getents.daemons_gid, mode=constants.JOB_QUEUE_FILES_PERMS)
3700 ca52cdeb Michael Hanselmann
3701 ca52cdeb Michael Hanselmann
3702 af5ebcb1 Michael Hanselmann
def JobQueueRename(old, new):
3703 af5ebcb1 Michael Hanselmann
  """Renames a job queue file.
3704 af5ebcb1 Michael Hanselmann

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

3707 10c2650b Iustin Pop
  @type old: str
3708 10c2650b Iustin Pop
  @param old: the old (actual) file name
3709 10c2650b Iustin Pop
  @type new: str
3710 10c2650b Iustin Pop
  @param new: the desired file name
3711 c8457ce7 Iustin Pop
  @rtype: tuple
3712 c8457ce7 Iustin Pop
  @return: the success of the operation and payload
3713 10c2650b Iustin Pop

3714 af5ebcb1 Michael Hanselmann
  """
3715 cffbbae7 Michael Hanselmann
  old = vcluster.LocalizeVirtualPath(old)
3716 cffbbae7 Michael Hanselmann
  new = vcluster.LocalizeVirtualPath(new)
3717 cffbbae7 Michael Hanselmann
3718 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(old)
3719 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(new)
3720 af5ebcb1 Michael Hanselmann
3721 8e5a705d René Nussbaumer
  getents = runtime.GetEnts()
3722 8e5a705d René Nussbaumer
3723 fe05a931 Michele Tartara
  utils.RenameFile(old, new, mkdir=True, mkdir_mode=0750,
3724 fe05a931 Michele Tartara
                   dir_uid=getents.masterd_uid, dir_gid=getents.daemons_gid)
3725 af5ebcb1 Michael Hanselmann
3726 af5ebcb1 Michael Hanselmann
3727 821d1bd1 Iustin Pop
def BlockdevClose(instance_name, disks):
3728 d61cbe76 Iustin Pop
  """Closes the given block devices.
3729 d61cbe76 Iustin Pop

3730 10c2650b Iustin Pop
  This means they will be switched to secondary mode (in case of
3731 10c2650b Iustin Pop
  DRBD).
3732 10c2650b Iustin Pop

3733 b2e7666a Iustin Pop
  @param instance_name: if the argument is not empty, the symlinks
3734 b2e7666a Iustin Pop
      of this instance will be removed
3735 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
3736 10c2650b Iustin Pop
  @param disks: the list of disks to be closed
3737 10c2650b Iustin Pop
  @rtype: tuple (success, message)
3738 10c2650b Iustin Pop
  @return: a tuple of success and message, where success
3739 10c2650b Iustin Pop
      indicates the succes of the operation, and message
3740 10c2650b Iustin Pop
      which will contain the error details in case we
3741 10c2650b Iustin Pop
      failed
3742 d61cbe76 Iustin Pop

3743 d61cbe76 Iustin Pop
  """
3744 d61cbe76 Iustin Pop
  bdevs = []
3745 d61cbe76 Iustin Pop
  for cf in disks:
3746 d61cbe76 Iustin Pop
    rd = _RecursiveFindBD(cf)
3747 d61cbe76 Iustin Pop
    if rd is None:
3748 2cc6781a Iustin Pop
      _Fail("Can't find device %s", cf)
3749 d61cbe76 Iustin Pop
    bdevs.append(rd)
3750 d61cbe76 Iustin Pop
3751 d61cbe76 Iustin Pop
  msg = []
3752 d61cbe76 Iustin Pop
  for rd in bdevs:
3753 d61cbe76 Iustin Pop
    try:
3754 d61cbe76 Iustin Pop
      rd.Close()
3755 d61cbe76 Iustin Pop
    except errors.BlockDeviceError, err:
3756 d61cbe76 Iustin Pop
      msg.append(str(err))
3757 d61cbe76 Iustin Pop
  if msg:
3758 afdc3985 Iustin Pop
    _Fail("Can't make devices secondary: %s", ",".join(msg))
3759 d61cbe76 Iustin Pop
  else:
3760 b2e7666a Iustin Pop
    if instance_name:
3761 5282084b Iustin Pop
      _RemoveBlockDevLinks(instance_name, disks)
3762 d61cbe76 Iustin Pop
3763 d61cbe76 Iustin Pop
3764 6217e295 Iustin Pop
def ValidateHVParams(hvname, hvparams):
3765 6217e295 Iustin Pop
  """Validates the given hypervisor parameters.
3766 6217e295 Iustin Pop

3767 6217e295 Iustin Pop
  @type hvname: string
3768 6217e295 Iustin Pop
  @param hvname: the hypervisor name
3769 6217e295 Iustin Pop
  @type hvparams: dict
3770 6217e295 Iustin Pop
  @param hvparams: the hypervisor parameters to be validated
3771 c26a6bd2 Iustin Pop
  @rtype: None
3772 6217e295 Iustin Pop

3773 6217e295 Iustin Pop
  """
3774 6217e295 Iustin Pop
  try:
3775 6217e295 Iustin Pop
    hv_type = hypervisor.GetHypervisor(hvname)
3776 6217e295 Iustin Pop
    hv_type.ValidateParameters(hvparams)
3777 6217e295 Iustin Pop
  except errors.HypervisorError, err:
3778 afdc3985 Iustin Pop
    _Fail(str(err), log=False)
3779 6217e295 Iustin Pop
3780 6217e295 Iustin Pop
3781 acd9ff9e Iustin Pop
def _CheckOSPList(os_obj, parameters):
3782 acd9ff9e Iustin Pop
  """Check whether a list of parameters is supported by the OS.
3783 acd9ff9e Iustin Pop

3784 acd9ff9e Iustin Pop
  @type os_obj: L{objects.OS}
3785 acd9ff9e Iustin Pop
  @param os_obj: OS object to check
3786 acd9ff9e Iustin Pop
  @type parameters: list
3787 acd9ff9e Iustin Pop
  @param parameters: the list of parameters to check
3788 acd9ff9e Iustin Pop

3789 acd9ff9e Iustin Pop
  """
3790 acd9ff9e Iustin Pop
  supported = [v[0] for v in os_obj.supported_parameters]
3791 acd9ff9e Iustin Pop
  delta = frozenset(parameters).difference(supported)
3792 acd9ff9e Iustin Pop
  if delta:
3793 acd9ff9e Iustin Pop
    _Fail("The following parameters are not supported"
3794 acd9ff9e Iustin Pop
          " by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
3795 acd9ff9e Iustin Pop
3796 acd9ff9e Iustin Pop
3797 ff030c75 Jose A. Lopes
def _CheckOSVariant(os_obj, name):
3798 ff030c75 Jose A. Lopes
  """Check whether an OS name conforms to the os variants specification.
3799 ff030c75 Jose A. Lopes

3800 ff030c75 Jose A. Lopes
  @type os_obj: L{objects.OS}
3801 ff030c75 Jose A. Lopes
  @param os_obj: OS object to check
3802 ff030c75 Jose A. Lopes

3803 ff030c75 Jose A. Lopes
  @type name: string
3804 ff030c75 Jose A. Lopes
  @param name: OS name passed by the user, to check for validity
3805 ff030c75 Jose A. Lopes

3806 ff030c75 Jose A. Lopes
  @rtype: NoneType
3807 ff030c75 Jose A. Lopes
  @return: None
3808 ff030c75 Jose A. Lopes
  @raise RPCFail: if OS variant is not valid
3809 ff030c75 Jose A. Lopes

3810 ff030c75 Jose A. Lopes
  """
3811 ff030c75 Jose A. Lopes
  variant = objects.OS.GetVariant(name)
3812 ff030c75 Jose A. Lopes
3813 ff030c75 Jose A. Lopes
  if not os_obj.supported_variants:
3814 ff030c75 Jose A. Lopes
    if variant:
3815 ff030c75 Jose A. Lopes
      _Fail("OS '%s' does not support variants ('%s' passed)" %
3816 ff030c75 Jose A. Lopes
            (os_obj.name, variant))
3817 ff030c75 Jose A. Lopes
    else:
3818 ff030c75 Jose A. Lopes
      return
3819 ff030c75 Jose A. Lopes
3820 ff030c75 Jose A. Lopes
  if not variant:
3821 ff030c75 Jose A. Lopes
    _Fail("OS name '%s' must include a variant" % name)
3822 ff030c75 Jose A. Lopes
3823 ff030c75 Jose A. Lopes
  if variant not in os_obj.supported_variants:
3824 ff030c75 Jose A. Lopes
    _Fail("OS '%s' does not support variant '%s'" % (os_obj.name, variant))
3825 ff030c75 Jose A. Lopes
3826 ff030c75 Jose A. Lopes
3827 ff030c75 Jose A. Lopes
def ValidateOS(required, osname, checks, osparams, force_variant):
3828 3cf06dd4 Jose A. Lopes
  """Validate the given OS parameters.
3829 acd9ff9e Iustin Pop

3830 acd9ff9e Iustin Pop
  @type required: boolean
3831 acd9ff9e Iustin Pop
  @param required: whether absence of the OS should translate into
3832 acd9ff9e Iustin Pop
      failure or not
3833 acd9ff9e Iustin Pop
  @type osname: string
3834 acd9ff9e Iustin Pop
  @param osname: the OS to be validated
3835 acd9ff9e Iustin Pop
  @type checks: list
3836 acd9ff9e Iustin Pop
  @param checks: list of the checks to run (currently only 'parameters')
3837 acd9ff9e Iustin Pop
  @type osparams: dict
3838 1a182390 Santi Raffa
  @param osparams: dictionary with OS parameters, some of which may be
3839 1a182390 Santi Raffa
                   private.
3840 acd9ff9e Iustin Pop
  @rtype: boolean
3841 acd9ff9e Iustin Pop
  @return: True if the validation passed, or False if the OS was not
3842 acd9ff9e Iustin Pop
      found and L{required} was false
3843 acd9ff9e Iustin Pop

3844 acd9ff9e Iustin Pop
  """
3845 acd9ff9e Iustin Pop
  if not constants.OS_VALIDATE_CALLS.issuperset(checks):
3846 acd9ff9e Iustin Pop
    _Fail("Unknown checks required for OS %s: %s", osname,
3847 acd9ff9e Iustin Pop
          set(checks).difference(constants.OS_VALIDATE_CALLS))
3848 acd9ff9e Iustin Pop
3849 870dc44c Iustin Pop
  name_only = objects.OS.GetName(osname)
3850 acd9ff9e Iustin Pop
  status, tbv = _TryOSFromDisk(name_only, None)
3851 acd9ff9e Iustin Pop
3852 acd9ff9e Iustin Pop
  if not status:
3853 acd9ff9e Iustin Pop
    if required:
3854 acd9ff9e Iustin Pop
      _Fail(tbv)
3855 acd9ff9e Iustin Pop
    else:
3856 acd9ff9e Iustin Pop
      return False
3857 acd9ff9e Iustin Pop
3858 ff030c75 Jose A. Lopes
  if not force_variant:
3859 ff030c75 Jose A. Lopes
    _CheckOSVariant(tbv, osname)
3860 ff030c75 Jose A. Lopes
3861 72db3fd7 Iustin Pop
  if max(tbv.api_versions) < constants.OS_API_V20:
3862 72db3fd7 Iustin Pop
    return True
3863 72db3fd7 Iustin Pop
3864 acd9ff9e Iustin Pop
  if constants.OS_VALIDATE_PARAMETERS in checks:
3865 acd9ff9e Iustin Pop
    _CheckOSPList(tbv, osparams.keys())
3866 acd9ff9e Iustin Pop
3867 a025e535 Vitaly Kuznetsov
  validate_env = OSCoreEnv(osname, tbv, osparams)
3868 acd9ff9e Iustin Pop
  result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
3869 896a03f6 Iustin Pop
                        cwd=tbv.path, reset_env=True)
3870 acd9ff9e Iustin Pop
  if result.failed:
3871 acd9ff9e Iustin Pop
    logging.error("os validate command '%s' returned error: %s output: %s",
3872 acd9ff9e Iustin Pop
                  result.cmd, result.fail_reason, result.output)
3873 acd9ff9e Iustin Pop
    _Fail("OS validation script failed (%s), output: %s",
3874 acd9ff9e Iustin Pop
          result.fail_reason, result.output, log=False)
3875 acd9ff9e Iustin Pop
3876 acd9ff9e Iustin Pop
  return True
3877 acd9ff9e Iustin Pop
3878 acd9ff9e Iustin Pop
3879 ec9c1bf8 Jose A. Lopes
def ExportOS(instance):
3880 ec9c1bf8 Jose A. Lopes
  """Creates a GZIPed tarball with an OS definition and environment.
3881 ec9c1bf8 Jose A. Lopes

3882 ec9c1bf8 Jose A. Lopes
  The archive contains a file with the environment variables needed by
3883 ec9c1bf8 Jose A. Lopes
  the OS scripts.
3884 ec9c1bf8 Jose A. Lopes

3885 ec9c1bf8 Jose A. Lopes
  @type instance: L{objects.Instance}
3886 ec9c1bf8 Jose A. Lopes
  @param instance: instance for which the OS definition is exported
3887 ec9c1bf8 Jose A. Lopes

3888 ec9c1bf8 Jose A. Lopes
  @rtype: string
3889 ec9c1bf8 Jose A. Lopes
  @return: filepath of the archive
3890 ec9c1bf8 Jose A. Lopes

3891 ec9c1bf8 Jose A. Lopes
  """
3892 ec9c1bf8 Jose A. Lopes
  assert instance
3893 ec9c1bf8 Jose A. Lopes
  assert instance.os
3894 ec9c1bf8 Jose A. Lopes
3895 ec9c1bf8 Jose A. Lopes
  temp_dir = tempfile.mkdtemp()
3896 ec9c1bf8 Jose A. Lopes
  inst_os = OSFromDisk(instance.os)
3897 ec9c1bf8 Jose A. Lopes
3898 ec9c1bf8 Jose A. Lopes
  result = utils.RunCmd(["ln", "-s", inst_os.path,
3899 ec9c1bf8 Jose A. Lopes
                         utils.PathJoin(temp_dir, "os")])
3900 ec9c1bf8 Jose A. Lopes
  if result.failed:
3901 ec9c1bf8 Jose A. Lopes
    _Fail("Failed to copy OS package '%s' to '%s': %s, output '%s'",
3902 ec9c1bf8 Jose A. Lopes
          inst_os, temp_dir, result.fail_reason, result.output)
3903 ec9c1bf8 Jose A. Lopes
3904 ec9c1bf8 Jose A. Lopes
  env = OSEnvironment(instance, inst_os)
3905 ec9c1bf8 Jose A. Lopes
  with open(utils.PathJoin(temp_dir, "environment"), "w") as f:
3906 ec9c1bf8 Jose A. Lopes
    for var in env:
3907 ec9c1bf8 Jose A. Lopes
      f.write(var + "=" + env[var] + "\n")
3908 ec9c1bf8 Jose A. Lopes
3909 ec9c1bf8 Jose A. Lopes
  (fd, os_package) = tempfile.mkstemp(suffix=".tgz")
3910 ec9c1bf8 Jose A. Lopes
  os.close(fd)
3911 ec9c1bf8 Jose A. Lopes
3912 ec9c1bf8 Jose A. Lopes
  result = utils.RunCmd(["tar", "--dereference", "-czv",
3913 ec9c1bf8 Jose A. Lopes
                         "-f", os_package,
3914 ec9c1bf8 Jose A. Lopes
                         "-C", temp_dir,
3915 ec9c1bf8 Jose A. Lopes
                         "."])
3916 ec9c1bf8 Jose A. Lopes
  if result.failed:
3917 ec9c1bf8 Jose A. Lopes
    _Fail("Failed to create OS archive '%s': %s, output '%s'",
3918 ec9c1bf8 Jose A. Lopes
          os_package, result.fail_reason, result.output)
3919 ec9c1bf8 Jose A. Lopes
3920 ec9c1bf8 Jose A. Lopes
  result = utils.RunCmd(["rm", "-rf", temp_dir])
3921 ec9c1bf8 Jose A. Lopes
  if result.failed:
3922 ec9c1bf8 Jose A. Lopes
    _Fail("Failed to remove copy of OS package '%s' in '%s': %s, output '%s'",
3923 ec9c1bf8 Jose A. Lopes
          inst_os, temp_dir, result.fail_reason, result.output)
3924 ec9c1bf8 Jose A. Lopes
3925 ec9c1bf8 Jose A. Lopes
  return os_package
3926 ec9c1bf8 Jose A. Lopes
3927 ec9c1bf8 Jose A. Lopes
3928 56aa9fd5 Iustin Pop
def DemoteFromMC():
3929 56aa9fd5 Iustin Pop
  """Demotes the current node from master candidate role.
3930 56aa9fd5 Iustin Pop

3931 56aa9fd5 Iustin Pop
  """
3932 56aa9fd5 Iustin Pop
  # try to ensure we're not the master by mistake
3933 56aa9fd5 Iustin Pop
  master, myself = ssconf.GetMasterAndMyself()
3934 56aa9fd5 Iustin Pop
  if master == myself:
3935 afdc3985 Iustin Pop
    _Fail("ssconf status shows I'm the master node, will not demote")
3936 f154a7a3 Michael Hanselmann
3937 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "check", constants.MASTERD])
3938 f154a7a3 Michael Hanselmann
  if not result.failed:
3939 afdc3985 Iustin Pop
    _Fail("The master daemon is running, will not demote")
3940 f154a7a3 Michael Hanselmann
3941 56aa9fd5 Iustin Pop
  try:
3942 710f30ec Michael Hanselmann
    if os.path.isfile(pathutils.CLUSTER_CONF_FILE):
3943 710f30ec Michael Hanselmann
      utils.CreateBackup(pathutils.CLUSTER_CONF_FILE)
3944 56aa9fd5 Iustin Pop
  except EnvironmentError, err:
3945 56aa9fd5 Iustin Pop
    if err.errno != errno.ENOENT:
3946 afdc3985 Iustin Pop
      _Fail("Error while backing up cluster file: %s", err, exc=True)
3947 f154a7a3 Michael Hanselmann
3948 710f30ec Michael Hanselmann
  utils.RemoveFile(pathutils.CLUSTER_CONF_FILE)
3949 56aa9fd5 Iustin Pop
3950 56aa9fd5 Iustin Pop
3951 f942a838 Michael Hanselmann
def _GetX509Filenames(cryptodir, name):
3952 f942a838 Michael Hanselmann
  """Returns the full paths for the private key and certificate.
3953 f942a838 Michael Hanselmann

3954 f942a838 Michael Hanselmann
  """
3955 f942a838 Michael Hanselmann
  return (utils.PathJoin(cryptodir, name),
3956 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_KEY_FILE),
3957 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_CERT_FILE))
3958 f942a838 Michael Hanselmann
3959 f942a838 Michael Hanselmann
3960 710f30ec Michael Hanselmann
def CreateX509Certificate(validity, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3961 f942a838 Michael Hanselmann
  """Creates a new X509 certificate for SSL/TLS.
3962 f942a838 Michael Hanselmann

3963 f942a838 Michael Hanselmann
  @type validity: int
3964 f942a838 Michael Hanselmann
  @param validity: Validity in seconds
3965 f942a838 Michael Hanselmann
  @rtype: tuple; (string, string)
3966 f942a838 Michael Hanselmann
  @return: Certificate name and public part
3967 f942a838 Michael Hanselmann

3968 f942a838 Michael Hanselmann
  """
3969 f942a838 Michael Hanselmann
  (key_pem, cert_pem) = \
3970 b705c7a6 Manuel Franceschini
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
3971 ab4b1cf2 Helga Velroyen
                                     min(validity, _MAX_SSL_CERT_VALIDITY), 1)
3972 f942a838 Michael Hanselmann
3973 f942a838 Michael Hanselmann
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
3974 f942a838 Michael Hanselmann
                              prefix="x509-%s-" % utils.TimestampForFilename())
3975 f942a838 Michael Hanselmann
  try:
3976 f942a838 Michael Hanselmann
    name = os.path.basename(cert_dir)
3977 f942a838 Michael Hanselmann
    assert len(name) > 5
3978 f942a838 Michael Hanselmann
3979 f942a838 Michael Hanselmann
    (_, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3980 f942a838 Michael Hanselmann
3981 f942a838 Michael Hanselmann
    utils.WriteFile(key_file, mode=0400, data=key_pem)
3982 f942a838 Michael Hanselmann
    utils.WriteFile(cert_file, mode=0400, data=cert_pem)
3983 f942a838 Michael Hanselmann
3984 f942a838 Michael Hanselmann
    # Never return private key as it shouldn't leave the node
3985 f942a838 Michael Hanselmann
    return (name, cert_pem)
3986 f942a838 Michael Hanselmann
  except Exception:
3987 f942a838 Michael Hanselmann
    shutil.rmtree(cert_dir, ignore_errors=True)
3988 f942a838 Michael Hanselmann
    raise
3989 f942a838 Michael Hanselmann
3990 f942a838 Michael Hanselmann
3991 710f30ec Michael Hanselmann
def RemoveX509Certificate(name, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3992 f942a838 Michael Hanselmann
  """Removes a X509 certificate.
3993 f942a838 Michael Hanselmann

3994 f942a838 Michael Hanselmann
  @type name: string
3995 f942a838 Michael Hanselmann
  @param name: Certificate name
3996 f942a838 Michael Hanselmann

3997 f942a838 Michael Hanselmann
  """
3998 f942a838 Michael Hanselmann
  (cert_dir, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3999 f942a838 Michael Hanselmann
4000 f942a838 Michael Hanselmann
  utils.RemoveFile(key_file)
4001 f942a838 Michael Hanselmann
  utils.RemoveFile(cert_file)
4002 f942a838 Michael Hanselmann
4003 f942a838 Michael Hanselmann
  try:
4004 f942a838 Michael Hanselmann
    os.rmdir(cert_dir)
4005 f942a838 Michael Hanselmann
  except EnvironmentError, err:
4006 f942a838 Michael Hanselmann
    _Fail("Cannot remove certificate directory '%s': %s",
4007 f942a838 Michael Hanselmann
          cert_dir, err)
4008 f942a838 Michael Hanselmann
4009 f942a838 Michael Hanselmann
4010 1651d116 Michael Hanselmann
def _GetImportExportIoCommand(instance, mode, ieio, ieargs):
4011 1651d116 Michael Hanselmann
  """Returns the command for the requested input/output.
4012 1651d116 Michael Hanselmann

4013 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
4014 1651d116 Michael Hanselmann
  @param instance: The instance object
4015 1651d116 Michael Hanselmann
  @param mode: Import/export mode
4016 1651d116 Michael Hanselmann
  @param ieio: Input/output type
4017 1651d116 Michael Hanselmann
  @param ieargs: Input/output arguments
4018 1651d116 Michael Hanselmann

4019 1651d116 Michael Hanselmann
  """
4020 1651d116 Michael Hanselmann
  assert mode in (constants.IEM_IMPORT, constants.IEM_EXPORT)
4021 1651d116 Michael Hanselmann
4022 1651d116 Michael Hanselmann
  env = None
4023 1651d116 Michael Hanselmann
  prefix = None
4024 1651d116 Michael Hanselmann
  suffix = None
4025 2ad5550d Michael Hanselmann
  exp_size = None
4026 1651d116 Michael Hanselmann
4027 1651d116 Michael Hanselmann
  if ieio == constants.IEIO_FILE:
4028 1651d116 Michael Hanselmann
    (filename, ) = ieargs
4029 1651d116 Michael Hanselmann
4030 1651d116 Michael Hanselmann
    if not utils.IsNormAbsPath(filename):
4031 1651d116 Michael Hanselmann
      _Fail("Path '%s' is not normalized or absolute", filename)
4032 1651d116 Michael Hanselmann
4033 748c9884 René Nussbaumer
    real_filename = os.path.realpath(filename)
4034 748c9884 René Nussbaumer
    directory = os.path.dirname(real_filename)
4035 1651d116 Michael Hanselmann
4036 710f30ec Michael Hanselmann
    if not utils.IsBelowDir(pathutils.EXPORT_DIR, real_filename):
4037 748c9884 René Nussbaumer
      _Fail("File '%s' is not under exports directory '%s': %s",
4038 710f30ec Michael Hanselmann
            filename, pathutils.EXPORT_DIR, real_filename)
4039 1651d116 Michael Hanselmann
4040 1651d116 Michael Hanselmann
    # Create directory
4041 1651d116 Michael Hanselmann
    utils.Makedirs(directory, mode=0750)
4042 1651d116 Michael Hanselmann
4043 1651d116 Michael Hanselmann
    quoted_filename = utils.ShellQuote(filename)
4044 1651d116 Michael Hanselmann
4045 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
4046 1651d116 Michael Hanselmann
      suffix = "> %s" % quoted_filename
4047 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
4048 1651d116 Michael Hanselmann
      suffix = "< %s" % quoted_filename
4049 1651d116 Michael Hanselmann
4050 2ad5550d Michael Hanselmann
      # Retrieve file size
4051 2ad5550d Michael Hanselmann
      try:
4052 2ad5550d Michael Hanselmann
        st = os.stat(filename)
4053 2ad5550d Michael Hanselmann
      except EnvironmentError, err:
4054 2ad5550d Michael Hanselmann
        logging.error("Can't stat(2) %s: %s", filename, err)
4055 2ad5550d Michael Hanselmann
      else:
4056 2ad5550d Michael Hanselmann
        exp_size = utils.BytesToMebibyte(st.st_size)
4057 2ad5550d Michael Hanselmann
4058 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_RAW_DISK:
4059 1651d116 Michael Hanselmann
    (disk, ) = ieargs
4060 1651d116 Michael Hanselmann
4061 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
4062 1651d116 Michael Hanselmann
4063 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
4064 a986a581 Thomas Thrainer
      # we use nocreat to fail if the device is not already there or we pass a
4065 a986a581 Thomas Thrainer
      # wrong path; we use notrunc to no attempt truncate on an LV device
4066 a986a581 Thomas Thrainer
      suffix = utils.BuildShellCmd("| dd of=%s conv=nocreat,notrunc bs=%s",
4067 a986a581 Thomas Thrainer
                                   real_disk.dev_path,
4068 a986a581 Thomas Thrainer
                                   str(1024 * 1024)) # 1 MB
4069 1651d116 Michael Hanselmann
4070 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
4071 1651d116 Michael Hanselmann
      # the block size on the read dd is 1MiB to match our units
4072 1651d116 Michael Hanselmann
      prefix = utils.BuildShellCmd("dd if=%s bs=%s count=%s |",
4073 1651d116 Michael Hanselmann
                                   real_disk.dev_path,
4074 1651d116 Michael Hanselmann
                                   str(1024 * 1024), # 1 MB
4075 1651d116 Michael Hanselmann
                                   str(disk.size))
4076 2ad5550d Michael Hanselmann
      exp_size = disk.size
4077 1651d116 Michael Hanselmann
4078 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_SCRIPT:
4079 1651d116 Michael Hanselmann
    (disk, disk_index, ) = ieargs
4080 1651d116 Michael Hanselmann
4081 1651d116 Michael Hanselmann
    assert isinstance(disk_index, (int, long))
4082 1651d116 Michael Hanselmann
4083 1651d116 Michael Hanselmann
    inst_os = OSFromDisk(instance.os)
4084 1651d116 Michael Hanselmann
    env = OSEnvironment(instance, inst_os)
4085 1651d116 Michael Hanselmann
4086 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
4087 1651d116 Michael Hanselmann
      env["IMPORT_DEVICE"] = env["DISK_%d_PATH" % disk_index]
4088 1651d116 Michael Hanselmann
      env["IMPORT_INDEX"] = str(disk_index)
4089 1651d116 Michael Hanselmann
      script = inst_os.import_script
4090 1651d116 Michael Hanselmann
4091 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
4092 0c3d9c7c Thomas Thrainer
      real_disk = _OpenRealBD(disk)
4093 1651d116 Michael Hanselmann
      env["EXPORT_DEVICE"] = real_disk.dev_path
4094 1651d116 Michael Hanselmann
      env["EXPORT_INDEX"] = str(disk_index)
4095 1651d116 Michael Hanselmann
      script = inst_os.export_script
4096 1651d116 Michael Hanselmann
4097 1651d116 Michael Hanselmann
    # TODO: Pass special environment only to script
4098 1651d116 Michael Hanselmann
    script_cmd = utils.BuildShellCmd("( cd %s && %s; )", inst_os.path, script)
4099 1651d116 Michael Hanselmann
4100 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
4101 1651d116 Michael Hanselmann
      suffix = "| %s" % script_cmd
4102 1651d116 Michael Hanselmann
4103 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
4104 1651d116 Michael Hanselmann
      prefix = "%s |" % script_cmd
4105 1651d116 Michael Hanselmann
4106 2ad5550d Michael Hanselmann
    # Let script predict size
4107 2ad5550d Michael Hanselmann
    exp_size = constants.IE_CUSTOM_SIZE
4108 2ad5550d Michael Hanselmann
4109 1651d116 Michael Hanselmann
  else:
4110 1651d116 Michael Hanselmann
    _Fail("Invalid %s I/O mode %r", mode, ieio)
4111 1651d116 Michael Hanselmann
4112 2ad5550d Michael Hanselmann
  return (env, prefix, suffix, exp_size)
4113 1651d116 Michael Hanselmann
4114 1651d116 Michael Hanselmann
4115 1651d116 Michael Hanselmann
def _CreateImportExportStatusDir(prefix):
4116 1651d116 Michael Hanselmann
  """Creates status directory for import/export.
4117 1651d116 Michael Hanselmann

4118 1651d116 Michael Hanselmann
  """
4119 710f30ec Michael Hanselmann
  return tempfile.mkdtemp(dir=pathutils.IMPORT_EXPORT_DIR,
4120 1651d116 Michael Hanselmann
                          prefix=("%s-%s-" %
4121 1651d116 Michael Hanselmann
                                  (prefix, utils.TimestampForFilename())))
4122 1651d116 Michael Hanselmann
4123 1651d116 Michael Hanselmann
4124 6613661a Iustin Pop
def StartImportExportDaemon(mode, opts, host, port, instance, component,
4125 6613661a Iustin Pop
                            ieio, ieioargs):
4126 1651d116 Michael Hanselmann
  """Starts an import or export daemon.
4127 1651d116 Michael Hanselmann

4128 1651d116 Michael Hanselmann
  @param mode: Import/output mode
4129 eb630f50 Michael Hanselmann
  @type opts: L{objects.ImportExportOptions}
4130 eb630f50 Michael Hanselmann
  @param opts: Daemon options
4131 1651d116 Michael Hanselmann
  @type host: string
4132 1651d116 Michael Hanselmann
  @param host: Remote host for export (None for import)
4133 1651d116 Michael Hanselmann
  @type port: int
4134 1651d116 Michael Hanselmann
  @param port: Remote port for export (None for import)
4135 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
4136 1651d116 Michael Hanselmann
  @param instance: Instance object
4137 6613661a Iustin Pop
  @type component: string
4138 6613661a Iustin Pop
  @param component: which part of the instance is transferred now,
4139 6613661a Iustin Pop
      e.g. 'disk/0'
4140 1651d116 Michael Hanselmann
  @param ieio: Input/output type
4141 1651d116 Michael Hanselmann
  @param ieioargs: Input/output arguments
4142 1651d116 Michael Hanselmann

4143 1651d116 Michael Hanselmann
  """
4144 1651d116 Michael Hanselmann
  if mode == constants.IEM_IMPORT:
4145 1651d116 Michael Hanselmann
    prefix = "import"
4146 1651d116 Michael Hanselmann
4147 1651d116 Michael Hanselmann
    if not (host is None and port is None):
4148 1651d116 Michael Hanselmann
      _Fail("Can not specify host or port on import")
4149 1651d116 Michael Hanselmann
4150 1651d116 Michael Hanselmann
  elif mode == constants.IEM_EXPORT:
4151 1651d116 Michael Hanselmann
    prefix = "export"
4152 1651d116 Michael Hanselmann
4153 1651d116 Michael Hanselmann
    if host is None or port is None:
4154 1651d116 Michael Hanselmann
      _Fail("Host and port must be specified for an export")
4155 1651d116 Michael Hanselmann
4156 1651d116 Michael Hanselmann
  else:
4157 1651d116 Michael Hanselmann
    _Fail("Invalid mode %r", mode)
4158 1651d116 Michael Hanselmann
4159 eb630f50 Michael Hanselmann
  if (opts.key_name is None) ^ (opts.ca_pem is None):
4160 1651d116 Michael Hanselmann
    _Fail("Cluster certificate can only be used for both key and CA")
4161 1651d116 Michael Hanselmann
4162 2ad5550d Michael Hanselmann
  (cmd_env, cmd_prefix, cmd_suffix, exp_size) = \
4163 1651d116 Michael Hanselmann
    _GetImportExportIoCommand(instance, mode, ieio, ieioargs)
4164 1651d116 Michael Hanselmann
4165 eb630f50 Michael Hanselmann
  if opts.key_name is None:
4166 1651d116 Michael Hanselmann
    # Use server.pem
4167 710f30ec Michael Hanselmann
    key_path = pathutils.NODED_CERT_FILE
4168 710f30ec Michael Hanselmann
    cert_path = pathutils.NODED_CERT_FILE
4169 eb630f50 Michael Hanselmann
    assert opts.ca_pem is None
4170 1651d116 Michael Hanselmann
  else:
4171 710f30ec Michael Hanselmann
    (_, key_path, cert_path) = _GetX509Filenames(pathutils.CRYPTO_KEYS_DIR,
4172 eb630f50 Michael Hanselmann
                                                 opts.key_name)
4173 eb630f50 Michael Hanselmann
    assert opts.ca_pem is not None
4174 1651d116 Michael Hanselmann
4175 63bcea2a Michael Hanselmann
  for i in [key_path, cert_path]:
4176 dcaabc4f Michael Hanselmann
    if not os.path.exists(i):
4177 63bcea2a Michael Hanselmann
      _Fail("File '%s' does not exist" % i)
4178 63bcea2a Michael Hanselmann
4179 6613661a Iustin Pop
  status_dir = _CreateImportExportStatusDir("%s-%s" % (prefix, component))
4180 1651d116 Michael Hanselmann
  try:
4181 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(status_dir, _IES_STATUS_FILE)
4182 1651d116 Michael Hanselmann
    pid_file = utils.PathJoin(status_dir, _IES_PID_FILE)
4183 63bcea2a Michael Hanselmann
    ca_file = utils.PathJoin(status_dir, _IES_CA_FILE)
4184 1651d116 Michael Hanselmann
4185 eb630f50 Michael Hanselmann
    if opts.ca_pem is None:
4186 1651d116 Michael Hanselmann
      # Use server.pem
4187 710f30ec Michael Hanselmann
      ca = utils.ReadFile(pathutils.NODED_CERT_FILE)
4188 eb630f50 Michael Hanselmann
    else:
4189 eb630f50 Michael Hanselmann
      ca = opts.ca_pem
4190 63bcea2a Michael Hanselmann
4191 eb630f50 Michael Hanselmann
    # Write CA file
4192 63bcea2a Michael Hanselmann
    utils.WriteFile(ca_file, data=ca, mode=0400)
4193 1651d116 Michael Hanselmann
4194 1651d116 Michael Hanselmann
    cmd = [
4195 710f30ec Michael Hanselmann
      pathutils.IMPORT_EXPORT_DAEMON,
4196 1651d116 Michael Hanselmann
      status_file, mode,
4197 1651d116 Michael Hanselmann
      "--key=%s" % key_path,
4198 1651d116 Michael Hanselmann
      "--cert=%s" % cert_path,
4199 63bcea2a Michael Hanselmann
      "--ca=%s" % ca_file,
4200 1651d116 Michael Hanselmann
      ]
4201 1651d116 Michael Hanselmann
4202 1651d116 Michael Hanselmann
    if host:
4203 1651d116 Michael Hanselmann
      cmd.append("--host=%s" % host)
4204 1651d116 Michael Hanselmann
4205 1651d116 Michael Hanselmann
    if port:
4206 1651d116 Michael Hanselmann
      cmd.append("--port=%s" % port)
4207 1651d116 Michael Hanselmann
4208 855d2fc7 Michael Hanselmann
    if opts.ipv6:
4209 855d2fc7 Michael Hanselmann
      cmd.append("--ipv6")
4210 855d2fc7 Michael Hanselmann
    else:
4211 855d2fc7 Michael Hanselmann
      cmd.append("--ipv4")
4212 855d2fc7 Michael Hanselmann
4213 a5310c2a Michael Hanselmann
    if opts.compress:
4214 a5310c2a Michael Hanselmann
      cmd.append("--compress=%s" % opts.compress)
4215 a5310c2a Michael Hanselmann
4216 af1d39b1 Michael Hanselmann
    if opts.magic:
4217 af1d39b1 Michael Hanselmann
      cmd.append("--magic=%s" % opts.magic)
4218 af1d39b1 Michael Hanselmann
4219 2ad5550d Michael Hanselmann
    if exp_size is not None:
4220 2ad5550d Michael Hanselmann
      cmd.append("--expected-size=%s" % exp_size)
4221 2ad5550d Michael Hanselmann
4222 1651d116 Michael Hanselmann
    if cmd_prefix:
4223 1651d116 Michael Hanselmann
      cmd.append("--cmd-prefix=%s" % cmd_prefix)
4224 1651d116 Michael Hanselmann
4225 1651d116 Michael Hanselmann
    if cmd_suffix:
4226 1651d116 Michael Hanselmann
      cmd.append("--cmd-suffix=%s" % cmd_suffix)
4227 1651d116 Michael Hanselmann
4228 4478301b Michael Hanselmann
    if mode == constants.IEM_EXPORT:
4229 4478301b Michael Hanselmann
      # Retry connection a few times when connecting to remote peer
4230 4478301b Michael Hanselmann
      cmd.append("--connect-retries=%s" % constants.RIE_CONNECT_RETRIES)
4231 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % constants.RIE_CONNECT_ATTEMPT_TIMEOUT)
4232 4478301b Michael Hanselmann
    elif opts.connect_timeout is not None:
4233 4478301b Michael Hanselmann
      assert mode == constants.IEM_IMPORT
4234 4478301b Michael Hanselmann
      # Overall timeout for establishing connection while listening
4235 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % opts.connect_timeout)
4236 4478301b Michael Hanselmann
4237 6aa7a354 Iustin Pop
    logfile = _InstanceLogName(prefix, instance.os, instance.name, component)
4238 1651d116 Michael Hanselmann
4239 1651d116 Michael Hanselmann
    # TODO: Once _InstanceLogName uses tempfile.mkstemp, StartDaemon has
4240 1651d116 Michael Hanselmann
    # support for receiving a file descriptor for output
4241 1651d116 Michael Hanselmann
    utils.StartDaemon(cmd, env=cmd_env, pidfile=pid_file,
4242 1651d116 Michael Hanselmann
                      output=logfile)
4243 1651d116 Michael Hanselmann
4244 1651d116 Michael Hanselmann
    # The import/export name is simply the status directory name
4245 1651d116 Michael Hanselmann
    return os.path.basename(status_dir)
4246 1651d116 Michael Hanselmann
4247 1651d116 Michael Hanselmann
  except Exception:
4248 1651d116 Michael Hanselmann
    shutil.rmtree(status_dir, ignore_errors=True)
4249 1651d116 Michael Hanselmann
    raise
4250 1651d116 Michael Hanselmann
4251 1651d116 Michael Hanselmann
4252 1651d116 Michael Hanselmann
def GetImportExportStatus(names):
4253 1651d116 Michael Hanselmann
  """Returns import/export daemon status.
4254 1651d116 Michael Hanselmann

4255 1651d116 Michael Hanselmann
  @type names: sequence
4256 1651d116 Michael Hanselmann
  @param names: List of names
4257 1651d116 Michael Hanselmann
  @rtype: List of dicts
4258 1651d116 Michael Hanselmann
  @return: Returns a list of the state of each named import/export or None if a
4259 1651d116 Michael Hanselmann
           status couldn't be read
4260 1651d116 Michael Hanselmann

4261 1651d116 Michael Hanselmann
  """
4262 1651d116 Michael Hanselmann
  result = []
4263 1651d116 Michael Hanselmann
4264 1651d116 Michael Hanselmann
  for name in names:
4265 710f30ec Michael Hanselmann
    status_file = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name,
4266 1651d116 Michael Hanselmann
                                 _IES_STATUS_FILE)
4267 1651d116 Michael Hanselmann
4268 1651d116 Michael Hanselmann
    try:
4269 1651d116 Michael Hanselmann
      data = utils.ReadFile(status_file)
4270 1651d116 Michael Hanselmann
    except EnvironmentError, err:
4271 1651d116 Michael Hanselmann
      if err.errno != errno.ENOENT:
4272 1651d116 Michael Hanselmann
        raise
4273 1651d116 Michael Hanselmann
      data = None
4274 1651d116 Michael Hanselmann
4275 1651d116 Michael Hanselmann
    if not data:
4276 1651d116 Michael Hanselmann
      result.append(None)
4277 1651d116 Michael Hanselmann
      continue
4278 1651d116 Michael Hanselmann
4279 1651d116 Michael Hanselmann
    result.append(serializer.LoadJson(data))
4280 1651d116 Michael Hanselmann
4281 1651d116 Michael Hanselmann
  return result
4282 1651d116 Michael Hanselmann
4283 1651d116 Michael Hanselmann
4284 f81c4737 Michael Hanselmann
def AbortImportExport(name):
4285 f81c4737 Michael Hanselmann
  """Sends SIGTERM to a running import/export daemon.
4286 f81c4737 Michael Hanselmann

4287 f81c4737 Michael Hanselmann
  """
4288 f81c4737 Michael Hanselmann
  logging.info("Abort import/export %s", name)
4289 f81c4737 Michael Hanselmann
4290 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4291 f81c4737 Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4292 f81c4737 Michael Hanselmann
4293 f81c4737 Michael Hanselmann
  if pid:
4294 f81c4737 Michael Hanselmann
    logging.info("Import/export %s is running with PID %s, sending SIGTERM",
4295 f81c4737 Michael Hanselmann
                 name, pid)
4296 560cbec1 Michael Hanselmann
    utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
4297 f81c4737 Michael Hanselmann
4298 f81c4737 Michael Hanselmann
4299 1651d116 Michael Hanselmann
def CleanupImportExport(name):
4300 1651d116 Michael Hanselmann
  """Cleanup after an import or export.
4301 1651d116 Michael Hanselmann

4302 1651d116 Michael Hanselmann
  If the import/export daemon is still running it's killed. Afterwards the
4303 1651d116 Michael Hanselmann
  whole status directory is removed.
4304 1651d116 Michael Hanselmann

4305 1651d116 Michael Hanselmann
  """
4306 1651d116 Michael Hanselmann
  logging.info("Finalizing import/export %s", name)
4307 1651d116 Michael Hanselmann
4308 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4309 1651d116 Michael Hanselmann
4310 debed9ae Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4311 1651d116 Michael Hanselmann
4312 1651d116 Michael Hanselmann
  if pid:
4313 1651d116 Michael Hanselmann
    logging.info("Import/export %s is still running with PID %s",
4314 1651d116 Michael Hanselmann
                 name, pid)
4315 1651d116 Michael Hanselmann
    utils.KillProcess(pid, waitpid=False)
4316 1651d116 Michael Hanselmann
4317 1651d116 Michael Hanselmann
  shutil.rmtree(status_dir, ignore_errors=True)
4318 1651d116 Michael Hanselmann
4319 1651d116 Michael Hanselmann
4320 0c3d9c7c Thomas Thrainer
def _FindDisks(disks):
4321 0c3d9c7c Thomas Thrainer
  """Finds attached L{BlockDev}s for the given disks.
4322 6b93ec9d Iustin Pop

4323 0c3d9c7c Thomas Thrainer
  @type disks: list of L{objects.Disk}
4324 0c3d9c7c Thomas Thrainer
  @param disks: the disk objects we need to find
4325 235a6b29 Thomas Thrainer

4326 0c3d9c7c Thomas Thrainer
  @return: list of L{BlockDev} objects or C{None} if a given disk
4327 0c3d9c7c Thomas Thrainer
           was not found or was no attached.
4328 235a6b29 Thomas Thrainer

4329 235a6b29 Thomas Thrainer
  """
4330 6b93ec9d Iustin Pop
  bdevs = []
4331 6b93ec9d Iustin Pop
4332 0c3d9c7c Thomas Thrainer
  for disk in disks:
4333 0c3d9c7c Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4334 6b93ec9d Iustin Pop
    if rd is None:
4335 0c3d9c7c Thomas Thrainer
      _Fail("Can't find device %s", disk)
4336 6b93ec9d Iustin Pop
    bdevs.append(rd)
4337 5a533f8a Iustin Pop
  return bdevs
4338 6b93ec9d Iustin Pop
4339 6b93ec9d Iustin Pop
4340 0c3d9c7c Thomas Thrainer
def DrbdDisconnectNet(disks):
4341 6b93ec9d Iustin Pop
  """Disconnects the network on a list of drbd devices.
4342 6b93ec9d Iustin Pop

4343 6b93ec9d Iustin Pop
  """
4344 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4345 6b93ec9d Iustin Pop
4346 6b93ec9d Iustin Pop
  # disconnect disks
4347 6b93ec9d Iustin Pop
  for rd in bdevs:
4348 6b93ec9d Iustin Pop
    try:
4349 6b93ec9d Iustin Pop
      rd.DisconnectNet()
4350 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
4351 2cc6781a Iustin Pop
      _Fail("Can't change network configuration to standalone mode: %s",
4352 2cc6781a Iustin Pop
            err, exc=True)
4353 6b93ec9d Iustin Pop
4354 6b93ec9d Iustin Pop
4355 0c3d9c7c Thomas Thrainer
def DrbdAttachNet(disks, instance_name, multimaster):
4356 6b93ec9d Iustin Pop
  """Attaches the network on a list of drbd devices.
4357 6b93ec9d Iustin Pop

4358 6b93ec9d Iustin Pop
  """
4359 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4360 6b93ec9d Iustin Pop
4361 6b93ec9d Iustin Pop
  if multimaster:
4362 53c776b5 Iustin Pop
    for idx, rd in enumerate(bdevs):
4363 6b93ec9d Iustin Pop
      try:
4364 53c776b5 Iustin Pop
        _SymlinkBlockDev(instance_name, rd.dev_path, idx)
4365 6b93ec9d Iustin Pop
      except EnvironmentError, err:
4366 2cc6781a Iustin Pop
        _Fail("Can't create symlink: %s", err)
4367 6b93ec9d Iustin Pop
  # reconnect disks, switch to new master configuration and if
4368 6b93ec9d Iustin Pop
  # needed primary mode
4369 6b93ec9d Iustin Pop
  for rd in bdevs:
4370 6b93ec9d Iustin Pop
    try:
4371 6b93ec9d Iustin Pop
      rd.AttachNet(multimaster)
4372 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
4373 2cc6781a Iustin Pop
      _Fail("Can't change network configuration: %s", err)
4374 3c0cdc83 Michael Hanselmann
4375 6b93ec9d Iustin Pop
  # wait until the disks are connected; we need to retry the re-attach
4376 6b93ec9d Iustin Pop
  # if the device becomes standalone, as this might happen if the one
4377 6b93ec9d Iustin Pop
  # node disconnects and reconnects in a different mode before the
4378 6b93ec9d Iustin Pop
  # other node reconnects; in this case, one or both of the nodes will
4379 6b93ec9d Iustin Pop
  # decide it has wrong configuration and switch to standalone
4380 3c0cdc83 Michael Hanselmann
4381 3c0cdc83 Michael Hanselmann
  def _Attach():
4382 6b93ec9d Iustin Pop
    all_connected = True
4383 3c0cdc83 Michael Hanselmann
4384 6b93ec9d Iustin Pop
    for rd in bdevs:
4385 6b93ec9d Iustin Pop
      stats = rd.GetProcStatus()
4386 3c0cdc83 Michael Hanselmann
4387 73e15b5e Apollon Oikonomopoulos
      if multimaster:
4388 73e15b5e Apollon Oikonomopoulos
        # In the multimaster case we have to wait explicitly until
4389 73e15b5e Apollon Oikonomopoulos
        # the resource is Connected and UpToDate/UpToDate, because
4390 73e15b5e Apollon Oikonomopoulos
        # we promote *both nodes* to primary directly afterwards.
4391 73e15b5e Apollon Oikonomopoulos
        # Being in resync is not enough, since there is a race during which we
4392 73e15b5e Apollon Oikonomopoulos
        # may promote a node with an Outdated disk to primary, effectively
4393 73e15b5e Apollon Oikonomopoulos
        # tearing down the connection.
4394 73e15b5e Apollon Oikonomopoulos
        all_connected = (all_connected and
4395 73e15b5e Apollon Oikonomopoulos
                         stats.is_connected and
4396 73e15b5e Apollon Oikonomopoulos
                         stats.is_disk_uptodate and
4397 73e15b5e Apollon Oikonomopoulos
                         stats.peer_disk_uptodate)
4398 73e15b5e Apollon Oikonomopoulos
      else:
4399 73e15b5e Apollon Oikonomopoulos
        all_connected = (all_connected and
4400 73e15b5e Apollon Oikonomopoulos
                         (stats.is_connected or stats.is_in_resync))
4401 3c0cdc83 Michael Hanselmann
4402 6b93ec9d Iustin Pop
      if stats.is_standalone:
4403 6b93ec9d Iustin Pop
        # peer had different config info and this node became
4404 6b93ec9d Iustin Pop
        # standalone, even though this should not happen with the
4405 6b93ec9d Iustin Pop
        # new staged way of changing disk configs
4406 6b93ec9d Iustin Pop
        try:
4407 c738375b Iustin Pop
          rd.AttachNet(multimaster)
4408 6b93ec9d Iustin Pop
        except errors.BlockDeviceError, err:
4409 2cc6781a Iustin Pop
          _Fail("Can't change network configuration: %s", err)
4410 3c0cdc83 Michael Hanselmann
4411 3c0cdc83 Michael Hanselmann
    if not all_connected:
4412 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
4413 3c0cdc83 Michael Hanselmann
4414 3c0cdc83 Michael Hanselmann
  try:
4415 3c0cdc83 Michael Hanselmann
    # Start with a delay of 100 miliseconds and go up to 5 seconds
4416 3c0cdc83 Michael Hanselmann
    utils.Retry(_Attach, (0.1, 1.5, 5.0), 2 * 60)
4417 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
4418 afdc3985 Iustin Pop
    _Fail("Timeout in disk reconnecting")
4419 3c0cdc83 Michael Hanselmann
4420 6b93ec9d Iustin Pop
  if multimaster:
4421 6b93ec9d Iustin Pop
    # change to primary mode
4422 6b93ec9d Iustin Pop
    for rd in bdevs:
4423 d3da87b8 Iustin Pop
      try:
4424 d3da87b8 Iustin Pop
        rd.Open()
4425 d3da87b8 Iustin Pop
      except errors.BlockDeviceError, err:
4426 2cc6781a Iustin Pop
        _Fail("Can't change to primary mode: %s", err)
4427 6b93ec9d Iustin Pop
4428 6b93ec9d Iustin Pop
4429 0c3d9c7c Thomas Thrainer
def DrbdWaitSync(disks):
4430 6b93ec9d Iustin Pop
  """Wait until DRBDs have synchronized.
4431 6b93ec9d Iustin Pop

4432 6b93ec9d Iustin Pop
  """
4433 db8667b7 Iustin Pop
  def _helper(rd):
4434 db8667b7 Iustin Pop
    stats = rd.GetProcStatus()
4435 db8667b7 Iustin Pop
    if not (stats.is_connected or stats.is_in_resync):
4436 db8667b7 Iustin Pop
      raise utils.RetryAgain()
4437 db8667b7 Iustin Pop
    return stats
4438 db8667b7 Iustin Pop
4439 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4440 6b93ec9d Iustin Pop
4441 6b93ec9d Iustin Pop
  min_resync = 100
4442 6b93ec9d Iustin Pop
  alldone = True
4443 6b93ec9d Iustin Pop
  for rd in bdevs:
4444 db8667b7 Iustin Pop
    try:
4445 db8667b7 Iustin Pop
      # poll each second for 15 seconds
4446 db8667b7 Iustin Pop
      stats = utils.Retry(_helper, 1, 15, args=[rd])
4447 db8667b7 Iustin Pop
    except utils.RetryTimeout:
4448 db8667b7 Iustin Pop
      stats = rd.GetProcStatus()
4449 db8667b7 Iustin Pop
      # last check
4450 db8667b7 Iustin Pop
      if not (stats.is_connected or stats.is_in_resync):
4451 db8667b7 Iustin Pop
        _Fail("DRBD device %s is not in sync: stats=%s", rd, stats)
4452 6b93ec9d Iustin Pop
    alldone = alldone and (not stats.is_in_resync)
4453 6b93ec9d Iustin Pop
    if stats.sync_percent is not None:
4454 6b93ec9d Iustin Pop
      min_resync = min(min_resync, stats.sync_percent)
4455 afdc3985 Iustin Pop
4456 c26a6bd2 Iustin Pop
  return (alldone, min_resync)
4457 6b93ec9d Iustin Pop
4458 6b93ec9d Iustin Pop
4459 0c3d9c7c Thomas Thrainer
def DrbdNeedsActivation(disks):
4460 235a6b29 Thomas Thrainer
  """Checks which of the passed disks needs activation and returns their UUIDs.
4461 235a6b29 Thomas Thrainer

4462 235a6b29 Thomas Thrainer
  """
4463 235a6b29 Thomas Thrainer
  faulty_disks = []
4464 235a6b29 Thomas Thrainer
4465 235a6b29 Thomas Thrainer
  for disk in disks:
4466 235a6b29 Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4467 235a6b29 Thomas Thrainer
    if rd is None:
4468 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4469 235a6b29 Thomas Thrainer
      continue
4470 235a6b29 Thomas Thrainer
4471 235a6b29 Thomas Thrainer
    stats = rd.GetProcStatus()
4472 235a6b29 Thomas Thrainer
    if stats.is_standalone or stats.is_diskless:
4473 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4474 235a6b29 Thomas Thrainer
4475 235a6b29 Thomas Thrainer
  return [disk.uuid for disk in faulty_disks]
4476 235a6b29 Thomas Thrainer
4477 235a6b29 Thomas Thrainer
4478 c46b9782 Luca Bigliardi
def GetDrbdUsermodeHelper():
4479 c46b9782 Luca Bigliardi
  """Returns DRBD usermode helper currently configured.
4480 c46b9782 Luca Bigliardi

4481 c46b9782 Luca Bigliardi
  """
4482 c46b9782 Luca Bigliardi
  try:
4483 47e0abee Thomas Thrainer
    return drbd.DRBD8.GetUsermodeHelper()
4484 c46b9782 Luca Bigliardi
  except errors.BlockDeviceError, err:
4485 c46b9782 Luca Bigliardi
    _Fail(str(err))
4486 c46b9782 Luca Bigliardi
4487 c46b9782 Luca Bigliardi
4488 8ef418bb Helga Velroyen
def PowercycleNode(hypervisor_type, hvparams=None):
4489 f5118ade Iustin Pop
  """Hard-powercycle the node.
4490 f5118ade Iustin Pop

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

4494 f5118ade Iustin Pop
  """
4495 f5118ade Iustin Pop
  hyper = hypervisor.GetHypervisor(hypervisor_type)
4496 f5118ade Iustin Pop
  try:
4497 f5118ade Iustin Pop
    pid = os.fork()
4498 29921401 Iustin Pop
  except OSError:
4499 f5118ade Iustin Pop
    # if we can't fork, we'll pretend that we're in the child process
4500 f5118ade Iustin Pop
    pid = 0
4501 f5118ade Iustin Pop
  if pid > 0:
4502 c26a6bd2 Iustin Pop
    return "Reboot scheduled in 5 seconds"
4503 1af6ac0f Luca Bigliardi
  # ensure the child is running on ram
4504 1af6ac0f Luca Bigliardi
  try:
4505 1af6ac0f Luca Bigliardi
    utils.Mlockall()
4506 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
4507 1af6ac0f Luca Bigliardi
    pass
4508 f5118ade Iustin Pop
  time.sleep(5)
4509 8ef418bb Helga Velroyen
  hyper.PowercycleNode(hvparams=hvparams)
4510 f5118ade Iustin Pop
4511 f5118ade Iustin Pop
4512 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdName(cmd):
4513 45bc4635 Iustin Pop
  """Verifies a restricted command name.
4514 1a2eb2dc Michael Hanselmann

4515 1a2eb2dc Michael Hanselmann
  @type cmd: string
4516 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4517 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4518 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4519 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4520 1a2eb2dc Michael Hanselmann

4521 1a2eb2dc Michael Hanselmann
  """
4522 1a2eb2dc Michael Hanselmann
  if not cmd.strip():
4523 1a2eb2dc Michael Hanselmann
    return (False, "Missing command name")
4524 1a2eb2dc Michael Hanselmann
4525 1a2eb2dc Michael Hanselmann
  if os.path.basename(cmd) != cmd:
4526 1a2eb2dc Michael Hanselmann
    return (False, "Invalid command name")
4527 1a2eb2dc Michael Hanselmann
4528 1a2eb2dc Michael Hanselmann
  if not constants.EXT_PLUGIN_MASK.match(cmd):
4529 1a2eb2dc Michael Hanselmann
    return (False, "Command name contains forbidden characters")
4530 1a2eb2dc Michael Hanselmann
4531 1a2eb2dc Michael Hanselmann
  return (True, None)
4532 1a2eb2dc Michael Hanselmann
4533 1a2eb2dc Michael Hanselmann
4534 405bffe2 Michael Hanselmann
def _CommonRestrictedCmdCheck(path, owner):
4535 45bc4635 Iustin Pop
  """Common checks for restricted command file system directories and files.
4536 1a2eb2dc Michael Hanselmann

4537 1a2eb2dc Michael Hanselmann
  @type path: string
4538 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4539 1a2eb2dc Michael Hanselmann
  @param owner: C{None} or tuple containing UID and GID
4540 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or C{os.stat} result)
4541 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4542 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's the result of C{os.stat}
4543 1a2eb2dc Michael Hanselmann

4544 1a2eb2dc Michael Hanselmann
  """
4545 1a2eb2dc Michael Hanselmann
  if owner is None:
4546 1a2eb2dc Michael Hanselmann
    # Default to root as owner
4547 1a2eb2dc Michael Hanselmann
    owner = (0, 0)
4548 1a2eb2dc Michael Hanselmann
4549 1a2eb2dc Michael Hanselmann
  try:
4550 1a2eb2dc Michael Hanselmann
    st = os.stat(path)
4551 1a2eb2dc Michael Hanselmann
  except EnvironmentError, err:
4552 1a2eb2dc Michael Hanselmann
    return (False, "Can't stat(2) '%s': %s" % (path, err))
4553 1a2eb2dc Michael Hanselmann
4554 1a2eb2dc Michael Hanselmann
  if stat.S_IMODE(st.st_mode) & (~_RCMD_MAX_MODE):
4555 1a2eb2dc Michael Hanselmann
    return (False, "Permissions on '%s' are too permissive" % path)
4556 1a2eb2dc Michael Hanselmann
4557 1a2eb2dc Michael Hanselmann
  if (st.st_uid, st.st_gid) != owner:
4558 1a2eb2dc Michael Hanselmann
    (owner_uid, owner_gid) = owner
4559 1a2eb2dc Michael Hanselmann
    return (False, "'%s' is not owned by %s:%s" % (path, owner_uid, owner_gid))
4560 1a2eb2dc Michael Hanselmann
4561 1a2eb2dc Michael Hanselmann
  return (True, st)
4562 1a2eb2dc Michael Hanselmann
4563 1a2eb2dc Michael Hanselmann
4564 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdDirectory(path, _owner=None):
4565 45bc4635 Iustin Pop
  """Verifies restricted command directory.
4566 1a2eb2dc Michael Hanselmann

4567 1a2eb2dc Michael Hanselmann
  @type path: string
4568 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4569 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4570 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4571 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4572 1a2eb2dc Michael Hanselmann

4573 1a2eb2dc Michael Hanselmann
  """
4574 405bffe2 Michael Hanselmann
  (status, value) = _CommonRestrictedCmdCheck(path, _owner)
4575 1a2eb2dc Michael Hanselmann
4576 1a2eb2dc Michael Hanselmann
  if not status:
4577 1a2eb2dc Michael Hanselmann
    return (False, value)
4578 1a2eb2dc Michael Hanselmann
4579 1a2eb2dc Michael Hanselmann
  if not stat.S_ISDIR(value.st_mode):
4580 1a2eb2dc Michael Hanselmann
    return (False, "Path '%s' is not a directory" % path)
4581 1a2eb2dc Michael Hanselmann
4582 1a2eb2dc Michael Hanselmann
  return (True, None)
4583 1a2eb2dc Michael Hanselmann
4584 1a2eb2dc Michael Hanselmann
4585 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmd(path, cmd, _owner=None):
4586 45bc4635 Iustin Pop
  """Verifies a whole restricted command and returns its executable filename.
4587 1a2eb2dc Michael Hanselmann

4588 1a2eb2dc Michael Hanselmann
  @type path: string
4589 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4590 1a2eb2dc Michael Hanselmann
  @type cmd: string
4591 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4592 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string)
4593 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4594 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise the second element is the
4595 1a2eb2dc Michael Hanselmann
    absolute path to the executable
4596 1a2eb2dc Michael Hanselmann

4597 1a2eb2dc Michael Hanselmann
  """
4598 1a2eb2dc Michael Hanselmann
  executable = utils.PathJoin(path, cmd)
4599 1a2eb2dc Michael Hanselmann
4600 405bffe2 Michael Hanselmann
  (status, msg) = _CommonRestrictedCmdCheck(executable, _owner)
4601 1a2eb2dc Michael Hanselmann
4602 1a2eb2dc Michael Hanselmann
  if not status:
4603 1a2eb2dc Michael Hanselmann
    return (False, msg)
4604 1a2eb2dc Michael Hanselmann
4605 1a2eb2dc Michael Hanselmann
  if not utils.IsExecutable(executable):
4606 1a2eb2dc Michael Hanselmann
    return (False, "access(2) thinks '%s' can't be executed" % executable)
4607 1a2eb2dc Michael Hanselmann
4608 1a2eb2dc Michael Hanselmann
  return (True, executable)
4609 1a2eb2dc Michael Hanselmann
4610 1a2eb2dc Michael Hanselmann
4611 405bffe2 Michael Hanselmann
def _PrepareRestrictedCmd(path, cmd,
4612 405bffe2 Michael Hanselmann
                          _verify_dir=_VerifyRestrictedCmdDirectory,
4613 405bffe2 Michael Hanselmann
                          _verify_name=_VerifyRestrictedCmdName,
4614 405bffe2 Michael Hanselmann
                          _verify_cmd=_VerifyRestrictedCmd):
4615 45bc4635 Iustin Pop
  """Performs a number of tests on a restricted command.
4616 1a2eb2dc Michael Hanselmann

4617 1a2eb2dc Michael Hanselmann
  @type path: string
4618 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4619 1a2eb2dc Michael Hanselmann
  @type cmd: string
4620 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4621 405bffe2 Michael Hanselmann
  @return: Same as L{_VerifyRestrictedCmd}
4622 1a2eb2dc Michael Hanselmann

4623 1a2eb2dc Michael Hanselmann
  """
4624 1a2eb2dc Michael Hanselmann
  # Verify the directory first
4625 1a2eb2dc Michael Hanselmann
  (status, msg) = _verify_dir(path)
4626 1a2eb2dc Michael Hanselmann
  if status:
4627 1a2eb2dc Michael Hanselmann
    # Check command if everything was alright
4628 1a2eb2dc Michael Hanselmann
    (status, msg) = _verify_name(cmd)
4629 1a2eb2dc Michael Hanselmann
4630 1a2eb2dc Michael Hanselmann
  if not status:
4631 1a2eb2dc Michael Hanselmann
    return (False, msg)
4632 1a2eb2dc Michael Hanselmann
4633 1a2eb2dc Michael Hanselmann
  # Check actual executable
4634 1a2eb2dc Michael Hanselmann
  return _verify_cmd(path, cmd)
4635 1a2eb2dc Michael Hanselmann
4636 1a2eb2dc Michael Hanselmann
4637 42bd26e8 Michael Hanselmann
def RunRestrictedCmd(cmd,
4638 1a2eb2dc Michael Hanselmann
                     _lock_timeout=_RCMD_LOCK_TIMEOUT,
4639 878c42ae Michael Hanselmann
                     _lock_file=pathutils.RESTRICTED_COMMANDS_LOCK_FILE,
4640 878c42ae Michael Hanselmann
                     _path=pathutils.RESTRICTED_COMMANDS_DIR,
4641 1a2eb2dc Michael Hanselmann
                     _sleep_fn=time.sleep,
4642 405bffe2 Michael Hanselmann
                     _prepare_fn=_PrepareRestrictedCmd,
4643 1a2eb2dc Michael Hanselmann
                     _runcmd_fn=utils.RunCmd,
4644 1fdeb284 Michael Hanselmann
                     _enabled=constants.ENABLE_RESTRICTED_COMMANDS):
4645 45bc4635 Iustin Pop
  """Executes a restricted command after performing strict tests.
4646 1a2eb2dc Michael Hanselmann

4647 1a2eb2dc Michael Hanselmann
  @type cmd: string
4648 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4649 1a2eb2dc Michael Hanselmann
  @rtype: string
4650 1a2eb2dc Michael Hanselmann
  @return: Command output
4651 1a2eb2dc Michael Hanselmann
  @raise RPCFail: In case of an error
4652 1a2eb2dc Michael Hanselmann

4653 1a2eb2dc Michael Hanselmann
  """
4654 45bc4635 Iustin Pop
  logging.info("Preparing to run restricted command '%s'", cmd)
4655 1a2eb2dc Michael Hanselmann
4656 1a2eb2dc Michael Hanselmann
  if not _enabled:
4657 45bc4635 Iustin Pop
    _Fail("Restricted commands disabled at configure time")
4658 1a2eb2dc Michael Hanselmann
4659 1a2eb2dc Michael Hanselmann
  lock = None
4660 1a2eb2dc Michael Hanselmann
  try:
4661 1a2eb2dc Michael Hanselmann
    cmdresult = None
4662 1a2eb2dc Michael Hanselmann
    try:
4663 1a2eb2dc Michael Hanselmann
      lock = utils.FileLock.Open(_lock_file)
4664 1a2eb2dc Michael Hanselmann
      lock.Exclusive(blocking=True, timeout=_lock_timeout)
4665 1a2eb2dc Michael Hanselmann
4666 1a2eb2dc Michael Hanselmann
      (status, value) = _prepare_fn(_path, cmd)
4667 1a2eb2dc Michael Hanselmann
4668 1a2eb2dc Michael Hanselmann
      if status:
4669 1a2eb2dc Michael Hanselmann
        cmdresult = _runcmd_fn([value], env={}, reset_env=True,
4670 1a2eb2dc Michael Hanselmann
                               postfork_fn=lambda _: lock.Unlock())
4671 1a2eb2dc Michael Hanselmann
      else:
4672 1a2eb2dc Michael Hanselmann
        logging.error(value)
4673 1a2eb2dc Michael Hanselmann
    except Exception: # pylint: disable=W0703
4674 1a2eb2dc Michael Hanselmann
      # Keep original error in log
4675 1a2eb2dc Michael Hanselmann
      logging.exception("Caught exception")
4676 1a2eb2dc Michael Hanselmann
4677 1a2eb2dc Michael Hanselmann
    if cmdresult is None:
4678 1a2eb2dc Michael Hanselmann
      logging.info("Sleeping for %0.1f seconds before returning",
4679 1a2eb2dc Michael Hanselmann
                   _RCMD_INVALID_DELAY)
4680 1a2eb2dc Michael Hanselmann
      _sleep_fn(_RCMD_INVALID_DELAY)
4681 1a2eb2dc Michael Hanselmann
4682 1a2eb2dc Michael Hanselmann
      # Do not include original error message in returned error
4683 1a2eb2dc Michael Hanselmann
      _Fail("Executing command '%s' failed" % cmd)
4684 1a2eb2dc Michael Hanselmann
    elif cmdresult.failed or cmdresult.fail_reason:
4685 45bc4635 Iustin Pop
      _Fail("Restricted command '%s' failed: %s; output: %s",
4686 1a2eb2dc Michael Hanselmann
            cmd, cmdresult.fail_reason, cmdresult.output)
4687 1a2eb2dc Michael Hanselmann
    else:
4688 1a2eb2dc Michael Hanselmann
      return cmdresult.output
4689 1a2eb2dc Michael Hanselmann
  finally:
4690 1a2eb2dc Michael Hanselmann
    if lock is not None:
4691 1a2eb2dc Michael Hanselmann
      # Release lock at last
4692 1a2eb2dc Michael Hanselmann
      lock.Close()
4693 1a2eb2dc Michael Hanselmann
      lock = None
4694 1a2eb2dc Michael Hanselmann
4695 1a2eb2dc Michael Hanselmann
4696 99e222b1 Michael Hanselmann
def SetWatcherPause(until, _filename=pathutils.WATCHER_PAUSEFILE):
4697 99e222b1 Michael Hanselmann
  """Creates or removes the watcher pause file.
4698 99e222b1 Michael Hanselmann

4699 99e222b1 Michael Hanselmann
  @type until: None or number
4700 99e222b1 Michael Hanselmann
  @param until: Unix timestamp saying until when the watcher shouldn't run
4701 99e222b1 Michael Hanselmann

4702 99e222b1 Michael Hanselmann
  """
4703 99e222b1 Michael Hanselmann
  if until is None:
4704 99e222b1 Michael Hanselmann
    logging.info("Received request to no longer pause watcher")
4705 99e222b1 Michael Hanselmann
    utils.RemoveFile(_filename)
4706 99e222b1 Michael Hanselmann
  else:
4707 99e222b1 Michael Hanselmann
    logging.info("Received request to pause watcher until %s", until)
4708 99e222b1 Michael Hanselmann
4709 99e222b1 Michael Hanselmann
    if not ht.TNumber(until):
4710 99e222b1 Michael Hanselmann
      _Fail("Duration must be numeric")
4711 99e222b1 Michael Hanselmann
4712 99e222b1 Michael Hanselmann
    utils.WriteFile(_filename, data="%d\n" % (until, ), mode=0644)
4713 99e222b1 Michael Hanselmann
4714 99e222b1 Michael Hanselmann
4715 4daa5eb9 Sebastian Gebhard
def ConfigureOVS(ovs_name, ovs_link):
4716 4daa5eb9 Sebastian Gebhard
  """Creates a OpenvSwitch on the node.
4717 4daa5eb9 Sebastian Gebhard

4718 4daa5eb9 Sebastian Gebhard
  This function sets up a OpenvSwitch on the node with given name nad
4719 4daa5eb9 Sebastian Gebhard
  connects it via a given eth device.
4720 4daa5eb9 Sebastian Gebhard

4721 4daa5eb9 Sebastian Gebhard
  @type ovs_name: string
4722 4daa5eb9 Sebastian Gebhard
  @param ovs_name: Name of the OpenvSwitch to create.
4723 4daa5eb9 Sebastian Gebhard
  @type ovs_link: None or string
4724 4daa5eb9 Sebastian Gebhard
  @param ovs_link: Ethernet device for outside connection (can be missing)
4725 4daa5eb9 Sebastian Gebhard

4726 4daa5eb9 Sebastian Gebhard
  """
4727 4daa5eb9 Sebastian Gebhard
  # Initialize the OpenvSwitch
4728 4daa5eb9 Sebastian Gebhard
  result = utils.RunCmd(["ovs-vsctl", "add-br", ovs_name])
4729 4daa5eb9 Sebastian Gebhard
  if result.failed:
4730 a1578ccf Sebastian Gebhard
    _Fail("Failed to create openvswitch. Script return value: %s, output: '%s'"
4731 a1578ccf Sebastian Gebhard
          % (result.exit_code, result.output), log=True)
4732 4daa5eb9 Sebastian Gebhard
4733 4daa5eb9 Sebastian Gebhard
  # And connect it to a physical interface, if given
4734 4daa5eb9 Sebastian Gebhard
  if ovs_link:
4735 4daa5eb9 Sebastian Gebhard
    result = utils.RunCmd(["ovs-vsctl", "add-port", ovs_name, ovs_link])
4736 4daa5eb9 Sebastian Gebhard
    if result.failed:
4737 4daa5eb9 Sebastian Gebhard
      _Fail("Failed to connect openvswitch to  interface %s. Script return"
4738 a1578ccf Sebastian Gebhard
            " value: %s, output: '%s'" % (ovs_link, result.exit_code,
4739 a1578ccf Sebastian Gebhard
            result.output), log=True)
4740 4daa5eb9 Sebastian Gebhard
4741 4daa5eb9 Sebastian Gebhard
4742 21a17f33 Hrvoje Ribicic
def GetFileInfo(file_path):
4743 21a17f33 Hrvoje Ribicic
  """ Checks if a file exists and returns information related to it.
4744 21a17f33 Hrvoje Ribicic

4745 21a17f33 Hrvoje Ribicic
  Currently returned information:
4746 21a17f33 Hrvoje Ribicic
    - file size: int, size in bytes
4747 21a17f33 Hrvoje Ribicic

4748 21a17f33 Hrvoje Ribicic
  @type file_path: string
4749 21a17f33 Hrvoje Ribicic
  @param file_path: Name of file to examine.
4750 21a17f33 Hrvoje Ribicic

4751 21a17f33 Hrvoje Ribicic
  @rtype: tuple of bool, dict
4752 21a17f33 Hrvoje Ribicic
  @return: Whether the file exists, and a dictionary of information about the
4753 21a17f33 Hrvoje Ribicic
           file gathered by os.stat.
4754 21a17f33 Hrvoje Ribicic

4755 21a17f33 Hrvoje Ribicic
  """
4756 21a17f33 Hrvoje Ribicic
  try:
4757 21a17f33 Hrvoje Ribicic
    stat_info = os.stat(file_path)
4758 21a17f33 Hrvoje Ribicic
    values_dict = {
4759 21a17f33 Hrvoje Ribicic
      constants.STAT_SIZE: stat_info.st_size,
4760 21a17f33 Hrvoje Ribicic
    }
4761 21a17f33 Hrvoje Ribicic
    return True, values_dict
4762 21a17f33 Hrvoje Ribicic
  except IOError:
4763 21a17f33 Hrvoje Ribicic
    return False, {}
4764 21a17f33 Hrvoje Ribicic
4765 21a17f33 Hrvoje Ribicic
4766 a8083063 Iustin Pop
class HooksRunner(object):
4767 a8083063 Iustin Pop
  """Hook runner.
4768 a8083063 Iustin Pop

4769 10c2650b Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not
4770 10c2650b Iustin Pop
  on the master side.
4771 a8083063 Iustin Pop

4772 a8083063 Iustin Pop
  """
4773 a8083063 Iustin Pop
  def __init__(self, hooks_base_dir=None):
4774 a8083063 Iustin Pop
    """Constructor for hooks runner.
4775 a8083063 Iustin Pop

4776 10c2650b Iustin Pop
    @type hooks_base_dir: str or None
4777 10c2650b Iustin Pop
    @param hooks_base_dir: if not None, this overrides the
4778 3329f4de Michael Hanselmann
        L{pathutils.HOOKS_BASE_DIR} (useful for unittests)
4779 a8083063 Iustin Pop

4780 a8083063 Iustin Pop
    """
4781 a8083063 Iustin Pop
    if hooks_base_dir is None:
4782 710f30ec Michael Hanselmann
      hooks_base_dir = pathutils.HOOKS_BASE_DIR
4783 fe267188 Iustin Pop
    # yeah, _BASE_DIR is not valid for attributes, we use it like a
4784 fe267188 Iustin Pop
    # constant
4785 b459a848 Andrea Spadaccini
    self._BASE_DIR = hooks_base_dir # pylint: disable=C0103
4786 a8083063 Iustin Pop
4787 0fa481f5 Andrea Spadaccini
  def RunLocalHooks(self, node_list, hpath, phase, env):
4788 0fa481f5 Andrea Spadaccini
    """Check that the hooks will be run only locally and then run them.
4789 0fa481f5 Andrea Spadaccini

4790 0fa481f5 Andrea Spadaccini
    """
4791 0fa481f5 Andrea Spadaccini
    assert len(node_list) == 1
4792 0fa481f5 Andrea Spadaccini
    node = node_list[0]
4793 0fa481f5 Andrea Spadaccini
    _, myself = ssconf.GetMasterAndMyself()
4794 0fa481f5 Andrea Spadaccini
    assert node == myself
4795 0fa481f5 Andrea Spadaccini
4796 0fa481f5 Andrea Spadaccini
    results = self.RunHooks(hpath, phase, env)
4797 0fa481f5 Andrea Spadaccini
4798 0fa481f5 Andrea Spadaccini
    # Return values in the form expected by HooksMaster
4799 0fa481f5 Andrea Spadaccini
    return {node: (None, False, results)}
4800 0fa481f5 Andrea Spadaccini
4801 a8083063 Iustin Pop
  def RunHooks(self, hpath, phase, env):
4802 a8083063 Iustin Pop
    """Run the scripts in the hooks directory.
4803 a8083063 Iustin Pop

4804 10c2650b Iustin Pop
    @type hpath: str
4805 10c2650b Iustin Pop
    @param hpath: the path to the hooks directory which
4806 10c2650b Iustin Pop
        holds the scripts
4807 10c2650b Iustin Pop
    @type phase: str
4808 10c2650b Iustin Pop
    @param phase: either L{constants.HOOKS_PHASE_PRE} or
4809 10c2650b Iustin Pop
        L{constants.HOOKS_PHASE_POST}
4810 10c2650b Iustin Pop
    @type env: dict
4811 10c2650b Iustin Pop
    @param env: dictionary with the environment for the hook
4812 10c2650b Iustin Pop
    @rtype: list
4813 10c2650b Iustin Pop
    @return: list of 3-element tuples:
4814 10c2650b Iustin Pop
      - script path
4815 10c2650b Iustin Pop
      - script result, either L{constants.HKR_SUCCESS} or
4816 10c2650b Iustin Pop
        L{constants.HKR_FAIL}
4817 10c2650b Iustin Pop
      - output of the script
4818 10c2650b Iustin Pop

4819 10c2650b Iustin Pop
    @raise errors.ProgrammerError: for invalid input
4820 10c2650b Iustin Pop
        parameters
4821 a8083063 Iustin Pop

4822 a8083063 Iustin Pop
    """
4823 a8083063 Iustin Pop
    if phase == constants.HOOKS_PHASE_PRE:
4824 a8083063 Iustin Pop
      suffix = "pre"
4825 a8083063 Iustin Pop
    elif phase == constants.HOOKS_PHASE_POST:
4826 a8083063 Iustin Pop
      suffix = "post"
4827 a8083063 Iustin Pop
    else:
4828 3fb4f740 Iustin Pop
      _Fail("Unknown hooks phase '%s'", phase)
4829 3fb4f740 Iustin Pop
4830 a8083063 Iustin Pop
    subdir = "%s-%s.d" % (hpath, suffix)
4831 0411c011 Iustin Pop
    dir_name = utils.PathJoin(self._BASE_DIR, subdir)
4832 6bb65e3a Guido Trotter
4833 6bb65e3a Guido Trotter
    results = []
4834 a9b7e346 Iustin Pop
4835 a9b7e346 Iustin Pop
    if not os.path.isdir(dir_name):
4836 a9b7e346 Iustin Pop
      # for non-existing/non-dirs, we simply exit instead of logging a
4837 a9b7e346 Iustin Pop
      # warning at every operation
4838 a9b7e346 Iustin Pop
      return results
4839 a9b7e346 Iustin Pop
4840 a9b7e346 Iustin Pop
    runparts_results = utils.RunParts(dir_name, env=env, reset_env=True)
4841 a9b7e346 Iustin Pop
4842 5ae4945a Iustin Pop
    for (relname, relstatus, runresult) in runparts_results:
4843 6bb65e3a Guido Trotter
      if relstatus == constants.RUNPARTS_SKIP:
4844 a8083063 Iustin Pop
        rrval = constants.HKR_SKIP
4845 a8083063 Iustin Pop
        output = ""
4846 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_ERR:
4847 6bb65e3a Guido Trotter
        rrval = constants.HKR_FAIL
4848 6bb65e3a Guido Trotter
        output = "Hook script execution error: %s" % runresult
4849 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_RUN:
4850 6bb65e3a Guido Trotter
        if runresult.failed:
4851 a8083063 Iustin Pop
          rrval = constants.HKR_FAIL
4852 a8083063 Iustin Pop
        else:
4853 6bb65e3a Guido Trotter
          rrval = constants.HKR_SUCCESS
4854 6bb65e3a Guido Trotter
        output = utils.SafeEncode(runresult.output.strip())
4855 6bb65e3a Guido Trotter
      results.append(("%s/%s" % (subdir, relname), rrval, output))
4856 6bb65e3a Guido Trotter
4857 6bb65e3a Guido Trotter
    return results
4858 3f78eef2 Iustin Pop
4859 3f78eef2 Iustin Pop
4860 8d528b7c Iustin Pop
class IAllocatorRunner(object):
4861 8d528b7c Iustin Pop
  """IAllocator runner.
4862 8d528b7c Iustin Pop

4863 8d528b7c Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not on
4864 8d528b7c Iustin Pop
  the master side.
4865 8d528b7c Iustin Pop

4866 8d528b7c Iustin Pop
  """
4867 7e950d31 Iustin Pop
  @staticmethod
4868 0359e5d0 Spyros Trigazis
  def Run(name, idata, ial_params):
4869 8d528b7c Iustin Pop
    """Run an iallocator script.
4870 8d528b7c Iustin Pop

4871 10c2650b Iustin Pop
    @type name: str
4872 10c2650b Iustin Pop
    @param name: the iallocator script name
4873 10c2650b Iustin Pop
    @type idata: str
4874 10c2650b Iustin Pop
    @param idata: the allocator input data
4875 0359e5d0 Spyros Trigazis
    @type ial_params: list
4876 0359e5d0 Spyros Trigazis
    @param ial_params: the iallocator parameters
4877 10c2650b Iustin Pop

4878 10c2650b Iustin Pop
    @rtype: tuple
4879 87f5c298 Iustin Pop
    @return: two element tuple of:
4880 87f5c298 Iustin Pop
       - status
4881 87f5c298 Iustin Pop
       - either error message or stdout of allocator (for success)
4882 8d528b7c Iustin Pop

4883 8d528b7c Iustin Pop
    """
4884 8d528b7c Iustin Pop
    alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
4885 8d528b7c Iustin Pop
                                  os.path.isfile)
4886 8d528b7c Iustin Pop
    if alloc_script is None:
4887 87f5c298 Iustin Pop
      _Fail("iallocator module '%s' not found in the search path", name)
4888 8d528b7c Iustin Pop
4889 8d528b7c Iustin Pop
    fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
4890 8d528b7c Iustin Pop
    try:
4891 8d528b7c Iustin Pop
      os.write(fd, idata)
4892 8d528b7c Iustin Pop
      os.close(fd)
4893 0359e5d0 Spyros Trigazis
      result = utils.RunCmd([alloc_script, fin_name] + ial_params)
4894 8d528b7c Iustin Pop
      if result.failed:
4895 87f5c298 Iustin Pop
        _Fail("iallocator module '%s' failed: %s, output '%s'",
4896 87f5c298 Iustin Pop
              name, result.fail_reason, result.output)
4897 8d528b7c Iustin Pop
    finally:
4898 8d528b7c Iustin Pop
      os.unlink(fin_name)
4899 8d528b7c Iustin Pop
4900 c26a6bd2 Iustin Pop
    return result.stdout
4901 8d528b7c Iustin Pop
4902 8d528b7c Iustin Pop
4903 3f78eef2 Iustin Pop
class DevCacheManager(object):
4904 c99a3cc0 Manuel Franceschini
  """Simple class for managing a cache of block device information.
4905 3f78eef2 Iustin Pop

4906 3f78eef2 Iustin Pop
  """
4907 3f78eef2 Iustin Pop
  _DEV_PREFIX = "/dev/"
4908 710f30ec Michael Hanselmann
  _ROOT_DIR = pathutils.BDEV_CACHE_DIR
4909 3f78eef2 Iustin Pop
4910 3f78eef2 Iustin Pop
  @classmethod
4911 3f78eef2 Iustin Pop
  def _ConvertPath(cls, dev_path):
4912 3f78eef2 Iustin Pop
    """Converts a /dev/name path to the cache file name.
4913 3f78eef2 Iustin Pop

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

4917 10c2650b Iustin Pop
    @type dev_path: str
4918 10c2650b Iustin Pop
    @param dev_path: the C{/dev/} path name
4919 10c2650b Iustin Pop
    @rtype: str
4920 10c2650b Iustin Pop
    @return: the converted path name
4921 3f78eef2 Iustin Pop

4922 3f78eef2 Iustin Pop
    """
4923 3f78eef2 Iustin Pop
    if dev_path.startswith(cls._DEV_PREFIX):
4924 3f78eef2 Iustin Pop
      dev_path = dev_path[len(cls._DEV_PREFIX):]
4925 3f78eef2 Iustin Pop
    dev_path = dev_path.replace("/", "_")
4926 0411c011 Iustin Pop
    fpath = utils.PathJoin(cls._ROOT_DIR, "bdev_%s" % dev_path)
4927 3f78eef2 Iustin Pop
    return fpath
4928 3f78eef2 Iustin Pop
4929 3f78eef2 Iustin Pop
  @classmethod
4930 3f78eef2 Iustin Pop
  def UpdateCache(cls, dev_path, owner, on_primary, iv_name):
4931 3f78eef2 Iustin Pop
    """Updates the cache information for a given device.
4932 3f78eef2 Iustin Pop

4933 10c2650b Iustin Pop
    @type dev_path: str
4934 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4935 10c2650b Iustin Pop
    @type owner: str
4936 10c2650b Iustin Pop
    @param owner: the owner (instance name) of the device
4937 10c2650b Iustin Pop
    @type on_primary: bool
4938 10c2650b Iustin Pop
    @param on_primary: whether this is the primary
4939 10c2650b Iustin Pop
        node nor not
4940 10c2650b Iustin Pop
    @type iv_name: str
4941 10c2650b Iustin Pop
    @param iv_name: the instance-visible name of the
4942 c41eea6e Iustin Pop
        device, as in objects.Disk.iv_name
4943 10c2650b Iustin Pop

4944 10c2650b Iustin Pop
    @rtype: None
4945 10c2650b Iustin Pop

4946 3f78eef2 Iustin Pop
    """
4947 cf5a8306 Iustin Pop
    if dev_path is None:
4948 18682bca Iustin Pop
      logging.error("DevCacheManager.UpdateCache got a None dev_path")
4949 cf5a8306 Iustin Pop
      return
4950 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4951 3f78eef2 Iustin Pop
    if on_primary:
4952 3f78eef2 Iustin Pop
      state = "primary"
4953 3f78eef2 Iustin Pop
    else:
4954 3f78eef2 Iustin Pop
      state = "secondary"
4955 3f78eef2 Iustin Pop
    if iv_name is None:
4956 3f78eef2 Iustin Pop
      iv_name = "not_visible"
4957 3f78eef2 Iustin Pop
    fdata = "%s %s %s\n" % (str(owner), state, iv_name)
4958 3f78eef2 Iustin Pop
    try:
4959 3f78eef2 Iustin Pop
      utils.WriteFile(fpath, data=fdata)
4960 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4961 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)
4962 3f78eef2 Iustin Pop
4963 3f78eef2 Iustin Pop
  @classmethod
4964 3f78eef2 Iustin Pop
  def RemoveCache(cls, dev_path):
4965 3f78eef2 Iustin Pop
    """Remove data for a dev_path.
4966 3f78eef2 Iustin Pop

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

4970 10c2650b Iustin Pop
    @type dev_path: str
4971 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4972 10c2650b Iustin Pop

4973 10c2650b Iustin Pop
    @rtype: None
4974 10c2650b Iustin Pop

4975 3f78eef2 Iustin Pop
    """
4976 cf5a8306 Iustin Pop
    if dev_path is None:
4977 18682bca Iustin Pop
      logging.error("DevCacheManager.RemoveCache got a None dev_path")
4978 cf5a8306 Iustin Pop
      return
4979 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4980 3f78eef2 Iustin Pop
    try:
4981 3f78eef2 Iustin Pop
      utils.RemoveFile(fpath)
4982 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4983 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)