Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ 6bce7ba2

History | View | Annotate | Download (145.3 kB)

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

114 2cc6781a Iustin Pop
  Its argument is the error message.
115 2cc6781a Iustin Pop

116 2cc6781a Iustin Pop
  """
117 2cc6781a Iustin Pop
118 13998ef2 Michael Hanselmann
119 584ea340 Michele Tartara
def _GetInstReasonFilename(instance_name):
120 a59d5fa1 Michele Tartara
  """Path of the file containing the reason of the instance status change.
121 a59d5fa1 Michele Tartara

122 a59d5fa1 Michele Tartara
  @type instance_name: string
123 a59d5fa1 Michele Tartara
  @param instance_name: The name of the instance
124 a59d5fa1 Michele Tartara
  @rtype: string
125 a59d5fa1 Michele Tartara
  @return: The path of the file
126 a59d5fa1 Michele Tartara

127 a59d5fa1 Michele Tartara
  """
128 a59d5fa1 Michele Tartara
  return utils.PathJoin(pathutils.INSTANCE_REASON_DIR, instance_name)
129 a59d5fa1 Michele Tartara
130 a59d5fa1 Michele Tartara
131 584ea340 Michele Tartara
def _StoreInstReasonTrail(instance_name, trail):
132 584ea340 Michele Tartara
  """Serialize a reason trail related to an instance change of state to file.
133 584ea340 Michele Tartara

134 584ea340 Michele Tartara
  The exact location of the file depends on the name of the instance and on
135 584ea340 Michele Tartara
  the configuration of the Ganeti cluster defined at deploy time.
136 584ea340 Michele Tartara

137 584ea340 Michele Tartara
  @type instance_name: string
138 584ea340 Michele Tartara
  @param instance_name: The name of the instance
139 584ea340 Michele Tartara
  @rtype: None
140 584ea340 Michele Tartara

141 584ea340 Michele Tartara
  """
142 584ea340 Michele Tartara
  json = serializer.DumpJson(trail)
143 584ea340 Michele Tartara
  filename = _GetInstReasonFilename(instance_name)
144 584ea340 Michele Tartara
  utils.WriteFile(filename, data=json)
145 584ea340 Michele Tartara
146 584ea340 Michele Tartara
147 2cc6781a Iustin Pop
def _Fail(msg, *args, **kwargs):
148 2cc6781a Iustin Pop
  """Log an error and the raise an RPCFail exception.
149 2cc6781a Iustin Pop

150 2cc6781a Iustin Pop
  This exception is then handled specially in the ganeti daemon and
151 2cc6781a Iustin Pop
  turned into a 'failed' return type. As such, this function is a
152 2cc6781a Iustin Pop
  useful shortcut for logging the error and returning it to the master
153 2cc6781a Iustin Pop
  daemon.
154 2cc6781a Iustin Pop

155 2cc6781a Iustin Pop
  @type msg: string
156 2cc6781a Iustin Pop
  @param msg: the text of the exception
157 2cc6781a Iustin Pop
  @raise RPCFail
158 2cc6781a Iustin Pop

159 2cc6781a Iustin Pop
  """
160 2cc6781a Iustin Pop
  if args:
161 2cc6781a Iustin Pop
    msg = msg % args
162 afdc3985 Iustin Pop
  if "log" not in kwargs or kwargs["log"]: # if we should log this error
163 afdc3985 Iustin Pop
    if "exc" in kwargs and kwargs["exc"]:
164 afdc3985 Iustin Pop
      logging.exception(msg)
165 afdc3985 Iustin Pop
    else:
166 afdc3985 Iustin Pop
      logging.error(msg)
167 2cc6781a Iustin Pop
  raise RPCFail(msg)
168 2cc6781a Iustin Pop
169 2cc6781a Iustin Pop
170 c657dcc9 Michael Hanselmann
def _GetConfig():
171 93384844 Iustin Pop
  """Simple wrapper to return a SimpleStore.
172 10c2650b Iustin Pop

173 93384844 Iustin Pop
  @rtype: L{ssconf.SimpleStore}
174 93384844 Iustin Pop
  @return: a SimpleStore instance
175 10c2650b Iustin Pop

176 10c2650b Iustin Pop
  """
177 93384844 Iustin Pop
  return ssconf.SimpleStore()
178 c657dcc9 Michael Hanselmann
179 c657dcc9 Michael Hanselmann
180 62c9ec92 Iustin Pop
def _GetSshRunner(cluster_name):
181 10c2650b Iustin Pop
  """Simple wrapper to return an SshRunner.
182 10c2650b Iustin Pop

183 10c2650b Iustin Pop
  @type cluster_name: str
184 10c2650b Iustin Pop
  @param cluster_name: the cluster name, which is needed
185 10c2650b Iustin Pop
      by the SshRunner constructor
186 10c2650b Iustin Pop
  @rtype: L{ssh.SshRunner}
187 10c2650b Iustin Pop
  @return: an SshRunner instance
188 10c2650b Iustin Pop

189 10c2650b Iustin Pop
  """
190 62c9ec92 Iustin Pop
  return ssh.SshRunner(cluster_name)
191 c92b310a Michael Hanselmann
192 c92b310a Michael Hanselmann
193 12bce260 Michael Hanselmann
def _Decompress(data):
194 12bce260 Michael Hanselmann
  """Unpacks data compressed by the RPC client.
195 12bce260 Michael Hanselmann

196 12bce260 Michael Hanselmann
  @type data: list or tuple
197 12bce260 Michael Hanselmann
  @param data: Data sent by RPC client
198 12bce260 Michael Hanselmann
  @rtype: str
199 12bce260 Michael Hanselmann
  @return: Decompressed data
200 12bce260 Michael Hanselmann

201 12bce260 Michael Hanselmann
  """
202 52e2f66e Michael Hanselmann
  assert isinstance(data, (list, tuple))
203 12bce260 Michael Hanselmann
  assert len(data) == 2
204 12bce260 Michael Hanselmann
  (encoding, content) = data
205 12bce260 Michael Hanselmann
  if encoding == constants.RPC_ENCODING_NONE:
206 12bce260 Michael Hanselmann
    return content
207 12bce260 Michael Hanselmann
  elif encoding == constants.RPC_ENCODING_ZLIB_BASE64:
208 12bce260 Michael Hanselmann
    return zlib.decompress(base64.b64decode(content))
209 12bce260 Michael Hanselmann
  else:
210 12bce260 Michael Hanselmann
    raise AssertionError("Unknown data encoding")
211 12bce260 Michael Hanselmann
212 12bce260 Michael Hanselmann
213 3bc6be5c Iustin Pop
def _CleanDirectory(path, exclude=None):
214 76ab5558 Michael Hanselmann
  """Removes all regular files in a directory.
215 76ab5558 Michael Hanselmann

216 10c2650b Iustin Pop
  @type path: str
217 10c2650b Iustin Pop
  @param path: the directory to clean
218 76ab5558 Michael Hanselmann
  @type exclude: list
219 10c2650b Iustin Pop
  @param exclude: list of files to be excluded, defaults
220 10c2650b Iustin Pop
      to the empty list
221 76ab5558 Michael Hanselmann

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

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

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

278 c8457ce7 Iustin Pop
  @rtype: tuple
279 c8457ce7 Iustin Pop
  @return: True, None
280 24fc781f Michael Hanselmann

281 24fc781f Michael Hanselmann
  """
282 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.QUEUE_DIR, exclude=[pathutils.JOB_QUEUE_LOCK_FILE])
283 710f30ec Michael Hanselmann
  _CleanDirectory(pathutils.JOB_QUEUE_ARCHIVE_DIR)
284 24fc781f Michael Hanselmann
285 24fc781f Michael Hanselmann
286 cb8028f3 Jose A. Lopes
def GetMasterNodeName():
287 cb8028f3 Jose A. Lopes
  """Returns the master node name.
288 bd1e4562 Iustin Pop

289 cb8028f3 Jose A. Lopes
  @rtype: string
290 cb8028f3 Jose A. Lopes
  @return: name of the master node
291 2a52a064 Iustin Pop
  @raise RPCFail: in case of errors
292 b1b6ea87 Iustin Pop

293 b1b6ea87 Iustin Pop
  """
294 b1b6ea87 Iustin Pop
  try:
295 cb8028f3 Jose A. Lopes
    return _GetConfig().GetMasterNode()
296 b1b6ea87 Iustin Pop
  except errors.ConfigurationError, err:
297 29921401 Iustin Pop
    _Fail("Cluster configuration incomplete: %s", err, exc=True)
298 b1b6ea87 Iustin Pop
299 b1b6ea87 Iustin Pop
300 0fa481f5 Andrea Spadaccini
def RunLocalHooks(hook_opcode, hooks_path, env_builder_fn):
301 0fa481f5 Andrea Spadaccini
  """Decorator that runs hooks before and after the decorated function.
302 0fa481f5 Andrea Spadaccini

303 0fa481f5 Andrea Spadaccini
  @type hook_opcode: string
304 0fa481f5 Andrea Spadaccini
  @param hook_opcode: opcode of the hook
305 0fa481f5 Andrea Spadaccini
  @type hooks_path: string
306 0fa481f5 Andrea Spadaccini
  @param hooks_path: path of the hooks
307 0fa481f5 Andrea Spadaccini
  @type env_builder_fn: function
308 0fa481f5 Andrea Spadaccini
  @param env_builder_fn: function that returns a dictionary containing the
309 3ccd3243 Andrea Spadaccini
    environment variables for the hooks. Will get all the parameters of the
310 3ccd3243 Andrea Spadaccini
    decorated function.
311 0fa481f5 Andrea Spadaccini
  @raise RPCFail: in case of pre-hook failure
312 0fa481f5 Andrea Spadaccini

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

339 3ccd3243 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
340 3ccd3243 Andrea Spadaccini
  @param master_params: network parameters of the master
341 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
342 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
343 57c7bc57 Andrea Spadaccini
    address setup script (unused, but necessary per the implementation of the
344 57c7bc57 Andrea Spadaccini
    _RunLocalHooks decorator)
345 3ccd3243 Andrea Spadaccini

346 2d88fdd3 Andrea Spadaccini
  """
347 57c7bc57 Andrea Spadaccini
  # pylint: disable=W0613
348 3ccd3243 Andrea Spadaccini
  ver = netutils.IPAddress.GetVersionFromAddressFamily(master_params.ip_family)
349 2d88fdd3 Andrea Spadaccini
  env = {
350 3ccd3243 Andrea Spadaccini
    "MASTER_NETDEV": master_params.netdev,
351 3ccd3243 Andrea Spadaccini
    "MASTER_IP": master_params.ip,
352 702eff21 Andrea Spadaccini
    "MASTER_NETMASK": str(master_params.netmask),
353 3ccd3243 Andrea Spadaccini
    "CLUSTER_IP_VERSION": str(ver),
354 2d88fdd3 Andrea Spadaccini
  }
355 2d88fdd3 Andrea Spadaccini
356 2d88fdd3 Andrea Spadaccini
  return env
357 2d88fdd3 Andrea Spadaccini
358 2d88fdd3 Andrea Spadaccini
359 702eff21 Andrea Spadaccini
def _RunMasterSetupScript(master_params, action, use_external_mip_script):
360 702eff21 Andrea Spadaccini
  """Execute the master IP address setup script.
361 702eff21 Andrea Spadaccini

362 702eff21 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
363 702eff21 Andrea Spadaccini
  @param master_params: network parameters of the master
364 702eff21 Andrea Spadaccini
  @type action: string
365 702eff21 Andrea Spadaccini
  @param action: action to pass to the script. Must be one of
366 702eff21 Andrea Spadaccini
    L{backend._MASTER_START} or L{backend._MASTER_STOP}
367 702eff21 Andrea Spadaccini
  @type use_external_mip_script: boolean
368 702eff21 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
369 702eff21 Andrea Spadaccini
    address setup script
370 702eff21 Andrea Spadaccini
  @raise backend.RPCFail: if there are errors during the execution of the
371 702eff21 Andrea Spadaccini
    script
372 702eff21 Andrea Spadaccini

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

393 c79198a0 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
394 c79198a0 Andrea Spadaccini
  @param master_params: network parameters of the master
395 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
396 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
397 57c7bc57 Andrea Spadaccini
    address setup script
398 702eff21 Andrea Spadaccini
  @raise RPCFail: in case of errors during the IP startup
399 8da2bd43 Andrea Spadaccini

400 fb460cf7 Andrea Spadaccini
  """
401 702eff21 Andrea Spadaccini
  _RunMasterSetupScript(master_params, _MASTER_START,
402 702eff21 Andrea Spadaccini
                        use_external_mip_script)
403 fb460cf7 Andrea Spadaccini
404 fb460cf7 Andrea Spadaccini
405 fb460cf7 Andrea Spadaccini
def StartMasterDaemons(no_voting):
406 a8083063 Iustin Pop
  """Activate local node as master node.
407 a8083063 Iustin Pop

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

410 3583908a Guido Trotter
  @type no_voting: boolean
411 3583908a Guido Trotter
  @param no_voting: whether to start ganeti-masterd without a node vote
412 fb460cf7 Andrea Spadaccini
      but still non-interactively
413 10c2650b Iustin Pop
  @rtype: None
414 a8083063 Iustin Pop

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

438 c79198a0 Andrea Spadaccini
  @type master_params: L{objects.MasterNetworkParameters}
439 c79198a0 Andrea Spadaccini
  @param master_params: network parameters of the master
440 57c7bc57 Andrea Spadaccini
  @type use_external_mip_script: boolean
441 57c7bc57 Andrea Spadaccini
  @param use_external_mip_script: whether to use an external master IP
442 57c7bc57 Andrea Spadaccini
    address setup script
443 702eff21 Andrea Spadaccini
  @raise RPCFail: in case of errors during the IP turndown
444 96e0d5cc Andrea Spadaccini

445 a8083063 Iustin Pop
  """
446 702eff21 Andrea Spadaccini
  _RunMasterSetupScript(master_params, _MASTER_STOP,
447 702eff21 Andrea Spadaccini
                        use_external_mip_script)
448 b1b6ea87 Iustin Pop
449 fb460cf7 Andrea Spadaccini
450 fb460cf7 Andrea Spadaccini
def StopMasterDaemons():
451 fb460cf7 Andrea Spadaccini
  """Stop the master daemons on this node.
452 fb460cf7 Andrea Spadaccini

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

455 fb460cf7 Andrea Spadaccini
  @rtype: None
456 fb460cf7 Andrea Spadaccini

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

471 41e079ce Andrea Spadaccini
  @param old_netmask: the old value of the netmask
472 41e079ce Andrea Spadaccini
  @param netmask: the new value of the netmask
473 41e079ce Andrea Spadaccini
  @param master_ip: the master IP
474 41e079ce Andrea Spadaccini
  @param master_netdev: the master network device
475 41e079ce Andrea Spadaccini

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

502 19ddc57a René Nussbaumer
  @param mode: The mode to operate. Either add or remove entry
503 19ddc57a René Nussbaumer
  @param host: The host to operate on
504 19ddc57a René Nussbaumer
  @param ip: The ip associated with the entry
505 19ddc57a René Nussbaumer

506 19ddc57a René Nussbaumer
  """
507 19ddc57a René Nussbaumer
  if mode == constants.ETC_HOSTS_ADD:
508 19ddc57a René Nussbaumer
    if not ip:
509 19ddc57a René Nussbaumer
      RPCFail("Mode 'add' needs 'ip' parameter, but parameter not"
510 19ddc57a René Nussbaumer
              " present")
511 19ddc57a René Nussbaumer
    utils.AddHostToEtcHosts(host, ip)
512 19ddc57a René Nussbaumer
  elif mode == constants.ETC_HOSTS_REMOVE:
513 19ddc57a René Nussbaumer
    if ip:
514 19ddc57a René Nussbaumer
      RPCFail("Mode 'remove' does not allow 'ip' parameter, but"
515 19ddc57a René Nussbaumer
              " parameter is present")
516 19ddc57a René Nussbaumer
    utils.RemoveHostFromEtcHosts(host)
517 19ddc57a René Nussbaumer
  else:
518 19ddc57a René Nussbaumer
    RPCFail("Mode not supported")
519 19ddc57a René Nussbaumer
520 19ddc57a René Nussbaumer
521 b989b9d9 Ken Wehr
def LeaveCluster(modify_ssh_setup):
522 10c2650b Iustin Pop
  """Cleans up and remove the current node.
523 10c2650b Iustin Pop

524 10c2650b Iustin Pop
  This function cleans up and prepares the current node to be removed
525 10c2650b Iustin Pop
  from the cluster.
526 10c2650b Iustin Pop

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

531 b989b9d9 Ken Wehr
  @param modify_ssh_setup: boolean
532 b989b9d9 Ken Wehr

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

570 b01b7a50 Helga Velroyen
  @type params: list
571 b01b7a50 Helga Velroyen
  @param params: list of storage parameters
572 b01b7a50 Helga Velroyen
  @type num_params: int
573 b01b7a50 Helga Velroyen
  @param num_params: expected number of parameters
574 b01b7a50 Helga Velroyen

575 b01b7a50 Helga Velroyen
  """
576 b01b7a50 Helga Velroyen
  if params is None:
577 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("No storage parameters for storage"
578 b01b7a50 Helga Velroyen
                                 " reporting is provided.")
579 b01b7a50 Helga Velroyen
  if not isinstance(params, list):
580 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("The storage parameters are not of type"
581 b01b7a50 Helga Velroyen
                                 " list: '%s'" % params)
582 b01b7a50 Helga Velroyen
  if not len(params) == num_params:
583 b01b7a50 Helga Velroyen
    raise errors.ProgrammerError("Did not receive the expected number of"
584 b01b7a50 Helga Velroyen
                                 "storage parameters: expected %s,"
585 b01b7a50 Helga Velroyen
                                 " received '%s'" % (num_params, len(params)))
586 b01b7a50 Helga Velroyen
587 b01b7a50 Helga Velroyen
588 3c8a599a Helga Velroyen
def _CheckLvmStorageParams(params):
589 3c8a599a Helga Velroyen
  """Performs sanity check for the 'exclusive storage' flag.
590 3c8a599a Helga Velroyen

591 3c8a599a Helga Velroyen
  @see: C{_CheckStorageParams}
592 3c8a599a Helga Velroyen

593 3c8a599a Helga Velroyen
  """
594 3c8a599a Helga Velroyen
  _CheckStorageParams(params, 1)
595 3c8a599a Helga Velroyen
  excl_stor = params[0]
596 3c8a599a Helga Velroyen
  if not isinstance(params[0], bool):
597 3c8a599a Helga Velroyen
    raise errors.ProgrammerError("Exclusive storage parameter is not"
598 3c8a599a Helga Velroyen
                                 " boolean: '%s'." % excl_stor)
599 3c8a599a Helga Velroyen
  return excl_stor
600 3c8a599a Helga Velroyen
601 3c8a599a Helga Velroyen
602 52a8a6ae Helga Velroyen
def _GetLvmVgSpaceInfo(name, params):
603 52a8a6ae Helga Velroyen
  """Wrapper around C{_GetVgInfo} which checks the storage parameters.
604 52a8a6ae Helga Velroyen

605 52a8a6ae Helga Velroyen
  @type name: string
606 52a8a6ae Helga Velroyen
  @param name: name of the volume group
607 52a8a6ae Helga Velroyen
  @type params: list
608 52a8a6ae Helga Velroyen
  @param params: list of storage parameters, which in this case should be
609 52a8a6ae Helga Velroyen
    containing only one for exclusive storage
610 52a8a6ae Helga Velroyen

611 52a8a6ae Helga Velroyen
  """
612 3c8a599a Helga Velroyen
  excl_stor = _CheckLvmStorageParams(params)
613 52a8a6ae Helga Velroyen
  return _GetVgInfo(name, excl_stor)
614 52a8a6ae Helga Velroyen
615 52a8a6ae Helga Velroyen
616 3f73b3ae Helga Velroyen
def _GetVgInfo(
617 3f73b3ae Helga Velroyen
    name, excl_stor, info_fn=bdev.LogicalVolume.GetVGInfo):
618 78519c10 Michael Hanselmann
  """Retrieves information about a LVM volume group.
619 78519c10 Michael Hanselmann

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

641 a18ab868 Helga Velroyen
  @see: C{_GetLvmVgSpaceInfo}
642 3c8a599a Helga Velroyen

643 3c8a599a Helga Velroyen
  """
644 3c8a599a Helga Velroyen
  excl_stor = _CheckLvmStorageParams(params)
645 3c8a599a Helga Velroyen
  return _GetVgSpindlesInfo(name, excl_stor)
646 3f73b3ae Helga Velroyen
647 3c8a599a Helga Velroyen
648 a18ab868 Helga Velroyen
def _GetVgSpindlesInfo(
649 a18ab868 Helga Velroyen
    name, excl_stor, info_fn=bdev.LogicalVolume.GetVgSpindlesInfo):
650 a1860404 Bernardo Dal Seno
  """Retrieves information about spindles in an LVM volume group.
651 a1860404 Bernardo Dal Seno

652 a1860404 Bernardo Dal Seno
  @type name: string
653 a1860404 Bernardo Dal Seno
  @param name: VG name
654 a1860404 Bernardo Dal Seno
  @type excl_stor: bool
655 a1860404 Bernardo Dal Seno
  @param excl_stor: exclusive storage
656 a1860404 Bernardo Dal Seno
  @rtype: dict
657 a1860404 Bernardo Dal Seno
  @return: dictionary whose keys are "name", "vg_free", "vg_size" for VG name,
658 a1860404 Bernardo Dal Seno
      free spindles, total spindles respectively
659 a1860404 Bernardo Dal Seno

660 a1860404 Bernardo Dal Seno
  """
661 a1860404 Bernardo Dal Seno
  if excl_stor:
662 a18ab868 Helga Velroyen
    (vg_free, vg_size) = info_fn(name)
663 a1860404 Bernardo Dal Seno
  else:
664 a1860404 Bernardo Dal Seno
    vg_free = 0
665 a1860404 Bernardo Dal Seno
    vg_size = 0
666 a1860404 Bernardo Dal Seno
  return {
667 0f0f6d7d Helga Velroyen
    "type": constants.ST_LVM_PV,
668 a1860404 Bernardo Dal Seno
    "name": name,
669 32389d91 Helga Velroyen
    "storage_free": vg_free,
670 32389d91 Helga Velroyen
    "storage_size": vg_size,
671 a1860404 Bernardo Dal Seno
    }
672 a1860404 Bernardo Dal Seno
673 a1860404 Bernardo Dal Seno
674 439e1d3f Helga Velroyen
def _GetHvInfo(name, hvparams, get_hv_fn=hypervisor.GetHypervisor):
675 78519c10 Michael Hanselmann
  """Retrieves node information from a hypervisor.
676 78519c10 Michael Hanselmann

677 78519c10 Michael Hanselmann
  The information returned depends on the hypervisor. Common items:
678 78519c10 Michael Hanselmann

679 78519c10 Michael Hanselmann
    - vg_size is the size of the configured volume group in MiB
680 78519c10 Michael Hanselmann
    - vg_free is the free size of the volume group in MiB
681 78519c10 Michael Hanselmann
    - memory_dom0 is the memory allocated for domain0 in MiB
682 78519c10 Michael Hanselmann
    - memory_free is the currently available (free) ram in MiB
683 78519c10 Michael Hanselmann
    - memory_total is the total number of ram in MiB
684 78519c10 Michael Hanselmann
    - hv_version: the hypervisor version, if available
685 78519c10 Michael Hanselmann

686 439e1d3f Helga Velroyen
  @type hvparams: dict of string
687 439e1d3f Helga Velroyen
  @param hvparams: the hypervisor's hvparams
688 439e1d3f Helga Velroyen

689 78519c10 Michael Hanselmann
  """
690 439e1d3f Helga Velroyen
  return get_hv_fn(name).GetNodeInfo(hvparams=hvparams)
691 439e1d3f Helga Velroyen
692 439e1d3f Helga Velroyen
693 439e1d3f Helga Velroyen
def _GetHvInfoAll(hv_specs, get_hv_fn=hypervisor.GetHypervisor):
694 439e1d3f Helga Velroyen
  """Retrieves node information for all hypervisors.
695 439e1d3f Helga Velroyen

696 439e1d3f Helga Velroyen
  See C{_GetHvInfo} for information on the output.
697 439e1d3f Helga Velroyen

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

701 439e1d3f Helga Velroyen
  """
702 439e1d3f Helga Velroyen
  if hv_specs is None:
703 439e1d3f Helga Velroyen
    return None
704 439e1d3f Helga Velroyen
705 439e1d3f Helga Velroyen
  result = []
706 439e1d3f Helga Velroyen
  for hvname, hvparams in hv_specs:
707 439e1d3f Helga Velroyen
    result.append(_GetHvInfo(hvname, hvparams, get_hv_fn))
708 439e1d3f Helga Velroyen
  return result
709 78519c10 Michael Hanselmann
710 78519c10 Michael Hanselmann
711 78519c10 Michael Hanselmann
def _GetNamedNodeInfo(names, fn):
712 78519c10 Michael Hanselmann
  """Calls C{fn} for all names in C{names} and returns a dictionary.
713 78519c10 Michael Hanselmann

714 78519c10 Michael Hanselmann
  @rtype: None or dict
715 78519c10 Michael Hanselmann

716 78519c10 Michael Hanselmann
  """
717 78519c10 Michael Hanselmann
  if names is None:
718 78519c10 Michael Hanselmann
    return None
719 78519c10 Michael Hanselmann
  else:
720 ff3be305 Michael Hanselmann
    return map(fn, names)
721 78519c10 Michael Hanselmann
722 78519c10 Michael Hanselmann
723 152759e4 Helga Velroyen
def GetNodeInfo(storage_units, hv_specs):
724 5bbd3f7f Michael Hanselmann
  """Gives back a hash with different information about the node.
725 a8083063 Iustin Pop

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

737 098c0958 Michael Hanselmann
  """
738 78519c10 Michael Hanselmann
  bootid = utils.ReadFile(_BOOT_ID_PATH, size=128).rstrip("\n")
739 4b92e992 Helga Velroyen
  storage_info = _GetNamedNodeInfo(
740 4b92e992 Helga Velroyen
    storage_units,
741 152759e4 Helga Velroyen
    (lambda (storage_type, storage_key, storage_params):
742 152759e4 Helga Velroyen
        _ApplyStorageInfoFunction(storage_type, storage_key, storage_params)))
743 439e1d3f Helga Velroyen
  hv_info = _GetHvInfoAll(hv_specs)
744 4b92e992 Helga Velroyen
  return (bootid, storage_info, hv_info)
745 4b92e992 Helga Velroyen
746 4b92e992 Helga Velroyen
747 b01b7a50 Helga Velroyen
def _GetFileStorageSpaceInfo(path, params):
748 13669ecd Helga Velroyen
  """Wrapper around filestorage.GetSpaceInfo.
749 13669ecd Helga Velroyen

750 13669ecd Helga Velroyen
  The purpose of this wrapper is to call filestorage.GetFileStorageSpaceInfo
751 13669ecd Helga Velroyen
  and ignore the *args parameter to not leak it into the filestorage
752 13669ecd Helga Velroyen
  module's code.
753 13669ecd Helga Velroyen

754 13669ecd Helga Velroyen
  @see: C{filestorage.GetFileStorageSpaceInfo} for description of the
755 13669ecd Helga Velroyen
    parameters.
756 13669ecd Helga Velroyen

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

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

804 d5a690cb Bernardo Dal Seno
  @type pvi_list: list of L{objects.LvmPvInfo} objects
805 d5a690cb Bernardo Dal Seno
  @param pvi_list: information about the PVs
806 d5a690cb Bernardo Dal Seno

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

810 d5a690cb Bernardo Dal Seno
  """
811 d5a690cb Bernardo Dal Seno
  res = []
812 d5a690cb Bernardo Dal Seno
  for pvi in pvi_list:
813 d5a690cb Bernardo Dal Seno
    if len(pvi.lv_list) > 1:
814 d5a690cb Bernardo Dal Seno
      res.append((pvi.name, pvi.lv_list))
815 d5a690cb Bernardo Dal Seno
  return res
816 d5a690cb Bernardo Dal Seno
817 d5a690cb Bernardo Dal Seno
818 75bf3149 Helga Velroyen
def _VerifyHypervisors(what, vm_capable, result, all_hvparams,
819 75bf3149 Helga Velroyen
                       get_hv_fn=hypervisor.GetHypervisor):
820 75bf3149 Helga Velroyen
  """Verifies the hypervisor. Appends the results to the 'results' list.
821 75bf3149 Helga Velroyen

822 75bf3149 Helga Velroyen
  @type what: C{dict}
823 75bf3149 Helga Velroyen
  @param what: a dictionary of things to check
824 75bf3149 Helga Velroyen
  @type vm_capable: boolean
825 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
826 75bf3149 Helga Velroyen
  @type result: dict
827 75bf3149 Helga Velroyen
  @param result: dictionary of verification results; results of the
828 75bf3149 Helga Velroyen
    verifications in this function will be added here
829 75bf3149 Helga Velroyen
  @type all_hvparams: dict of dict of string
830 75bf3149 Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
831 75bf3149 Helga Velroyen
  @type get_hv_fn: function
832 75bf3149 Helga Velroyen
  @param get_hv_fn: function to retrieve the hypervisor, to improve testability
833 75bf3149 Helga Velroyen

834 75bf3149 Helga Velroyen
  """
835 75bf3149 Helga Velroyen
  if not vm_capable:
836 75bf3149 Helga Velroyen
    return
837 75bf3149 Helga Velroyen
838 75bf3149 Helga Velroyen
  if constants.NV_HYPERVISOR in what:
839 75bf3149 Helga Velroyen
    result[constants.NV_HYPERVISOR] = {}
840 75bf3149 Helga Velroyen
    for hv_name in what[constants.NV_HYPERVISOR]:
841 75bf3149 Helga Velroyen
      hvparams = all_hvparams[hv_name]
842 75bf3149 Helga Velroyen
      try:
843 75bf3149 Helga Velroyen
        val = get_hv_fn(hv_name).Verify(hvparams=hvparams)
844 75bf3149 Helga Velroyen
      except errors.HypervisorError, err:
845 75bf3149 Helga Velroyen
        val = "Error while checking hypervisor: %s" % str(err)
846 75bf3149 Helga Velroyen
      result[constants.NV_HYPERVISOR][hv_name] = val
847 75bf3149 Helga Velroyen
848 75bf3149 Helga Velroyen
849 75bf3149 Helga Velroyen
def _VerifyHvparams(what, vm_capable, result,
850 75bf3149 Helga Velroyen
                    get_hv_fn=hypervisor.GetHypervisor):
851 75bf3149 Helga Velroyen
  """Verifies the hvparams. Appends the results to the 'results' list.
852 75bf3149 Helga Velroyen

853 75bf3149 Helga Velroyen
  @type what: C{dict}
854 75bf3149 Helga Velroyen
  @param what: a dictionary of things to check
855 75bf3149 Helga Velroyen
  @type vm_capable: boolean
856 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
857 75bf3149 Helga Velroyen
  @type result: dict
858 75bf3149 Helga Velroyen
  @param result: dictionary of verification results; results of the
859 75bf3149 Helga Velroyen
    verifications in this function will be added here
860 75bf3149 Helga Velroyen
  @type get_hv_fn: function
861 75bf3149 Helga Velroyen
  @param get_hv_fn: function to retrieve the hypervisor, to improve testability
862 75bf3149 Helga Velroyen

863 75bf3149 Helga Velroyen
  """
864 75bf3149 Helga Velroyen
  if not vm_capable:
865 75bf3149 Helga Velroyen
    return
866 75bf3149 Helga Velroyen
867 75bf3149 Helga Velroyen
  if constants.NV_HVPARAMS in what:
868 75bf3149 Helga Velroyen
    result[constants.NV_HVPARAMS] = []
869 75bf3149 Helga Velroyen
    for source, hv_name, hvparms in what[constants.NV_HVPARAMS]:
870 75bf3149 Helga Velroyen
      try:
871 75bf3149 Helga Velroyen
        logging.info("Validating hv %s, %s", hv_name, hvparms)
872 75bf3149 Helga Velroyen
        get_hv_fn(hv_name).ValidateParameters(hvparms)
873 75bf3149 Helga Velroyen
      except errors.HypervisorError, err:
874 75bf3149 Helga Velroyen
        result[constants.NV_HVPARAMS].append((source, hv_name, str(err)))
875 75bf3149 Helga Velroyen
876 75bf3149 Helga Velroyen
877 5b0dfcef Helga Velroyen
def _VerifyInstanceList(what, vm_capable, result, all_hvparams):
878 5b0dfcef Helga Velroyen
  """Verifies the instance list.
879 5b0dfcef Helga Velroyen

880 5b0dfcef Helga Velroyen
  @type what: C{dict}
881 5b0dfcef Helga Velroyen
  @param what: a dictionary of things to check
882 5b0dfcef Helga Velroyen
  @type vm_capable: boolean
883 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
884 5b0dfcef Helga Velroyen
  @type result: dict
885 5b0dfcef Helga Velroyen
  @param result: dictionary of verification results; results of the
886 5b0dfcef Helga Velroyen
    verifications in this function will be added here
887 5b0dfcef Helga Velroyen
  @type all_hvparams: dict of dict of string
888 5b0dfcef Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
889 5b0dfcef Helga Velroyen

890 5b0dfcef Helga Velroyen
  """
891 5b0dfcef Helga Velroyen
  if constants.NV_INSTANCELIST in what and vm_capable:
892 5b0dfcef Helga Velroyen
    # GetInstanceList can fail
893 5b0dfcef Helga Velroyen
    try:
894 5b0dfcef Helga Velroyen
      val = GetInstanceList(what[constants.NV_INSTANCELIST],
895 5b0dfcef Helga Velroyen
                            all_hvparams=all_hvparams)
896 5b0dfcef Helga Velroyen
    except RPCFail, err:
897 5b0dfcef Helga Velroyen
      val = str(err)
898 5b0dfcef Helga Velroyen
    result[constants.NV_INSTANCELIST] = val
899 5b0dfcef Helga Velroyen
900 5b0dfcef Helga Velroyen
901 5b0dfcef Helga Velroyen
def _VerifyNodeInfo(what, vm_capable, result, all_hvparams):
902 5b0dfcef Helga Velroyen
  """Verifies the node info.
903 5b0dfcef Helga Velroyen

904 5b0dfcef Helga Velroyen
  @type what: C{dict}
905 5b0dfcef Helga Velroyen
  @param what: a dictionary of things to check
906 5b0dfcef Helga Velroyen
  @type vm_capable: boolean
907 5b0dfcef Helga Velroyen
  @param vm_capable: whether or not this node is vm capable
908 5b0dfcef Helga Velroyen
  @type result: dict
909 5b0dfcef Helga Velroyen
  @param result: dictionary of verification results; results of the
910 5b0dfcef Helga Velroyen
    verifications in this function will be added here
911 5b0dfcef Helga Velroyen
  @type all_hvparams: dict of dict of string
912 5b0dfcef Helga Velroyen
  @param all_hvparams: dictionary mapping hypervisor names to hvparams
913 5b0dfcef Helga Velroyen

914 5b0dfcef Helga Velroyen
  """
915 5b0dfcef Helga Velroyen
  if constants.NV_HVINFO in what and vm_capable:
916 5b0dfcef Helga Velroyen
    hvname = what[constants.NV_HVINFO]
917 5b0dfcef Helga Velroyen
    hyper = hypervisor.GetHypervisor(hvname)
918 5b0dfcef Helga Velroyen
    hvparams = all_hvparams[hvname]
919 5b0dfcef Helga Velroyen
    result[constants.NV_HVINFO] = hyper.GetNodeInfo(hvparams=hvparams)
920 5b0dfcef Helga Velroyen
921 5b0dfcef Helga Velroyen
922 a6c43c02 Helga Velroyen
def _VerifyClientCertificate(cert_file=pathutils.NODED_CLIENT_CERT_FILE):
923 a6c43c02 Helga Velroyen
  """Verify the existance and validity of the client SSL certificate.
924 a6c43c02 Helga Velroyen

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

943 e69d05fd Iustin Pop
  Based on the input L{what} parameter, various checks are done on the
944 e69d05fd Iustin Pop
  local node.
945 e69d05fd Iustin Pop

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

949 e69d05fd Iustin Pop
  If the I{nodelist} key is present, we check that we have
950 e69d05fd Iustin Pop
  connectivity via ssh with the target nodes (and check the hostname
951 e69d05fd Iustin Pop
  report).
952 a8083063 Iustin Pop

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

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

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

1178 d722af8b Helga Velroyen
  Token types can be 'ssl' or 'ssh'. So far only some actions are implemented
1179 d722af8b Helga Velroyen
  for 'ssl'. Action 'get' returns the digest of the public client ssl
1180 d722af8b Helga Velroyen
  certificate. Action 'create' creates a new client certificate and private key
1181 d722af8b Helga Velroyen
  and also returns the digest of the certificate. The third parameter of a
1182 d722af8b Helga Velroyen
  token request are optional parameters for the actions, so far only the
1183 d722af8b Helga Velroyen
  filename is supported.
1184 d722af8b Helga Velroyen

1185 d722af8b Helga Velroyen
  @type token_requests: list of tuples of (string, string, dict), where the
1186 d722af8b Helga Velroyen
    first string is in constants.CRYPTO_TYPES, the second in
1187 d722af8b Helga Velroyen
    constants.CRYPTO_ACTIONS. The third parameter is a dictionary of string
1188 d722af8b Helga Velroyen
    to string.
1189 d722af8b Helga Velroyen
  @param token_requests: list of requests of cryptographic tokens and actions
1190 d722af8b Helga Velroyen
    to perform on them. The actions come with a dictionary of options.
1191 b544a3c2 Helga Velroyen
  @rtype: list of tuples (string, string)
1192 b544a3c2 Helga Velroyen
  @return: list of tuples of the token type and the public crypto token
1193 b544a3c2 Helga Velroyen

1194 b544a3c2 Helga Velroyen
  """
1195 d722af8b Helga Velroyen
  _VALID_CERT_FILES = [pathutils.NODED_CERT_FILE,
1196 d722af8b Helga Velroyen
                       pathutils.NODED_CLIENT_CERT_FILE,
1197 d722af8b Helga Velroyen
                       pathutils.NODED_CLIENT_CERT_FILE_TMP]
1198 d722af8b Helga Velroyen
  _DEFAULT_CERT_FILE = pathutils.NODED_CLIENT_CERT_FILE
1199 b544a3c2 Helga Velroyen
  tokens = []
1200 d722af8b Helga Velroyen
  for (token_type, action, options) in token_requests:
1201 b544a3c2 Helga Velroyen
    if token_type not in constants.CRYPTO_TYPES:
1202 d722af8b Helga Velroyen
      raise errors.ProgrammerError("Token type '%s' not supported." %
1203 b544a3c2 Helga Velroyen
                                   token_type)
1204 d722af8b Helga Velroyen
    if action not in constants.CRYPTO_ACTIONS:
1205 d722af8b Helga Velroyen
      raise errors.ProgrammerError("Action '%s' is not supported." %
1206 d722af8b Helga Velroyen
                                   action)
1207 b544a3c2 Helga Velroyen
    if token_type == constants.CRYPTO_TYPE_SSL_DIGEST:
1208 d722af8b Helga Velroyen
      if action == constants.CRYPTO_ACTION_CREATE:
1209 d722af8b Helga Velroyen
        cert_filename = None
1210 d722af8b Helga Velroyen
        if options:
1211 d722af8b Helga Velroyen
          cert_filename = options.get(constants.CRYPTO_OPTION_CERT_FILE)
1212 d722af8b Helga Velroyen
        if not cert_filename:
1213 d722af8b Helga Velroyen
          cert_filename = _DEFAULT_CERT_FILE
1214 d722af8b Helga Velroyen
        # For security reason, we don't allow arbitrary filenames
1215 d722af8b Helga Velroyen
        if not cert_filename in _VALID_CERT_FILES:
1216 d722af8b Helga Velroyen
          raise errors.ProgrammerError(
1217 d722af8b Helga Velroyen
            "The certificate file name path '%s' is not allowed." %
1218 d722af8b Helga Velroyen
            cert_filename)
1219 d722af8b Helga Velroyen
        utils.GenerateNewSslCert(
1220 d722af8b Helga Velroyen
          True, cert_filename,
1221 d722af8b Helga Velroyen
          "Create new client SSL certificate in %s." % cert_filename)
1222 d722af8b Helga Velroyen
        tokens.append((token_type,
1223 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest(
1224 d722af8b Helga Velroyen
                         cert_filename=cert_filename)))
1225 d722af8b Helga Velroyen
      elif action == constants.CRYPTO_ACTION_GET:
1226 d722af8b Helga Velroyen
        tokens.append((token_type,
1227 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest()))
1228 b544a3c2 Helga Velroyen
  return tokens
1229 b544a3c2 Helga Velroyen
1230 b544a3c2 Helga Velroyen
1231 2be7273c Apollon Oikonomopoulos
def GetBlockDevSizes(devices):
1232 2be7273c Apollon Oikonomopoulos
  """Return the size of the given block devices
1233 2be7273c Apollon Oikonomopoulos

1234 2be7273c Apollon Oikonomopoulos
  @type devices: list
1235 2be7273c Apollon Oikonomopoulos
  @param devices: list of block device nodes to query
1236 2be7273c Apollon Oikonomopoulos
  @rtype: dict
1237 2be7273c Apollon Oikonomopoulos
  @return:
1238 2be7273c Apollon Oikonomopoulos
    dictionary of all block devices under /dev (key). The value is their
1239 2be7273c Apollon Oikonomopoulos
    size in MiB.
1240 2be7273c Apollon Oikonomopoulos

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

1243 2be7273c Apollon Oikonomopoulos
  """
1244 2be7273c Apollon Oikonomopoulos
  DEV_PREFIX = "/dev/"
1245 2be7273c Apollon Oikonomopoulos
  blockdevs = {}
1246 2be7273c Apollon Oikonomopoulos
1247 2be7273c Apollon Oikonomopoulos
  for devpath in devices:
1248 cf00dba0 René Nussbaumer
    if not utils.IsBelowDir(DEV_PREFIX, devpath):
1249 2be7273c Apollon Oikonomopoulos
      continue
1250 2be7273c Apollon Oikonomopoulos
1251 2be7273c Apollon Oikonomopoulos
    try:
1252 2be7273c Apollon Oikonomopoulos
      st = os.stat(devpath)
1253 2be7273c Apollon Oikonomopoulos
    except EnvironmentError, err:
1254 2be7273c Apollon Oikonomopoulos
      logging.warning("Error stat()'ing device %s: %s", devpath, str(err))
1255 2be7273c Apollon Oikonomopoulos
      continue
1256 2be7273c Apollon Oikonomopoulos
1257 2be7273c Apollon Oikonomopoulos
    if stat.S_ISBLK(st.st_mode):
1258 2be7273c Apollon Oikonomopoulos
      result = utils.RunCmd(["blockdev", "--getsize64", devpath])
1259 2be7273c Apollon Oikonomopoulos
      if result.failed:
1260 2be7273c Apollon Oikonomopoulos
        # We don't want to fail, just do not list this device as available
1261 2be7273c Apollon Oikonomopoulos
        logging.warning("Cannot get size for block device %s", devpath)
1262 2be7273c Apollon Oikonomopoulos
        continue
1263 2be7273c Apollon Oikonomopoulos
1264 2be7273c Apollon Oikonomopoulos
      size = int(result.stdout) / (1024 * 1024)
1265 2be7273c Apollon Oikonomopoulos
      blockdevs[devpath] = size
1266 2be7273c Apollon Oikonomopoulos
  return blockdevs
1267 2be7273c Apollon Oikonomopoulos
1268 2be7273c Apollon Oikonomopoulos
1269 84d7e26b Dmitry Chernyak
def GetVolumeList(vg_names):
1270 a8083063 Iustin Pop
  """Compute list of logical volumes and their size.
1271 a8083063 Iustin Pop

1272 84d7e26b Dmitry Chernyak
  @type vg_names: list
1273 397693d3 Iustin Pop
  @param vg_names: the volume groups whose LVs we should list, or
1274 397693d3 Iustin Pop
      empty for all volume groups
1275 10c2650b Iustin Pop
  @rtype: dict
1276 10c2650b Iustin Pop
  @return:
1277 10c2650b Iustin Pop
      dictionary of all partions (key) with value being a tuple of
1278 10c2650b Iustin Pop
      their size (in MiB), inactive and online status::
1279 10c2650b Iustin Pop

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

1282 10c2650b Iustin Pop
      in case of errors, a string is returned with the error
1283 10c2650b Iustin Pop
      details.
1284 a8083063 Iustin Pop

1285 a8083063 Iustin Pop
  """
1286 cb2037a2 Iustin Pop
  lvs = {}
1287 d0c8c01d Iustin Pop
  sep = "|"
1288 397693d3 Iustin Pop
  if not vg_names:
1289 397693d3 Iustin Pop
    vg_names = []
1290 cb2037a2 Iustin Pop
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
1291 cb2037a2 Iustin Pop
                         "--separator=%s" % sep,
1292 84d7e26b Dmitry Chernyak
                         "-ovg_name,lv_name,lv_size,lv_attr"] + vg_names)
1293 a8083063 Iustin Pop
  if result.failed:
1294 29d376ec Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s", result.output)
1295 cb2037a2 Iustin Pop
1296 cb2037a2 Iustin Pop
  for line in result.stdout.splitlines():
1297 df4c2628 Iustin Pop
    line = line.strip()
1298 0b5303da Iustin Pop
    match = _LVSLINE_REGEX.match(line)
1299 df4c2628 Iustin Pop
    if not match:
1300 18682bca Iustin Pop
      logging.error("Invalid line returned from lvs output: '%s'", line)
1301 df4c2628 Iustin Pop
      continue
1302 84d7e26b Dmitry Chernyak
    vg_name, name, size, attr = match.groups()
1303 d0c8c01d Iustin Pop
    inactive = attr[4] == "-"
1304 d0c8c01d Iustin Pop
    online = attr[5] == "o"
1305 d0c8c01d Iustin Pop
    virtual = attr[0] == "v"
1306 33f2a81a Iustin Pop
    if virtual:
1307 33f2a81a Iustin Pop
      # we don't want to report such volumes as existing, since they
1308 33f2a81a Iustin Pop
      # don't really hold data
1309 33f2a81a Iustin Pop
      continue
1310 e687ec01 Michael Hanselmann
    lvs[vg_name + "/" + name] = (size, inactive, online)
1311 cb2037a2 Iustin Pop
1312 cb2037a2 Iustin Pop
  return lvs
1313 a8083063 Iustin Pop
1314 a8083063 Iustin Pop
1315 a8083063 Iustin Pop
def ListVolumeGroups():
1316 2f8598a5 Alexander Schreiber
  """List the volume groups and their size.
1317 a8083063 Iustin Pop

1318 10c2650b Iustin Pop
  @rtype: dict
1319 10c2650b Iustin Pop
  @return: dictionary with keys volume name and values the
1320 10c2650b Iustin Pop
      size of the volume
1321 a8083063 Iustin Pop

1322 a8083063 Iustin Pop
  """
1323 c26a6bd2 Iustin Pop
  return utils.ListVolumeGroups()
1324 a8083063 Iustin Pop
1325 a8083063 Iustin Pop
1326 dcb93971 Michael Hanselmann
def NodeVolumes():
1327 dcb93971 Michael Hanselmann
  """List all volumes on this node.
1328 dcb93971 Michael Hanselmann

1329 10c2650b Iustin Pop
  @rtype: list
1330 10c2650b Iustin Pop
  @return:
1331 10c2650b Iustin Pop
    A list of dictionaries, each having four keys:
1332 10c2650b Iustin Pop
      - name: the logical volume name,
1333 10c2650b Iustin Pop
      - size: the size of the logical volume
1334 10c2650b Iustin Pop
      - dev: the physical device on which the LV lives
1335 10c2650b Iustin Pop
      - vg: the volume group to which it belongs
1336 10c2650b Iustin Pop

1337 10c2650b Iustin Pop
    In case of errors, we return an empty list and log the
1338 10c2650b Iustin Pop
    error.
1339 10c2650b Iustin Pop

1340 10c2650b Iustin Pop
    Note that since a logical volume can live on multiple physical
1341 10c2650b Iustin Pop
    volumes, the resulting list might include a logical volume
1342 10c2650b Iustin Pop
    multiple times.
1343 10c2650b Iustin Pop

1344 dcb93971 Michael Hanselmann
  """
1345 dcb93971 Michael Hanselmann
  result = utils.RunCmd(["lvs", "--noheadings", "--units=m", "--nosuffix",
1346 dcb93971 Michael Hanselmann
                         "--separator=|",
1347 dcb93971 Michael Hanselmann
                         "--options=lv_name,lv_size,devices,vg_name"])
1348 dcb93971 Michael Hanselmann
  if result.failed:
1349 10bfe6cb Iustin Pop
    _Fail("Failed to list logical volumes, lvs output: %s",
1350 10bfe6cb Iustin Pop
          result.output)
1351 dcb93971 Michael Hanselmann
1352 dcb93971 Michael Hanselmann
  def parse_dev(dev):
1353 d0c8c01d Iustin Pop
    return dev.split("(")[0]
1354 89e5ab02 Iustin Pop
1355 89e5ab02 Iustin Pop
  def handle_dev(dev):
1356 89e5ab02 Iustin Pop
    return [parse_dev(x) for x in dev.split(",")]
1357 dcb93971 Michael Hanselmann
1358 dcb93971 Michael Hanselmann
  def map_line(line):
1359 89e5ab02 Iustin Pop
    line = [v.strip() for v in line]
1360 d0c8c01d Iustin Pop
    return [{"name": line[0], "size": line[1],
1361 d0c8c01d Iustin Pop
             "dev": dev, "vg": line[3]} for dev in handle_dev(line[2])]
1362 89e5ab02 Iustin Pop
1363 89e5ab02 Iustin Pop
  all_devs = []
1364 89e5ab02 Iustin Pop
  for line in result.stdout.splitlines():
1365 d0c8c01d Iustin Pop
    if line.count("|") >= 3:
1366 d0c8c01d Iustin Pop
      all_devs.extend(map_line(line.split("|")))
1367 89e5ab02 Iustin Pop
    else:
1368 89e5ab02 Iustin Pop
      logging.warning("Strange line in the output from lvs: '%s'", line)
1369 89e5ab02 Iustin Pop
  return all_devs
1370 dcb93971 Michael Hanselmann
1371 dcb93971 Michael Hanselmann
1372 a8083063 Iustin Pop
def BridgesExist(bridges_list):
1373 2f8598a5 Alexander Schreiber
  """Check if a list of bridges exist on the current node.
1374 a8083063 Iustin Pop

1375 b1206984 Iustin Pop
  @rtype: boolean
1376 b1206984 Iustin Pop
  @return: C{True} if all of them exist, C{False} otherwise
1377 a8083063 Iustin Pop

1378 a8083063 Iustin Pop
  """
1379 35c0c8da Iustin Pop
  missing = []
1380 a8083063 Iustin Pop
  for bridge in bridges_list:
1381 a8083063 Iustin Pop
    if not utils.BridgeExists(bridge):
1382 35c0c8da Iustin Pop
      missing.append(bridge)
1383 a8083063 Iustin Pop
1384 35c0c8da Iustin Pop
  if missing:
1385 1f864b60 Iustin Pop
    _Fail("Missing bridges %s", utils.CommaJoin(missing))
1386 35c0c8da Iustin Pop
1387 a8083063 Iustin Pop
1388 2bff1928 Helga Velroyen
def GetInstanceListForHypervisor(hname, hvparams=None,
1389 2bff1928 Helga Velroyen
                                 get_hv_fn=hypervisor.GetHypervisor):
1390 2bff1928 Helga Velroyen
  """Provides a list of instances of the given hypervisor.
1391 2bff1928 Helga Velroyen

1392 2bff1928 Helga Velroyen
  @type hname: string
1393 2bff1928 Helga Velroyen
  @param hname: name of the hypervisor
1394 2bff1928 Helga Velroyen
  @type hvparams: dict of strings
1395 2bff1928 Helga Velroyen
  @param hvparams: hypervisor parameters for the given hypervisor
1396 2bff1928 Helga Velroyen
  @type get_hv_fn: function
1397 2bff1928 Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1398 2bff1928 Helga Velroyen
    name; optional parameter to increase testability
1399 2bff1928 Helga Velroyen

1400 2bff1928 Helga Velroyen
  @rtype: list
1401 2bff1928 Helga Velroyen
  @return: a list of all running instances on the current node
1402 2bff1928 Helga Velroyen
    - instance1.example.com
1403 2bff1928 Helga Velroyen
    - instance2.example.com
1404 2bff1928 Helga Velroyen

1405 2bff1928 Helga Velroyen
  """
1406 2bff1928 Helga Velroyen
  results = []
1407 2bff1928 Helga Velroyen
  try:
1408 2bff1928 Helga Velroyen
    hv = get_hv_fn(hname)
1409 5b0dfcef Helga Velroyen
    names = hv.ListInstances(hvparams=hvparams)
1410 2bff1928 Helga Velroyen
    results.extend(names)
1411 2bff1928 Helga Velroyen
  except errors.HypervisorError, err:
1412 2bff1928 Helga Velroyen
    _Fail("Error enumerating instances (hypervisor %s): %s",
1413 2bff1928 Helga Velroyen
          hname, err, exc=True)
1414 2bff1928 Helga Velroyen
  return results
1415 2bff1928 Helga Velroyen
1416 2bff1928 Helga Velroyen
1417 fac83f8a Helga Velroyen
def GetInstanceList(hypervisor_list, all_hvparams=None,
1418 fac83f8a Helga Velroyen
                    get_hv_fn=hypervisor.GetHypervisor):
1419 2f8598a5 Alexander Schreiber
  """Provides a list of instances.
1420 a8083063 Iustin Pop

1421 e69d05fd Iustin Pop
  @type hypervisor_list: list
1422 e69d05fd Iustin Pop
  @param hypervisor_list: the list of hypervisors to query information
1423 fac83f8a Helga Velroyen
  @type all_hvparams: dict of dict of strings
1424 fac83f8a Helga Velroyen
  @param all_hvparams: a dictionary mapping hypervisor types to respective
1425 fac83f8a Helga Velroyen
    cluster-wide hypervisor parameters
1426 fac83f8a Helga Velroyen
  @type get_hv_fn: function
1427 fac83f8a Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1428 fac83f8a Helga Velroyen
    name; optional parameter to increase testability
1429 e69d05fd Iustin Pop

1430 e69d05fd Iustin Pop
  @rtype: list
1431 e69d05fd Iustin Pop
  @return: a list of all running instances on the current node
1432 10c2650b Iustin Pop
    - instance1.example.com
1433 10c2650b Iustin Pop
    - instance2.example.com
1434 a8083063 Iustin Pop

1435 098c0958 Michael Hanselmann
  """
1436 e69d05fd Iustin Pop
  results = []
1437 e69d05fd Iustin Pop
  for hname in hypervisor_list:
1438 5b0dfcef Helga Velroyen
    hvparams = all_hvparams[hname]
1439 5b0dfcef Helga Velroyen
    results.extend(GetInstanceListForHypervisor(hname, hvparams=hvparams,
1440 2bff1928 Helga Velroyen
                                                get_hv_fn=get_hv_fn))
1441 e69d05fd Iustin Pop
  return results
1442 a8083063 Iustin Pop
1443 a8083063 Iustin Pop
1444 0bbec3af Helga Velroyen
def GetInstanceInfo(instance, hname, hvparams=None):
1445 5bbd3f7f Michael Hanselmann
  """Gives back the information about an instance as a dictionary.
1446 a8083063 Iustin Pop

1447 e69d05fd Iustin Pop
  @type instance: string
1448 e69d05fd Iustin Pop
  @param instance: the instance name
1449 e69d05fd Iustin Pop
  @type hname: string
1450 e69d05fd Iustin Pop
  @param hname: the hypervisor type of the instance
1451 0bbec3af Helga Velroyen
  @type hvparams: dict of strings
1452 0bbec3af Helga Velroyen
  @param hvparams: the instance's hvparams
1453 a8083063 Iustin Pop

1454 e69d05fd Iustin Pop
  @rtype: dict
1455 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
1456 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1457 a3f0f306 Jose A. Lopes
      - state: state of instance (HvInstanceState)
1458 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1459 1cb97324 Agata Murawska
      - vcpus: the number of vcpus (int)
1460 a8083063 Iustin Pop

1461 098c0958 Michael Hanselmann
  """
1462 a8083063 Iustin Pop
  output = {}
1463 a8083063 Iustin Pop
1464 0bbec3af Helga Velroyen
  iinfo = hypervisor.GetHypervisor(hname).GetInstanceInfo(instance,
1465 0bbec3af Helga Velroyen
                                                          hvparams=hvparams)
1466 a8083063 Iustin Pop
  if iinfo is not None:
1467 d0c8c01d Iustin Pop
    output["memory"] = iinfo[2]
1468 1cb97324 Agata Murawska
    output["vcpus"] = iinfo[3]
1469 d0c8c01d Iustin Pop
    output["state"] = iinfo[4]
1470 d0c8c01d Iustin Pop
    output["time"] = iinfo[5]
1471 a8083063 Iustin Pop
1472 c26a6bd2 Iustin Pop
  return output
1473 a8083063 Iustin Pop
1474 a8083063 Iustin Pop
1475 56e7640c Iustin Pop
def GetInstanceMigratable(instance):
1476 3361ab37 Helga Velroyen
  """Computes whether an instance can be migrated.
1477 56e7640c Iustin Pop

1478 56e7640c Iustin Pop
  @type instance: L{objects.Instance}
1479 56e7640c Iustin Pop
  @param instance: object representing the instance to be checked.
1480 56e7640c Iustin Pop

1481 56e7640c Iustin Pop
  @rtype: tuple
1482 56e7640c Iustin Pop
  @return: tuple of (result, description) where:
1483 56e7640c Iustin Pop
      - result: whether the instance can be migrated or not
1484 56e7640c Iustin Pop
      - description: a description of the issue, if relevant
1485 56e7640c Iustin Pop

1486 56e7640c Iustin Pop
  """
1487 56e7640c Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1488 afdc3985 Iustin Pop
  iname = instance.name
1489 3361ab37 Helga Velroyen
  if iname not in hyper.ListInstances(instance.hvparams):
1490 afdc3985 Iustin Pop
    _Fail("Instance %s is not running", iname)
1491 56e7640c Iustin Pop
1492 56e7640c Iustin Pop
  for idx in range(len(instance.disks)):
1493 afdc3985 Iustin Pop
    link_name = _GetBlockDevSymlinkPath(iname, idx)
1494 56e7640c Iustin Pop
    if not os.path.islink(link_name):
1495 b8ebd37b Iustin Pop
      logging.warning("Instance %s is missing symlink %s for disk %d",
1496 b8ebd37b Iustin Pop
                      iname, link_name, idx)
1497 56e7640c Iustin Pop
1498 56e7640c Iustin Pop
1499 0200a1af Helga Velroyen
def GetAllInstancesInfo(hypervisor_list, all_hvparams):
1500 a8083063 Iustin Pop
  """Gather data about all instances.
1501 a8083063 Iustin Pop

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

1506 e69d05fd Iustin Pop
  @type hypervisor_list: list
1507 e69d05fd Iustin Pop
  @param hypervisor_list: list of hypervisors to query for instance data
1508 0200a1af Helga Velroyen
  @type all_hvparams: dict of dict of strings
1509 0200a1af Helga Velroyen
  @param all_hvparams: mapping of hypervisor names to hvparams
1510 e69d05fd Iustin Pop

1511 955db481 Guido Trotter
  @rtype: dict
1512 e69d05fd Iustin Pop
  @return: dictionary of instance: data, with data having the following keys:
1513 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1514 e69d05fd Iustin Pop
      - state: xen state of instance (string)
1515 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1516 10c2650b Iustin Pop
      - vcpus: the number of vcpus
1517 a8083063 Iustin Pop

1518 098c0958 Michael Hanselmann
  """
1519 a8083063 Iustin Pop
  output = {}
1520 e69d05fd Iustin Pop
  for hname in hypervisor_list:
1521 0200a1af Helga Velroyen
    hvparams = all_hvparams[hname]
1522 0200a1af Helga Velroyen
    iinfo = hypervisor.GetHypervisor(hname).GetAllInstancesInfo(hvparams)
1523 e69d05fd Iustin Pop
    if iinfo:
1524 29921401 Iustin Pop
      for name, _, memory, vcpus, state, times in iinfo:
1525 f23b5ae8 Iustin Pop
        value = {
1526 d0c8c01d Iustin Pop
          "memory": memory,
1527 d0c8c01d Iustin Pop
          "vcpus": vcpus,
1528 d0c8c01d Iustin Pop
          "state": state,
1529 d0c8c01d Iustin Pop
          "time": times,
1530 e69d05fd Iustin Pop
          }
1531 b33b6f55 Iustin Pop
        if name in output:
1532 b33b6f55 Iustin Pop
          # we only check static parameters, like memory and vcpus,
1533 b33b6f55 Iustin Pop
          # and not state and time which can change between the
1534 b33b6f55 Iustin Pop
          # invocations of the different hypervisors
1535 d0c8c01d Iustin Pop
          for key in "memory", "vcpus":
1536 b33b6f55 Iustin Pop
            if value[key] != output[name][key]:
1537 2fa74ef4 Iustin Pop
              _Fail("Instance %s is running twice"
1538 2fa74ef4 Iustin Pop
                    " with different parameters", name)
1539 f23b5ae8 Iustin Pop
        output[name] = value
1540 a8083063 Iustin Pop
1541 c26a6bd2 Iustin Pop
  return output
1542 a8083063 Iustin Pop
1543 a8083063 Iustin Pop
1544 b9e12624 Hrvoje Ribicic
def GetInstanceConsoleInfo(instance_param_dict,
1545 b9e12624 Hrvoje Ribicic
                           get_hv_fn=hypervisor.GetHypervisor):
1546 b9e12624 Hrvoje Ribicic
  """Gather data about the console access of a set of instances of this node.
1547 b9e12624 Hrvoje Ribicic

1548 b9e12624 Hrvoje Ribicic
  This function assumes that the caller already knows which instances are on
1549 b9e12624 Hrvoje Ribicic
  this node, by calling a function such as L{GetAllInstancesInfo} or
1550 b9e12624 Hrvoje Ribicic
  L{GetInstanceList}.
1551 b9e12624 Hrvoje Ribicic

1552 b9e12624 Hrvoje Ribicic
  For every instance, a large amount of configuration data needs to be
1553 b9e12624 Hrvoje Ribicic
  provided to the hypervisor interface in order to receive the console
1554 b9e12624 Hrvoje Ribicic
  information. Whether this could or should be cut down can be discussed.
1555 b9e12624 Hrvoje Ribicic
  The information is provided in a dictionary indexed by instance name,
1556 b9e12624 Hrvoje Ribicic
  allowing any number of instance queries to be done.
1557 b9e12624 Hrvoje Ribicic

1558 b9e12624 Hrvoje Ribicic
  @type instance_param_dict: dict of string to tuple of dictionaries, where the
1559 c42be2c0 Petr Pudlak
    dictionaries represent: L{objects.Instance}, L{objects.Node},
1560 c42be2c0 Petr Pudlak
    L{objects.NodeGroup}, HvParams, BeParams
1561 b9e12624 Hrvoje Ribicic
  @param instance_param_dict: mapping of instance name to parameters necessary
1562 b9e12624 Hrvoje Ribicic
    for console information retrieval
1563 b9e12624 Hrvoje Ribicic

1564 b9e12624 Hrvoje Ribicic
  @rtype: dict
1565 b9e12624 Hrvoje Ribicic
  @return: dictionary of instance: data, with data having the following keys:
1566 b9e12624 Hrvoje Ribicic
      - instance: instance name
1567 b9e12624 Hrvoje Ribicic
      - kind: console kind
1568 b9e12624 Hrvoje Ribicic
      - message: used with kind == CONS_MESSAGE, indicates console to be
1569 b9e12624 Hrvoje Ribicic
                 unavailable, supplies error message
1570 b9e12624 Hrvoje Ribicic
      - host: host to connect to
1571 b9e12624 Hrvoje Ribicic
      - port: port to use
1572 b9e12624 Hrvoje Ribicic
      - user: user for login
1573 b9e12624 Hrvoje Ribicic
      - command: the command, broken into parts as an array
1574 b9e12624 Hrvoje Ribicic
      - display: unknown, potentially unused?
1575 b9e12624 Hrvoje Ribicic

1576 b9e12624 Hrvoje Ribicic
  """
1577 b9e12624 Hrvoje Ribicic
1578 b9e12624 Hrvoje Ribicic
  output = {}
1579 b9e12624 Hrvoje Ribicic
  for inst_name in instance_param_dict:
1580 b9e12624 Hrvoje Ribicic
    instance = instance_param_dict[inst_name]["instance"]
1581 b9e12624 Hrvoje Ribicic
    pnode = instance_param_dict[inst_name]["node"]
1582 c42be2c0 Petr Pudlak
    group = instance_param_dict[inst_name]["group"]
1583 b9e12624 Hrvoje Ribicic
    hvparams = instance_param_dict[inst_name]["hvParams"]
1584 b9e12624 Hrvoje Ribicic
    beparams = instance_param_dict[inst_name]["beParams"]
1585 b9e12624 Hrvoje Ribicic
1586 b9e12624 Hrvoje Ribicic
    instance = objects.Instance.FromDict(instance)
1587 b9e12624 Hrvoje Ribicic
    pnode = objects.Node.FromDict(pnode)
1588 c42be2c0 Petr Pudlak
    group = objects.NodeGroup.FromDict(group)
1589 b9e12624 Hrvoje Ribicic
1590 b9e12624 Hrvoje Ribicic
    h = get_hv_fn(instance.hypervisor)
1591 c42be2c0 Petr Pudlak
    output[inst_name] = h.GetInstanceConsole(instance, pnode, group,
1592 c42be2c0 Petr Pudlak
                                             hvparams, beparams).ToDict()
1593 b9e12624 Hrvoje Ribicic
1594 b9e12624 Hrvoje Ribicic
  return output
1595 b9e12624 Hrvoje Ribicic
1596 b9e12624 Hrvoje Ribicic
1597 6aa7a354 Iustin Pop
def _InstanceLogName(kind, os_name, instance, component):
1598 81a3406c Iustin Pop
  """Compute the OS log filename for a given instance and operation.
1599 81a3406c Iustin Pop

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

1603 81a3406c Iustin Pop
  @type kind: string
1604 81a3406c Iustin Pop
  @param kind: the operation type (e.g. add, import, etc.)
1605 81a3406c Iustin Pop
  @type os_name: string
1606 81a3406c Iustin Pop
  @param os_name: the os name
1607 81a3406c Iustin Pop
  @type instance: string
1608 81a3406c Iustin Pop
  @param instance: the name of the instance being imported/added/etc.
1609 6aa7a354 Iustin Pop
  @type component: string or None
1610 6aa7a354 Iustin Pop
  @param component: the name of the component of the instance being
1611 6aa7a354 Iustin Pop
      transferred
1612 81a3406c Iustin Pop

1613 81a3406c Iustin Pop
  """
1614 1651d116 Michael Hanselmann
  # TODO: Use tempfile.mkstemp to create unique filename
1615 6aa7a354 Iustin Pop
  if component:
1616 6aa7a354 Iustin Pop
    assert "/" not in component
1617 6aa7a354 Iustin Pop
    c_msg = "-%s" % component
1618 6aa7a354 Iustin Pop
  else:
1619 6aa7a354 Iustin Pop
    c_msg = ""
1620 6aa7a354 Iustin Pop
  base = ("%s-%s-%s%s-%s.log" %
1621 6aa7a354 Iustin Pop
          (kind, os_name, instance, c_msg, utils.TimestampForFilename()))
1622 710f30ec Michael Hanselmann
  return utils.PathJoin(pathutils.LOG_OS_DIR, base)
1623 81a3406c Iustin Pop
1624 81a3406c Iustin Pop
1625 4a0e011f Iustin Pop
def InstanceOsAdd(instance, reinstall, debug):
1626 2f8598a5 Alexander Schreiber
  """Add an OS to an instance.
1627 a8083063 Iustin Pop

1628 d15a9ad3 Guido Trotter
  @type instance: L{objects.Instance}
1629 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1630 e557bae9 Guido Trotter
  @type reinstall: boolean
1631 e557bae9 Guido Trotter
  @param reinstall: whether this is an instance reinstall
1632 4a0e011f Iustin Pop
  @type debug: integer
1633 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1634 c26a6bd2 Iustin Pop
  @rtype: None
1635 a8083063 Iustin Pop

1636 a8083063 Iustin Pop
  """
1637 255dcebd Iustin Pop
  inst_os = OSFromDisk(instance.os)
1638 255dcebd Iustin Pop
1639 4a0e011f Iustin Pop
  create_env = OSEnvironment(instance, inst_os, debug)
1640 e557bae9 Guido Trotter
  if reinstall:
1641 d0c8c01d Iustin Pop
    create_env["INSTANCE_REINSTALL"] = "1"
1642 a8083063 Iustin Pop
1643 6aa7a354 Iustin Pop
  logfile = _InstanceLogName("add", instance.os, instance.name, None)
1644 decd5f45 Iustin Pop
1645 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.create_script], env=create_env,
1646 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1647 decd5f45 Iustin Pop
  if result.failed:
1648 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s, logfile: %s,"
1649 d868edb4 Iustin Pop
                  " output: %s", result.cmd, result.fail_reason, logfile,
1650 18682bca Iustin Pop
                  result.output)
1651 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1652 20e01edd Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1653 afdc3985 Iustin Pop
    _Fail("OS create script failed (%s), last lines in the"
1654 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1655 decd5f45 Iustin Pop
1656 decd5f45 Iustin Pop
1657 4a0e011f Iustin Pop
def RunRenameInstance(instance, old_name, debug):
1658 decd5f45 Iustin Pop
  """Run the OS rename script for an instance.
1659 decd5f45 Iustin Pop

1660 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1661 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1662 d15a9ad3 Guido Trotter
  @type old_name: string
1663 d15a9ad3 Guido Trotter
  @param old_name: previous instance name
1664 4a0e011f Iustin Pop
  @type debug: integer
1665 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1666 10c2650b Iustin Pop
  @rtype: boolean
1667 10c2650b Iustin Pop
  @return: the success of the operation
1668 decd5f45 Iustin Pop

1669 decd5f45 Iustin Pop
  """
1670 decd5f45 Iustin Pop
  inst_os = OSFromDisk(instance.os)
1671 decd5f45 Iustin Pop
1672 4a0e011f Iustin Pop
  rename_env = OSEnvironment(instance, inst_os, debug)
1673 d0c8c01d Iustin Pop
  rename_env["OLD_INSTANCE_NAME"] = old_name
1674 decd5f45 Iustin Pop
1675 81a3406c Iustin Pop
  logfile = _InstanceLogName("rename", instance.os,
1676 6aa7a354 Iustin Pop
                             "%s-%s" % (old_name, instance.name), None)
1677 a8083063 Iustin Pop
1678 d868edb4 Iustin Pop
  result = utils.RunCmd([inst_os.rename_script], env=rename_env,
1679 896a03f6 Iustin Pop
                        cwd=inst_os.path, output=logfile, reset_env=True)
1680 a8083063 Iustin Pop
1681 a8083063 Iustin Pop
  if result.failed:
1682 18682bca Iustin Pop
    logging.error("os create command '%s' returned error: %s output: %s",
1683 d868edb4 Iustin Pop
                  result.cmd, result.fail_reason, result.output)
1684 26f15862 Iustin Pop
    lines = [utils.SafeEncode(val)
1685 96841384 Iustin Pop
             for val in utils.TailFile(logfile, lines=20)]
1686 afdc3985 Iustin Pop
    _Fail("OS rename script failed (%s), last lines in the"
1687 afdc3985 Iustin Pop
          " log file:\n%s", result.fail_reason, "\n".join(lines), log=False)
1688 a8083063 Iustin Pop
1689 a8083063 Iustin Pop
1690 3b721842 Michael Hanselmann
def _GetBlockDevSymlinkPath(instance_name, idx, _dir=None):
1691 3b721842 Michael Hanselmann
  """Returns symlink path for block device.
1692 3b721842 Michael Hanselmann

1693 3b721842 Michael Hanselmann
  """
1694 3b721842 Michael Hanselmann
  if _dir is None:
1695 3b721842 Michael Hanselmann
    _dir = pathutils.DISK_LINKS_DIR
1696 3b721842 Michael Hanselmann
1697 3b721842 Michael Hanselmann
  return utils.PathJoin(_dir,
1698 3b721842 Michael Hanselmann
                        ("%s%s%s" %
1699 3b721842 Michael Hanselmann
                         (instance_name, constants.DISK_SEPARATOR, idx)))
1700 5282084b Iustin Pop
1701 5282084b Iustin Pop
1702 5282084b Iustin Pop
def _SymlinkBlockDev(instance_name, device_path, idx):
1703 9332fd8a Iustin Pop
  """Set up symlinks to a instance's block device.
1704 9332fd8a Iustin Pop

1705 9332fd8a Iustin Pop
  This is an auxiliary function run when an instance is start (on the primary
1706 9332fd8a Iustin Pop
  node) or when an instance is migrated (on the target node).
1707 9332fd8a Iustin Pop

1708 9332fd8a Iustin Pop

1709 5282084b Iustin Pop
  @param instance_name: the name of the target instance
1710 5282084b Iustin Pop
  @param device_path: path of the physical block device, on the node
1711 5282084b Iustin Pop
  @param idx: the disk index
1712 5282084b Iustin Pop
  @return: absolute path to the disk's symlink
1713 9332fd8a Iustin Pop

1714 9332fd8a Iustin Pop
  """
1715 5282084b Iustin Pop
  link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1716 9332fd8a Iustin Pop
  try:
1717 9332fd8a Iustin Pop
    os.symlink(device_path, link_name)
1718 5282084b Iustin Pop
  except OSError, err:
1719 5282084b Iustin Pop
    if err.errno == errno.EEXIST:
1720 9332fd8a Iustin Pop
      if (not os.path.islink(link_name) or
1721 9332fd8a Iustin Pop
          os.readlink(link_name) != device_path):
1722 9332fd8a Iustin Pop
        os.remove(link_name)
1723 9332fd8a Iustin Pop
        os.symlink(device_path, link_name)
1724 9332fd8a Iustin Pop
    else:
1725 9332fd8a Iustin Pop
      raise
1726 9332fd8a Iustin Pop
1727 9332fd8a Iustin Pop
  return link_name
1728 9332fd8a Iustin Pop
1729 9332fd8a Iustin Pop
1730 5282084b Iustin Pop
def _RemoveBlockDevLinks(instance_name, disks):
1731 3c9c571d Iustin Pop
  """Remove the block device symlinks belonging to the given instance.
1732 3c9c571d Iustin Pop

1733 3c9c571d Iustin Pop
  """
1734 29921401 Iustin Pop
  for idx, _ in enumerate(disks):
1735 5282084b Iustin Pop
    link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1736 5282084b Iustin Pop
    if os.path.islink(link_name):
1737 3c9c571d Iustin Pop
      try:
1738 03dfa658 Iustin Pop
        os.remove(link_name)
1739 03dfa658 Iustin Pop
      except OSError:
1740 03dfa658 Iustin Pop
        logging.exception("Can't remove symlink '%s'", link_name)
1741 3c9c571d Iustin Pop
1742 3c9c571d Iustin Pop
1743 66d3d195 Dimitris Aragiorgis
def _CalculateDeviceURI(instance, disk, device):
1744 66d3d195 Dimitris Aragiorgis
  """Get the URI for the device.
1745 66d3d195 Dimitris Aragiorgis

1746 66d3d195 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
1747 66d3d195 Dimitris Aragiorgis
  @param instance: the instance which disk belongs to
1748 66d3d195 Dimitris Aragiorgis
  @type disk: L{objects.Disk}
1749 66d3d195 Dimitris Aragiorgis
  @param disk: the target disk object
1750 66d3d195 Dimitris Aragiorgis
  @type device: L{bdev.BlockDev}
1751 66d3d195 Dimitris Aragiorgis
  @param device: the corresponding BlockDevice
1752 66d3d195 Dimitris Aragiorgis
  @rtype: string
1753 66d3d195 Dimitris Aragiorgis
  @return: the device uri if any else None
1754 66d3d195 Dimitris Aragiorgis

1755 66d3d195 Dimitris Aragiorgis
  """
1756 66d3d195 Dimitris Aragiorgis
  access_mode = disk.params.get(constants.LDP_ACCESS,
1757 66d3d195 Dimitris Aragiorgis
                                constants.DISK_KERNELSPACE)
1758 66d3d195 Dimitris Aragiorgis
  if access_mode == constants.DISK_USERSPACE:
1759 66d3d195 Dimitris Aragiorgis
    # This can raise errors.BlockDeviceError
1760 66d3d195 Dimitris Aragiorgis
    return device.GetUserspaceAccessUri(instance.hypervisor)
1761 66d3d195 Dimitris Aragiorgis
  else:
1762 66d3d195 Dimitris Aragiorgis
    return None
1763 66d3d195 Dimitris Aragiorgis
1764 66d3d195 Dimitris Aragiorgis
1765 9332fd8a Iustin Pop
def _GatherAndLinkBlockDevs(instance):
1766 a8083063 Iustin Pop
  """Set up an instance's block device(s).
1767 a8083063 Iustin Pop

1768 a8083063 Iustin Pop
  This is run on the primary node at instance startup. The block
1769 a8083063 Iustin Pop
  devices must be already assembled.
1770 a8083063 Iustin Pop

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

1776 a8083063 Iustin Pop
  """
1777 a8083063 Iustin Pop
  block_devices = []
1778 9332fd8a Iustin Pop
  for idx, disk in enumerate(instance.disks):
1779 a8083063 Iustin Pop
    device = _RecursiveFindBD(disk)
1780 a8083063 Iustin Pop
    if device is None:
1781 a8083063 Iustin Pop
      raise errors.BlockDeviceError("Block device '%s' is not set up." %
1782 a8083063 Iustin Pop
                                    str(disk))
1783 a8083063 Iustin Pop
    device.Open()
1784 9332fd8a Iustin Pop
    try:
1785 5282084b Iustin Pop
      link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
1786 9332fd8a Iustin Pop
    except OSError, e:
1787 9332fd8a Iustin Pop
      raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
1788 9332fd8a Iustin Pop
                                    e.strerror)
1789 66d3d195 Dimitris Aragiorgis
    uri = _CalculateDeviceURI(instance, disk, device)
1790 9332fd8a Iustin Pop
1791 66d3d195 Dimitris Aragiorgis
    block_devices.append((disk, link_name, uri))
1792 9332fd8a Iustin Pop
1793 a8083063 Iustin Pop
  return block_devices
1794 a8083063 Iustin Pop
1795 a8083063 Iustin Pop
1796 1fa6fcba Michele Tartara
def StartInstance(instance, startup_paused, reason, store_reason=True):
1797 a8083063 Iustin Pop
  """Start an instance.
1798 a8083063 Iustin Pop

1799 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1800 e69d05fd Iustin Pop
  @param instance: the instance object
1801 323f9095 Stephen Shirley
  @type startup_paused: bool
1802 323f9095 Stephen Shirley
  @param instance: pause instance at startup?
1803 1fa6fcba Michele Tartara
  @type reason: list of reasons
1804 1fa6fcba Michele Tartara
  @param reason: the reason trail for this startup
1805 1fa6fcba Michele Tartara
  @type store_reason: boolean
1806 1fa6fcba Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1807 c26a6bd2 Iustin Pop
  @rtype: None
1808 a8083063 Iustin Pop

1809 098c0958 Michael Hanselmann
  """
1810 3361ab37 Helga Velroyen
  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
1811 3361ab37 Helga Velroyen
                                                   instance.hvparams)
1812 a8083063 Iustin Pop
1813 a8083063 Iustin Pop
  if instance.name in running_instances:
1814 c26a6bd2 Iustin Pop
    logging.info("Instance %s already running, not starting", instance.name)
1815 c26a6bd2 Iustin Pop
    return
1816 a8083063 Iustin Pop
1817 a8083063 Iustin Pop
  try:
1818 ec596c24 Iustin Pop
    block_devices = _GatherAndLinkBlockDevs(instance)
1819 ec596c24 Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
1820 323f9095 Stephen Shirley
    hyper.StartInstance(instance, block_devices, startup_paused)
1821 1fa6fcba Michele Tartara
    if store_reason:
1822 1fa6fcba Michele Tartara
      _StoreInstReasonTrail(instance.name, reason)
1823 ec596c24 Iustin Pop
  except errors.BlockDeviceError, err:
1824 2cc6781a Iustin Pop
    _Fail("Block device error: %s", err, exc=True)
1825 a8083063 Iustin Pop
  except errors.HypervisorError, err:
1826 5282084b Iustin Pop
    _RemoveBlockDevLinks(instance.name, instance.disks)
1827 2cc6781a Iustin Pop
    _Fail("Hypervisor error: %s", err, exc=True)
1828 a8083063 Iustin Pop
1829 a8083063 Iustin Pop
1830 1f350e0f Michele Tartara
def InstanceShutdown(instance, timeout, reason, store_reason=True):
1831 a8083063 Iustin Pop
  """Shut an instance down.
1832 a8083063 Iustin Pop

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

1835 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1836 e69d05fd Iustin Pop
  @param instance: the instance object
1837 6263189c Guido Trotter
  @type timeout: integer
1838 6263189c Guido Trotter
  @param timeout: maximum timeout for soft shutdown
1839 1f350e0f Michele Tartara
  @type reason: list of reasons
1840 1f350e0f Michele Tartara
  @param reason: the reason trail for this shutdown
1841 1f350e0f Michele Tartara
  @type store_reason: boolean
1842 1f350e0f Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1843 c26a6bd2 Iustin Pop
  @rtype: None
1844 a8083063 Iustin Pop

1845 098c0958 Michael Hanselmann
  """
1846 e69d05fd Iustin Pop
  hv_name = instance.hypervisor
1847 e4e9b806 Guido Trotter
  hyper = hypervisor.GetHypervisor(hv_name)
1848 c26a6bd2 Iustin Pop
  iname = instance.name
1849 a8083063 Iustin Pop
1850 3361ab37 Helga Velroyen
  if instance.name not in hyper.ListInstances(instance.hvparams):
1851 c26a6bd2 Iustin Pop
    logging.info("Instance %s not running, doing nothing", iname)
1852 c26a6bd2 Iustin Pop
    return
1853 a8083063 Iustin Pop
1854 3c0cdc83 Michael Hanselmann
  class _TryShutdown:
1855 3c0cdc83 Michael Hanselmann
    def __init__(self):
1856 3c0cdc83 Michael Hanselmann
      self.tried_once = False
1857 a8083063 Iustin Pop
1858 3c0cdc83 Michael Hanselmann
    def __call__(self):
1859 3361ab37 Helga Velroyen
      if iname not in hyper.ListInstances(instance.hvparams):
1860 3c0cdc83 Michael Hanselmann
        return
1861 3c0cdc83 Michael Hanselmann
1862 3c0cdc83 Michael Hanselmann
      try:
1863 3c0cdc83 Michael Hanselmann
        hyper.StopInstance(instance, retry=self.tried_once)
1864 1f350e0f Michele Tartara
        if store_reason:
1865 1f350e0f Michele Tartara
          _StoreInstReasonTrail(instance.name, reason)
1866 3c0cdc83 Michael Hanselmann
      except errors.HypervisorError, err:
1867 3361ab37 Helga Velroyen
        if iname not in hyper.ListInstances(instance.hvparams):
1868 3c0cdc83 Michael Hanselmann
          # if the instance is no longer existing, consider this a
1869 3c0cdc83 Michael Hanselmann
          # success and go to cleanup
1870 3c0cdc83 Michael Hanselmann
          return
1871 3c0cdc83 Michael Hanselmann
1872 3c0cdc83 Michael Hanselmann
        _Fail("Failed to stop instance %s: %s", iname, err)
1873 3c0cdc83 Michael Hanselmann
1874 3c0cdc83 Michael Hanselmann
      self.tried_once = True
1875 3c0cdc83 Michael Hanselmann
1876 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
1877 3c0cdc83 Michael Hanselmann
1878 3c0cdc83 Michael Hanselmann
  try:
1879 3c0cdc83 Michael Hanselmann
    utils.Retry(_TryShutdown(), 5, timeout)
1880 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
1881 a8083063 Iustin Pop
    # the shutdown did not succeed
1882 e4e9b806 Guido Trotter
    logging.error("Shutdown of '%s' unsuccessful, forcing", iname)
1883 a8083063 Iustin Pop
1884 a8083063 Iustin Pop
    try:
1885 a8083063 Iustin Pop
      hyper.StopInstance(instance, force=True)
1886 a8083063 Iustin Pop
    except errors.HypervisorError, err:
1887 3361ab37 Helga Velroyen
      if iname in hyper.ListInstances(instance.hvparams):
1888 3782acd7 Iustin Pop
        # only raise an error if the instance still exists, otherwise
1889 3782acd7 Iustin Pop
        # the error could simply be "instance ... unknown"!
1890 3782acd7 Iustin Pop
        _Fail("Failed to force stop instance %s: %s", iname, err)
1891 a8083063 Iustin Pop
1892 a8083063 Iustin Pop
    time.sleep(1)
1893 3c0cdc83 Michael Hanselmann
1894 3361ab37 Helga Velroyen
    if iname in hyper.ListInstances(instance.hvparams):
1895 c26a6bd2 Iustin Pop
      _Fail("Could not shutdown instance %s even by destroy", iname)
1896 3c9c571d Iustin Pop
1897 f28ec899 Guido Trotter
  try:
1898 f28ec899 Guido Trotter
    hyper.CleanupInstance(instance.name)
1899 f28ec899 Guido Trotter
  except errors.HypervisorError, err:
1900 f28ec899 Guido Trotter
    logging.warning("Failed to execute post-shutdown cleanup step: %s", err)
1901 f28ec899 Guido Trotter
1902 c26a6bd2 Iustin Pop
  _RemoveBlockDevLinks(iname, instance.disks)
1903 a8083063 Iustin Pop
1904 a8083063 Iustin Pop
1905 55cec070 Michele Tartara
def InstanceReboot(instance, reboot_type, shutdown_timeout, reason):
1906 007a2f3e Alexander Schreiber
  """Reboot an instance.
1907 007a2f3e Alexander Schreiber

1908 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1909 10c2650b Iustin Pop
  @param instance: the instance object to reboot
1910 10c2650b Iustin Pop
  @type reboot_type: str
1911 10c2650b Iustin Pop
  @param reboot_type: the type of reboot, one the following
1912 10c2650b Iustin Pop
    constants:
1913 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_SOFT}: only reboot the
1914 10c2650b Iustin Pop
        instance OS, do not recreate the VM
1915 10c2650b Iustin Pop
      - L{constants.INSTANCE_REBOOT_HARD}: tear down and
1916 10c2650b Iustin Pop
        restart the VM (at the hypervisor level)
1917 73e5a4f4 Iustin Pop
      - the other reboot type (L{constants.INSTANCE_REBOOT_FULL}) is
1918 73e5a4f4 Iustin Pop
        not accepted here, since that mode is handled differently, in
1919 73e5a4f4 Iustin Pop
        cmdlib, and translates into full stop and start of the
1920 73e5a4f4 Iustin Pop
        instance (instead of a call_instance_reboot RPC)
1921 23057d29 Michael Hanselmann
  @type shutdown_timeout: integer
1922 23057d29 Michael Hanselmann
  @param shutdown_timeout: maximum timeout for soft shutdown
1923 55cec070 Michele Tartara
  @type reason: list of reasons
1924 55cec070 Michele Tartara
  @param reason: the reason trail for this reboot
1925 c26a6bd2 Iustin Pop
  @rtype: None
1926 007a2f3e Alexander Schreiber

1927 007a2f3e Alexander Schreiber
  """
1928 3361ab37 Helga Velroyen
  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
1929 3361ab37 Helga Velroyen
                                                   instance.hvparams)
1930 007a2f3e Alexander Schreiber
1931 007a2f3e Alexander Schreiber
  if instance.name not in running_instances:
1932 2cc6781a Iustin Pop
    _Fail("Cannot reboot instance %s that is not running", instance.name)
1933 007a2f3e Alexander Schreiber
1934 e69d05fd Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1935 007a2f3e Alexander Schreiber
  if reboot_type == constants.INSTANCE_REBOOT_SOFT:
1936 007a2f3e Alexander Schreiber
    try:
1937 007a2f3e Alexander Schreiber
      hyper.RebootInstance(instance)
1938 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1939 2cc6781a Iustin Pop
      _Fail("Failed to soft reboot instance %s: %s", instance.name, err)
1940 007a2f3e Alexander Schreiber
  elif reboot_type == constants.INSTANCE_REBOOT_HARD:
1941 007a2f3e Alexander Schreiber
    try:
1942 1f350e0f Michele Tartara
      InstanceShutdown(instance, shutdown_timeout, reason, store_reason=False)
1943 1fa6fcba Michele Tartara
      result = StartInstance(instance, False, reason, store_reason=False)
1944 55cec070 Michele Tartara
      _StoreInstReasonTrail(instance.name, reason)
1945 4a90bd4f Michele Tartara
      return result
1946 007a2f3e Alexander Schreiber
    except errors.HypervisorError, err:
1947 2cc6781a Iustin Pop
      _Fail("Failed to hard reboot instance %s: %s", instance.name, err)
1948 007a2f3e Alexander Schreiber
  else:
1949 2cc6781a Iustin Pop
    _Fail("Invalid reboot_type received: %s", reboot_type)
1950 007a2f3e Alexander Schreiber
1951 007a2f3e Alexander Schreiber
1952 ebe466d8 Guido Trotter
def InstanceBalloonMemory(instance, memory):
1953 ebe466d8 Guido Trotter
  """Resize an instance's memory.
1954 ebe466d8 Guido Trotter

1955 ebe466d8 Guido Trotter
  @type instance: L{objects.Instance}
1956 ebe466d8 Guido Trotter
  @param instance: the instance object
1957 ebe466d8 Guido Trotter
  @type memory: int
1958 ebe466d8 Guido Trotter
  @param memory: new memory amount in MB
1959 ebe466d8 Guido Trotter
  @rtype: None
1960 ebe466d8 Guido Trotter

1961 ebe466d8 Guido Trotter
  """
1962 ebe466d8 Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1963 3361ab37 Helga Velroyen
  running = hyper.ListInstances(instance.hvparams)
1964 ebe466d8 Guido Trotter
  if instance.name not in running:
1965 ebe466d8 Guido Trotter
    logging.info("Instance %s is not running, cannot balloon", instance.name)
1966 ebe466d8 Guido Trotter
    return
1967 ebe466d8 Guido Trotter
  try:
1968 ebe466d8 Guido Trotter
    hyper.BalloonInstanceMemory(instance, memory)
1969 ebe466d8 Guido Trotter
  except errors.HypervisorError, err:
1970 ebe466d8 Guido Trotter
    _Fail("Failed to balloon instance memory: %s", err, exc=True)
1971 ebe466d8 Guido Trotter
1972 ebe466d8 Guido Trotter
1973 6906a9d8 Guido Trotter
def MigrationInfo(instance):
1974 6906a9d8 Guido Trotter
  """Gather information about an instance to be migrated.
1975 6906a9d8 Guido Trotter

1976 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1977 6906a9d8 Guido Trotter
  @param instance: the instance definition
1978 6906a9d8 Guido Trotter

1979 6906a9d8 Guido Trotter
  """
1980 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1981 cd42d0ad Guido Trotter
  try:
1982 cd42d0ad Guido Trotter
    info = hyper.MigrationInfo(instance)
1983 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
1984 2cc6781a Iustin Pop
    _Fail("Failed to fetch migration information: %s", err, exc=True)
1985 c26a6bd2 Iustin Pop
  return info
1986 6906a9d8 Guido Trotter
1987 6906a9d8 Guido Trotter
1988 6906a9d8 Guido Trotter
def AcceptInstance(instance, info, target):
1989 6906a9d8 Guido Trotter
  """Prepare the node to accept an instance.
1990 6906a9d8 Guido Trotter

1991 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1992 6906a9d8 Guido Trotter
  @param instance: the instance definition
1993 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
1994 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
1995 6906a9d8 Guido Trotter
  @type target: string
1996 6906a9d8 Guido Trotter
  @param target: target host (usually ip), on this node
1997 6906a9d8 Guido Trotter

1998 6906a9d8 Guido Trotter
  """
1999 77fcff4a Apollon Oikonomopoulos
  # TODO: why is this required only for DTS_EXT_MIRROR?
2000 77fcff4a Apollon Oikonomopoulos
  if instance.disk_template in constants.DTS_EXT_MIRROR:
2001 77fcff4a Apollon Oikonomopoulos
    # Create the symlinks, as the disks are not active
2002 77fcff4a Apollon Oikonomopoulos
    # in any way
2003 77fcff4a Apollon Oikonomopoulos
    try:
2004 77fcff4a Apollon Oikonomopoulos
      _GatherAndLinkBlockDevs(instance)
2005 77fcff4a Apollon Oikonomopoulos
    except errors.BlockDeviceError, err:
2006 77fcff4a Apollon Oikonomopoulos
      _Fail("Block device error: %s", err, exc=True)
2007 77fcff4a Apollon Oikonomopoulos
2008 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2009 cd42d0ad Guido Trotter
  try:
2010 cd42d0ad Guido Trotter
    hyper.AcceptInstance(instance, info, target)
2011 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2012 77fcff4a Apollon Oikonomopoulos
    if instance.disk_template in constants.DTS_EXT_MIRROR:
2013 77fcff4a Apollon Oikonomopoulos
      _RemoveBlockDevLinks(instance.name, instance.disks)
2014 2cc6781a Iustin Pop
    _Fail("Failed to accept instance: %s", err, exc=True)
2015 6906a9d8 Guido Trotter
2016 6906a9d8 Guido Trotter
2017 6a1434d7 Andrea Spadaccini
def FinalizeMigrationDst(instance, info, success):
2018 6906a9d8 Guido Trotter
  """Finalize any preparation to accept an instance.
2019 6906a9d8 Guido Trotter

2020 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2021 6906a9d8 Guido Trotter
  @param instance: the instance definition
2022 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
2023 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
2024 6906a9d8 Guido Trotter
  @type success: boolean
2025 6906a9d8 Guido Trotter
  @param success: whether the migration was a success or a failure
2026 6906a9d8 Guido Trotter

2027 6906a9d8 Guido Trotter
  """
2028 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2029 cd42d0ad Guido Trotter
  try:
2030 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationDst(instance, info, success)
2031 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2032 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize migration on the target node: %s", err, exc=True)
2033 6906a9d8 Guido Trotter
2034 6906a9d8 Guido Trotter
2035 bc0a2284 Helga Velroyen
def MigrateInstance(cluster_name, instance, target, live):
2036 2a10865c Iustin Pop
  """Migrates an instance to another node.
2037 2a10865c Iustin Pop

2038 bc0a2284 Helga Velroyen
  @type cluster_name: string
2039 bc0a2284 Helga Velroyen
  @param cluster_name: name of the cluster
2040 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
2041 9f0e6b37 Iustin Pop
  @param instance: the instance definition
2042 9f0e6b37 Iustin Pop
  @type target: string
2043 9f0e6b37 Iustin Pop
  @param target: the target node name
2044 9f0e6b37 Iustin Pop
  @type live: boolean
2045 9f0e6b37 Iustin Pop
  @param live: whether the migration should be done live or not (the
2046 9f0e6b37 Iustin Pop
      interpretation of this parameter is left to the hypervisor)
2047 c03fe62b Andrea Spadaccini
  @raise RPCFail: if migration fails for some reason
2048 9f0e6b37 Iustin Pop

2049 2a10865c Iustin Pop
  """
2050 53c776b5 Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2051 2a10865c Iustin Pop
2052 2a10865c Iustin Pop
  try:
2053 bc0a2284 Helga Velroyen
    hyper.MigrateInstance(cluster_name, instance, target, live)
2054 2a10865c Iustin Pop
  except errors.HypervisorError, err:
2055 2cc6781a Iustin Pop
    _Fail("Failed to migrate instance: %s", err, exc=True)
2056 2a10865c Iustin Pop
2057 2a10865c Iustin Pop
2058 6a1434d7 Andrea Spadaccini
def FinalizeMigrationSource(instance, success, live):
2059 6a1434d7 Andrea Spadaccini
  """Finalize the instance migration on the source node.
2060 6a1434d7 Andrea Spadaccini

2061 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2062 6a1434d7 Andrea Spadaccini
  @param instance: the instance definition of the migrated instance
2063 6a1434d7 Andrea Spadaccini
  @type success: bool
2064 6a1434d7 Andrea Spadaccini
  @param success: whether the migration succeeded or not
2065 6a1434d7 Andrea Spadaccini
  @type live: bool
2066 6a1434d7 Andrea Spadaccini
  @param live: whether the user requested a live migration or not
2067 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the execution fails for some reason
2068 6a1434d7 Andrea Spadaccini

2069 6a1434d7 Andrea Spadaccini
  """
2070 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2071 6a1434d7 Andrea Spadaccini
2072 6a1434d7 Andrea Spadaccini
  try:
2073 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationSource(instance, success, live)
2074 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2075 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize the migration on the source node: %s", err,
2076 6a1434d7 Andrea Spadaccini
          exc=True)
2077 6a1434d7 Andrea Spadaccini
2078 6a1434d7 Andrea Spadaccini
2079 6a1434d7 Andrea Spadaccini
def GetMigrationStatus(instance):
2080 6a1434d7 Andrea Spadaccini
  """Get the migration status
2081 6a1434d7 Andrea Spadaccini

2082 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2083 6a1434d7 Andrea Spadaccini
  @param instance: the instance that is being migrated
2084 6a1434d7 Andrea Spadaccini
  @rtype: L{objects.MigrationStatus}
2085 6a1434d7 Andrea Spadaccini
  @return: the status of the current migration (one of
2086 6a1434d7 Andrea Spadaccini
           L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2087 6a1434d7 Andrea Spadaccini
           progress info that can be retrieved from the hypervisor
2088 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the migration status cannot be retrieved
2089 6a1434d7 Andrea Spadaccini

2090 6a1434d7 Andrea Spadaccini
  """
2091 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2092 6a1434d7 Andrea Spadaccini
  try:
2093 6a1434d7 Andrea Spadaccini
    return hyper.GetMigrationStatus(instance)
2094 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2095 6a1434d7 Andrea Spadaccini
    _Fail("Failed to get migration status: %s", err, exc=True)
2096 6a1434d7 Andrea Spadaccini
2097 6a1434d7 Andrea Spadaccini
2098 c5708931 Dimitris Aragiorgis
def HotplugDevice(instance, action, dev_type, device, extra, seq):
2099 c5708931 Dimitris Aragiorgis
  """Hotplug a device
2100 c5708931 Dimitris Aragiorgis

2101 c5708931 Dimitris Aragiorgis
  Hotplug is currently supported only for KVM Hypervisor.
2102 c5708931 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
2103 c5708931 Dimitris Aragiorgis
  @param instance: the instance to which we hotplug a device
2104 c5708931 Dimitris Aragiorgis
  @type action: string
2105 c5708931 Dimitris Aragiorgis
  @param action: the hotplug action to perform
2106 c5708931 Dimitris Aragiorgis
  @type dev_type: string
2107 c5708931 Dimitris Aragiorgis
  @param dev_type: the device type to hotplug
2108 c5708931 Dimitris Aragiorgis
  @type device: either L{objects.NIC} or L{objects.Disk}
2109 c5708931 Dimitris Aragiorgis
  @param device: the device object to hotplug
2110 c5708931 Dimitris Aragiorgis
  @type extra: string
2111 c5708931 Dimitris Aragiorgis
  @param extra: extra info used by hotplug code (e.g. disk link)
2112 c5708931 Dimitris Aragiorgis
  @type seq: int
2113 c5708931 Dimitris Aragiorgis
  @param seq: the index of the device from master perspective
2114 c5708931 Dimitris Aragiorgis
  @raise RPCFail: in case instance does not have KVM hypervisor
2115 c5708931 Dimitris Aragiorgis

2116 c5708931 Dimitris Aragiorgis
  """
2117 c5708931 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2118 c5708931 Dimitris Aragiorgis
  try:
2119 50e0f1d9 Dimitris Aragiorgis
    hyper.VerifyHotplugSupport(instance, action, dev_type)
2120 50e0f1d9 Dimitris Aragiorgis
  except errors.HotplugError, err:
2121 c5708931 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2122 c5708931 Dimitris Aragiorgis
2123 c5708931 Dimitris Aragiorgis
  if action == constants.HOTPLUG_ACTION_ADD:
2124 c5708931 Dimitris Aragiorgis
    fn = hyper.HotAddDevice
2125 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_REMOVE:
2126 c5708931 Dimitris Aragiorgis
    fn = hyper.HotDelDevice
2127 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_MODIFY:
2128 c5708931 Dimitris Aragiorgis
    fn = hyper.HotModDevice
2129 c5708931 Dimitris Aragiorgis
  else:
2130 c5708931 Dimitris Aragiorgis
    assert action in constants.HOTPLUG_ALL_ACTIONS
2131 c5708931 Dimitris Aragiorgis
2132 c5708931 Dimitris Aragiorgis
  return fn(instance, dev_type, device, extra, seq)
2133 c5708931 Dimitris Aragiorgis
2134 c5708931 Dimitris Aragiorgis
2135 24711492 Dimitris Aragiorgis
def HotplugSupported(instance):
2136 24711492 Dimitris Aragiorgis
  """Checks if hotplug is generally supported.
2137 24711492 Dimitris Aragiorgis

2138 24711492 Dimitris Aragiorgis
  """
2139 24711492 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2140 24711492 Dimitris Aragiorgis
  try:
2141 24711492 Dimitris Aragiorgis
    hyper.HotplugSupported(instance)
2142 24711492 Dimitris Aragiorgis
  except errors.HotplugError, err:
2143 24711492 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2144 24711492 Dimitris Aragiorgis
2145 24711492 Dimitris Aragiorgis
2146 ee1478e5 Bernardo Dal Seno
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
2147 a8083063 Iustin Pop
  """Creates a block device for an instance.
2148 a8083063 Iustin Pop

2149 b1206984 Iustin Pop
  @type disk: L{objects.Disk}
2150 b1206984 Iustin Pop
  @param disk: the object describing the disk we should create
2151 b1206984 Iustin Pop
  @type size: int
2152 b1206984 Iustin Pop
  @param size: the size of the physical underlying device, in MiB
2153 b1206984 Iustin Pop
  @type owner: str
2154 b1206984 Iustin Pop
  @param owner: the name of the instance for which disk is created,
2155 b1206984 Iustin Pop
      used for device cache data
2156 b1206984 Iustin Pop
  @type on_primary: boolean
2157 b1206984 Iustin Pop
  @param on_primary:  indicates if it is the primary node or not
2158 b1206984 Iustin Pop
  @type info: string
2159 b1206984 Iustin Pop
  @param info: string that will be sent to the physical device
2160 b1206984 Iustin Pop
      creation, used for example to set (LVM) tags on LVs
2161 ee1478e5 Bernardo Dal Seno
  @type excl_stor: boolean
2162 ee1478e5 Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
2163 b1206984 Iustin Pop

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

2168 a8083063 Iustin Pop
  """
2169 d0c8c01d Iustin Pop
  # TODO: remove the obsolete "size" argument
2170 b459a848 Andrea Spadaccini
  # pylint: disable=W0613
2171 a8083063 Iustin Pop
  clist = []
2172 a8083063 Iustin Pop
  if disk.children:
2173 a8083063 Iustin Pop
    for child in disk.children:
2174 1063abd1 Iustin Pop
      try:
2175 1063abd1 Iustin Pop
        crdev = _RecursiveAssembleBD(child, owner, on_primary)
2176 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2177 2cc6781a Iustin Pop
        _Fail("Can't assemble device %s: %s", child, err)
2178 a8083063 Iustin Pop
      if on_primary or disk.AssembleOnSecondary():
2179 a8083063 Iustin Pop
        # we need the children open in case the device itself has to
2180 a8083063 Iustin Pop
        # be assembled
2181 1063abd1 Iustin Pop
        try:
2182 b459a848 Andrea Spadaccini
          # pylint: disable=E1103
2183 1063abd1 Iustin Pop
          crdev.Open()
2184 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
2185 2cc6781a Iustin Pop
          _Fail("Can't make child '%s' read-write: %s", child, err)
2186 a8083063 Iustin Pop
      clist.append(crdev)
2187 a8083063 Iustin Pop
2188 dab69e97 Iustin Pop
  try:
2189 ee1478e5 Bernardo Dal Seno
    device = bdev.Create(disk, clist, excl_stor)
2190 1063abd1 Iustin Pop
  except errors.BlockDeviceError, err:
2191 2cc6781a Iustin Pop
    _Fail("Can't create block device: %s", err)
2192 6c626518 Iustin Pop
2193 a8083063 Iustin Pop
  if on_primary or disk.AssembleOnSecondary():
2194 1063abd1 Iustin Pop
    try:
2195 1063abd1 Iustin Pop
      device.Assemble()
2196 1063abd1 Iustin Pop
    except errors.BlockDeviceError, err:
2197 2cc6781a Iustin Pop
      _Fail("Can't assemble device after creation, unusual event: %s", err)
2198 a8083063 Iustin Pop
    if on_primary or disk.OpenOnSecondary():
2199 1063abd1 Iustin Pop
      try:
2200 1063abd1 Iustin Pop
        device.Open(force=True)
2201 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2202 2cc6781a Iustin Pop
        _Fail("Can't make device r/w after creation, unusual event: %s", err)
2203 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(device.dev_path, owner,
2204 3f78eef2 Iustin Pop
                                on_primary, disk.iv_name)
2205 a0c3fea1 Michael Hanselmann
2206 a0c3fea1 Michael Hanselmann
  device.SetInfo(info)
2207 a0c3fea1 Michael Hanselmann
2208 c26a6bd2 Iustin Pop
  return device.unique_id
2209 a8083063 Iustin Pop
2210 a8083063 Iustin Pop
2211 da63bb4e René Nussbaumer
def _WipeDevice(path, offset, size):
2212 69dd363f René Nussbaumer
  """This function actually wipes the device.
2213 69dd363f René Nussbaumer

2214 69dd363f René Nussbaumer
  @param path: The path to the device to wipe
2215 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
2216 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
2217 69dd363f René Nussbaumer

2218 69dd363f René Nussbaumer
  """
2219 0188611b Michael Hanselmann
  # Internal sizes are always in Mebibytes; if the following "dd" command
2220 0188611b Michael Hanselmann
  # should use a different block size the offset and size given to this
2221 0188611b Michael Hanselmann
  # function must be adjusted accordingly before being passed to "dd".
2222 0188611b Michael Hanselmann
  block_size = 1024 * 1024
2223 0188611b Michael Hanselmann
2224 da63bb4e René Nussbaumer
  cmd = [constants.DD_CMD, "if=/dev/zero", "seek=%d" % offset,
2225 0188611b Michael Hanselmann
         "bs=%s" % block_size, "oflag=direct", "of=%s" % path,
2226 da63bb4e René Nussbaumer
         "count=%d" % size]
2227 da63bb4e René Nussbaumer
  result = utils.RunCmd(cmd)
2228 69dd363f René Nussbaumer
2229 69dd363f René Nussbaumer
  if result.failed:
2230 69dd363f René Nussbaumer
    _Fail("Wipe command '%s' exited with error: %s; output: %s", result.cmd,
2231 69dd363f René Nussbaumer
          result.fail_reason, result.output)
2232 69dd363f René Nussbaumer
2233 69dd363f René Nussbaumer
2234 da63bb4e René Nussbaumer
def BlockdevWipe(disk, offset, size):
2235 69dd363f René Nussbaumer
  """Wipes a block device.
2236 69dd363f René Nussbaumer

2237 69dd363f René Nussbaumer
  @type disk: L{objects.Disk}
2238 69dd363f René Nussbaumer
  @param disk: the disk object we want to wipe
2239 da63bb4e René Nussbaumer
  @type offset: int
2240 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
2241 da63bb4e René Nussbaumer
  @type size: int
2242 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
2243 69dd363f René Nussbaumer

2244 69dd363f René Nussbaumer
  """
2245 69dd363f René Nussbaumer
  try:
2246 69dd363f René Nussbaumer
    rdev = _RecursiveFindBD(disk)
2247 da63bb4e René Nussbaumer
  except errors.BlockDeviceError:
2248 da63bb4e René Nussbaumer
    rdev = None
2249 da63bb4e René Nussbaumer
2250 da63bb4e René Nussbaumer
  if not rdev:
2251 da63bb4e René Nussbaumer
    _Fail("Cannot execute wipe for device %s: device not found", disk.iv_name)
2252 da63bb4e René Nussbaumer
2253 da63bb4e René Nussbaumer
  # Do cross verify some of the parameters
2254 0188611b Michael Hanselmann
  if offset < 0:
2255 0188611b Michael Hanselmann
    _Fail("Negative offset")
2256 0188611b Michael Hanselmann
  if size < 0:
2257 0188611b Michael Hanselmann
    _Fail("Negative size")
2258 da63bb4e René Nussbaumer
  if offset > rdev.size:
2259 da63bb4e René Nussbaumer
    _Fail("Offset is bigger than device size")
2260 da63bb4e René Nussbaumer
  if (offset + size) > rdev.size:
2261 da63bb4e René Nussbaumer
    _Fail("The provided offset and size to wipe is bigger than device size")
2262 69dd363f René Nussbaumer
2263 da63bb4e René Nussbaumer
  _WipeDevice(rdev.dev_path, offset, size)
2264 69dd363f René Nussbaumer
2265 69dd363f René Nussbaumer
2266 5119c79e René Nussbaumer
def BlockdevPauseResumeSync(disks, pause):
2267 5119c79e René Nussbaumer
  """Pause or resume the sync of the block device.
2268 5119c79e René Nussbaumer

2269 0f39886a René Nussbaumer
  @type disks: list of L{objects.Disk}
2270 0f39886a René Nussbaumer
  @param disks: the disks object we want to pause/resume
2271 5119c79e René Nussbaumer
  @type pause: bool
2272 5119c79e René Nussbaumer
  @param pause: Wheater to pause or resume
2273 5119c79e René Nussbaumer

2274 5119c79e René Nussbaumer
  """
2275 5119c79e René Nussbaumer
  success = []
2276 5119c79e René Nussbaumer
  for disk in disks:
2277 5119c79e René Nussbaumer
    try:
2278 5119c79e René Nussbaumer
      rdev = _RecursiveFindBD(disk)
2279 5119c79e René Nussbaumer
    except errors.BlockDeviceError:
2280 5119c79e René Nussbaumer
      rdev = None
2281 5119c79e René Nussbaumer
2282 5119c79e René Nussbaumer
    if not rdev:
2283 5119c79e René Nussbaumer
      success.append((False, ("Cannot change sync for device %s:"
2284 5119c79e René Nussbaumer
                              " device not found" % disk.iv_name)))
2285 5119c79e René Nussbaumer
      continue
2286 5119c79e René Nussbaumer
2287 5119c79e René Nussbaumer
    result = rdev.PauseResumeSync(pause)
2288 5119c79e René Nussbaumer
2289 5119c79e René Nussbaumer
    if result:
2290 5119c79e René Nussbaumer
      success.append((result, None))
2291 5119c79e René Nussbaumer
    else:
2292 5119c79e René Nussbaumer
      if pause:
2293 5119c79e René Nussbaumer
        msg = "Pause"
2294 5119c79e René Nussbaumer
      else:
2295 5119c79e René Nussbaumer
        msg = "Resume"
2296 5119c79e René Nussbaumer
      success.append((result, "%s for device %s failed" % (msg, disk.iv_name)))
2297 5119c79e René Nussbaumer
2298 5119c79e René Nussbaumer
  return success
2299 5119c79e René Nussbaumer
2300 5119c79e René Nussbaumer
2301 821d1bd1 Iustin Pop
def BlockdevRemove(disk):
2302 a8083063 Iustin Pop
  """Remove a block device.
2303 a8083063 Iustin Pop

2304 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
2305 10c2650b Iustin Pop

2306 c41eea6e Iustin Pop
  @type disk: L{objects.Disk}
2307 10c2650b Iustin Pop
  @param disk: the disk object we should remove
2308 10c2650b Iustin Pop
  @rtype: boolean
2309 10c2650b Iustin Pop
  @return: the success of the operation
2310 a8083063 Iustin Pop

2311 a8083063 Iustin Pop
  """
2312 e1bc0878 Iustin Pop
  msgs = []
2313 a8083063 Iustin Pop
  try:
2314 bca2e7f4 Iustin Pop
    rdev = _RecursiveFindBD(disk)
2315 a8083063 Iustin Pop
  except errors.BlockDeviceError, err:
2316 a8083063 Iustin Pop
    # probably can't attach
2317 18682bca Iustin Pop
    logging.info("Can't attach to device %s in remove", disk)
2318 a8083063 Iustin Pop
    rdev = None
2319 a8083063 Iustin Pop
  if rdev is not None:
2320 3f78eef2 Iustin Pop
    r_path = rdev.dev_path
2321 b3ae67d7 Dimitris Aragiorgis
2322 b3ae67d7 Dimitris Aragiorgis
    def _TryRemove():
2323 b3ae67d7 Dimitris Aragiorgis
      try:
2324 b3ae67d7 Dimitris Aragiorgis
        rdev.Remove()
2325 b3ae67d7 Dimitris Aragiorgis
        return []
2326 b3ae67d7 Dimitris Aragiorgis
      except errors.BlockDeviceError, err:
2327 b3ae67d7 Dimitris Aragiorgis
        return [str(err)]
2328 b3ae67d7 Dimitris Aragiorgis
2329 b3ae67d7 Dimitris Aragiorgis
    msgs.extend(utils.SimpleRetry([], _TryRemove,
2330 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_INTERVAL,
2331 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_TIMEOUT))
2332 b3ae67d7 Dimitris Aragiorgis
2333 c26a6bd2 Iustin Pop
    if not msgs:
2334 3f78eef2 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2335 e1bc0878 Iustin Pop
2336 a8083063 Iustin Pop
  if disk.children:
2337 a8083063 Iustin Pop
    for child in disk.children:
2338 c26a6bd2 Iustin Pop
      try:
2339 c26a6bd2 Iustin Pop
        BlockdevRemove(child)
2340 c26a6bd2 Iustin Pop
      except RPCFail, err:
2341 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2342 e1bc0878 Iustin Pop
2343 c26a6bd2 Iustin Pop
  if msgs:
2344 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2345 afdc3985 Iustin Pop
2346 a8083063 Iustin Pop
2347 3f78eef2 Iustin Pop
def _RecursiveAssembleBD(disk, owner, as_primary):
2348 a8083063 Iustin Pop
  """Activate a block device for an instance.
2349 a8083063 Iustin Pop

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

2352 10c2650b Iustin Pop
  @note: this function is called recursively.
2353 a8083063 Iustin Pop

2354 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2355 10c2650b Iustin Pop
  @param disk: the disk we try to assemble
2356 10c2650b Iustin Pop
  @type owner: str
2357 10c2650b Iustin Pop
  @param owner: the name of the instance which owns the disk
2358 10c2650b Iustin Pop
  @type as_primary: boolean
2359 10c2650b Iustin Pop
  @param as_primary: if we should make the block device
2360 10c2650b Iustin Pop
      read/write
2361 a8083063 Iustin Pop

2362 10c2650b Iustin Pop
  @return: the assembled device or None (in case no device
2363 10c2650b Iustin Pop
      was assembled)
2364 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: in case there is an error
2365 10c2650b Iustin Pop
      during the activation of the children or the device
2366 10c2650b Iustin Pop
      itself
2367 a8083063 Iustin Pop

2368 a8083063 Iustin Pop
  """
2369 a8083063 Iustin Pop
  children = []
2370 a8083063 Iustin Pop
  if disk.children:
2371 fc1dc9d7 Iustin Pop
    mcn = disk.ChildrenNeeded()
2372 fc1dc9d7 Iustin Pop
    if mcn == -1:
2373 fc1dc9d7 Iustin Pop
      mcn = 0 # max number of Nones allowed
2374 fc1dc9d7 Iustin Pop
    else:
2375 fc1dc9d7 Iustin Pop
      mcn = len(disk.children) - mcn # max number of Nones
2376 a8083063 Iustin Pop
    for chld_disk in disk.children:
2377 fc1dc9d7 Iustin Pop
      try:
2378 fc1dc9d7 Iustin Pop
        cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary)
2379 fc1dc9d7 Iustin Pop
      except errors.BlockDeviceError, err:
2380 7803d4d3 Iustin Pop
        if children.count(None) >= mcn:
2381 fc1dc9d7 Iustin Pop
          raise
2382 fc1dc9d7 Iustin Pop
        cdev = None
2383 1063abd1 Iustin Pop
        logging.error("Error in child activation (but continuing): %s",
2384 1063abd1 Iustin Pop
                      str(err))
2385 fc1dc9d7 Iustin Pop
      children.append(cdev)
2386 a8083063 Iustin Pop
2387 a8083063 Iustin Pop
  if as_primary or disk.AssembleOnSecondary():
2388 94dcbdb0 Andrea Spadaccini
    r_dev = bdev.Assemble(disk, children)
2389 a8083063 Iustin Pop
    result = r_dev
2390 a8083063 Iustin Pop
    if as_primary or disk.OpenOnSecondary():
2391 a8083063 Iustin Pop
      r_dev.Open()
2392 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(r_dev.dev_path, owner,
2393 3f78eef2 Iustin Pop
                                as_primary, disk.iv_name)
2394 3f78eef2 Iustin Pop
2395 a8083063 Iustin Pop
  else:
2396 a8083063 Iustin Pop
    result = True
2397 a8083063 Iustin Pop
  return result
2398 a8083063 Iustin Pop
2399 a8083063 Iustin Pop
2400 c417e115 Iustin Pop
def BlockdevAssemble(disk, owner, as_primary, idx):
2401 a8083063 Iustin Pop
  """Activate a block device for an instance.
2402 a8083063 Iustin Pop

2403 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
2404 a8083063 Iustin Pop

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

2409 a8083063 Iustin Pop
  """
2410 53c14ef1 Iustin Pop
  try:
2411 53c14ef1 Iustin Pop
    result = _RecursiveAssembleBD(disk, owner, as_primary)
2412 89ff748d Thomas Thrainer
    if isinstance(result, BlockDev):
2413 b459a848 Andrea Spadaccini
      # pylint: disable=E1103
2414 ff5def9b Dimitris Aragiorgis
      dev_path = result.dev_path
2415 ff5def9b Dimitris Aragiorgis
      link_name = None
2416 c417e115 Iustin Pop
      if as_primary:
2417 ff5def9b Dimitris Aragiorgis
        link_name = _SymlinkBlockDev(owner, dev_path, idx)
2418 ff5def9b Dimitris Aragiorgis
    elif result:
2419 ff5def9b Dimitris Aragiorgis
      return result, result
2420 ff5def9b Dimitris Aragiorgis
    else:
2421 ff5def9b Dimitris Aragiorgis
      _Fail("Unexpected result from _RecursiveAssembleBD")
2422 53c14ef1 Iustin Pop
  except errors.BlockDeviceError, err:
2423 afdc3985 Iustin Pop
    _Fail("Error while assembling disk: %s", err, exc=True)
2424 c417e115 Iustin Pop
  except OSError, err:
2425 c417e115 Iustin Pop
    _Fail("Error while symlinking disk: %s", err, exc=True)
2426 afdc3985 Iustin Pop
2427 ff5def9b Dimitris Aragiorgis
  return dev_path, link_name
2428 a8083063 Iustin Pop
2429 a8083063 Iustin Pop
2430 821d1bd1 Iustin Pop
def BlockdevShutdown(disk):
2431 a8083063 Iustin Pop
  """Shut down a block device.
2432 a8083063 Iustin Pop

2433 5bbd3f7f Michael Hanselmann
  First, if the device is assembled (Attach() is successful), then
2434 c41eea6e Iustin Pop
  the device is shutdown. Then the children of the device are
2435 c41eea6e Iustin Pop
  shutdown.
2436 a8083063 Iustin Pop

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

2441 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2442 10c2650b Iustin Pop
  @param disk: the description of the disk we should
2443 10c2650b Iustin Pop
      shutdown
2444 c26a6bd2 Iustin Pop
  @rtype: None
2445 10c2650b Iustin Pop

2446 a8083063 Iustin Pop
  """
2447 cacfd1fd Iustin Pop
  msgs = []
2448 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2449 a8083063 Iustin Pop
  if r_dev is not None:
2450 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
2451 cacfd1fd Iustin Pop
    try:
2452 746f7476 Iustin Pop
      r_dev.Shutdown()
2453 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2454 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
2455 cacfd1fd Iustin Pop
      msgs.append(str(err))
2456 746f7476 Iustin Pop
2457 a8083063 Iustin Pop
  if disk.children:
2458 a8083063 Iustin Pop
    for child in disk.children:
2459 c26a6bd2 Iustin Pop
      try:
2460 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
2461 c26a6bd2 Iustin Pop
      except RPCFail, err:
2462 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2463 746f7476 Iustin Pop
2464 c26a6bd2 Iustin Pop
  if msgs:
2465 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2466 a8083063 Iustin Pop
2467 a8083063 Iustin Pop
2468 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
2469 153d9724 Iustin Pop
  """Extend a mirrored block device.
2470 a8083063 Iustin Pop

2471 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2472 10c2650b Iustin Pop
  @param parent_cdev: the disk to which we should add children
2473 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2474 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should add
2475 c26a6bd2 Iustin Pop
  @rtype: None
2476 10c2650b Iustin Pop

2477 a8083063 Iustin Pop
  """
2478 bca2e7f4 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
2479 153d9724 Iustin Pop
  if parent_bdev is None:
2480 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in add children", parent_cdev)
2481 153d9724 Iustin Pop
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
2482 153d9724 Iustin Pop
  if new_bdevs.count(None) > 0:
2483 2cc6781a Iustin Pop
    _Fail("Can't find new device(s) to add: %s:%s", new_bdevs, new_cdevs)
2484 153d9724 Iustin Pop
  parent_bdev.AddChildren(new_bdevs)
2485 a8083063 Iustin Pop
2486 a8083063 Iustin Pop
2487 821d1bd1 Iustin Pop
def BlockdevRemovechildren(parent_cdev, new_cdevs):
2488 153d9724 Iustin Pop
  """Shrink a mirrored block device.
2489 a8083063 Iustin Pop

2490 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2491 10c2650b Iustin Pop
  @param parent_cdev: the disk from which we should remove children
2492 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2493 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should remove
2494 c26a6bd2 Iustin Pop
  @rtype: None
2495 10c2650b Iustin Pop

2496 a8083063 Iustin Pop
  """
2497 153d9724 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
2498 153d9724 Iustin Pop
  if parent_bdev is None:
2499 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in remove children", parent_cdev)
2500 e739bd57 Iustin Pop
  devs = []
2501 e739bd57 Iustin Pop
  for disk in new_cdevs:
2502 e739bd57 Iustin Pop
    rpath = disk.StaticDevPath()
2503 e739bd57 Iustin Pop
    if rpath is None:
2504 e739bd57 Iustin Pop
      bd = _RecursiveFindBD(disk)
2505 e739bd57 Iustin Pop
      if bd is None:
2506 2cc6781a Iustin Pop
        _Fail("Can't find device %s while removing children", disk)
2507 e739bd57 Iustin Pop
      else:
2508 e739bd57 Iustin Pop
        devs.append(bd.dev_path)
2509 e739bd57 Iustin Pop
    else:
2510 e51db2a6 Iustin Pop
      if not utils.IsNormAbsPath(rpath):
2511 e51db2a6 Iustin Pop
        _Fail("Strange path returned from StaticDevPath: '%s'", rpath)
2512 e739bd57 Iustin Pop
      devs.append(rpath)
2513 e739bd57 Iustin Pop
  parent_bdev.RemoveChildren(devs)
2514 a8083063 Iustin Pop
2515 a8083063 Iustin Pop
2516 821d1bd1 Iustin Pop
def BlockdevGetmirrorstatus(disks):
2517 a8083063 Iustin Pop
  """Get the mirroring status of a list of devices.
2518 a8083063 Iustin Pop

2519 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
2520 10c2650b Iustin Pop
  @param disks: the list of disks which we should query
2521 10c2650b Iustin Pop
  @rtype: disk
2522 c6a9dffa Michael Hanselmann
  @return: List of L{objects.BlockDevStatus}, one for each disk
2523 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if any of the disks cannot be
2524 10c2650b Iustin Pop
      found
2525 a8083063 Iustin Pop

2526 a8083063 Iustin Pop
  """
2527 a8083063 Iustin Pop
  stats = []
2528 a8083063 Iustin Pop
  for dsk in disks:
2529 a8083063 Iustin Pop
    rbd = _RecursiveFindBD(dsk)
2530 a8083063 Iustin Pop
    if rbd is None:
2531 3efa9051 Iustin Pop
      _Fail("Can't find device %s", dsk)
2532 96acbc09 Michael Hanselmann
2533 36145b12 Michael Hanselmann
    stats.append(rbd.CombinedSyncStatus())
2534 96acbc09 Michael Hanselmann
2535 c26a6bd2 Iustin Pop
  return stats
2536 a8083063 Iustin Pop
2537 a8083063 Iustin Pop
2538 c6a9dffa Michael Hanselmann
def BlockdevGetmirrorstatusMulti(disks):
2539 c6a9dffa Michael Hanselmann
  """Get the mirroring status of a list of devices.
2540 c6a9dffa Michael Hanselmann

2541 c6a9dffa Michael Hanselmann
  @type disks: list of L{objects.Disk}
2542 c6a9dffa Michael Hanselmann
  @param disks: the list of disks which we should query
2543 c6a9dffa Michael Hanselmann
  @rtype: disk
2544 c6a9dffa Michael Hanselmann
  @return: List of tuples, (bool, status), one for each disk; bool denotes
2545 c6a9dffa Michael Hanselmann
    success/failure, status is L{objects.BlockDevStatus} on success, string
2546 c6a9dffa Michael Hanselmann
    otherwise
2547 c6a9dffa Michael Hanselmann

2548 c6a9dffa Michael Hanselmann
  """
2549 c6a9dffa Michael Hanselmann
  result = []
2550 c6a9dffa Michael Hanselmann
  for disk in disks:
2551 c6a9dffa Michael Hanselmann
    try:
2552 c6a9dffa Michael Hanselmann
      rbd = _RecursiveFindBD(disk)
2553 c6a9dffa Michael Hanselmann
      if rbd is None:
2554 c6a9dffa Michael Hanselmann
        result.append((False, "Can't find device %s" % disk))
2555 c6a9dffa Michael Hanselmann
        continue
2556 c6a9dffa Michael Hanselmann
2557 c6a9dffa Michael Hanselmann
      status = rbd.CombinedSyncStatus()
2558 c6a9dffa Michael Hanselmann
    except errors.BlockDeviceError, err:
2559 c6a9dffa Michael Hanselmann
      logging.exception("Error while getting disk status")
2560 c6a9dffa Michael Hanselmann
      result.append((False, str(err)))
2561 c6a9dffa Michael Hanselmann
    else:
2562 c6a9dffa Michael Hanselmann
      result.append((True, status))
2563 c6a9dffa Michael Hanselmann
2564 c6a9dffa Michael Hanselmann
  assert len(disks) == len(result)
2565 c6a9dffa Michael Hanselmann
2566 c6a9dffa Michael Hanselmann
  return result
2567 c6a9dffa Michael Hanselmann
2568 c6a9dffa Michael Hanselmann
2569 bca2e7f4 Iustin Pop
def _RecursiveFindBD(disk):
2570 a8083063 Iustin Pop
  """Check if a device is activated.
2571 a8083063 Iustin Pop

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

2574 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2575 10c2650b Iustin Pop
  @param disk: the disk object we need to find
2576 a8083063 Iustin Pop

2577 10c2650b Iustin Pop
  @return: None if the device can't be found,
2578 10c2650b Iustin Pop
      otherwise the device instance
2579 a8083063 Iustin Pop

2580 a8083063 Iustin Pop
  """
2581 a8083063 Iustin Pop
  children = []
2582 a8083063 Iustin Pop
  if disk.children:
2583 a8083063 Iustin Pop
    for chdisk in disk.children:
2584 a8083063 Iustin Pop
      children.append(_RecursiveFindBD(chdisk))
2585 a8083063 Iustin Pop
2586 94dcbdb0 Andrea Spadaccini
  return bdev.FindDevice(disk, children)
2587 a8083063 Iustin Pop
2588 a8083063 Iustin Pop
2589 f2e07bb4 Michael Hanselmann
def _OpenRealBD(disk):
2590 f2e07bb4 Michael Hanselmann
  """Opens the underlying block device of a disk.
2591 f2e07bb4 Michael Hanselmann

2592 f2e07bb4 Michael Hanselmann
  @type disk: L{objects.Disk}
2593 f2e07bb4 Michael Hanselmann
  @param disk: the disk object we want to open
2594 f2e07bb4 Michael Hanselmann

2595 f2e07bb4 Michael Hanselmann
  """
2596 f2e07bb4 Michael Hanselmann
  real_disk = _RecursiveFindBD(disk)
2597 f2e07bb4 Michael Hanselmann
  if real_disk is None:
2598 f2e07bb4 Michael Hanselmann
    _Fail("Block device '%s' is not set up", disk)
2599 f2e07bb4 Michael Hanselmann
2600 f2e07bb4 Michael Hanselmann
  real_disk.Open()
2601 f2e07bb4 Michael Hanselmann
2602 f2e07bb4 Michael Hanselmann
  return real_disk
2603 f2e07bb4 Michael Hanselmann
2604 f2e07bb4 Michael Hanselmann
2605 821d1bd1 Iustin Pop
def BlockdevFind(disk):
2606 a8083063 Iustin Pop
  """Check if a device is activated.
2607 a8083063 Iustin Pop

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

2610 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2611 10c2650b Iustin Pop
  @param disk: the disk to find
2612 96acbc09 Michael Hanselmann
  @rtype: None or objects.BlockDevStatus
2613 96acbc09 Michael Hanselmann
  @return: None if the disk cannot be found, otherwise a the current
2614 96acbc09 Michael Hanselmann
           information
2615 a8083063 Iustin Pop

2616 a8083063 Iustin Pop
  """
2617 23829f6f Iustin Pop
  try:
2618 23829f6f Iustin Pop
    rbd = _RecursiveFindBD(disk)
2619 23829f6f Iustin Pop
  except errors.BlockDeviceError, err:
2620 2cc6781a Iustin Pop
    _Fail("Failed to find device: %s", err, exc=True)
2621 96acbc09 Michael Hanselmann
2622 a8083063 Iustin Pop
  if rbd is None:
2623 c26a6bd2 Iustin Pop
    return None
2624 96acbc09 Michael Hanselmann
2625 96acbc09 Michael Hanselmann
  return rbd.GetSyncStatus()
2626 a8083063 Iustin Pop
2627 a8083063 Iustin Pop
2628 6ef8077e Bernardo Dal Seno
def BlockdevGetdimensions(disks):
2629 968a7623 Iustin Pop
  """Computes the size of the given disks.
2630 968a7623 Iustin Pop

2631 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
2632 968a7623 Iustin Pop

2633 968a7623 Iustin Pop
  @type disks: list of L{objects.Disk}
2634 968a7623 Iustin Pop
  @param disks: the list of disk to compute the size for
2635 968a7623 Iustin Pop
  @rtype: list
2636 968a7623 Iustin Pop
  @return: list with elements None if the disk cannot be found,
2637 6ef8077e Bernardo Dal Seno
      otherwise the pair (size, spindles), where spindles is None if the
2638 6ef8077e Bernardo Dal Seno
      device doesn't support that
2639 968a7623 Iustin Pop

2640 968a7623 Iustin Pop
  """
2641 968a7623 Iustin Pop
  result = []
2642 968a7623 Iustin Pop
  for cf in disks:
2643 968a7623 Iustin Pop
    try:
2644 968a7623 Iustin Pop
      rbd = _RecursiveFindBD(cf)
2645 1122eb25 Iustin Pop
    except errors.BlockDeviceError:
2646 968a7623 Iustin Pop
      result.append(None)
2647 968a7623 Iustin Pop
      continue
2648 968a7623 Iustin Pop
    if rbd is None:
2649 968a7623 Iustin Pop
      result.append(None)
2650 968a7623 Iustin Pop
    else:
2651 6ef8077e Bernardo Dal Seno
      result.append(rbd.GetActualDimensions())
2652 968a7623 Iustin Pop
  return result
2653 968a7623 Iustin Pop
2654 968a7623 Iustin Pop
2655 a8083063 Iustin Pop
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
2656 a8083063 Iustin Pop
  """Write a file to the filesystem.
2657 a8083063 Iustin Pop

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

2661 10c2650b Iustin Pop
  @type file_name: str
2662 10c2650b Iustin Pop
  @param file_name: the target file name
2663 10c2650b Iustin Pop
  @type data: str
2664 10c2650b Iustin Pop
  @param data: the new contents of the file
2665 10c2650b Iustin Pop
  @type mode: int
2666 10c2650b Iustin Pop
  @param mode: the mode to give the file (can be None)
2667 9a914f7a René Nussbaumer
  @type uid: string
2668 9a914f7a René Nussbaumer
  @param uid: the owner of the file
2669 9a914f7a René Nussbaumer
  @type gid: string
2670 9a914f7a René Nussbaumer
  @param gid: the group of the file
2671 10c2650b Iustin Pop
  @type atime: float
2672 10c2650b Iustin Pop
  @param atime: the atime to set on the file (can be None)
2673 10c2650b Iustin Pop
  @type mtime: float
2674 10c2650b Iustin Pop
  @param mtime: the mtime to set on the file (can be None)
2675 c26a6bd2 Iustin Pop
  @rtype: None
2676 10c2650b Iustin Pop

2677 a8083063 Iustin Pop
  """
2678 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
2679 cffbbae7 Michael Hanselmann
2680 a8083063 Iustin Pop
  if not os.path.isabs(file_name):
2681 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile is not absolute: '%s'", file_name)
2682 a8083063 Iustin Pop
2683 360b0dc2 Iustin Pop
  if file_name not in _ALLOWED_UPLOAD_FILES:
2684 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile not in allowed upload targets: '%s'",
2685 2cc6781a Iustin Pop
          file_name)
2686 a8083063 Iustin Pop
2687 12bce260 Michael Hanselmann
  raw_data = _Decompress(data)
2688 12bce260 Michael Hanselmann
2689 9a914f7a René Nussbaumer
  if not (isinstance(uid, basestring) and isinstance(gid, basestring)):
2690 9a914f7a René Nussbaumer
    _Fail("Invalid username/groupname type")
2691 9a914f7a René Nussbaumer
2692 9a914f7a René Nussbaumer
  getents = runtime.GetEnts()
2693 9a914f7a René Nussbaumer
  uid = getents.LookupUser(uid)
2694 9a914f7a René Nussbaumer
  gid = getents.LookupGroup(gid)
2695 9a914f7a René Nussbaumer
2696 8f065ae2 Iustin Pop
  utils.SafeWriteFile(file_name, None,
2697 8f065ae2 Iustin Pop
                      data=raw_data, mode=mode, uid=uid, gid=gid,
2698 8f065ae2 Iustin Pop
                      atime=atime, mtime=mtime)
2699 a8083063 Iustin Pop
2700 386b57af Iustin Pop
2701 b2f29800 René Nussbaumer
def RunOob(oob_program, command, node, timeout):
2702 b2f29800 René Nussbaumer
  """Executes oob_program with given command on given node.
2703 b2f29800 René Nussbaumer

2704 b2f29800 René Nussbaumer
  @param oob_program: The path to the executable oob_program
2705 b2f29800 René Nussbaumer
  @param command: The command to invoke on oob_program
2706 b2f29800 René Nussbaumer
  @param node: The node given as an argument to the program
2707 b2f29800 René Nussbaumer
  @param timeout: Timeout after which we kill the oob program
2708 b2f29800 René Nussbaumer

2709 b2f29800 René Nussbaumer
  @return: stdout
2710 b2f29800 René Nussbaumer
  @raise RPCFail: If execution fails for some reason
2711 b2f29800 René Nussbaumer

2712 b2f29800 René Nussbaumer
  """
2713 b2f29800 René Nussbaumer
  result = utils.RunCmd([oob_program, command, node], timeout=timeout)
2714 b2f29800 René Nussbaumer
2715 b2f29800 René Nussbaumer
  if result.failed:
2716 b2f29800 René Nussbaumer
    _Fail("'%s' failed with reason '%s'; output: %s", result.cmd,
2717 b2f29800 René Nussbaumer
          result.fail_reason, result.output)
2718 b2f29800 René Nussbaumer
2719 b2f29800 René Nussbaumer
  return result.stdout
2720 b2f29800 René Nussbaumer
2721 b2f29800 René Nussbaumer
2722 c19f9810 Iustin Pop
def _OSOndiskAPIVersion(os_dir):
2723 2f8598a5 Alexander Schreiber
  """Compute and return the API version of a given OS.
2724 a8083063 Iustin Pop

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

2728 10c2650b Iustin Pop
  @type os_dir: str
2729 c19f9810 Iustin Pop
  @param os_dir: the directory in which we should look for the OS
2730 8e70b181 Iustin Pop
  @rtype: tuple
2731 8e70b181 Iustin Pop
  @return: tuple (status, data) with status denoting the validity and
2732 8e70b181 Iustin Pop
      data holding either the vaid versions or an error message
2733 a8083063 Iustin Pop

2734 a8083063 Iustin Pop
  """
2735 e02b9114 Iustin Pop
  api_file = utils.PathJoin(os_dir, constants.OS_API_FILE)
2736 a8083063 Iustin Pop
2737 a8083063 Iustin Pop
  try:
2738 a8083063 Iustin Pop
    st = os.stat(api_file)
2739 a8083063 Iustin Pop
  except EnvironmentError, err:
2740 b6b45e0d Guido Trotter
    return False, ("Required file '%s' not found under path %s: %s" %
2741 eb93b673 Guido Trotter
                   (constants.OS_API_FILE, os_dir, utils.ErrnoOrStr(err)))
2742 a8083063 Iustin Pop
2743 a8083063 Iustin Pop
  if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2744 b6b45e0d Guido Trotter
    return False, ("File '%s' in %s is not a regular file" %
2745 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir))
2746 a8083063 Iustin Pop
2747 a8083063 Iustin Pop
  try:
2748 3374afa9 Guido Trotter
    api_versions = utils.ReadFile(api_file).splitlines()
2749 a8083063 Iustin Pop
  except EnvironmentError, err:
2750 255dcebd Iustin Pop
    return False, ("Error while reading the API version file at %s: %s" %
2751 eb93b673 Guido Trotter
                   (api_file, utils.ErrnoOrStr(err)))
2752 a8083063 Iustin Pop
2753 a8083063 Iustin Pop
  try:
2754 63b9b186 Guido Trotter
    api_versions = [int(version.strip()) for version in api_versions]
2755 a8083063 Iustin Pop
  except (TypeError, ValueError), err:
2756 255dcebd Iustin Pop
    return False, ("API version(s) can't be converted to integer: %s" %
2757 255dcebd Iustin Pop
                   str(err))
2758 a8083063 Iustin Pop
2759 255dcebd Iustin Pop
  return True, api_versions
2760 a8083063 Iustin Pop
2761 386b57af Iustin Pop
2762 7c3d51d4 Guido Trotter
def DiagnoseOS(top_dirs=None):
2763 a8083063 Iustin Pop
  """Compute the validity for all OSes.
2764 a8083063 Iustin Pop

2765 10c2650b Iustin Pop
  @type top_dirs: list
2766 10c2650b Iustin Pop
  @param top_dirs: the list of directories in which to
2767 10c2650b Iustin Pop
      search (if not given defaults to
2768 3329f4de Michael Hanselmann
      L{pathutils.OS_SEARCH_PATH})
2769 10c2650b Iustin Pop
  @rtype: list of L{objects.OS}
2770 bad78e66 Iustin Pop
  @return: a list of tuples (name, path, status, diagnose, variants,
2771 bad78e66 Iustin Pop
      parameters, api_version) for all (potential) OSes under all
2772 bad78e66 Iustin Pop
      search paths, where:
2773 255dcebd Iustin Pop
          - name is the (potential) OS name
2774 255dcebd Iustin Pop
          - path is the full path to the OS
2775 255dcebd Iustin Pop
          - status True/False is the validity of the OS
2776 255dcebd Iustin Pop
          - diagnose is the error message for an invalid OS, otherwise empty
2777 ba00557a Guido Trotter
          - variants is a list of supported OS variants, if any
2778 c7d04a6b Iustin Pop
          - parameters is a list of (name, help) parameters, if any
2779 bad78e66 Iustin Pop
          - api_version is a list of support OS API versions
2780 a8083063 Iustin Pop

2781 a8083063 Iustin Pop
  """
2782 7c3d51d4 Guido Trotter
  if top_dirs is None:
2783 710f30ec Michael Hanselmann
    top_dirs = pathutils.OS_SEARCH_PATH
2784 a8083063 Iustin Pop
2785 a8083063 Iustin Pop
  result = []
2786 65fe4693 Iustin Pop
  for dir_name in top_dirs:
2787 65fe4693 Iustin Pop
    if os.path.isdir(dir_name):
2788 7c3d51d4 Guido Trotter
      try:
2789 65fe4693 Iustin Pop
        f_names = utils.ListVisibleFiles(dir_name)
2790 7c3d51d4 Guido Trotter
      except EnvironmentError, err:
2791 29921401 Iustin Pop
        logging.exception("Can't list the OS directory %s: %s", dir_name, err)
2792 7c3d51d4 Guido Trotter
        break
2793 7c3d51d4 Guido Trotter
      for name in f_names:
2794 e02b9114 Iustin Pop
        os_path = utils.PathJoin(dir_name, name)
2795 255dcebd Iustin Pop
        status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
2796 255dcebd Iustin Pop
        if status:
2797 255dcebd Iustin Pop
          diagnose = ""
2798 ba00557a Guido Trotter
          variants = os_inst.supported_variants
2799 c7d04a6b Iustin Pop
          parameters = os_inst.supported_parameters
2800 bad78e66 Iustin Pop
          api_versions = os_inst.api_versions
2801 255dcebd Iustin Pop
        else:
2802 255dcebd Iustin Pop
          diagnose = os_inst
2803 bad78e66 Iustin Pop
          variants = parameters = api_versions = []
2804 bad78e66 Iustin Pop
        result.append((name, os_path, status, diagnose, variants,
2805 bad78e66 Iustin Pop
                       parameters, api_versions))
2806 a8083063 Iustin Pop
2807 c26a6bd2 Iustin Pop
  return result
2808 a8083063 Iustin Pop
2809 a8083063 Iustin Pop
2810 255dcebd Iustin Pop
def _TryOSFromDisk(name, base_dir=None):
2811 a8083063 Iustin Pop
  """Create an OS instance from disk.
2812 a8083063 Iustin Pop

2813 a8083063 Iustin Pop
  This function will return an OS instance if the given name is a
2814 8e70b181 Iustin Pop
  valid OS name.
2815 a8083063 Iustin Pop

2816 8ee4dc80 Guido Trotter
  @type base_dir: string
2817 8ee4dc80 Guido Trotter
  @keyword base_dir: Base directory containing OS installations.
2818 8ee4dc80 Guido Trotter
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2819 255dcebd Iustin Pop
  @rtype: tuple
2820 255dcebd Iustin Pop
  @return: success and either the OS instance if we find a valid one,
2821 255dcebd Iustin Pop
      or error message
2822 7c3d51d4 Guido Trotter

2823 a8083063 Iustin Pop
  """
2824 56bcd3f4 Guido Trotter
  if base_dir is None:
2825 710f30ec Michael Hanselmann
    os_dir = utils.FindFile(name, pathutils.OS_SEARCH_PATH, os.path.isdir)
2826 c34c0cfd Iustin Pop
  else:
2827 f95c81bf Iustin Pop
    os_dir = utils.FindFile(name, [base_dir], os.path.isdir)
2828 f95c81bf Iustin Pop
2829 f95c81bf Iustin Pop
  if os_dir is None:
2830 5c0433d6 Iustin Pop
    return False, "Directory for OS %s not found in search path" % name
2831 a8083063 Iustin Pop
2832 c19f9810 Iustin Pop
  status, api_versions = _OSOndiskAPIVersion(os_dir)
2833 255dcebd Iustin Pop
  if not status:
2834 255dcebd Iustin Pop
    # push the error up
2835 255dcebd Iustin Pop
    return status, api_versions
2836 a8083063 Iustin Pop
2837 d1a7d66f Guido Trotter
  if not constants.OS_API_VERSIONS.intersection(api_versions):
2838 255dcebd Iustin Pop
    return False, ("API version mismatch for path '%s': found %s, want %s." %
2839 d1a7d66f Guido Trotter
                   (os_dir, api_versions, constants.OS_API_VERSIONS))
2840 a8083063 Iustin Pop
2841 35007011 Iustin Pop
  # OS Files dictionary, we will populate it with the absolute path
2842 35007011 Iustin Pop
  # names; if the value is True, then it is a required file, otherwise
2843 35007011 Iustin Pop
  # an optional one
2844 35007011 Iustin Pop
  os_files = dict.fromkeys(constants.OS_SCRIPTS, True)
2845 a8083063 Iustin Pop
2846 95075fba Guido Trotter
  if max(api_versions) >= constants.OS_API_V15:
2847 35007011 Iustin Pop
    os_files[constants.OS_VARIANTS_FILE] = False
2848 95075fba Guido Trotter
2849 c7d04a6b Iustin Pop
  if max(api_versions) >= constants.OS_API_V20:
2850 35007011 Iustin Pop
    os_files[constants.OS_PARAMETERS_FILE] = True
2851 c7d04a6b Iustin Pop
  else:
2852 c7d04a6b Iustin Pop
    del os_files[constants.OS_SCRIPT_VERIFY]
2853 c7d04a6b Iustin Pop
2854 35007011 Iustin Pop
  for (filename, required) in os_files.items():
2855 e02b9114 Iustin Pop
    os_files[filename] = utils.PathJoin(os_dir, filename)
2856 a8083063 Iustin Pop
2857 a8083063 Iustin Pop
    try:
2858 ea79fc15 Michael Hanselmann
      st = os.stat(os_files[filename])
2859 a8083063 Iustin Pop
    except EnvironmentError, err:
2860 35007011 Iustin Pop
      if err.errno == errno.ENOENT and not required:
2861 35007011 Iustin Pop
        del os_files[filename]
2862 35007011 Iustin Pop
        continue
2863 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is missing (%s)" %
2864 eb93b673 Guido Trotter
                     (filename, os_dir, utils.ErrnoOrStr(err)))
2865 a8083063 Iustin Pop
2866 a8083063 Iustin Pop
    if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2867 41ba4061 Guido Trotter
      return False, ("File '%s' under path '%s' is not a regular file" %
2868 ea79fc15 Michael Hanselmann
                     (filename, os_dir))
2869 255dcebd Iustin Pop
2870 ea79fc15 Michael Hanselmann
    if filename in constants.OS_SCRIPTS:
2871 0757c107 Guido Trotter
      if stat.S_IMODE(st.st_mode) & stat.S_IXUSR != stat.S_IXUSR:
2872 0757c107 Guido Trotter
        return False, ("File '%s' under path '%s' is not executable" %
2873 ea79fc15 Michael Hanselmann
                       (filename, os_dir))
2874 0757c107 Guido Trotter
2875 845da3e8 Iustin Pop
  variants = []
2876 95075fba Guido Trotter
  if constants.OS_VARIANTS_FILE in os_files:
2877 95075fba Guido Trotter
    variants_file = os_files[constants.OS_VARIANTS_FILE]
2878 95075fba Guido Trotter
    try:
2879 5a7cb9d3 Iustin Pop
      variants = \
2880 5a7cb9d3 Iustin Pop
        utils.FilterEmptyLinesAndComments(utils.ReadFile(variants_file))
2881 95075fba Guido Trotter
    except EnvironmentError, err:
2882 35007011 Iustin Pop
      # we accept missing files, but not other errors
2883 35007011 Iustin Pop
      if err.errno != errno.ENOENT:
2884 35007011 Iustin Pop
        return False, ("Error while reading the OS variants file at %s: %s" %
2885 eb93b673 Guido Trotter
                       (variants_file, utils.ErrnoOrStr(err)))
2886 0757c107 Guido Trotter
2887 c7d04a6b Iustin Pop
  parameters = []
2888 c7d04a6b Iustin Pop
  if constants.OS_PARAMETERS_FILE in os_files:
2889 c7d04a6b Iustin Pop
    parameters_file = os_files[constants.OS_PARAMETERS_FILE]
2890 c7d04a6b Iustin Pop
    try:
2891 c7d04a6b Iustin Pop
      parameters = utils.ReadFile(parameters_file).splitlines()
2892 c7d04a6b Iustin Pop
    except EnvironmentError, err:
2893 c7d04a6b Iustin Pop
      return False, ("Error while reading the OS parameters file at %s: %s" %
2894 eb93b673 Guido Trotter
                     (parameters_file, utils.ErrnoOrStr(err)))
2895 c7d04a6b Iustin Pop
    parameters = [v.split(None, 1) for v in parameters]
2896 c7d04a6b Iustin Pop
2897 8e70b181 Iustin Pop
  os_obj = objects.OS(name=name, path=os_dir,
2898 41ba4061 Guido Trotter
                      create_script=os_files[constants.OS_SCRIPT_CREATE],
2899 41ba4061 Guido Trotter
                      export_script=os_files[constants.OS_SCRIPT_EXPORT],
2900 41ba4061 Guido Trotter
                      import_script=os_files[constants.OS_SCRIPT_IMPORT],
2901 41ba4061 Guido Trotter
                      rename_script=os_files[constants.OS_SCRIPT_RENAME],
2902 40684c3a Iustin Pop
                      verify_script=os_files.get(constants.OS_SCRIPT_VERIFY,
2903 40684c3a Iustin Pop
                                                 None),
2904 95075fba Guido Trotter
                      supported_variants=variants,
2905 c7d04a6b Iustin Pop
                      supported_parameters=parameters,
2906 255dcebd Iustin Pop
                      api_versions=api_versions)
2907 255dcebd Iustin Pop
  return True, os_obj
2908 255dcebd Iustin Pop
2909 255dcebd Iustin Pop
2910 255dcebd Iustin Pop
def OSFromDisk(name, base_dir=None):
2911 255dcebd Iustin Pop
  """Create an OS instance from disk.
2912 255dcebd Iustin Pop

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

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

2920 255dcebd Iustin Pop
  @type base_dir: string
2921 255dcebd Iustin Pop
  @keyword base_dir: Base directory containing OS installations.
2922 255dcebd Iustin Pop
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2923 255dcebd Iustin Pop
  @rtype: L{objects.OS}
2924 255dcebd Iustin Pop
  @return: the OS instance if we find a valid one
2925 255dcebd Iustin Pop
  @raise RPCFail: if we don't find a valid OS
2926 255dcebd Iustin Pop

2927 255dcebd Iustin Pop
  """
2928 870dc44c Iustin Pop
  name_only = objects.OS.GetName(name)
2929 6ee7102a Guido Trotter
  status, payload = _TryOSFromDisk(name_only, base_dir)
2930 255dcebd Iustin Pop
2931 255dcebd Iustin Pop
  if not status:
2932 255dcebd Iustin Pop
    _Fail(payload)
2933 a8083063 Iustin Pop
2934 255dcebd Iustin Pop
  return payload
2935 a8083063 Iustin Pop
2936 a8083063 Iustin Pop
2937 a025e535 Vitaly Kuznetsov
def OSCoreEnv(os_name, inst_os, os_params, debug=0):
2938 efaa9b06 Iustin Pop
  """Calculate the basic environment for an os script.
2939 2266edb2 Guido Trotter

2940 a025e535 Vitaly Kuznetsov
  @type os_name: str
2941 a025e535 Vitaly Kuznetsov
  @param os_name: full operating system name (including variant)
2942 099c52ad Iustin Pop
  @type inst_os: L{objects.OS}
2943 099c52ad Iustin Pop
  @param inst_os: operating system for which the environment is being built
2944 1bdcbbab Iustin Pop
  @type os_params: dict
2945 1bdcbbab Iustin Pop
  @param os_params: the OS parameters
2946 2266edb2 Guido Trotter
  @type debug: integer
2947 10c2650b Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2948 2266edb2 Guido Trotter
  @rtype: dict
2949 2266edb2 Guido Trotter
  @return: dict of environment variables
2950 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2951 10c2650b Iustin Pop
      cannot be found
2952 2266edb2 Guido Trotter

2953 2266edb2 Guido Trotter
  """
2954 2266edb2 Guido Trotter
  result = {}
2955 099c52ad Iustin Pop
  api_version = \
2956 099c52ad Iustin Pop
    max(constants.OS_API_VERSIONS.intersection(inst_os.api_versions))
2957 d0c8c01d Iustin Pop
  result["OS_API_VERSION"] = "%d" % api_version
2958 d0c8c01d Iustin Pop
  result["OS_NAME"] = inst_os.name
2959 d0c8c01d Iustin Pop
  result["DEBUG_LEVEL"] = "%d" % debug
2960 efaa9b06 Iustin Pop
2961 efaa9b06 Iustin Pop
  # OS variants
2962 35007011 Iustin Pop
  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
2963 870dc44c Iustin Pop
    variant = objects.OS.GetVariant(os_name)
2964 870dc44c Iustin Pop
    if not variant:
2965 099c52ad Iustin Pop
      variant = inst_os.supported_variants[0]
2966 35007011 Iustin Pop
  else:
2967 35007011 Iustin Pop
    variant = ""
2968 35007011 Iustin Pop
  result["OS_VARIANT"] = variant
2969 efaa9b06 Iustin Pop
2970 1bdcbbab Iustin Pop
  # OS params
2971 1bdcbbab Iustin Pop
  for pname, pvalue in os_params.items():
2972 d0c8c01d Iustin Pop
    result["OSP_%s" % pname.upper()] = pvalue
2973 1bdcbbab Iustin Pop
2974 9a6ade06 Iustin Pop
  # Set a default path otherwise programs called by OS scripts (or
2975 9a6ade06 Iustin Pop
  # even hooks called from OS scripts) might break, and we don't want
2976 9a6ade06 Iustin Pop
  # to have each script require setting a PATH variable
2977 9a6ade06 Iustin Pop
  result["PATH"] = constants.HOOKS_PATH
2978 9a6ade06 Iustin Pop
2979 efaa9b06 Iustin Pop
  return result
2980 efaa9b06 Iustin Pop
2981 efaa9b06 Iustin Pop
2982 efaa9b06 Iustin Pop
def OSEnvironment(instance, inst_os, debug=0):
2983 efaa9b06 Iustin Pop
  """Calculate the environment for an os script.
2984 efaa9b06 Iustin Pop

2985 efaa9b06 Iustin Pop
  @type instance: L{objects.Instance}
2986 efaa9b06 Iustin Pop
  @param instance: target instance for the os script run
2987 efaa9b06 Iustin Pop
  @type inst_os: L{objects.OS}
2988 efaa9b06 Iustin Pop
  @param inst_os: operating system for which the environment is being built
2989 efaa9b06 Iustin Pop
  @type debug: integer
2990 efaa9b06 Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2991 efaa9b06 Iustin Pop
  @rtype: dict
2992 efaa9b06 Iustin Pop
  @return: dict of environment variables
2993 efaa9b06 Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2994 efaa9b06 Iustin Pop
      cannot be found
2995 efaa9b06 Iustin Pop

2996 efaa9b06 Iustin Pop
  """
2997 a025e535 Vitaly Kuznetsov
  result = OSCoreEnv(instance.os, inst_os, instance.osparams, debug=debug)
2998 efaa9b06 Iustin Pop
2999 519719fd Marco Casavecchia
  for attr in ["name", "os", "uuid", "ctime", "mtime", "primary_node"]:
3000 f2165b8a Iustin Pop
    result["INSTANCE_%s" % attr.upper()] = str(getattr(instance, attr))
3001 f2165b8a Iustin Pop
3002 d0c8c01d Iustin Pop
  result["HYPERVISOR"] = instance.hypervisor
3003 d0c8c01d Iustin Pop
  result["DISK_COUNT"] = "%d" % len(instance.disks)
3004 d0c8c01d Iustin Pop
  result["NIC_COUNT"] = "%d" % len(instance.nics)
3005 d0c8c01d Iustin Pop
  result["INSTANCE_SECONDARY_NODES"] = \
3006 d0c8c01d Iustin Pop
      ("%s" % " ".join(instance.secondary_nodes))
3007 efaa9b06 Iustin Pop
3008 efaa9b06 Iustin Pop
  # Disks
3009 2266edb2 Guido Trotter
  for idx, disk in enumerate(instance.disks):
3010 f2e07bb4 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
3011 d0c8c01d Iustin Pop
    result["DISK_%d_PATH" % idx] = real_disk.dev_path
3012 d0c8c01d Iustin Pop
    result["DISK_%d_ACCESS" % idx] = disk.mode
3013 8a348b15 Christos Stavrakakis
    result["DISK_%d_UUID" % idx] = disk.uuid
3014 8a348b15 Christos Stavrakakis
    if disk.name:
3015 8a348b15 Christos Stavrakakis
      result["DISK_%d_NAME" % idx] = disk.name
3016 2266edb2 Guido Trotter
    if constants.HV_DISK_TYPE in instance.hvparams:
3017 d0c8c01d Iustin Pop
      result["DISK_%d_FRONTEND_TYPE" % idx] = \
3018 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_DISK_TYPE]
3019 cd3b4ff4 Helga Velroyen
    if disk.dev_type in constants.DTS_BLOCK:
3020 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = "block"
3021 a09639d1 Santi Raffa
    elif disk.dev_type in constants.DTS_FILEBASED:
3022 d0c8c01d Iustin Pop
      result["DISK_%d_BACKEND_TYPE" % idx] = \
3023 a57e502a Thomas Thrainer
        "file:%s" % disk.logical_id[0]
3024 efaa9b06 Iustin Pop
3025 efaa9b06 Iustin Pop
  # NICs
3026 2266edb2 Guido Trotter
  for idx, nic in enumerate(instance.nics):
3027 d0c8c01d Iustin Pop
    result["NIC_%d_MAC" % idx] = nic.mac
3028 8a348b15 Christos Stavrakakis
    result["NIC_%d_UUID" % idx] = nic.uuid
3029 8a348b15 Christos Stavrakakis
    if nic.name:
3030 8a348b15 Christos Stavrakakis
      result["NIC_%d_NAME" % idx] = nic.name
3031 2266edb2 Guido Trotter
    if nic.ip:
3032 d0c8c01d Iustin Pop
      result["NIC_%d_IP" % idx] = nic.ip
3033 d0c8c01d Iustin Pop
    result["NIC_%d_MODE" % idx] = nic.nicparams[constants.NIC_MODE]
3034 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
3035 d0c8c01d Iustin Pop
      result["NIC_%d_BRIDGE" % idx] = nic.nicparams[constants.NIC_LINK]
3036 1ba9227f Guido Trotter
    if nic.nicparams[constants.NIC_LINK]:
3037 d0c8c01d Iustin Pop
      result["NIC_%d_LINK" % idx] = nic.nicparams[constants.NIC_LINK]
3038 d89168ff Guido Trotter
    if nic.netinfo:
3039 d89168ff Guido Trotter
      nobj = objects.Network.FromDict(nic.netinfo)
3040 d89168ff Guido Trotter
      result.update(nobj.HooksDict("NIC_%d_" % idx))
3041 2266edb2 Guido Trotter
    if constants.HV_NIC_TYPE in instance.hvparams:
3042 d0c8c01d Iustin Pop
      result["NIC_%d_FRONTEND_TYPE" % idx] = \
3043 2266edb2 Guido Trotter
        instance.hvparams[constants.HV_NIC_TYPE]
3044 2266edb2 Guido Trotter
3045 efaa9b06 Iustin Pop
  # HV/BE params
3046 67fc3042 Iustin Pop
  for source, kind in [(instance.beparams, "BE"), (instance.hvparams, "HV")]:
3047 67fc3042 Iustin Pop
    for key, value in source.items():
3048 030b218a Iustin Pop
      result["INSTANCE_%s_%s" % (kind, key)] = str(value)
3049 67fc3042 Iustin Pop
3050 2266edb2 Guido Trotter
  return result
3051 a8083063 Iustin Pop
3052 f2e07bb4 Michael Hanselmann
3053 b954f097 Constantinos Venetsanopoulos
def DiagnoseExtStorage(top_dirs=None):
3054 b954f097 Constantinos Venetsanopoulos
  """Compute the validity for all ExtStorage Providers.
3055 b954f097 Constantinos Venetsanopoulos

3056 b954f097 Constantinos Venetsanopoulos
  @type top_dirs: list
3057 b954f097 Constantinos Venetsanopoulos
  @param top_dirs: the list of directories in which to
3058 b954f097 Constantinos Venetsanopoulos
      search (if not given defaults to
3059 b954f097 Constantinos Venetsanopoulos
      L{pathutils.ES_SEARCH_PATH})
3060 b954f097 Constantinos Venetsanopoulos
  @rtype: list of L{objects.ExtStorage}
3061 b954f097 Constantinos Venetsanopoulos
  @return: a list of tuples (name, path, status, diagnose, parameters)
3062 b954f097 Constantinos Venetsanopoulos
      for all (potential) ExtStorage Providers under all
3063 b954f097 Constantinos Venetsanopoulos
      search paths, where:
3064 b954f097 Constantinos Venetsanopoulos
          - name is the (potential) ExtStorage Provider
3065 b954f097 Constantinos Venetsanopoulos
          - path is the full path to the ExtStorage Provider
3066 b954f097 Constantinos Venetsanopoulos
          - status True/False is the validity of the ExtStorage Provider
3067 b954f097 Constantinos Venetsanopoulos
          - diagnose is the error message for an invalid ExtStorage Provider,
3068 b954f097 Constantinos Venetsanopoulos
            otherwise empty
3069 b954f097 Constantinos Venetsanopoulos
          - parameters is a list of (name, help) parameters, if any
3070 b954f097 Constantinos Venetsanopoulos

3071 b954f097 Constantinos Venetsanopoulos
  """
3072 b954f097 Constantinos Venetsanopoulos
  if top_dirs is None:
3073 b954f097 Constantinos Venetsanopoulos
    top_dirs = pathutils.ES_SEARCH_PATH
3074 b954f097 Constantinos Venetsanopoulos
3075 b954f097 Constantinos Venetsanopoulos
  result = []
3076 b954f097 Constantinos Venetsanopoulos
  for dir_name in top_dirs:
3077 b954f097 Constantinos Venetsanopoulos
    if os.path.isdir(dir_name):
3078 b954f097 Constantinos Venetsanopoulos
      try:
3079 b954f097 Constantinos Venetsanopoulos
        f_names = utils.ListVisibleFiles(dir_name)
3080 b954f097 Constantinos Venetsanopoulos
      except EnvironmentError, err:
3081 b954f097 Constantinos Venetsanopoulos
        logging.exception("Can't list the ExtStorage directory %s: %s",
3082 b954f097 Constantinos Venetsanopoulos
                          dir_name, err)
3083 b954f097 Constantinos Venetsanopoulos
        break
3084 b954f097 Constantinos Venetsanopoulos
      for name in f_names:
3085 b954f097 Constantinos Venetsanopoulos
        es_path = utils.PathJoin(dir_name, name)
3086 b954f097 Constantinos Venetsanopoulos
        status, es_inst = bdev.ExtStorageFromDisk(name, base_dir=dir_name)
3087 b954f097 Constantinos Venetsanopoulos
        if status:
3088 b954f097 Constantinos Venetsanopoulos
          diagnose = ""
3089 b954f097 Constantinos Venetsanopoulos
          parameters = es_inst.supported_parameters
3090 b954f097 Constantinos Venetsanopoulos
        else:
3091 b954f097 Constantinos Venetsanopoulos
          diagnose = es_inst
3092 b954f097 Constantinos Venetsanopoulos
          parameters = []
3093 b954f097 Constantinos Venetsanopoulos
        result.append((name, es_path, status, diagnose, parameters))
3094 b954f097 Constantinos Venetsanopoulos
3095 b954f097 Constantinos Venetsanopoulos
  return result
3096 b954f097 Constantinos Venetsanopoulos
3097 b954f097 Constantinos Venetsanopoulos
3098 be9150ea Bernardo Dal Seno
def BlockdevGrow(disk, amount, dryrun, backingstore, excl_stor):
3099 594609c0 Iustin Pop
  """Grow a stack of block devices.
3100 594609c0 Iustin Pop

3101 594609c0 Iustin Pop
  This function is called recursively, with the childrens being the
3102 10c2650b Iustin Pop
  first ones to resize.
3103 594609c0 Iustin Pop

3104 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
3105 10c2650b Iustin Pop
  @param disk: the disk to be grown
3106 a59faf4b Iustin Pop
  @type amount: integer
3107 a59faf4b Iustin Pop
  @param amount: the amount (in mebibytes) to grow with
3108 a59faf4b Iustin Pop
  @type dryrun: boolean
3109 a59faf4b Iustin Pop
  @param dryrun: whether to execute the operation in simulation mode
3110 a59faf4b Iustin Pop
      only, without actually increasing the size
3111 cad0723b Iustin Pop
  @param backingstore: whether to execute the operation on backing storage
3112 cad0723b Iustin Pop
      only, or on "logical" storage only; e.g. DRBD is logical storage,
3113 cad0723b Iustin Pop
      whereas LVM, file, RBD are backing storage
3114 10c2650b Iustin Pop
  @rtype: (status, result)
3115 be9150ea Bernardo Dal Seno
  @type excl_stor: boolean
3116 be9150ea Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
3117 a59faf4b Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3118 a59faf4b Iustin Pop
      the errors message if status is False
3119 594609c0 Iustin Pop

3120 594609c0 Iustin Pop
  """
3121 594609c0 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3122 594609c0 Iustin Pop
  if r_dev is None:
3123 afdc3985 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3124 594609c0 Iustin Pop
3125 594609c0 Iustin Pop
  try:
3126 be9150ea Bernardo Dal Seno
    r_dev.Grow(amount, dryrun, backingstore, excl_stor)
3127 594609c0 Iustin Pop
  except errors.BlockDeviceError, err:
3128 2cc6781a Iustin Pop
    _Fail("Failed to grow block device: %s", err, exc=True)
3129 594609c0 Iustin Pop
3130 594609c0 Iustin Pop
3131 821d1bd1 Iustin Pop
def BlockdevSnapshot(disk):
3132 a8083063 Iustin Pop
  """Create a snapshot copy of a block device.
3133 a8083063 Iustin Pop

3134 a8083063 Iustin Pop
  This function is called recursively, and the snapshot is actually created
3135 a8083063 Iustin Pop
  just for the leaf lvm backend device.
3136 a8083063 Iustin Pop

3137 e9e9263d Guido Trotter
  @type disk: L{objects.Disk}
3138 e9e9263d Guido Trotter
  @param disk: the disk to be snapshotted
3139 e9e9263d Guido Trotter
  @rtype: string
3140 800ac399 Iustin Pop
  @return: snapshot disk ID as (vg, lv)
3141 a8083063 Iustin Pop

3142 098c0958 Michael Hanselmann
  """
3143 cd3b4ff4 Helga Velroyen
  if disk.dev_type == constants.DT_DRBD8:
3144 433c63aa Iustin Pop
    if not disk.children:
3145 433c63aa Iustin Pop
      _Fail("DRBD device '%s' without backing storage cannot be snapshotted",
3146 433c63aa Iustin Pop
            disk.unique_id)
3147 433c63aa Iustin Pop
    return BlockdevSnapshot(disk.children[0])
3148 cd3b4ff4 Helga Velroyen
  elif disk.dev_type == constants.DT_PLAIN:
3149 a8083063 Iustin Pop
    r_dev = _RecursiveFindBD(disk)
3150 a8083063 Iustin Pop
    if r_dev is not None:
3151 433c63aa Iustin Pop
      # FIXME: choose a saner value for the snapshot size
3152 a8083063 Iustin Pop
      # let's stay on the safe side and ask for the full size, for now
3153 c26a6bd2 Iustin Pop
      return r_dev.Snapshot(disk.size)
3154 a8083063 Iustin Pop
    else:
3155 87812fd3 Iustin Pop
      _Fail("Cannot find block device %s", disk)
3156 a8083063 Iustin Pop
  else:
3157 87812fd3 Iustin Pop
    _Fail("Cannot snapshot non-lvm block device '%s' of type '%s'",
3158 87812fd3 Iustin Pop
          disk.unique_id, disk.dev_type)
3159 a8083063 Iustin Pop
3160 a8083063 Iustin Pop
3161 48e175a2 Iustin Pop
def BlockdevSetInfo(disk, info):
3162 48e175a2 Iustin Pop
  """Sets 'metadata' information on block devices.
3163 48e175a2 Iustin Pop

3164 48e175a2 Iustin Pop
  This function sets 'info' metadata on block devices. Initial
3165 48e175a2 Iustin Pop
  information is set at device creation; this function should be used
3166 48e175a2 Iustin Pop
  for example after renames.
3167 48e175a2 Iustin Pop

3168 48e175a2 Iustin Pop
  @type disk: L{objects.Disk}
3169 48e175a2 Iustin Pop
  @param disk: the disk to be grown
3170 48e175a2 Iustin Pop
  @type info: string
3171 48e175a2 Iustin Pop
  @param info: new 'info' metadata
3172 48e175a2 Iustin Pop
  @rtype: (status, result)
3173 48e175a2 Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3174 48e175a2 Iustin Pop
      the errors message if status is False
3175 48e175a2 Iustin Pop

3176 48e175a2 Iustin Pop
  """
3177 48e175a2 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3178 48e175a2 Iustin Pop
  if r_dev is None:
3179 48e175a2 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3180 48e175a2 Iustin Pop
3181 48e175a2 Iustin Pop
  try:
3182 48e175a2 Iustin Pop
    r_dev.SetInfo(info)
3183 48e175a2 Iustin Pop
  except errors.BlockDeviceError, err:
3184 48e175a2 Iustin Pop
    _Fail("Failed to set information on block device: %s", err, exc=True)
3185 48e175a2 Iustin Pop
3186 48e175a2 Iustin Pop
3187 a8083063 Iustin Pop
def FinalizeExport(instance, snap_disks):
3188 a8083063 Iustin Pop
  """Write out the export configuration information.
3189 a8083063 Iustin Pop

3190 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
3191 10c2650b Iustin Pop
  @param instance: the instance which we export, used for
3192 10c2650b Iustin Pop
      saving configuration
3193 10c2650b Iustin Pop
  @type snap_disks: list of L{objects.Disk}
3194 10c2650b Iustin Pop
  @param snap_disks: list of snapshot block devices, which
3195 10c2650b Iustin Pop
      will be used to get the actual name of the dump file
3196 a8083063 Iustin Pop

3197 c26a6bd2 Iustin Pop
  @rtype: None
3198 a8083063 Iustin Pop

3199 098c0958 Michael Hanselmann
  """
3200 710f30ec Michael Hanselmann
  destdir = utils.PathJoin(pathutils.EXPORT_DIR, instance.name + ".new")
3201 710f30ec Michael Hanselmann
  finaldestdir = utils.PathJoin(pathutils.EXPORT_DIR, instance.name)
3202 a8083063 Iustin Pop
3203 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
3204 a8083063 Iustin Pop
3205 a8083063 Iustin Pop
  config.add_section(constants.INISECT_EXP)
3206 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "version", "0")
3207 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "timestamp", "%d" % int(time.time()))
3208 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "source", instance.primary_node)
3209 d0c8c01d Iustin Pop
  config.set(constants.INISECT_EXP, "os", instance.os)
3210 775b8743 Michael Hanselmann
  config.set(constants.INISECT_EXP, "compression", "none")
3211 a8083063 Iustin Pop
3212 a8083063 Iustin Pop
  config.add_section(constants.INISECT_INS)
3213 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "name", instance.name)
3214 1db993d5 Guido Trotter
  config.set(constants.INISECT_INS, "maxmem", "%d" %
3215 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MAXMEM])
3216 1db993d5 Guido Trotter
  config.set(constants.INISECT_INS, "minmem", "%d" %
3217 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MINMEM])
3218 1db993d5 Guido Trotter
  # "memory" is deprecated, but useful for exporting to old ganeti versions
3219 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "memory", "%d" %
3220 1db993d5 Guido Trotter
             instance.beparams[constants.BE_MAXMEM])
3221 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "vcpus", "%d" %
3222 51de46bf Iustin Pop
             instance.beparams[constants.BE_VCPUS])
3223 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "disk_template", instance.disk_template)
3224 d0c8c01d Iustin Pop
  config.set(constants.INISECT_INS, "hypervisor", instance.hypervisor)
3225 fbb2c636 Michael Hanselmann
  config.set(constants.INISECT_INS, "tags", " ".join(instance.GetTags()))
3226 66f93869 Manuel Franceschini
3227 95268cc3 Iustin Pop
  nic_total = 0
3228 a8083063 Iustin Pop
  for nic_count, nic in enumerate(instance.nics):
3229 95268cc3 Iustin Pop
    nic_total += 1
3230 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_mac" %
3231 d0c8c01d Iustin Pop
               nic_count, "%s" % nic.mac)
3232 d0c8c01d Iustin Pop
    config.set(constants.INISECT_INS, "nic%d_ip" % nic_count, "%s" % nic.ip)
3233 7a476bb5 Dimitris Aragiorgis
    config.set(constants.INISECT_INS, "nic%d_network" % nic_count,
3234 7a476bb5 Dimitris Aragiorgis
               "%s" % nic.network)
3235 6801eb5c Iustin Pop
    for param in constants.NICS_PARAMETER_TYPES:
3236 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "nic%d_%s" % (nic_count, param),
3237 d0c8c01d Iustin Pop
                 "%s" % nic.nicparams.get(param, None))
3238 a8083063 Iustin Pop
  # TODO: redundant: on load can read nics until it doesn't exist
3239 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "nic_count", "%d" % nic_total)
3240 a8083063 Iustin Pop
3241 726d7d68 Iustin Pop
  disk_total = 0
3242 a8083063 Iustin Pop
  for disk_count, disk in enumerate(snap_disks):
3243 19d7f90a Guido Trotter
    if disk:
3244 726d7d68 Iustin Pop
      disk_total += 1
3245 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_ivname" % disk_count,
3246 d0c8c01d Iustin Pop
                 ("%s" % disk.iv_name))
3247 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_dump" % disk_count,
3248 a57e502a Thomas Thrainer
                 ("%s" % disk.logical_id[1]))
3249 d0c8c01d Iustin Pop
      config.set(constants.INISECT_INS, "disk%d_size" % disk_count,
3250 d0c8c01d Iustin Pop
                 ("%d" % disk.size))
3251 d0c8c01d Iustin Pop
3252 e687ec01 Michael Hanselmann
  config.set(constants.INISECT_INS, "disk_count", "%d" % disk_total)
3253 a8083063 Iustin Pop
3254 3c8954ad Iustin Pop
  # New-style hypervisor/backend parameters
3255 3c8954ad Iustin Pop
3256 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_HYP)
3257 3c8954ad Iustin Pop
  for name, value in instance.hvparams.items():
3258 3c8954ad Iustin Pop
    if name not in constants.HVC_GLOBALS:
3259 3c8954ad Iustin Pop
      config.set(constants.INISECT_HYP, name, str(value))
3260 3c8954ad Iustin Pop
3261 3c8954ad Iustin Pop
  config.add_section(constants.INISECT_BEP)
3262 3c8954ad Iustin Pop
  for name, value in instance.beparams.items():
3263 3c8954ad Iustin Pop
    config.set(constants.INISECT_BEP, name, str(value))
3264 3c8954ad Iustin Pop
3265 535b49cb Iustin Pop
  config.add_section(constants.INISECT_OSP)
3266 535b49cb Iustin Pop
  for name, value in instance.osparams.items():
3267 535b49cb Iustin Pop
    config.set(constants.INISECT_OSP, name, str(value))
3268 535b49cb Iustin Pop
3269 6bce7ba2 Santi Raffa
  config.add_section(constants.INISECT_OSP_PRIVATE)
3270 6bce7ba2 Santi Raffa
  for name, value in instance.osparams_private.items():
3271 6bce7ba2 Santi Raffa
    config.set(constants.INISECT_OSP_PRIVATE, name, str(value.Get()))
3272 6bce7ba2 Santi Raffa
3273 c4feafe8 Iustin Pop
  utils.WriteFile(utils.PathJoin(destdir, constants.EXPORT_CONF_FILE),
3274 726d7d68 Iustin Pop
                  data=config.Dumps())
3275 56569f4e Michael Hanselmann
  shutil.rmtree(finaldestdir, ignore_errors=True)
3276 a8083063 Iustin Pop
  shutil.move(destdir, finaldestdir)
3277 a8083063 Iustin Pop
3278 a8083063 Iustin Pop
3279 a8083063 Iustin Pop
def ExportInfo(dest):
3280 a8083063 Iustin Pop
  """Get export configuration information.
3281 a8083063 Iustin Pop

3282 10c2650b Iustin Pop
  @type dest: str
3283 10c2650b Iustin Pop
  @param dest: directory containing the export
3284 a8083063 Iustin Pop

3285 10c2650b Iustin Pop
  @rtype: L{objects.SerializableConfigParser}
3286 10c2650b Iustin Pop
  @return: a serializable config file containing the
3287 10c2650b Iustin Pop
      export info
3288 a8083063 Iustin Pop

3289 a8083063 Iustin Pop
  """
3290 c4feafe8 Iustin Pop
  cff = utils.PathJoin(dest, constants.EXPORT_CONF_FILE)
3291 a8083063 Iustin Pop
3292 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
3293 a8083063 Iustin Pop
  config.read(cff)
3294 a8083063 Iustin Pop
3295 a8083063 Iustin Pop
  if (not config.has_section(constants.INISECT_EXP) or
3296 a8083063 Iustin Pop
      not config.has_section(constants.INISECT_INS)):
3297 3eccac06 Iustin Pop
    _Fail("Export info file doesn't have the required fields")
3298 a8083063 Iustin Pop
3299 c26a6bd2 Iustin Pop
  return config.Dumps()
3300 a8083063 Iustin Pop
3301 a8083063 Iustin Pop
3302 a8083063 Iustin Pop
def ListExports():
3303 a8083063 Iustin Pop
  """Return a list of exports currently available on this machine.
3304 098c0958 Michael Hanselmann

3305 10c2650b Iustin Pop
  @rtype: list
3306 10c2650b Iustin Pop
  @return: list of the exports
3307 10c2650b Iustin Pop

3308 a8083063 Iustin Pop
  """
3309 710f30ec Michael Hanselmann
  if os.path.isdir(pathutils.EXPORT_DIR):
3310 710f30ec Michael Hanselmann
    return sorted(utils.ListVisibleFiles(pathutils.EXPORT_DIR))
3311 a8083063 Iustin Pop
  else:
3312 afdc3985 Iustin Pop
    _Fail("No exports directory")
3313 a8083063 Iustin Pop
3314 a8083063 Iustin Pop
3315 a8083063 Iustin Pop
def RemoveExport(export):
3316 a8083063 Iustin Pop
  """Remove an existing export from the node.
3317 a8083063 Iustin Pop

3318 10c2650b Iustin Pop
  @type export: str
3319 10c2650b Iustin Pop
  @param export: the name of the export to remove
3320 c26a6bd2 Iustin Pop
  @rtype: None
3321 a8083063 Iustin Pop

3322 098c0958 Michael Hanselmann
  """
3323 710f30ec Michael Hanselmann
  target = utils.PathJoin(pathutils.EXPORT_DIR, export)
3324 a8083063 Iustin Pop
3325 35fbcd11 Iustin Pop
  try:
3326 35fbcd11 Iustin Pop
    shutil.rmtree(target)
3327 35fbcd11 Iustin Pop
  except EnvironmentError, err:
3328 35fbcd11 Iustin Pop
    _Fail("Error while removing the export: %s", err, exc=True)
3329 a8083063 Iustin Pop
3330 a8083063 Iustin Pop
3331 821d1bd1 Iustin Pop
def BlockdevRename(devlist):
3332 f3e513ad Iustin Pop
  """Rename a list of block devices.
3333 f3e513ad Iustin Pop

3334 10c2650b Iustin Pop
  @type devlist: list of tuples
3335 a57e502a Thomas Thrainer
  @param devlist: list of tuples of the form  (disk, new_unique_id); disk is
3336 a57e502a Thomas Thrainer
      an L{objects.Disk} object describing the current disk, and new
3337 a57e502a Thomas Thrainer
      unique_id is the name we rename it to
3338 10c2650b Iustin Pop
  @rtype: boolean
3339 10c2650b Iustin Pop
  @return: True if all renames succeeded, False otherwise
3340 f3e513ad Iustin Pop

3341 f3e513ad Iustin Pop
  """
3342 6b5e3f70 Iustin Pop
  msgs = []
3343 f3e513ad Iustin Pop
  result = True
3344 f3e513ad Iustin Pop
  for disk, unique_id in devlist:
3345 f3e513ad Iustin Pop
    dev = _RecursiveFindBD(disk)
3346 f3e513ad Iustin Pop
    if dev is None:
3347 6b5e3f70 Iustin Pop
      msgs.append("Can't find device %s in rename" % str(disk))
3348 f3e513ad Iustin Pop
      result = False
3349 f3e513ad Iustin Pop
      continue
3350 f3e513ad Iustin Pop
    try:
3351 3f78eef2 Iustin Pop
      old_rpath = dev.dev_path
3352 f3e513ad Iustin Pop
      dev.Rename(unique_id)
3353 3f78eef2 Iustin Pop
      new_rpath = dev.dev_path
3354 3f78eef2 Iustin Pop
      if old_rpath != new_rpath:
3355 3f78eef2 Iustin Pop
        DevCacheManager.RemoveCache(old_rpath)
3356 3f78eef2 Iustin Pop
        # FIXME: we should add the new cache information here, like:
3357 3f78eef2 Iustin Pop
        # DevCacheManager.UpdateCache(new_rpath, owner, ...)
3358 3f78eef2 Iustin Pop
        # but we don't have the owner here - maybe parse from existing
3359 3f78eef2 Iustin Pop
        # cache? for now, we only lose lvm data when we rename, which
3360 3f78eef2 Iustin Pop
        # is less critical than DRBD or MD
3361 f3e513ad Iustin Pop
    except errors.BlockDeviceError, err:
3362 6b5e3f70 Iustin Pop
      msgs.append("Can't rename device '%s' to '%s': %s" %
3363 6b5e3f70 Iustin Pop
                  (dev, unique_id, err))
3364 18682bca Iustin Pop
      logging.exception("Can't rename device '%s' to '%s'", dev, unique_id)
3365 f3e513ad Iustin Pop
      result = False
3366 afdc3985 Iustin Pop
  if not result:
3367 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
3368 f3e513ad Iustin Pop
3369 f3e513ad Iustin Pop
3370 4b97f902 Apollon Oikonomopoulos
def _TransformFileStorageDir(fs_dir):
3371 778b75bb Manuel Franceschini
  """Checks whether given file_storage_dir is valid.
3372 778b75bb Manuel Franceschini

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

3377 4b97f902 Apollon Oikonomopoulos
  @type fs_dir: str
3378 4b97f902 Apollon Oikonomopoulos
  @param fs_dir: the path to check
3379 d61cbe76 Iustin Pop

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

3382 778b75bb Manuel Franceschini
  """
3383 13a6c760 Helga Velroyen
  filestorage.CheckFileStoragePath(fs_dir)
3384 5e09a309 Michael Hanselmann
3385 5e09a309 Michael Hanselmann
  return os.path.normpath(fs_dir)
3386 778b75bb Manuel Franceschini
3387 778b75bb Manuel Franceschini
3388 778b75bb Manuel Franceschini
def CreateFileStorageDir(file_storage_dir):
3389 778b75bb Manuel Franceschini
  """Create file storage directory.
3390 778b75bb Manuel Franceschini

3391 b1206984 Iustin Pop
  @type file_storage_dir: str
3392 b1206984 Iustin Pop
  @param file_storage_dir: directory to create
3393 778b75bb Manuel Franceschini

3394 b1206984 Iustin Pop
  @rtype: tuple
3395 b1206984 Iustin Pop
  @return: tuple with first element a boolean indicating wheter dir
3396 b1206984 Iustin Pop
      creation was successful or not
3397 778b75bb Manuel Franceschini

3398 778b75bb Manuel Franceschini
  """
3399 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3400 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3401 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3402 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3403 b2b8bcce Iustin Pop
            file_storage_dir)
3404 778b75bb Manuel Franceschini
  else:
3405 b2b8bcce Iustin Pop
    try:
3406 b2b8bcce Iustin Pop
      os.makedirs(file_storage_dir, 0750)
3407 b2b8bcce Iustin Pop
    except OSError, err:
3408 b2b8bcce Iustin Pop
      _Fail("Cannot create file storage directory '%s': %s",
3409 b2b8bcce Iustin Pop
            file_storage_dir, err, exc=True)
3410 778b75bb Manuel Franceschini
3411 778b75bb Manuel Franceschini
3412 778b75bb Manuel Franceschini
def RemoveFileStorageDir(file_storage_dir):
3413 778b75bb Manuel Franceschini
  """Remove file storage directory.
3414 778b75bb Manuel Franceschini

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

3417 10c2650b Iustin Pop
  @type file_storage_dir: str
3418 10c2650b Iustin Pop
  @param file_storage_dir: the directory we should cleanup
3419 10c2650b Iustin Pop
  @rtype: tuple (success,)
3420 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3421 5bbd3f7f Michael Hanselmann
      whether the operation was successful
3422 778b75bb Manuel Franceschini

3423 778b75bb Manuel Franceschini
  """
3424 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3425 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3426 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3427 b2b8bcce Iustin Pop
      _Fail("Specified Storage directory '%s' is not a directory",
3428 b2b8bcce Iustin Pop
            file_storage_dir)
3429 afdc3985 Iustin Pop
    # deletes dir only if empty, otherwise we want to fail the rpc call
3430 b2b8bcce Iustin Pop
    try:
3431 b2b8bcce Iustin Pop
      os.rmdir(file_storage_dir)
3432 b2b8bcce Iustin Pop
    except OSError, err:
3433 b2b8bcce Iustin Pop
      _Fail("Cannot remove file storage directory '%s': %s",
3434 b2b8bcce Iustin Pop
            file_storage_dir, err)
3435 b2b8bcce Iustin Pop
3436 778b75bb Manuel Franceschini
3437 778b75bb Manuel Franceschini
def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir):
3438 778b75bb Manuel Franceschini
  """Rename the file storage directory.
3439 778b75bb Manuel Franceschini

3440 10c2650b Iustin Pop
  @type old_file_storage_dir: str
3441 10c2650b Iustin Pop
  @param old_file_storage_dir: the current path
3442 10c2650b Iustin Pop
  @type new_file_storage_dir: str
3443 10c2650b Iustin Pop
  @param new_file_storage_dir: the name we should rename to
3444 10c2650b Iustin Pop
  @rtype: tuple (success,)
3445 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3446 10c2650b Iustin Pop
      whether the operation was successful
3447 778b75bb Manuel Franceschini

3448 778b75bb Manuel Franceschini
  """
3449 778b75bb Manuel Franceschini
  old_file_storage_dir = _TransformFileStorageDir(old_file_storage_dir)
3450 778b75bb Manuel Franceschini
  new_file_storage_dir = _TransformFileStorageDir(new_file_storage_dir)
3451 b2b8bcce Iustin Pop
  if not os.path.exists(new_file_storage_dir):
3452 b2b8bcce Iustin Pop
    if os.path.isdir(old_file_storage_dir):
3453 b2b8bcce Iustin Pop
      try:
3454 b2b8bcce Iustin Pop
        os.rename(old_file_storage_dir, new_file_storage_dir)
3455 b2b8bcce Iustin Pop
      except OSError, err:
3456 b2b8bcce Iustin Pop
        _Fail("Cannot rename '%s' to '%s': %s",
3457 b2b8bcce Iustin Pop
              old_file_storage_dir, new_file_storage_dir, err)
3458 778b75bb Manuel Franceschini
    else:
3459 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3460 b2b8bcce Iustin Pop
            old_file_storage_dir)
3461 b2b8bcce Iustin Pop
  else:
3462 b2b8bcce Iustin Pop
    if os.path.exists(old_file_storage_dir):
3463 b2b8bcce Iustin Pop
      _Fail("Cannot rename '%s' to '%s': both locations exist",
3464 b2b8bcce Iustin Pop
            old_file_storage_dir, new_file_storage_dir)
3465 778b75bb Manuel Franceschini
3466 778b75bb Manuel Franceschini
3467 c8457ce7 Iustin Pop
def _EnsureJobQueueFile(file_name):
3468 dc31eae3 Michael Hanselmann
  """Checks whether the given filename is in the queue directory.
3469 ca52cdeb Michael Hanselmann

3470 10c2650b Iustin Pop
  @type file_name: str
3471 10c2650b Iustin Pop
  @param file_name: the file name we should check
3472 c8457ce7 Iustin Pop
  @rtype: None
3473 c8457ce7 Iustin Pop
  @raises RPCFail: if the file is not valid
3474 10c2650b Iustin Pop

3475 ca52cdeb Michael Hanselmann
  """
3476 b3589802 Michael Hanselmann
  if not utils.IsBelowDir(pathutils.QUEUE_DIR, file_name):
3477 c8457ce7 Iustin Pop
    _Fail("Passed job queue file '%s' does not belong to"
3478 b3589802 Michael Hanselmann
          " the queue directory '%s'", file_name, pathutils.QUEUE_DIR)
3479 dc31eae3 Michael Hanselmann
3480 dc31eae3 Michael Hanselmann
3481 dc31eae3 Michael Hanselmann
def JobQueueUpdate(file_name, content):
3482 dc31eae3 Michael Hanselmann
  """Updates a file in the queue directory.
3483 dc31eae3 Michael Hanselmann

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

3487 10c2650b Iustin Pop
  @type file_name: str
3488 10c2650b Iustin Pop
  @param file_name: the job file name
3489 10c2650b Iustin Pop
  @type content: str
3490 10c2650b Iustin Pop
  @param content: the new job contents
3491 10c2650b Iustin Pop
  @rtype: boolean
3492 10c2650b Iustin Pop
  @return: the success of the operation
3493 10c2650b Iustin Pop

3494 dc31eae3 Michael Hanselmann
  """
3495 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
3496 cffbbae7 Michael Hanselmann
3497 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(file_name)
3498 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
3499 ca52cdeb Michael Hanselmann
3500 ca52cdeb Michael Hanselmann
  # Write and replace the file atomically
3501 82b22e19 René Nussbaumer
  utils.WriteFile(file_name, data=_Decompress(content), uid=getents.masterd_uid,
3502 fe05a931 Michele Tartara
                  gid=getents.daemons_gid, mode=constants.JOB_QUEUE_FILES_PERMS)
3503 ca52cdeb Michael Hanselmann
3504 ca52cdeb Michael Hanselmann
3505 af5ebcb1 Michael Hanselmann
def JobQueueRename(old, new):
3506 af5ebcb1 Michael Hanselmann
  """Renames a job queue file.
3507 af5ebcb1 Michael Hanselmann

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

3510 10c2650b Iustin Pop
  @type old: str
3511 10c2650b Iustin Pop
  @param old: the old (actual) file name
3512 10c2650b Iustin Pop
  @type new: str
3513 10c2650b Iustin Pop
  @param new: the desired file name
3514 c8457ce7 Iustin Pop
  @rtype: tuple
3515 c8457ce7 Iustin Pop
  @return: the success of the operation and payload
3516 10c2650b Iustin Pop

3517 af5ebcb1 Michael Hanselmann
  """
3518 cffbbae7 Michael Hanselmann
  old = vcluster.LocalizeVirtualPath(old)
3519 cffbbae7 Michael Hanselmann
  new = vcluster.LocalizeVirtualPath(new)
3520 cffbbae7 Michael Hanselmann
3521 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(old)
3522 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(new)
3523 af5ebcb1 Michael Hanselmann
3524 8e5a705d René Nussbaumer
  getents = runtime.GetEnts()
3525 8e5a705d René Nussbaumer
3526 fe05a931 Michele Tartara
  utils.RenameFile(old, new, mkdir=True, mkdir_mode=0750,
3527 fe05a931 Michele Tartara
                   dir_uid=getents.masterd_uid, dir_gid=getents.daemons_gid)
3528 af5ebcb1 Michael Hanselmann
3529 af5ebcb1 Michael Hanselmann
3530 821d1bd1 Iustin Pop
def BlockdevClose(instance_name, disks):
3531 d61cbe76 Iustin Pop
  """Closes the given block devices.
3532 d61cbe76 Iustin Pop

3533 10c2650b Iustin Pop
  This means they will be switched to secondary mode (in case of
3534 10c2650b Iustin Pop
  DRBD).
3535 10c2650b Iustin Pop

3536 b2e7666a Iustin Pop
  @param instance_name: if the argument is not empty, the symlinks
3537 b2e7666a Iustin Pop
      of this instance will be removed
3538 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
3539 10c2650b Iustin Pop
  @param disks: the list of disks to be closed
3540 10c2650b Iustin Pop
  @rtype: tuple (success, message)
3541 10c2650b Iustin Pop
  @return: a tuple of success and message, where success
3542 10c2650b Iustin Pop
      indicates the succes of the operation, and message
3543 10c2650b Iustin Pop
      which will contain the error details in case we
3544 10c2650b Iustin Pop
      failed
3545 d61cbe76 Iustin Pop

3546 d61cbe76 Iustin Pop
  """
3547 d61cbe76 Iustin Pop
  bdevs = []
3548 d61cbe76 Iustin Pop
  for cf in disks:
3549 d61cbe76 Iustin Pop
    rd = _RecursiveFindBD(cf)
3550 d61cbe76 Iustin Pop
    if rd is None:
3551 2cc6781a Iustin Pop
      _Fail("Can't find device %s", cf)
3552 d61cbe76 Iustin Pop
    bdevs.append(rd)
3553 d61cbe76 Iustin Pop
3554 d61cbe76 Iustin Pop
  msg = []
3555 d61cbe76 Iustin Pop
  for rd in bdevs:
3556 d61cbe76 Iustin Pop
    try:
3557 d61cbe76 Iustin Pop
      rd.Close()
3558 d61cbe76 Iustin Pop
    except errors.BlockDeviceError, err:
3559 d61cbe76 Iustin Pop
      msg.append(str(err))
3560 d61cbe76 Iustin Pop
  if msg:
3561 afdc3985 Iustin Pop
    _Fail("Can't make devices secondary: %s", ",".join(msg))
3562 d61cbe76 Iustin Pop
  else:
3563 b2e7666a Iustin Pop
    if instance_name:
3564 5282084b Iustin Pop
      _RemoveBlockDevLinks(instance_name, disks)
3565 d61cbe76 Iustin Pop
3566 d61cbe76 Iustin Pop
3567 6217e295 Iustin Pop
def ValidateHVParams(hvname, hvparams):
3568 6217e295 Iustin Pop
  """Validates the given hypervisor parameters.
3569 6217e295 Iustin Pop

3570 6217e295 Iustin Pop
  @type hvname: string
3571 6217e295 Iustin Pop
  @param hvname: the hypervisor name
3572 6217e295 Iustin Pop
  @type hvparams: dict
3573 6217e295 Iustin Pop
  @param hvparams: the hypervisor parameters to be validated
3574 c26a6bd2 Iustin Pop
  @rtype: None
3575 6217e295 Iustin Pop

3576 6217e295 Iustin Pop
  """
3577 6217e295 Iustin Pop
  try:
3578 6217e295 Iustin Pop
    hv_type = hypervisor.GetHypervisor(hvname)
3579 6217e295 Iustin Pop
    hv_type.ValidateParameters(hvparams)
3580 6217e295 Iustin Pop
  except errors.HypervisorError, err:
3581 afdc3985 Iustin Pop
    _Fail(str(err), log=False)
3582 6217e295 Iustin Pop
3583 6217e295 Iustin Pop
3584 acd9ff9e Iustin Pop
def _CheckOSPList(os_obj, parameters):
3585 acd9ff9e Iustin Pop
  """Check whether a list of parameters is supported by the OS.
3586 acd9ff9e Iustin Pop

3587 acd9ff9e Iustin Pop
  @type os_obj: L{objects.OS}
3588 acd9ff9e Iustin Pop
  @param os_obj: OS object to check
3589 acd9ff9e Iustin Pop
  @type parameters: list
3590 acd9ff9e Iustin Pop
  @param parameters: the list of parameters to check
3591 acd9ff9e Iustin Pop

3592 acd9ff9e Iustin Pop
  """
3593 acd9ff9e Iustin Pop
  supported = [v[0] for v in os_obj.supported_parameters]
3594 acd9ff9e Iustin Pop
  delta = frozenset(parameters).difference(supported)
3595 acd9ff9e Iustin Pop
  if delta:
3596 acd9ff9e Iustin Pop
    _Fail("The following parameters are not supported"
3597 acd9ff9e Iustin Pop
          " by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
3598 acd9ff9e Iustin Pop
3599 acd9ff9e Iustin Pop
3600 acd9ff9e Iustin Pop
def ValidateOS(required, osname, checks, osparams):
3601 acd9ff9e Iustin Pop
  """Validate the given OS' parameters.
3602 acd9ff9e Iustin Pop

3603 acd9ff9e Iustin Pop
  @type required: boolean
3604 acd9ff9e Iustin Pop
  @param required: whether absence of the OS should translate into
3605 acd9ff9e Iustin Pop
      failure or not
3606 acd9ff9e Iustin Pop
  @type osname: string
3607 acd9ff9e Iustin Pop
  @param osname: the OS to be validated
3608 acd9ff9e Iustin Pop
  @type checks: list
3609 acd9ff9e Iustin Pop
  @param checks: list of the checks to run (currently only 'parameters')
3610 acd9ff9e Iustin Pop
  @type osparams: dict
3611 1a182390 Santi Raffa
  @param osparams: dictionary with OS parameters, some of which may be
3612 1a182390 Santi Raffa
                   private.
3613 acd9ff9e Iustin Pop
  @rtype: boolean
3614 acd9ff9e Iustin Pop
  @return: True if the validation passed, or False if the OS was not
3615 acd9ff9e Iustin Pop
      found and L{required} was false
3616 acd9ff9e Iustin Pop

3617 acd9ff9e Iustin Pop
  """
3618 acd9ff9e Iustin Pop
  if not constants.OS_VALIDATE_CALLS.issuperset(checks):
3619 acd9ff9e Iustin Pop
    _Fail("Unknown checks required for OS %s: %s", osname,
3620 acd9ff9e Iustin Pop
          set(checks).difference(constants.OS_VALIDATE_CALLS))
3621 acd9ff9e Iustin Pop
3622 870dc44c Iustin Pop
  name_only = objects.OS.GetName(osname)
3623 acd9ff9e Iustin Pop
  status, tbv = _TryOSFromDisk(name_only, None)
3624 acd9ff9e Iustin Pop
3625 acd9ff9e Iustin Pop
  if not status:
3626 acd9ff9e Iustin Pop
    if required:
3627 acd9ff9e Iustin Pop
      _Fail(tbv)
3628 acd9ff9e Iustin Pop
    else:
3629 acd9ff9e Iustin Pop
      return False
3630 acd9ff9e Iustin Pop
3631 72db3fd7 Iustin Pop
  if max(tbv.api_versions) < constants.OS_API_V20:
3632 72db3fd7 Iustin Pop
    return True
3633 72db3fd7 Iustin Pop
3634 acd9ff9e Iustin Pop
  if constants.OS_VALIDATE_PARAMETERS in checks:
3635 acd9ff9e Iustin Pop
    _CheckOSPList(tbv, osparams.keys())
3636 acd9ff9e Iustin Pop
3637 a025e535 Vitaly Kuznetsov
  validate_env = OSCoreEnv(osname, tbv, osparams)
3638 acd9ff9e Iustin Pop
  result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
3639 896a03f6 Iustin Pop
                        cwd=tbv.path, reset_env=True)
3640 acd9ff9e Iustin Pop
  if result.failed:
3641 acd9ff9e Iustin Pop
    logging.error("os validate command '%s' returned error: %s output: %s",
3642 acd9ff9e Iustin Pop
                  result.cmd, result.fail_reason, result.output)
3643 acd9ff9e Iustin Pop
    _Fail("OS validation script failed (%s), output: %s",
3644 acd9ff9e Iustin Pop
          result.fail_reason, result.output, log=False)
3645 acd9ff9e Iustin Pop
3646 acd9ff9e Iustin Pop
  return True
3647 acd9ff9e Iustin Pop
3648 acd9ff9e Iustin Pop
3649 56aa9fd5 Iustin Pop
def DemoteFromMC():
3650 56aa9fd5 Iustin Pop
  """Demotes the current node from master candidate role.
3651 56aa9fd5 Iustin Pop

3652 56aa9fd5 Iustin Pop
  """
3653 56aa9fd5 Iustin Pop
  # try to ensure we're not the master by mistake
3654 56aa9fd5 Iustin Pop
  master, myself = ssconf.GetMasterAndMyself()
3655 56aa9fd5 Iustin Pop
  if master == myself:
3656 afdc3985 Iustin Pop
    _Fail("ssconf status shows I'm the master node, will not demote")
3657 f154a7a3 Michael Hanselmann
3658 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "check", constants.MASTERD])
3659 f154a7a3 Michael Hanselmann
  if not result.failed:
3660 afdc3985 Iustin Pop
    _Fail("The master daemon is running, will not demote")
3661 f154a7a3 Michael Hanselmann
3662 56aa9fd5 Iustin Pop
  try:
3663 710f30ec Michael Hanselmann
    if os.path.isfile(pathutils.CLUSTER_CONF_FILE):
3664 710f30ec Michael Hanselmann
      utils.CreateBackup(pathutils.CLUSTER_CONF_FILE)
3665 56aa9fd5 Iustin Pop
  except EnvironmentError, err:
3666 56aa9fd5 Iustin Pop
    if err.errno != errno.ENOENT:
3667 afdc3985 Iustin Pop
      _Fail("Error while backing up cluster file: %s", err, exc=True)
3668 f154a7a3 Michael Hanselmann
3669 710f30ec Michael Hanselmann
  utils.RemoveFile(pathutils.CLUSTER_CONF_FILE)
3670 56aa9fd5 Iustin Pop
3671 56aa9fd5 Iustin Pop
3672 f942a838 Michael Hanselmann
def _GetX509Filenames(cryptodir, name):
3673 f942a838 Michael Hanselmann
  """Returns the full paths for the private key and certificate.
3674 f942a838 Michael Hanselmann

3675 f942a838 Michael Hanselmann
  """
3676 f942a838 Michael Hanselmann
  return (utils.PathJoin(cryptodir, name),
3677 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_KEY_FILE),
3678 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_CERT_FILE))
3679 f942a838 Michael Hanselmann
3680 f942a838 Michael Hanselmann
3681 710f30ec Michael Hanselmann
def CreateX509Certificate(validity, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3682 f942a838 Michael Hanselmann
  """Creates a new X509 certificate for SSL/TLS.
3683 f942a838 Michael Hanselmann

3684 f942a838 Michael Hanselmann
  @type validity: int
3685 f942a838 Michael Hanselmann
  @param validity: Validity in seconds
3686 f942a838 Michael Hanselmann
  @rtype: tuple; (string, string)
3687 f942a838 Michael Hanselmann
  @return: Certificate name and public part
3688 f942a838 Michael Hanselmann

3689 f942a838 Michael Hanselmann
  """
3690 f942a838 Michael Hanselmann
  (key_pem, cert_pem) = \
3691 b705c7a6 Manuel Franceschini
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
3692 f942a838 Michael Hanselmann
                                     min(validity, _MAX_SSL_CERT_VALIDITY))
3693 f942a838 Michael Hanselmann
3694 f942a838 Michael Hanselmann
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
3695 f942a838 Michael Hanselmann
                              prefix="x509-%s-" % utils.TimestampForFilename())
3696 f942a838 Michael Hanselmann
  try:
3697 f942a838 Michael Hanselmann
    name = os.path.basename(cert_dir)
3698 f942a838 Michael Hanselmann
    assert len(name) > 5
3699 f942a838 Michael Hanselmann
3700 f942a838 Michael Hanselmann
    (_, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3701 f942a838 Michael Hanselmann
3702 f942a838 Michael Hanselmann
    utils.WriteFile(key_file, mode=0400, data=key_pem)
3703 f942a838 Michael Hanselmann
    utils.WriteFile(cert_file, mode=0400, data=cert_pem)
3704 f942a838 Michael Hanselmann
3705 f942a838 Michael Hanselmann
    # Never return private key as it shouldn't leave the node
3706 f942a838 Michael Hanselmann
    return (name, cert_pem)
3707 f942a838 Michael Hanselmann
  except Exception:
3708 f942a838 Michael Hanselmann
    shutil.rmtree(cert_dir, ignore_errors=True)
3709 f942a838 Michael Hanselmann
    raise
3710 f942a838 Michael Hanselmann
3711 f942a838 Michael Hanselmann
3712 710f30ec Michael Hanselmann
def RemoveX509Certificate(name, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3713 f942a838 Michael Hanselmann
  """Removes a X509 certificate.
3714 f942a838 Michael Hanselmann

3715 f942a838 Michael Hanselmann
  @type name: string
3716 f942a838 Michael Hanselmann
  @param name: Certificate name
3717 f942a838 Michael Hanselmann

3718 f942a838 Michael Hanselmann
  """
3719 f942a838 Michael Hanselmann
  (cert_dir, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3720 f942a838 Michael Hanselmann
3721 f942a838 Michael Hanselmann
  utils.RemoveFile(key_file)
3722 f942a838 Michael Hanselmann
  utils.RemoveFile(cert_file)
3723 f942a838 Michael Hanselmann
3724 f942a838 Michael Hanselmann
  try:
3725 f942a838 Michael Hanselmann
    os.rmdir(cert_dir)
3726 f942a838 Michael Hanselmann
  except EnvironmentError, err:
3727 f942a838 Michael Hanselmann
    _Fail("Cannot remove certificate directory '%s': %s",
3728 f942a838 Michael Hanselmann
          cert_dir, err)
3729 f942a838 Michael Hanselmann
3730 f942a838 Michael Hanselmann
3731 1651d116 Michael Hanselmann
def _GetImportExportIoCommand(instance, mode, ieio, ieargs):
3732 1651d116 Michael Hanselmann
  """Returns the command for the requested input/output.
3733 1651d116 Michael Hanselmann

3734 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
3735 1651d116 Michael Hanselmann
  @param instance: The instance object
3736 1651d116 Michael Hanselmann
  @param mode: Import/export mode
3737 1651d116 Michael Hanselmann
  @param ieio: Input/output type
3738 1651d116 Michael Hanselmann
  @param ieargs: Input/output arguments
3739 1651d116 Michael Hanselmann

3740 1651d116 Michael Hanselmann
  """
3741 1651d116 Michael Hanselmann
  assert mode in (constants.IEM_IMPORT, constants.IEM_EXPORT)
3742 1651d116 Michael Hanselmann
3743 1651d116 Michael Hanselmann
  env = None
3744 1651d116 Michael Hanselmann
  prefix = None
3745 1651d116 Michael Hanselmann
  suffix = None
3746 2ad5550d Michael Hanselmann
  exp_size = None
3747 1651d116 Michael Hanselmann
3748 1651d116 Michael Hanselmann
  if ieio == constants.IEIO_FILE:
3749 1651d116 Michael Hanselmann
    (filename, ) = ieargs
3750 1651d116 Michael Hanselmann
3751 1651d116 Michael Hanselmann
    if not utils.IsNormAbsPath(filename):
3752 1651d116 Michael Hanselmann
      _Fail("Path '%s' is not normalized or absolute", filename)
3753 1651d116 Michael Hanselmann
3754 748c9884 René Nussbaumer
    real_filename = os.path.realpath(filename)
3755 748c9884 René Nussbaumer
    directory = os.path.dirname(real_filename)
3756 1651d116 Michael Hanselmann
3757 710f30ec Michael Hanselmann
    if not utils.IsBelowDir(pathutils.EXPORT_DIR, real_filename):
3758 748c9884 René Nussbaumer
      _Fail("File '%s' is not under exports directory '%s': %s",
3759 710f30ec Michael Hanselmann
            filename, pathutils.EXPORT_DIR, real_filename)
3760 1651d116 Michael Hanselmann
3761 1651d116 Michael Hanselmann
    # Create directory
3762 1651d116 Michael Hanselmann
    utils.Makedirs(directory, mode=0750)
3763 1651d116 Michael Hanselmann
3764 1651d116 Michael Hanselmann
    quoted_filename = utils.ShellQuote(filename)
3765 1651d116 Michael Hanselmann
3766 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3767 1651d116 Michael Hanselmann
      suffix = "> %s" % quoted_filename
3768 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3769 1651d116 Michael Hanselmann
      suffix = "< %s" % quoted_filename
3770 1651d116 Michael Hanselmann
3771 2ad5550d Michael Hanselmann
      # Retrieve file size
3772 2ad5550d Michael Hanselmann
      try:
3773 2ad5550d Michael Hanselmann
        st = os.stat(filename)
3774 2ad5550d Michael Hanselmann
      except EnvironmentError, err:
3775 2ad5550d Michael Hanselmann
        logging.error("Can't stat(2) %s: %s", filename, err)
3776 2ad5550d Michael Hanselmann
      else:
3777 2ad5550d Michael Hanselmann
        exp_size = utils.BytesToMebibyte(st.st_size)
3778 2ad5550d Michael Hanselmann
3779 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_RAW_DISK:
3780 1651d116 Michael Hanselmann
    (disk, ) = ieargs
3781 1651d116 Michael Hanselmann
3782 1651d116 Michael Hanselmann
    real_disk = _OpenRealBD(disk)
3783 1651d116 Michael Hanselmann
3784 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3785 a986a581 Thomas Thrainer
      # we use nocreat to fail if the device is not already there or we pass a
3786 a986a581 Thomas Thrainer
      # wrong path; we use notrunc to no attempt truncate on an LV device
3787 a986a581 Thomas Thrainer
      suffix = utils.BuildShellCmd("| dd of=%s conv=nocreat,notrunc bs=%s",
3788 a986a581 Thomas Thrainer
                                   real_disk.dev_path,
3789 a986a581 Thomas Thrainer
                                   str(1024 * 1024)) # 1 MB
3790 1651d116 Michael Hanselmann
3791 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3792 1651d116 Michael Hanselmann
      # the block size on the read dd is 1MiB to match our units
3793 1651d116 Michael Hanselmann
      prefix = utils.BuildShellCmd("dd if=%s bs=%s count=%s |",
3794 1651d116 Michael Hanselmann
                                   real_disk.dev_path,
3795 1651d116 Michael Hanselmann
                                   str(1024 * 1024), # 1 MB
3796 1651d116 Michael Hanselmann
                                   str(disk.size))
3797 2ad5550d Michael Hanselmann
      exp_size = disk.size
3798 1651d116 Michael Hanselmann
3799 1651d116 Michael Hanselmann
  elif ieio == constants.IEIO_SCRIPT:
3800 1651d116 Michael Hanselmann
    (disk, disk_index, ) = ieargs
3801 1651d116 Michael Hanselmann
3802 1651d116 Michael Hanselmann
    assert isinstance(disk_index, (int, long))
3803 1651d116 Michael Hanselmann
3804 1651d116 Michael Hanselmann
    inst_os = OSFromDisk(instance.os)
3805 1651d116 Michael Hanselmann
    env = OSEnvironment(instance, inst_os)
3806 1651d116 Michael Hanselmann
3807 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3808 1651d116 Michael Hanselmann
      env["IMPORT_DEVICE"] = env["DISK_%d_PATH" % disk_index]
3809 1651d116 Michael Hanselmann
      env["IMPORT_INDEX"] = str(disk_index)
3810 1651d116 Michael Hanselmann
      script = inst_os.import_script
3811 1651d116 Michael Hanselmann
3812 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3813 0c3d9c7c Thomas Thrainer
      real_disk = _OpenRealBD(disk)
3814 1651d116 Michael Hanselmann
      env["EXPORT_DEVICE"] = real_disk.dev_path
3815 1651d116 Michael Hanselmann
      env["EXPORT_INDEX"] = str(disk_index)
3816 1651d116 Michael Hanselmann
      script = inst_os.export_script
3817 1651d116 Michael Hanselmann
3818 1651d116 Michael Hanselmann
    # TODO: Pass special environment only to script
3819 1651d116 Michael Hanselmann
    script_cmd = utils.BuildShellCmd("( cd %s && %s; )", inst_os.path, script)
3820 1651d116 Michael Hanselmann
3821 1651d116 Michael Hanselmann
    if mode == constants.IEM_IMPORT:
3822 1651d116 Michael Hanselmann
      suffix = "| %s" % script_cmd
3823 1651d116 Michael Hanselmann
3824 1651d116 Michael Hanselmann
    elif mode == constants.IEM_EXPORT:
3825 1651d116 Michael Hanselmann
      prefix = "%s |" % script_cmd
3826 1651d116 Michael Hanselmann
3827 2ad5550d Michael Hanselmann
    # Let script predict size
3828 2ad5550d Michael Hanselmann
    exp_size = constants.IE_CUSTOM_SIZE
3829 2ad5550d Michael Hanselmann
3830 1651d116 Michael Hanselmann
  else:
3831 1651d116 Michael Hanselmann
    _Fail("Invalid %s I/O mode %r", mode, ieio)
3832 1651d116 Michael Hanselmann
3833 2ad5550d Michael Hanselmann
  return (env, prefix, suffix, exp_size)
3834 1651d116 Michael Hanselmann
3835 1651d116 Michael Hanselmann
3836 1651d116 Michael Hanselmann
def _CreateImportExportStatusDir(prefix):
3837 1651d116 Michael Hanselmann
  """Creates status directory for import/export.
3838 1651d116 Michael Hanselmann

3839 1651d116 Michael Hanselmann
  """
3840 710f30ec Michael Hanselmann
  return tempfile.mkdtemp(dir=pathutils.IMPORT_EXPORT_DIR,
3841 1651d116 Michael Hanselmann
                          prefix=("%s-%s-" %
3842 1651d116 Michael Hanselmann
                                  (prefix, utils.TimestampForFilename())))
3843 1651d116 Michael Hanselmann
3844 1651d116 Michael Hanselmann
3845 6613661a Iustin Pop
def StartImportExportDaemon(mode, opts, host, port, instance, component,
3846 6613661a Iustin Pop
                            ieio, ieioargs):
3847 1651d116 Michael Hanselmann
  """Starts an import or export daemon.
3848 1651d116 Michael Hanselmann

3849 1651d116 Michael Hanselmann
  @param mode: Import/output mode
3850 eb630f50 Michael Hanselmann
  @type opts: L{objects.ImportExportOptions}
3851 eb630f50 Michael Hanselmann
  @param opts: Daemon options
3852 1651d116 Michael Hanselmann
  @type host: string
3853 1651d116 Michael Hanselmann
  @param host: Remote host for export (None for import)
3854 1651d116 Michael Hanselmann
  @type port: int
3855 1651d116 Michael Hanselmann
  @param port: Remote port for export (None for import)
3856 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
3857 1651d116 Michael Hanselmann
  @param instance: Instance object
3858 6613661a Iustin Pop
  @type component: string
3859 6613661a Iustin Pop
  @param component: which part of the instance is transferred now,
3860 6613661a Iustin Pop
      e.g. 'disk/0'
3861 1651d116 Michael Hanselmann
  @param ieio: Input/output type
3862 1651d116 Michael Hanselmann
  @param ieioargs: Input/output arguments
3863 1651d116 Michael Hanselmann

3864 1651d116 Michael Hanselmann
  """
3865 1651d116 Michael Hanselmann
  if mode == constants.IEM_IMPORT:
3866 1651d116 Michael Hanselmann
    prefix = "import"
3867 1651d116 Michael Hanselmann
3868 1651d116 Michael Hanselmann
    if not (host is None and port is None):
3869 1651d116 Michael Hanselmann
      _Fail("Can not specify host or port on import")
3870 1651d116 Michael Hanselmann
3871 1651d116 Michael Hanselmann
  elif mode == constants.IEM_EXPORT:
3872 1651d116 Michael Hanselmann
    prefix = "export"
3873 1651d116 Michael Hanselmann
3874 1651d116 Michael Hanselmann
    if host is None or port is None:
3875 1651d116 Michael Hanselmann
      _Fail("Host and port must be specified for an export")
3876 1651d116 Michael Hanselmann
3877 1651d116 Michael Hanselmann
  else:
3878 1651d116 Michael Hanselmann
    _Fail("Invalid mode %r", mode)
3879 1651d116 Michael Hanselmann
3880 eb630f50 Michael Hanselmann
  if (opts.key_name is None) ^ (opts.ca_pem is None):
3881 1651d116 Michael Hanselmann
    _Fail("Cluster certificate can only be used for both key and CA")
3882 1651d116 Michael Hanselmann
3883 2ad5550d Michael Hanselmann
  (cmd_env, cmd_prefix, cmd_suffix, exp_size) = \
3884 1651d116 Michael Hanselmann
    _GetImportExportIoCommand(instance, mode, ieio, ieioargs)
3885 1651d116 Michael Hanselmann
3886 eb630f50 Michael Hanselmann
  if opts.key_name is None:
3887 1651d116 Michael Hanselmann
    # Use server.pem
3888 710f30ec Michael Hanselmann
    key_path = pathutils.NODED_CERT_FILE
3889 710f30ec Michael Hanselmann
    cert_path = pathutils.NODED_CERT_FILE
3890 eb630f50 Michael Hanselmann
    assert opts.ca_pem is None
3891 1651d116 Michael Hanselmann
  else:
3892 710f30ec Michael Hanselmann
    (_, key_path, cert_path) = _GetX509Filenames(pathutils.CRYPTO_KEYS_DIR,
3893 eb630f50 Michael Hanselmann
                                                 opts.key_name)
3894 eb630f50 Michael Hanselmann
    assert opts.ca_pem is not None
3895 1651d116 Michael Hanselmann
3896 63bcea2a Michael Hanselmann
  for i in [key_path, cert_path]:
3897 dcaabc4f Michael Hanselmann
    if not os.path.exists(i):
3898 63bcea2a Michael Hanselmann
      _Fail("File '%s' does not exist" % i)
3899 63bcea2a Michael Hanselmann
3900 6613661a Iustin Pop
  status_dir = _CreateImportExportStatusDir("%s-%s" % (prefix, component))
3901 1651d116 Michael Hanselmann
  try:
3902 1651d116 Michael Hanselmann
    status_file = utils.PathJoin(status_dir, _IES_STATUS_FILE)
3903 1651d116 Michael Hanselmann
    pid_file = utils.PathJoin(status_dir, _IES_PID_FILE)
3904 63bcea2a Michael Hanselmann
    ca_file = utils.PathJoin(status_dir, _IES_CA_FILE)
3905 1651d116 Michael Hanselmann
3906 eb630f50 Michael Hanselmann
    if opts.ca_pem is None:
3907 1651d116 Michael Hanselmann
      # Use server.pem
3908 710f30ec Michael Hanselmann
      ca = utils.ReadFile(pathutils.NODED_CERT_FILE)
3909 eb630f50 Michael Hanselmann
    else:
3910 eb630f50 Michael Hanselmann
      ca = opts.ca_pem
3911 63bcea2a Michael Hanselmann
3912 eb630f50 Michael Hanselmann
    # Write CA file
3913 63bcea2a Michael Hanselmann
    utils.WriteFile(ca_file, data=ca, mode=0400)
3914 1651d116 Michael Hanselmann
3915 1651d116 Michael Hanselmann
    cmd = [
3916 710f30ec Michael Hanselmann
      pathutils.IMPORT_EXPORT_DAEMON,
3917 1651d116 Michael Hanselmann
      status_file, mode,
3918 1651d116 Michael Hanselmann
      "--key=%s" % key_path,
3919 1651d116 Michael Hanselmann
      "--cert=%s" % cert_path,
3920 63bcea2a Michael Hanselmann
      "--ca=%s" % ca_file,
3921 1651d116 Michael Hanselmann
      ]
3922 1651d116 Michael Hanselmann
3923 1651d116 Michael Hanselmann
    if host:
3924 1651d116 Michael Hanselmann
      cmd.append("--host=%s" % host)
3925 1651d116 Michael Hanselmann
3926 1651d116 Michael Hanselmann
    if port:
3927 1651d116 Michael Hanselmann
      cmd.append("--port=%s" % port)
3928 1651d116 Michael Hanselmann
3929 855d2fc7 Michael Hanselmann
    if opts.ipv6:
3930 855d2fc7 Michael Hanselmann
      cmd.append("--ipv6")
3931 855d2fc7 Michael Hanselmann
    else:
3932 855d2fc7 Michael Hanselmann
      cmd.append("--ipv4")
3933 855d2fc7 Michael Hanselmann
3934 a5310c2a Michael Hanselmann
    if opts.compress:
3935 a5310c2a Michael Hanselmann
      cmd.append("--compress=%s" % opts.compress)
3936 a5310c2a Michael Hanselmann
3937 af1d39b1 Michael Hanselmann
    if opts.magic:
3938 af1d39b1 Michael Hanselmann
      cmd.append("--magic=%s" % opts.magic)
3939 af1d39b1 Michael Hanselmann
3940 2ad5550d Michael Hanselmann
    if exp_size is not None:
3941 2ad5550d Michael Hanselmann
      cmd.append("--expected-size=%s" % exp_size)
3942 2ad5550d Michael Hanselmann
3943 1651d116 Michael Hanselmann
    if cmd_prefix:
3944 1651d116 Michael Hanselmann
      cmd.append("--cmd-prefix=%s" % cmd_prefix)
3945 1651d116 Michael Hanselmann
3946 1651d116 Michael Hanselmann
    if cmd_suffix:
3947 1651d116 Michael Hanselmann
      cmd.append("--cmd-suffix=%s" % cmd_suffix)
3948 1651d116 Michael Hanselmann
3949 4478301b Michael Hanselmann
    if mode == constants.IEM_EXPORT:
3950 4478301b Michael Hanselmann
      # Retry connection a few times when connecting to remote peer
3951 4478301b Michael Hanselmann
      cmd.append("--connect-retries=%s" % constants.RIE_CONNECT_RETRIES)
3952 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % constants.RIE_CONNECT_ATTEMPT_TIMEOUT)
3953 4478301b Michael Hanselmann
    elif opts.connect_timeout is not None:
3954 4478301b Michael Hanselmann
      assert mode == constants.IEM_IMPORT
3955 4478301b Michael Hanselmann
      # Overall timeout for establishing connection while listening
3956 4478301b Michael Hanselmann
      cmd.append("--connect-timeout=%s" % opts.connect_timeout)
3957 4478301b Michael Hanselmann
3958 6aa7a354 Iustin Pop
    logfile = _InstanceLogName(prefix, instance.os, instance.name, component)
3959 1651d116 Michael Hanselmann
3960 1651d116 Michael Hanselmann
    # TODO: Once _InstanceLogName uses tempfile.mkstemp, StartDaemon has
3961 1651d116 Michael Hanselmann
    # support for receiving a file descriptor for output
3962 1651d116 Michael Hanselmann
    utils.StartDaemon(cmd, env=cmd_env, pidfile=pid_file,
3963 1651d116 Michael Hanselmann
                      output=logfile)
3964 1651d116 Michael Hanselmann
3965 1651d116 Michael Hanselmann
    # The import/export name is simply the status directory name
3966 1651d116 Michael Hanselmann
    return os.path.basename(status_dir)
3967 1651d116 Michael Hanselmann
3968 1651d116 Michael Hanselmann
  except Exception:
3969 1651d116 Michael Hanselmann
    shutil.rmtree(status_dir, ignore_errors=True)
3970 1651d116 Michael Hanselmann
    raise
3971 1651d116 Michael Hanselmann
3972 1651d116 Michael Hanselmann
3973 1651d116 Michael Hanselmann
def GetImportExportStatus(names):
3974 1651d116 Michael Hanselmann
  """Returns import/export daemon status.
3975 1651d116 Michael Hanselmann

3976 1651d116 Michael Hanselmann
  @type names: sequence
3977 1651d116 Michael Hanselmann
  @param names: List of names
3978 1651d116 Michael Hanselmann
  @rtype: List of dicts
3979 1651d116 Michael Hanselmann
  @return: Returns a list of the state of each named import/export or None if a
3980 1651d116 Michael Hanselmann
           status couldn't be read
3981 1651d116 Michael Hanselmann

3982 1651d116 Michael Hanselmann
  """
3983 1651d116 Michael Hanselmann
  result = []
3984 1651d116 Michael Hanselmann
3985 1651d116 Michael Hanselmann
  for name in names:
3986 710f30ec Michael Hanselmann
    status_file = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name,
3987 1651d116 Michael Hanselmann
                                 _IES_STATUS_FILE)
3988 1651d116 Michael Hanselmann
3989 1651d116 Michael Hanselmann
    try:
3990 1651d116 Michael Hanselmann
      data = utils.ReadFile(status_file)
3991 1651d116 Michael Hanselmann
    except EnvironmentError, err:
3992 1651d116 Michael Hanselmann
      if err.errno != errno.ENOENT:
3993 1651d116 Michael Hanselmann
        raise
3994 1651d116 Michael Hanselmann
      data = None
3995 1651d116 Michael Hanselmann
3996 1651d116 Michael Hanselmann
    if not data:
3997 1651d116 Michael Hanselmann
      result.append(None)
3998 1651d116 Michael Hanselmann
      continue
3999 1651d116 Michael Hanselmann
4000 1651d116 Michael Hanselmann
    result.append(serializer.LoadJson(data))
4001 1651d116 Michael Hanselmann
4002 1651d116 Michael Hanselmann
  return result
4003 1651d116 Michael Hanselmann
4004 1651d116 Michael Hanselmann
4005 f81c4737 Michael Hanselmann
def AbortImportExport(name):
4006 f81c4737 Michael Hanselmann
  """Sends SIGTERM to a running import/export daemon.
4007 f81c4737 Michael Hanselmann

4008 f81c4737 Michael Hanselmann
  """
4009 f81c4737 Michael Hanselmann
  logging.info("Abort import/export %s", name)
4010 f81c4737 Michael Hanselmann
4011 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4012 f81c4737 Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4013 f81c4737 Michael Hanselmann
4014 f81c4737 Michael Hanselmann
  if pid:
4015 f81c4737 Michael Hanselmann
    logging.info("Import/export %s is running with PID %s, sending SIGTERM",
4016 f81c4737 Michael Hanselmann
                 name, pid)
4017 560cbec1 Michael Hanselmann
    utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
4018 f81c4737 Michael Hanselmann
4019 f81c4737 Michael Hanselmann
4020 1651d116 Michael Hanselmann
def CleanupImportExport(name):
4021 1651d116 Michael Hanselmann
  """Cleanup after an import or export.
4022 1651d116 Michael Hanselmann

4023 1651d116 Michael Hanselmann
  If the import/export daemon is still running it's killed. Afterwards the
4024 1651d116 Michael Hanselmann
  whole status directory is removed.
4025 1651d116 Michael Hanselmann

4026 1651d116 Michael Hanselmann
  """
4027 1651d116 Michael Hanselmann
  logging.info("Finalizing import/export %s", name)
4028 1651d116 Michael Hanselmann
4029 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4030 1651d116 Michael Hanselmann
4031 debed9ae Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4032 1651d116 Michael Hanselmann
4033 1651d116 Michael Hanselmann
  if pid:
4034 1651d116 Michael Hanselmann
    logging.info("Import/export %s is still running with PID %s",
4035 1651d116 Michael Hanselmann
                 name, pid)
4036 1651d116 Michael Hanselmann
    utils.KillProcess(pid, waitpid=False)
4037 1651d116 Michael Hanselmann
4038 1651d116 Michael Hanselmann
  shutil.rmtree(status_dir, ignore_errors=True)
4039 1651d116 Michael Hanselmann
4040 1651d116 Michael Hanselmann
4041 0c3d9c7c Thomas Thrainer
def _FindDisks(disks):
4042 0c3d9c7c Thomas Thrainer
  """Finds attached L{BlockDev}s for the given disks.
4043 6b93ec9d Iustin Pop

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

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

4050 235a6b29 Thomas Thrainer
  """
4051 6b93ec9d Iustin Pop
  bdevs = []
4052 6b93ec9d Iustin Pop
4053 0c3d9c7c Thomas Thrainer
  for disk in disks:
4054 0c3d9c7c Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4055 6b93ec9d Iustin Pop
    if rd is None:
4056 0c3d9c7c Thomas Thrainer
      _Fail("Can't find device %s", disk)
4057 6b93ec9d Iustin Pop
    bdevs.append(rd)
4058 5a533f8a Iustin Pop
  return bdevs
4059 6b93ec9d Iustin Pop
4060 6b93ec9d Iustin Pop
4061 0c3d9c7c Thomas Thrainer
def DrbdDisconnectNet(disks):
4062 6b93ec9d Iustin Pop
  """Disconnects the network on a list of drbd devices.
4063 6b93ec9d Iustin Pop

4064 6b93ec9d Iustin Pop
  """
4065 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4066 6b93ec9d Iustin Pop
4067 6b93ec9d Iustin Pop
  # disconnect disks
4068 6b93ec9d Iustin Pop
  for rd in bdevs:
4069 6b93ec9d Iustin Pop
    try:
4070 6b93ec9d Iustin Pop
      rd.DisconnectNet()
4071 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
4072 2cc6781a Iustin Pop
      _Fail("Can't change network configuration to standalone mode: %s",
4073 2cc6781a Iustin Pop
            err, exc=True)
4074 6b93ec9d Iustin Pop
4075 6b93ec9d Iustin Pop
4076 0c3d9c7c Thomas Thrainer
def DrbdAttachNet(disks, instance_name, multimaster):
4077 6b93ec9d Iustin Pop
  """Attaches the network on a list of drbd devices.
4078 6b93ec9d Iustin Pop

4079 6b93ec9d Iustin Pop
  """
4080 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4081 6b93ec9d Iustin Pop
4082 6b93ec9d Iustin Pop
  if multimaster:
4083 53c776b5 Iustin Pop
    for idx, rd in enumerate(bdevs):
4084 6b93ec9d Iustin Pop
      try:
4085 53c776b5 Iustin Pop
        _SymlinkBlockDev(instance_name, rd.dev_path, idx)
4086 6b93ec9d Iustin Pop
      except EnvironmentError, err:
4087 2cc6781a Iustin Pop
        _Fail("Can't create symlink: %s", err)
4088 6b93ec9d Iustin Pop
  # reconnect disks, switch to new master configuration and if
4089 6b93ec9d Iustin Pop
  # needed primary mode
4090 6b93ec9d Iustin Pop
  for rd in bdevs:
4091 6b93ec9d Iustin Pop
    try:
4092 6b93ec9d Iustin Pop
      rd.AttachNet(multimaster)
4093 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
4094 2cc6781a Iustin Pop
      _Fail("Can't change network configuration: %s", err)
4095 3c0cdc83 Michael Hanselmann
4096 6b93ec9d Iustin Pop
  # wait until the disks are connected; we need to retry the re-attach
4097 6b93ec9d Iustin Pop
  # if the device becomes standalone, as this might happen if the one
4098 6b93ec9d Iustin Pop
  # node disconnects and reconnects in a different mode before the
4099 6b93ec9d Iustin Pop
  # other node reconnects; in this case, one or both of the nodes will
4100 6b93ec9d Iustin Pop
  # decide it has wrong configuration and switch to standalone
4101 3c0cdc83 Michael Hanselmann
4102 3c0cdc83 Michael Hanselmann
  def _Attach():
4103 6b93ec9d Iustin Pop
    all_connected = True
4104 3c0cdc83 Michael Hanselmann
4105 6b93ec9d Iustin Pop
    for rd in bdevs:
4106 6b93ec9d Iustin Pop
      stats = rd.GetProcStatus()
4107 3c0cdc83 Michael Hanselmann
4108 73e15b5e Apollon Oikonomopoulos
      if multimaster:
4109 73e15b5e Apollon Oikonomopoulos
        # In the multimaster case we have to wait explicitly until
4110 73e15b5e Apollon Oikonomopoulos
        # the resource is Connected and UpToDate/UpToDate, because
4111 73e15b5e Apollon Oikonomopoulos
        # we promote *both nodes* to primary directly afterwards.
4112 73e15b5e Apollon Oikonomopoulos
        # Being in resync is not enough, since there is a race during which we
4113 73e15b5e Apollon Oikonomopoulos
        # may promote a node with an Outdated disk to primary, effectively
4114 73e15b5e Apollon Oikonomopoulos
        # tearing down the connection.
4115 73e15b5e Apollon Oikonomopoulos
        all_connected = (all_connected and
4116 73e15b5e Apollon Oikonomopoulos
                         stats.is_connected and
4117 73e15b5e Apollon Oikonomopoulos
                         stats.is_disk_uptodate and
4118 73e15b5e Apollon Oikonomopoulos
                         stats.peer_disk_uptodate)
4119 73e15b5e Apollon Oikonomopoulos
      else:
4120 73e15b5e Apollon Oikonomopoulos
        all_connected = (all_connected and
4121 73e15b5e Apollon Oikonomopoulos
                         (stats.is_connected or stats.is_in_resync))
4122 3c0cdc83 Michael Hanselmann
4123 6b93ec9d Iustin Pop
      if stats.is_standalone:
4124 6b93ec9d Iustin Pop
        # peer had different config info and this node became
4125 6b93ec9d Iustin Pop
        # standalone, even though this should not happen with the
4126 6b93ec9d Iustin Pop
        # new staged way of changing disk configs
4127 6b93ec9d Iustin Pop
        try:
4128 c738375b Iustin Pop
          rd.AttachNet(multimaster)
4129 6b93ec9d Iustin Pop
        except errors.BlockDeviceError, err:
4130 2cc6781a Iustin Pop
          _Fail("Can't change network configuration: %s", err)
4131 3c0cdc83 Michael Hanselmann
4132 3c0cdc83 Michael Hanselmann
    if not all_connected:
4133 3c0cdc83 Michael Hanselmann
      raise utils.RetryAgain()
4134 3c0cdc83 Michael Hanselmann
4135 3c0cdc83 Michael Hanselmann
  try:
4136 3c0cdc83 Michael Hanselmann
    # Start with a delay of 100 miliseconds and go up to 5 seconds
4137 3c0cdc83 Michael Hanselmann
    utils.Retry(_Attach, (0.1, 1.5, 5.0), 2 * 60)
4138 3c0cdc83 Michael Hanselmann
  except utils.RetryTimeout:
4139 afdc3985 Iustin Pop
    _Fail("Timeout in disk reconnecting")
4140 3c0cdc83 Michael Hanselmann
4141 6b93ec9d Iustin Pop
  if multimaster:
4142 6b93ec9d Iustin Pop
    # change to primary mode
4143 6b93ec9d Iustin Pop
    for rd in bdevs:
4144 d3da87b8 Iustin Pop
      try:
4145 d3da87b8 Iustin Pop
        rd.Open()
4146 d3da87b8 Iustin Pop
      except errors.BlockDeviceError, err:
4147 2cc6781a Iustin Pop
        _Fail("Can't change to primary mode: %s", err)
4148 6b93ec9d Iustin Pop
4149 6b93ec9d Iustin Pop
4150 0c3d9c7c Thomas Thrainer
def DrbdWaitSync(disks):
4151 6b93ec9d Iustin Pop
  """Wait until DRBDs have synchronized.
4152 6b93ec9d Iustin Pop

4153 6b93ec9d Iustin Pop
  """
4154 db8667b7 Iustin Pop
  def _helper(rd):
4155 db8667b7 Iustin Pop
    stats = rd.GetProcStatus()
4156 db8667b7 Iustin Pop
    if not (stats.is_connected or stats.is_in_resync):
4157 db8667b7 Iustin Pop
      raise utils.RetryAgain()
4158 db8667b7 Iustin Pop
    return stats
4159 db8667b7 Iustin Pop
4160 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4161 6b93ec9d Iustin Pop
4162 6b93ec9d Iustin Pop
  min_resync = 100
4163 6b93ec9d Iustin Pop
  alldone = True
4164 6b93ec9d Iustin Pop
  for rd in bdevs:
4165 db8667b7 Iustin Pop
    try:
4166 db8667b7 Iustin Pop
      # poll each second for 15 seconds
4167 db8667b7 Iustin Pop
      stats = utils.Retry(_helper, 1, 15, args=[rd])
4168 db8667b7 Iustin Pop
    except utils.RetryTimeout:
4169 db8667b7 Iustin Pop
      stats = rd.GetProcStatus()
4170 db8667b7 Iustin Pop
      # last check
4171 db8667b7 Iustin Pop
      if not (stats.is_connected or stats.is_in_resync):
4172 db8667b7 Iustin Pop
        _Fail("DRBD device %s is not in sync: stats=%s", rd, stats)
4173 6b93ec9d Iustin Pop
    alldone = alldone and (not stats.is_in_resync)
4174 6b93ec9d Iustin Pop
    if stats.sync_percent is not None:
4175 6b93ec9d Iustin Pop
      min_resync = min(min_resync, stats.sync_percent)
4176 afdc3985 Iustin Pop
4177 c26a6bd2 Iustin Pop
  return (alldone, min_resync)
4178 6b93ec9d Iustin Pop
4179 6b93ec9d Iustin Pop
4180 0c3d9c7c Thomas Thrainer
def DrbdNeedsActivation(disks):
4181 235a6b29 Thomas Thrainer
  """Checks which of the passed disks needs activation and returns their UUIDs.
4182 235a6b29 Thomas Thrainer

4183 235a6b29 Thomas Thrainer
  """
4184 235a6b29 Thomas Thrainer
  faulty_disks = []
4185 235a6b29 Thomas Thrainer
4186 235a6b29 Thomas Thrainer
  for disk in disks:
4187 235a6b29 Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4188 235a6b29 Thomas Thrainer
    if rd is None:
4189 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4190 235a6b29 Thomas Thrainer
      continue
4191 235a6b29 Thomas Thrainer
4192 235a6b29 Thomas Thrainer
    stats = rd.GetProcStatus()
4193 235a6b29 Thomas Thrainer
    if stats.is_standalone or stats.is_diskless:
4194 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4195 235a6b29 Thomas Thrainer
4196 235a6b29 Thomas Thrainer
  return [disk.uuid for disk in faulty_disks]
4197 235a6b29 Thomas Thrainer
4198 235a6b29 Thomas Thrainer
4199 c46b9782 Luca Bigliardi
def GetDrbdUsermodeHelper():
4200 c46b9782 Luca Bigliardi
  """Returns DRBD usermode helper currently configured.
4201 c46b9782 Luca Bigliardi

4202 c46b9782 Luca Bigliardi
  """
4203 c46b9782 Luca Bigliardi
  try:
4204 47e0abee Thomas Thrainer
    return drbd.DRBD8.GetUsermodeHelper()
4205 c46b9782 Luca Bigliardi
  except errors.BlockDeviceError, err:
4206 c46b9782 Luca Bigliardi
    _Fail(str(err))
4207 c46b9782 Luca Bigliardi
4208 c46b9782 Luca Bigliardi
4209 8ef418bb Helga Velroyen
def PowercycleNode(hypervisor_type, hvparams=None):
4210 f5118ade Iustin Pop
  """Hard-powercycle the node.
4211 f5118ade Iustin Pop

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

4215 f5118ade Iustin Pop
  """
4216 f5118ade Iustin Pop
  hyper = hypervisor.GetHypervisor(hypervisor_type)
4217 f5118ade Iustin Pop
  try:
4218 f5118ade Iustin Pop
    pid = os.fork()
4219 29921401 Iustin Pop
  except OSError:
4220 f5118ade Iustin Pop
    # if we can't fork, we'll pretend that we're in the child process
4221 f5118ade Iustin Pop
    pid = 0
4222 f5118ade Iustin Pop
  if pid > 0:
4223 c26a6bd2 Iustin Pop
    return "Reboot scheduled in 5 seconds"
4224 1af6ac0f Luca Bigliardi
  # ensure the child is running on ram
4225 1af6ac0f Luca Bigliardi
  try:
4226 1af6ac0f Luca Bigliardi
    utils.Mlockall()
4227 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
4228 1af6ac0f Luca Bigliardi
    pass
4229 f5118ade Iustin Pop
  time.sleep(5)
4230 8ef418bb Helga Velroyen
  hyper.PowercycleNode(hvparams=hvparams)
4231 f5118ade Iustin Pop
4232 f5118ade Iustin Pop
4233 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdName(cmd):
4234 45bc4635 Iustin Pop
  """Verifies a restricted command name.
4235 1a2eb2dc Michael Hanselmann

4236 1a2eb2dc Michael Hanselmann
  @type cmd: string
4237 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4238 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4239 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4240 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4241 1a2eb2dc Michael Hanselmann

4242 1a2eb2dc Michael Hanselmann
  """
4243 1a2eb2dc Michael Hanselmann
  if not cmd.strip():
4244 1a2eb2dc Michael Hanselmann
    return (False, "Missing command name")
4245 1a2eb2dc Michael Hanselmann
4246 1a2eb2dc Michael Hanselmann
  if os.path.basename(cmd) != cmd:
4247 1a2eb2dc Michael Hanselmann
    return (False, "Invalid command name")
4248 1a2eb2dc Michael Hanselmann
4249 1a2eb2dc Michael Hanselmann
  if not constants.EXT_PLUGIN_MASK.match(cmd):
4250 1a2eb2dc Michael Hanselmann
    return (False, "Command name contains forbidden characters")
4251 1a2eb2dc Michael Hanselmann
4252 1a2eb2dc Michael Hanselmann
  return (True, None)
4253 1a2eb2dc Michael Hanselmann
4254 1a2eb2dc Michael Hanselmann
4255 405bffe2 Michael Hanselmann
def _CommonRestrictedCmdCheck(path, owner):
4256 45bc4635 Iustin Pop
  """Common checks for restricted command file system directories and files.
4257 1a2eb2dc Michael Hanselmann

4258 1a2eb2dc Michael Hanselmann
  @type path: string
4259 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4260 1a2eb2dc Michael Hanselmann
  @param owner: C{None} or tuple containing UID and GID
4261 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or C{os.stat} result)
4262 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4263 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's the result of C{os.stat}
4264 1a2eb2dc Michael Hanselmann

4265 1a2eb2dc Michael Hanselmann
  """
4266 1a2eb2dc Michael Hanselmann
  if owner is None:
4267 1a2eb2dc Michael Hanselmann
    # Default to root as owner
4268 1a2eb2dc Michael Hanselmann
    owner = (0, 0)
4269 1a2eb2dc Michael Hanselmann
4270 1a2eb2dc Michael Hanselmann
  try:
4271 1a2eb2dc Michael Hanselmann
    st = os.stat(path)
4272 1a2eb2dc Michael Hanselmann
  except EnvironmentError, err:
4273 1a2eb2dc Michael Hanselmann
    return (False, "Can't stat(2) '%s': %s" % (path, err))
4274 1a2eb2dc Michael Hanselmann
4275 1a2eb2dc Michael Hanselmann
  if stat.S_IMODE(st.st_mode) & (~_RCMD_MAX_MODE):
4276 1a2eb2dc Michael Hanselmann
    return (False, "Permissions on '%s' are too permissive" % path)
4277 1a2eb2dc Michael Hanselmann
4278 1a2eb2dc Michael Hanselmann
  if (st.st_uid, st.st_gid) != owner:
4279 1a2eb2dc Michael Hanselmann
    (owner_uid, owner_gid) = owner
4280 1a2eb2dc Michael Hanselmann
    return (False, "'%s' is not owned by %s:%s" % (path, owner_uid, owner_gid))
4281 1a2eb2dc Michael Hanselmann
4282 1a2eb2dc Michael Hanselmann
  return (True, st)
4283 1a2eb2dc Michael Hanselmann
4284 1a2eb2dc Michael Hanselmann
4285 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdDirectory(path, _owner=None):
4286 45bc4635 Iustin Pop
  """Verifies restricted command directory.
4287 1a2eb2dc Michael Hanselmann

4288 1a2eb2dc Michael Hanselmann
  @type path: string
4289 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4290 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4291 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4292 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4293 1a2eb2dc Michael Hanselmann

4294 1a2eb2dc Michael Hanselmann
  """
4295 405bffe2 Michael Hanselmann
  (status, value) = _CommonRestrictedCmdCheck(path, _owner)
4296 1a2eb2dc Michael Hanselmann
4297 1a2eb2dc Michael Hanselmann
  if not status:
4298 1a2eb2dc Michael Hanselmann
    return (False, value)
4299 1a2eb2dc Michael Hanselmann
4300 1a2eb2dc Michael Hanselmann
  if not stat.S_ISDIR(value.st_mode):
4301 1a2eb2dc Michael Hanselmann
    return (False, "Path '%s' is not a directory" % path)
4302 1a2eb2dc Michael Hanselmann
4303 1a2eb2dc Michael Hanselmann
  return (True, None)
4304 1a2eb2dc Michael Hanselmann
4305 1a2eb2dc Michael Hanselmann
4306 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmd(path, cmd, _owner=None):
4307 45bc4635 Iustin Pop
  """Verifies a whole restricted command and returns its executable filename.
4308 1a2eb2dc Michael Hanselmann

4309 1a2eb2dc Michael Hanselmann
  @type path: string
4310 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4311 1a2eb2dc Michael Hanselmann
  @type cmd: string
4312 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4313 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string)
4314 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4315 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise the second element is the
4316 1a2eb2dc Michael Hanselmann
    absolute path to the executable
4317 1a2eb2dc Michael Hanselmann

4318 1a2eb2dc Michael Hanselmann
  """
4319 1a2eb2dc Michael Hanselmann
  executable = utils.PathJoin(path, cmd)
4320 1a2eb2dc Michael Hanselmann
4321 405bffe2 Michael Hanselmann
  (status, msg) = _CommonRestrictedCmdCheck(executable, _owner)
4322 1a2eb2dc Michael Hanselmann
4323 1a2eb2dc Michael Hanselmann
  if not status:
4324 1a2eb2dc Michael Hanselmann
    return (False, msg)
4325 1a2eb2dc Michael Hanselmann
4326 1a2eb2dc Michael Hanselmann
  if not utils.IsExecutable(executable):
4327 1a2eb2dc Michael Hanselmann
    return (False, "access(2) thinks '%s' can't be executed" % executable)
4328 1a2eb2dc Michael Hanselmann
4329 1a2eb2dc Michael Hanselmann
  return (True, executable)
4330 1a2eb2dc Michael Hanselmann
4331 1a2eb2dc Michael Hanselmann
4332 405bffe2 Michael Hanselmann
def _PrepareRestrictedCmd(path, cmd,
4333 405bffe2 Michael Hanselmann
                          _verify_dir=_VerifyRestrictedCmdDirectory,
4334 405bffe2 Michael Hanselmann
                          _verify_name=_VerifyRestrictedCmdName,
4335 405bffe2 Michael Hanselmann
                          _verify_cmd=_VerifyRestrictedCmd):
4336 45bc4635 Iustin Pop
  """Performs a number of tests on a restricted command.
4337 1a2eb2dc Michael Hanselmann

4338 1a2eb2dc Michael Hanselmann
  @type path: string
4339 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4340 1a2eb2dc Michael Hanselmann
  @type cmd: string
4341 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4342 405bffe2 Michael Hanselmann
  @return: Same as L{_VerifyRestrictedCmd}
4343 1a2eb2dc Michael Hanselmann

4344 1a2eb2dc Michael Hanselmann
  """
4345 1a2eb2dc Michael Hanselmann
  # Verify the directory first
4346 1a2eb2dc Michael Hanselmann
  (status, msg) = _verify_dir(path)
4347 1a2eb2dc Michael Hanselmann
  if status:
4348 1a2eb2dc Michael Hanselmann
    # Check command if everything was alright
4349 1a2eb2dc Michael Hanselmann
    (status, msg) = _verify_name(cmd)
4350 1a2eb2dc Michael Hanselmann
4351 1a2eb2dc Michael Hanselmann
  if not status:
4352 1a2eb2dc Michael Hanselmann
    return (False, msg)
4353 1a2eb2dc Michael Hanselmann
4354 1a2eb2dc Michael Hanselmann
  # Check actual executable
4355 1a2eb2dc Michael Hanselmann
  return _verify_cmd(path, cmd)
4356 1a2eb2dc Michael Hanselmann
4357 1a2eb2dc Michael Hanselmann
4358 42bd26e8 Michael Hanselmann
def RunRestrictedCmd(cmd,
4359 1a2eb2dc Michael Hanselmann
                     _lock_timeout=_RCMD_LOCK_TIMEOUT,
4360 878c42ae Michael Hanselmann
                     _lock_file=pathutils.RESTRICTED_COMMANDS_LOCK_FILE,
4361 878c42ae Michael Hanselmann
                     _path=pathutils.RESTRICTED_COMMANDS_DIR,
4362 1a2eb2dc Michael Hanselmann
                     _sleep_fn=time.sleep,
4363 405bffe2 Michael Hanselmann
                     _prepare_fn=_PrepareRestrictedCmd,
4364 1a2eb2dc Michael Hanselmann
                     _runcmd_fn=utils.RunCmd,
4365 1fdeb284 Michael Hanselmann
                     _enabled=constants.ENABLE_RESTRICTED_COMMANDS):
4366 45bc4635 Iustin Pop
  """Executes a restricted command after performing strict tests.
4367 1a2eb2dc Michael Hanselmann

4368 1a2eb2dc Michael Hanselmann
  @type cmd: string
4369 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4370 1a2eb2dc Michael Hanselmann
  @rtype: string
4371 1a2eb2dc Michael Hanselmann
  @return: Command output
4372 1a2eb2dc Michael Hanselmann
  @raise RPCFail: In case of an error
4373 1a2eb2dc Michael Hanselmann

4374 1a2eb2dc Michael Hanselmann
  """
4375 45bc4635 Iustin Pop
  logging.info("Preparing to run restricted command '%s'", cmd)
4376 1a2eb2dc Michael Hanselmann
4377 1a2eb2dc Michael Hanselmann
  if not _enabled:
4378 45bc4635 Iustin Pop
    _Fail("Restricted commands disabled at configure time")
4379 1a2eb2dc Michael Hanselmann
4380 1a2eb2dc Michael Hanselmann
  lock = None
4381 1a2eb2dc Michael Hanselmann
  try:
4382 1a2eb2dc Michael Hanselmann
    cmdresult = None
4383 1a2eb2dc Michael Hanselmann
    try:
4384 1a2eb2dc Michael Hanselmann
      lock = utils.FileLock.Open(_lock_file)
4385 1a2eb2dc Michael Hanselmann
      lock.Exclusive(blocking=True, timeout=_lock_timeout)
4386 1a2eb2dc Michael Hanselmann
4387 1a2eb2dc Michael Hanselmann
      (status, value) = _prepare_fn(_path, cmd)
4388 1a2eb2dc Michael Hanselmann
4389 1a2eb2dc Michael Hanselmann
      if status:
4390 1a2eb2dc Michael Hanselmann
        cmdresult = _runcmd_fn([value], env={}, reset_env=True,
4391 1a2eb2dc Michael Hanselmann
                               postfork_fn=lambda _: lock.Unlock())
4392 1a2eb2dc Michael Hanselmann
      else:
4393 1a2eb2dc Michael Hanselmann
        logging.error(value)
4394 1a2eb2dc Michael Hanselmann
    except Exception: # pylint: disable=W0703
4395 1a2eb2dc Michael Hanselmann
      # Keep original error in log
4396 1a2eb2dc Michael Hanselmann
      logging.exception("Caught exception")
4397 1a2eb2dc Michael Hanselmann
4398 1a2eb2dc Michael Hanselmann
    if cmdresult is None:
4399 1a2eb2dc Michael Hanselmann
      logging.info("Sleeping for %0.1f seconds before returning",
4400 1a2eb2dc Michael Hanselmann
                   _RCMD_INVALID_DELAY)
4401 1a2eb2dc Michael Hanselmann
      _sleep_fn(_RCMD_INVALID_DELAY)
4402 1a2eb2dc Michael Hanselmann
4403 1a2eb2dc Michael Hanselmann
      # Do not include original error message in returned error
4404 1a2eb2dc Michael Hanselmann
      _Fail("Executing command '%s' failed" % cmd)
4405 1a2eb2dc Michael Hanselmann
    elif cmdresult.failed or cmdresult.fail_reason:
4406 45bc4635 Iustin Pop
      _Fail("Restricted command '%s' failed: %s; output: %s",
4407 1a2eb2dc Michael Hanselmann
            cmd, cmdresult.fail_reason, cmdresult.output)
4408 1a2eb2dc Michael Hanselmann
    else:
4409 1a2eb2dc Michael Hanselmann
      return cmdresult.output
4410 1a2eb2dc Michael Hanselmann
  finally:
4411 1a2eb2dc Michael Hanselmann
    if lock is not None:
4412 1a2eb2dc Michael Hanselmann
      # Release lock at last
4413 1a2eb2dc Michael Hanselmann
      lock.Close()
4414 1a2eb2dc Michael Hanselmann
      lock = None
4415 1a2eb2dc Michael Hanselmann
4416 1a2eb2dc Michael Hanselmann
4417 99e222b1 Michael Hanselmann
def SetWatcherPause(until, _filename=pathutils.WATCHER_PAUSEFILE):
4418 99e222b1 Michael Hanselmann
  """Creates or removes the watcher pause file.
4419 99e222b1 Michael Hanselmann

4420 99e222b1 Michael Hanselmann
  @type until: None or number
4421 99e222b1 Michael Hanselmann
  @param until: Unix timestamp saying until when the watcher shouldn't run
4422 99e222b1 Michael Hanselmann

4423 99e222b1 Michael Hanselmann
  """
4424 99e222b1 Michael Hanselmann
  if until is None:
4425 99e222b1 Michael Hanselmann
    logging.info("Received request to no longer pause watcher")
4426 99e222b1 Michael Hanselmann
    utils.RemoveFile(_filename)
4427 99e222b1 Michael Hanselmann
  else:
4428 99e222b1 Michael Hanselmann
    logging.info("Received request to pause watcher until %s", until)
4429 99e222b1 Michael Hanselmann
4430 99e222b1 Michael Hanselmann
    if not ht.TNumber(until):
4431 99e222b1 Michael Hanselmann
      _Fail("Duration must be numeric")
4432 99e222b1 Michael Hanselmann
4433 99e222b1 Michael Hanselmann
    utils.WriteFile(_filename, data="%d\n" % (until, ), mode=0644)
4434 99e222b1 Michael Hanselmann
4435 99e222b1 Michael Hanselmann
4436 4daa5eb9 Sebastian Gebhard
def ConfigureOVS(ovs_name, ovs_link):
4437 4daa5eb9 Sebastian Gebhard
  """Creates a OpenvSwitch on the node.
4438 4daa5eb9 Sebastian Gebhard

4439 4daa5eb9 Sebastian Gebhard
  This function sets up a OpenvSwitch on the node with given name nad
4440 4daa5eb9 Sebastian Gebhard
  connects it via a given eth device.
4441 4daa5eb9 Sebastian Gebhard

4442 4daa5eb9 Sebastian Gebhard
  @type ovs_name: string
4443 4daa5eb9 Sebastian Gebhard
  @param ovs_name: Name of the OpenvSwitch to create.
4444 4daa5eb9 Sebastian Gebhard
  @type ovs_link: None or string
4445 4daa5eb9 Sebastian Gebhard
  @param ovs_link: Ethernet device for outside connection (can be missing)
4446 4daa5eb9 Sebastian Gebhard

4447 4daa5eb9 Sebastian Gebhard
  """
4448 4daa5eb9 Sebastian Gebhard
  # Initialize the OpenvSwitch
4449 4daa5eb9 Sebastian Gebhard
  result = utils.RunCmd(["ovs-vsctl", "add-br", ovs_name])
4450 4daa5eb9 Sebastian Gebhard
  if result.failed:
4451 a1578ccf Sebastian Gebhard
    _Fail("Failed to create openvswitch. Script return value: %s, output: '%s'"
4452 a1578ccf Sebastian Gebhard
          % (result.exit_code, result.output), log=True)
4453 4daa5eb9 Sebastian Gebhard
4454 4daa5eb9 Sebastian Gebhard
  # And connect it to a physical interface, if given
4455 4daa5eb9 Sebastian Gebhard
  if ovs_link:
4456 4daa5eb9 Sebastian Gebhard
    result = utils.RunCmd(["ovs-vsctl", "add-port", ovs_name, ovs_link])
4457 4daa5eb9 Sebastian Gebhard
    if result.failed:
4458 4daa5eb9 Sebastian Gebhard
      _Fail("Failed to connect openvswitch to  interface %s. Script return"
4459 a1578ccf Sebastian Gebhard
            " value: %s, output: '%s'" % (ovs_link, result.exit_code,
4460 a1578ccf Sebastian Gebhard
            result.output), log=True)
4461 4daa5eb9 Sebastian Gebhard
4462 4daa5eb9 Sebastian Gebhard
4463 a8083063 Iustin Pop
class HooksRunner(object):
4464 a8083063 Iustin Pop
  """Hook runner.
4465 a8083063 Iustin Pop

4466 10c2650b Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not
4467 10c2650b Iustin Pop
  on the master side.
4468 a8083063 Iustin Pop

4469 a8083063 Iustin Pop
  """
4470 a8083063 Iustin Pop
  def __init__(self, hooks_base_dir=None):
4471 a8083063 Iustin Pop
    """Constructor for hooks runner.
4472 a8083063 Iustin Pop

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

4477 a8083063 Iustin Pop
    """
4478 a8083063 Iustin Pop
    if hooks_base_dir is None:
4479 710f30ec Michael Hanselmann
      hooks_base_dir = pathutils.HOOKS_BASE_DIR
4480 fe267188 Iustin Pop
    # yeah, _BASE_DIR is not valid for attributes, we use it like a
4481 fe267188 Iustin Pop
    # constant
4482 b459a848 Andrea Spadaccini
    self._BASE_DIR = hooks_base_dir # pylint: disable=C0103
4483 a8083063 Iustin Pop
4484 0fa481f5 Andrea Spadaccini
  def RunLocalHooks(self, node_list, hpath, phase, env):
4485 0fa481f5 Andrea Spadaccini
    """Check that the hooks will be run only locally and then run them.
4486 0fa481f5 Andrea Spadaccini

4487 0fa481f5 Andrea Spadaccini
    """
4488 0fa481f5 Andrea Spadaccini
    assert len(node_list) == 1
4489 0fa481f5 Andrea Spadaccini
    node = node_list[0]
4490 0fa481f5 Andrea Spadaccini
    _, myself = ssconf.GetMasterAndMyself()
4491 0fa481f5 Andrea Spadaccini
    assert node == myself
4492 0fa481f5 Andrea Spadaccini
4493 0fa481f5 Andrea Spadaccini
    results = self.RunHooks(hpath, phase, env)
4494 0fa481f5 Andrea Spadaccini
4495 0fa481f5 Andrea Spadaccini
    # Return values in the form expected by HooksMaster
4496 0fa481f5 Andrea Spadaccini
    return {node: (None, False, results)}
4497 0fa481f5 Andrea Spadaccini
4498 a8083063 Iustin Pop
  def RunHooks(self, hpath, phase, env):
4499 a8083063 Iustin Pop
    """Run the scripts in the hooks directory.
4500 a8083063 Iustin Pop

4501 10c2650b Iustin Pop
    @type hpath: str
4502 10c2650b Iustin Pop
    @param hpath: the path to the hooks directory which
4503 10c2650b Iustin Pop
        holds the scripts
4504 10c2650b Iustin Pop
    @type phase: str
4505 10c2650b Iustin Pop
    @param phase: either L{constants.HOOKS_PHASE_PRE} or
4506 10c2650b Iustin Pop
        L{constants.HOOKS_PHASE_POST}
4507 10c2650b Iustin Pop
    @type env: dict
4508 10c2650b Iustin Pop
    @param env: dictionary with the environment for the hook
4509 10c2650b Iustin Pop
    @rtype: list
4510 10c2650b Iustin Pop
    @return: list of 3-element tuples:
4511 10c2650b Iustin Pop
      - script path
4512 10c2650b Iustin Pop
      - script result, either L{constants.HKR_SUCCESS} or
4513 10c2650b Iustin Pop
        L{constants.HKR_FAIL}
4514 10c2650b Iustin Pop
      - output of the script
4515 10c2650b Iustin Pop

4516 10c2650b Iustin Pop
    @raise errors.ProgrammerError: for invalid input
4517 10c2650b Iustin Pop
        parameters
4518 a8083063 Iustin Pop

4519 a8083063 Iustin Pop
    """
4520 a8083063 Iustin Pop
    if phase == constants.HOOKS_PHASE_PRE:
4521 a8083063 Iustin Pop
      suffix = "pre"
4522 a8083063 Iustin Pop
    elif phase == constants.HOOKS_PHASE_POST:
4523 a8083063 Iustin Pop
      suffix = "post"
4524 a8083063 Iustin Pop
    else:
4525 3fb4f740 Iustin Pop
      _Fail("Unknown hooks phase '%s'", phase)
4526 3fb4f740 Iustin Pop
4527 a8083063 Iustin Pop
    subdir = "%s-%s.d" % (hpath, suffix)
4528 0411c011 Iustin Pop
    dir_name = utils.PathJoin(self._BASE_DIR, subdir)
4529 6bb65e3a Guido Trotter
4530 6bb65e3a Guido Trotter
    results = []
4531 a9b7e346 Iustin Pop
4532 a9b7e346 Iustin Pop
    if not os.path.isdir(dir_name):
4533 a9b7e346 Iustin Pop
      # for non-existing/non-dirs, we simply exit instead of logging a
4534 a9b7e346 Iustin Pop
      # warning at every operation
4535 a9b7e346 Iustin Pop
      return results
4536 a9b7e346 Iustin Pop
4537 a9b7e346 Iustin Pop
    runparts_results = utils.RunParts(dir_name, env=env, reset_env=True)
4538 a9b7e346 Iustin Pop
4539 5ae4945a Iustin Pop
    for (relname, relstatus, runresult) in runparts_results:
4540 6bb65e3a Guido Trotter
      if relstatus == constants.RUNPARTS_SKIP:
4541 a8083063 Iustin Pop
        rrval = constants.HKR_SKIP
4542 a8083063 Iustin Pop
        output = ""
4543 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_ERR:
4544 6bb65e3a Guido Trotter
        rrval = constants.HKR_FAIL
4545 6bb65e3a Guido Trotter
        output = "Hook script execution error: %s" % runresult
4546 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_RUN:
4547 6bb65e3a Guido Trotter
        if runresult.failed:
4548 a8083063 Iustin Pop
          rrval = constants.HKR_FAIL
4549 a8083063 Iustin Pop
        else:
4550 6bb65e3a Guido Trotter
          rrval = constants.HKR_SUCCESS
4551 6bb65e3a Guido Trotter
        output = utils.SafeEncode(runresult.output.strip())
4552 6bb65e3a Guido Trotter
      results.append(("%s/%s" % (subdir, relname), rrval, output))
4553 6bb65e3a Guido Trotter
4554 6bb65e3a Guido Trotter
    return results
4555 3f78eef2 Iustin Pop
4556 3f78eef2 Iustin Pop
4557 8d528b7c Iustin Pop
class IAllocatorRunner(object):
4558 8d528b7c Iustin Pop
  """IAllocator runner.
4559 8d528b7c Iustin Pop

4560 8d528b7c Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not on
4561 8d528b7c Iustin Pop
  the master side.
4562 8d528b7c Iustin Pop

4563 8d528b7c Iustin Pop
  """
4564 7e950d31 Iustin Pop
  @staticmethod
4565 0359e5d0 Spyros Trigazis
  def Run(name, idata, ial_params):
4566 8d528b7c Iustin Pop
    """Run an iallocator script.
4567 8d528b7c Iustin Pop

4568 10c2650b Iustin Pop
    @type name: str
4569 10c2650b Iustin Pop
    @param name: the iallocator script name
4570 10c2650b Iustin Pop
    @type idata: str
4571 10c2650b Iustin Pop
    @param idata: the allocator input data
4572 0359e5d0 Spyros Trigazis
    @type ial_params: list
4573 0359e5d0 Spyros Trigazis
    @param ial_params: the iallocator parameters
4574 10c2650b Iustin Pop

4575 10c2650b Iustin Pop
    @rtype: tuple
4576 87f5c298 Iustin Pop
    @return: two element tuple of:
4577 87f5c298 Iustin Pop
       - status
4578 87f5c298 Iustin Pop
       - either error message or stdout of allocator (for success)
4579 8d528b7c Iustin Pop

4580 8d528b7c Iustin Pop
    """
4581 8d528b7c Iustin Pop
    alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
4582 8d528b7c Iustin Pop
                                  os.path.isfile)
4583 8d528b7c Iustin Pop
    if alloc_script is None:
4584 87f5c298 Iustin Pop
      _Fail("iallocator module '%s' not found in the search path", name)
4585 8d528b7c Iustin Pop
4586 8d528b7c Iustin Pop
    fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
4587 8d528b7c Iustin Pop
    try:
4588 8d528b7c Iustin Pop
      os.write(fd, idata)
4589 8d528b7c Iustin Pop
      os.close(fd)
4590 0359e5d0 Spyros Trigazis
      result = utils.RunCmd([alloc_script, fin_name] + ial_params)
4591 8d528b7c Iustin Pop
      if result.failed:
4592 87f5c298 Iustin Pop
        _Fail("iallocator module '%s' failed: %s, output '%s'",
4593 87f5c298 Iustin Pop
              name, result.fail_reason, result.output)
4594 8d528b7c Iustin Pop
    finally:
4595 8d528b7c Iustin Pop
      os.unlink(fin_name)
4596 8d528b7c Iustin Pop
4597 c26a6bd2 Iustin Pop
    return result.stdout
4598 8d528b7c Iustin Pop
4599 8d528b7c Iustin Pop
4600 3f78eef2 Iustin Pop
class DevCacheManager(object):
4601 c99a3cc0 Manuel Franceschini
  """Simple class for managing a cache of block device information.
4602 3f78eef2 Iustin Pop

4603 3f78eef2 Iustin Pop
  """
4604 3f78eef2 Iustin Pop
  _DEV_PREFIX = "/dev/"
4605 710f30ec Michael Hanselmann
  _ROOT_DIR = pathutils.BDEV_CACHE_DIR
4606 3f78eef2 Iustin Pop
4607 3f78eef2 Iustin Pop
  @classmethod
4608 3f78eef2 Iustin Pop
  def _ConvertPath(cls, dev_path):
4609 3f78eef2 Iustin Pop
    """Converts a /dev/name path to the cache file name.
4610 3f78eef2 Iustin Pop

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

4614 10c2650b Iustin Pop
    @type dev_path: str
4615 10c2650b Iustin Pop
    @param dev_path: the C{/dev/} path name
4616 10c2650b Iustin Pop
    @rtype: str
4617 10c2650b Iustin Pop
    @return: the converted path name
4618 3f78eef2 Iustin Pop

4619 3f78eef2 Iustin Pop
    """
4620 3f78eef2 Iustin Pop
    if dev_path.startswith(cls._DEV_PREFIX):
4621 3f78eef2 Iustin Pop
      dev_path = dev_path[len(cls._DEV_PREFIX):]
4622 3f78eef2 Iustin Pop
    dev_path = dev_path.replace("/", "_")
4623 0411c011 Iustin Pop
    fpath = utils.PathJoin(cls._ROOT_DIR, "bdev_%s" % dev_path)
4624 3f78eef2 Iustin Pop
    return fpath
4625 3f78eef2 Iustin Pop
4626 3f78eef2 Iustin Pop
  @classmethod
4627 3f78eef2 Iustin Pop
  def UpdateCache(cls, dev_path, owner, on_primary, iv_name):
4628 3f78eef2 Iustin Pop
    """Updates the cache information for a given device.
4629 3f78eef2 Iustin Pop

4630 10c2650b Iustin Pop
    @type dev_path: str
4631 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4632 10c2650b Iustin Pop
    @type owner: str
4633 10c2650b Iustin Pop
    @param owner: the owner (instance name) of the device
4634 10c2650b Iustin Pop
    @type on_primary: bool
4635 10c2650b Iustin Pop
    @param on_primary: whether this is the primary
4636 10c2650b Iustin Pop
        node nor not
4637 10c2650b Iustin Pop
    @type iv_name: str
4638 10c2650b Iustin Pop
    @param iv_name: the instance-visible name of the
4639 c41eea6e Iustin Pop
        device, as in objects.Disk.iv_name
4640 10c2650b Iustin Pop

4641 10c2650b Iustin Pop
    @rtype: None
4642 10c2650b Iustin Pop

4643 3f78eef2 Iustin Pop
    """
4644 cf5a8306 Iustin Pop
    if dev_path is None:
4645 18682bca Iustin Pop
      logging.error("DevCacheManager.UpdateCache got a None dev_path")
4646 cf5a8306 Iustin Pop
      return
4647 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4648 3f78eef2 Iustin Pop
    if on_primary:
4649 3f78eef2 Iustin Pop
      state = "primary"
4650 3f78eef2 Iustin Pop
    else:
4651 3f78eef2 Iustin Pop
      state = "secondary"
4652 3f78eef2 Iustin Pop
    if iv_name is None:
4653 3f78eef2 Iustin Pop
      iv_name = "not_visible"
4654 3f78eef2 Iustin Pop
    fdata = "%s %s %s\n" % (str(owner), state, iv_name)
4655 3f78eef2 Iustin Pop
    try:
4656 3f78eef2 Iustin Pop
      utils.WriteFile(fpath, data=fdata)
4657 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4658 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)
4659 3f78eef2 Iustin Pop
4660 3f78eef2 Iustin Pop
  @classmethod
4661 3f78eef2 Iustin Pop
  def RemoveCache(cls, dev_path):
4662 3f78eef2 Iustin Pop
    """Remove data for a dev_path.
4663 3f78eef2 Iustin Pop

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

4667 10c2650b Iustin Pop
    @type dev_path: str
4668 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4669 10c2650b Iustin Pop

4670 10c2650b Iustin Pop
    @rtype: None
4671 10c2650b Iustin Pop

4672 3f78eef2 Iustin Pop
    """
4673 cf5a8306 Iustin Pop
    if dev_path is None:
4674 18682bca Iustin Pop
      logging.error("DevCacheManager.RemoveCache got a None dev_path")
4675 cf5a8306 Iustin Pop
      return
4676 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4677 3f78eef2 Iustin Pop
    try:
4678 3f78eef2 Iustin Pop
      utils.RemoveFile(fpath)
4679 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4680 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)