Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ 653bc0f1

History | View | Annotate | Download (145.9 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 ab4b1cf2 Helga Velroyen
1210 ab4b1cf2 Helga Velroyen
        # extract file name from options
1211 d722af8b Helga Velroyen
        cert_filename = None
1212 d722af8b Helga Velroyen
        if options:
1213 d722af8b Helga Velroyen
          cert_filename = options.get(constants.CRYPTO_OPTION_CERT_FILE)
1214 d722af8b Helga Velroyen
        if not cert_filename:
1215 d722af8b Helga Velroyen
          cert_filename = _DEFAULT_CERT_FILE
1216 d722af8b Helga Velroyen
        # For security reason, we don't allow arbitrary filenames
1217 d722af8b Helga Velroyen
        if not cert_filename in _VALID_CERT_FILES:
1218 d722af8b Helga Velroyen
          raise errors.ProgrammerError(
1219 d722af8b Helga Velroyen
            "The certificate file name path '%s' is not allowed." %
1220 d722af8b Helga Velroyen
            cert_filename)
1221 ab4b1cf2 Helga Velroyen
1222 ab4b1cf2 Helga Velroyen
        # extract serial number from options
1223 ab4b1cf2 Helga Velroyen
        serial_no = None
1224 ab4b1cf2 Helga Velroyen
        if options:
1225 ab4b1cf2 Helga Velroyen
          try:
1226 ab4b1cf2 Helga Velroyen
            serial_no = int(options[constants.CRYPTO_OPTION_SERIAL_NO])
1227 ab4b1cf2 Helga Velroyen
          except ValueError:
1228 ab4b1cf2 Helga Velroyen
            raise errors.ProgrammerError(
1229 ab4b1cf2 Helga Velroyen
              "The given serial number is not an intenger: %s." %
1230 ab4b1cf2 Helga Velroyen
              options.get(constants.CRYPTO_OPTION_SERIAL_NO))
1231 ab4b1cf2 Helga Velroyen
          except KeyError:
1232 ab4b1cf2 Helga Velroyen
            raise errors.ProgrammerError("No serial number was provided.")
1233 ab4b1cf2 Helga Velroyen
1234 ab4b1cf2 Helga Velroyen
        if not serial_no:
1235 ab4b1cf2 Helga Velroyen
          raise errors.ProgrammerError(
1236 ab4b1cf2 Helga Velroyen
            "Cannot create an SSL certificate without a serial no.")
1237 ab4b1cf2 Helga Velroyen
1238 d722af8b Helga Velroyen
        utils.GenerateNewSslCert(
1239 ab4b1cf2 Helga Velroyen
          True, cert_filename, serial_no,
1240 d722af8b Helga Velroyen
          "Create new client SSL certificate in %s." % cert_filename)
1241 d722af8b Helga Velroyen
        tokens.append((token_type,
1242 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest(
1243 d722af8b Helga Velroyen
                         cert_filename=cert_filename)))
1244 d722af8b Helga Velroyen
      elif action == constants.CRYPTO_ACTION_GET:
1245 d722af8b Helga Velroyen
        tokens.append((token_type,
1246 b3cc1646 Helga Velroyen
                       utils.GetCertificateDigest()))
1247 b544a3c2 Helga Velroyen
  return tokens
1248 b544a3c2 Helga Velroyen
1249 b544a3c2 Helga Velroyen
1250 2be7273c Apollon Oikonomopoulos
def GetBlockDevSizes(devices):
1251 2be7273c Apollon Oikonomopoulos
  """Return the size of the given block devices
1252 2be7273c Apollon Oikonomopoulos

1253 2be7273c Apollon Oikonomopoulos
  @type devices: list
1254 2be7273c Apollon Oikonomopoulos
  @param devices: list of block device nodes to query
1255 2be7273c Apollon Oikonomopoulos
  @rtype: dict
1256 2be7273c Apollon Oikonomopoulos
  @return:
1257 2be7273c Apollon Oikonomopoulos
    dictionary of all block devices under /dev (key). The value is their
1258 2be7273c Apollon Oikonomopoulos
    size in MiB.
1259 2be7273c Apollon Oikonomopoulos

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

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

1291 84d7e26b Dmitry Chernyak
  @type vg_names: list
1292 397693d3 Iustin Pop
  @param vg_names: the volume groups whose LVs we should list, or
1293 397693d3 Iustin Pop
      empty for all volume groups
1294 10c2650b Iustin Pop
  @rtype: dict
1295 10c2650b Iustin Pop
  @return:
1296 10c2650b Iustin Pop
      dictionary of all partions (key) with value being a tuple of
1297 10c2650b Iustin Pop
      their size (in MiB), inactive and online status::
1298 10c2650b Iustin Pop

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

1301 10c2650b Iustin Pop
      in case of errors, a string is returned with the error
1302 10c2650b Iustin Pop
      details.
1303 a8083063 Iustin Pop

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

1337 10c2650b Iustin Pop
  @rtype: dict
1338 10c2650b Iustin Pop
  @return: dictionary with keys volume name and values the
1339 10c2650b Iustin Pop
      size of the volume
1340 a8083063 Iustin Pop

1341 a8083063 Iustin Pop
  """
1342 c26a6bd2 Iustin Pop
  return utils.ListVolumeGroups()
1343 a8083063 Iustin Pop
1344 a8083063 Iustin Pop
1345 dcb93971 Michael Hanselmann
def NodeVolumes():
1346 dcb93971 Michael Hanselmann
  """List all volumes on this node.
1347 dcb93971 Michael Hanselmann

1348 10c2650b Iustin Pop
  @rtype: list
1349 10c2650b Iustin Pop
  @return:
1350 10c2650b Iustin Pop
    A list of dictionaries, each having four keys:
1351 10c2650b Iustin Pop
      - name: the logical volume name,
1352 10c2650b Iustin Pop
      - size: the size of the logical volume
1353 10c2650b Iustin Pop
      - dev: the physical device on which the LV lives
1354 10c2650b Iustin Pop
      - vg: the volume group to which it belongs
1355 10c2650b Iustin Pop

1356 10c2650b Iustin Pop
    In case of errors, we return an empty list and log the
1357 10c2650b Iustin Pop
    error.
1358 10c2650b Iustin Pop

1359 10c2650b Iustin Pop
    Note that since a logical volume can live on multiple physical
1360 10c2650b Iustin Pop
    volumes, the resulting list might include a logical volume
1361 10c2650b Iustin Pop
    multiple times.
1362 10c2650b Iustin Pop

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

1394 b1206984 Iustin Pop
  @rtype: boolean
1395 b1206984 Iustin Pop
  @return: C{True} if all of them exist, C{False} otherwise
1396 a8083063 Iustin Pop

1397 a8083063 Iustin Pop
  """
1398 35c0c8da Iustin Pop
  missing = []
1399 a8083063 Iustin Pop
  for bridge in bridges_list:
1400 a8083063 Iustin Pop
    if not utils.BridgeExists(bridge):
1401 35c0c8da Iustin Pop
      missing.append(bridge)
1402 a8083063 Iustin Pop
1403 35c0c8da Iustin Pop
  if missing:
1404 1f864b60 Iustin Pop
    _Fail("Missing bridges %s", utils.CommaJoin(missing))
1405 35c0c8da Iustin Pop
1406 a8083063 Iustin Pop
1407 2bff1928 Helga Velroyen
def GetInstanceListForHypervisor(hname, hvparams=None,
1408 2bff1928 Helga Velroyen
                                 get_hv_fn=hypervisor.GetHypervisor):
1409 2bff1928 Helga Velroyen
  """Provides a list of instances of the given hypervisor.
1410 2bff1928 Helga Velroyen

1411 2bff1928 Helga Velroyen
  @type hname: string
1412 2bff1928 Helga Velroyen
  @param hname: name of the hypervisor
1413 2bff1928 Helga Velroyen
  @type hvparams: dict of strings
1414 2bff1928 Helga Velroyen
  @param hvparams: hypervisor parameters for the given hypervisor
1415 2bff1928 Helga Velroyen
  @type get_hv_fn: function
1416 2bff1928 Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1417 2bff1928 Helga Velroyen
    name; optional parameter to increase testability
1418 2bff1928 Helga Velroyen

1419 2bff1928 Helga Velroyen
  @rtype: list
1420 2bff1928 Helga Velroyen
  @return: a list of all running instances on the current node
1421 2bff1928 Helga Velroyen
    - instance1.example.com
1422 2bff1928 Helga Velroyen
    - instance2.example.com
1423 2bff1928 Helga Velroyen

1424 2bff1928 Helga Velroyen
  """
1425 2bff1928 Helga Velroyen
  results = []
1426 2bff1928 Helga Velroyen
  try:
1427 2bff1928 Helga Velroyen
    hv = get_hv_fn(hname)
1428 5b0dfcef Helga Velroyen
    names = hv.ListInstances(hvparams=hvparams)
1429 2bff1928 Helga Velroyen
    results.extend(names)
1430 2bff1928 Helga Velroyen
  except errors.HypervisorError, err:
1431 2bff1928 Helga Velroyen
    _Fail("Error enumerating instances (hypervisor %s): %s",
1432 2bff1928 Helga Velroyen
          hname, err, exc=True)
1433 2bff1928 Helga Velroyen
  return results
1434 2bff1928 Helga Velroyen
1435 2bff1928 Helga Velroyen
1436 fac83f8a Helga Velroyen
def GetInstanceList(hypervisor_list, all_hvparams=None,
1437 fac83f8a Helga Velroyen
                    get_hv_fn=hypervisor.GetHypervisor):
1438 2f8598a5 Alexander Schreiber
  """Provides a list of instances.
1439 a8083063 Iustin Pop

1440 e69d05fd Iustin Pop
  @type hypervisor_list: list
1441 e69d05fd Iustin Pop
  @param hypervisor_list: the list of hypervisors to query information
1442 fac83f8a Helga Velroyen
  @type all_hvparams: dict of dict of strings
1443 fac83f8a Helga Velroyen
  @param all_hvparams: a dictionary mapping hypervisor types to respective
1444 fac83f8a Helga Velroyen
    cluster-wide hypervisor parameters
1445 fac83f8a Helga Velroyen
  @type get_hv_fn: function
1446 fac83f8a Helga Velroyen
  @param get_hv_fn: function that returns a hypervisor for the given hypervisor
1447 fac83f8a Helga Velroyen
    name; optional parameter to increase testability
1448 e69d05fd Iustin Pop

1449 e69d05fd Iustin Pop
  @rtype: list
1450 e69d05fd Iustin Pop
  @return: a list of all running instances on the current node
1451 10c2650b Iustin Pop
    - instance1.example.com
1452 10c2650b Iustin Pop
    - instance2.example.com
1453 a8083063 Iustin Pop

1454 098c0958 Michael Hanselmann
  """
1455 e69d05fd Iustin Pop
  results = []
1456 e69d05fd Iustin Pop
  for hname in hypervisor_list:
1457 5b0dfcef Helga Velroyen
    hvparams = all_hvparams[hname]
1458 5b0dfcef Helga Velroyen
    results.extend(GetInstanceListForHypervisor(hname, hvparams=hvparams,
1459 2bff1928 Helga Velroyen
                                                get_hv_fn=get_hv_fn))
1460 e69d05fd Iustin Pop
  return results
1461 a8083063 Iustin Pop
1462 a8083063 Iustin Pop
1463 0bbec3af Helga Velroyen
def GetInstanceInfo(instance, hname, hvparams=None):
1464 5bbd3f7f Michael Hanselmann
  """Gives back the information about an instance as a dictionary.
1465 a8083063 Iustin Pop

1466 e69d05fd Iustin Pop
  @type instance: string
1467 e69d05fd Iustin Pop
  @param instance: the instance name
1468 e69d05fd Iustin Pop
  @type hname: string
1469 e69d05fd Iustin Pop
  @param hname: the hypervisor type of the instance
1470 0bbec3af Helga Velroyen
  @type hvparams: dict of strings
1471 0bbec3af Helga Velroyen
  @param hvparams: the instance's hvparams
1472 a8083063 Iustin Pop

1473 e69d05fd Iustin Pop
  @rtype: dict
1474 e69d05fd Iustin Pop
  @return: dictionary with the following keys:
1475 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1476 a3f0f306 Jose A. Lopes
      - state: state of instance (HvInstanceState)
1477 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1478 1cb97324 Agata Murawska
      - vcpus: the number of vcpus (int)
1479 a8083063 Iustin Pop

1480 098c0958 Michael Hanselmann
  """
1481 a8083063 Iustin Pop
  output = {}
1482 a8083063 Iustin Pop
1483 0bbec3af Helga Velroyen
  iinfo = hypervisor.GetHypervisor(hname).GetInstanceInfo(instance,
1484 0bbec3af Helga Velroyen
                                                          hvparams=hvparams)
1485 a8083063 Iustin Pop
  if iinfo is not None:
1486 d0c8c01d Iustin Pop
    output["memory"] = iinfo[2]
1487 1cb97324 Agata Murawska
    output["vcpus"] = iinfo[3]
1488 d0c8c01d Iustin Pop
    output["state"] = iinfo[4]
1489 d0c8c01d Iustin Pop
    output["time"] = iinfo[5]
1490 a8083063 Iustin Pop
1491 c26a6bd2 Iustin Pop
  return output
1492 a8083063 Iustin Pop
1493 a8083063 Iustin Pop
1494 56e7640c Iustin Pop
def GetInstanceMigratable(instance):
1495 3361ab37 Helga Velroyen
  """Computes whether an instance can be migrated.
1496 56e7640c Iustin Pop

1497 56e7640c Iustin Pop
  @type instance: L{objects.Instance}
1498 56e7640c Iustin Pop
  @param instance: object representing the instance to be checked.
1499 56e7640c Iustin Pop

1500 56e7640c Iustin Pop
  @rtype: tuple
1501 56e7640c Iustin Pop
  @return: tuple of (result, description) where:
1502 56e7640c Iustin Pop
      - result: whether the instance can be migrated or not
1503 56e7640c Iustin Pop
      - description: a description of the issue, if relevant
1504 56e7640c Iustin Pop

1505 56e7640c Iustin Pop
  """
1506 56e7640c Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1507 afdc3985 Iustin Pop
  iname = instance.name
1508 3361ab37 Helga Velroyen
  if iname not in hyper.ListInstances(instance.hvparams):
1509 afdc3985 Iustin Pop
    _Fail("Instance %s is not running", iname)
1510 56e7640c Iustin Pop
1511 56e7640c Iustin Pop
  for idx in range(len(instance.disks)):
1512 afdc3985 Iustin Pop
    link_name = _GetBlockDevSymlinkPath(iname, idx)
1513 56e7640c Iustin Pop
    if not os.path.islink(link_name):
1514 b8ebd37b Iustin Pop
      logging.warning("Instance %s is missing symlink %s for disk %d",
1515 b8ebd37b Iustin Pop
                      iname, link_name, idx)
1516 56e7640c Iustin Pop
1517 56e7640c Iustin Pop
1518 0200a1af Helga Velroyen
def GetAllInstancesInfo(hypervisor_list, all_hvparams):
1519 a8083063 Iustin Pop
  """Gather data about all instances.
1520 a8083063 Iustin Pop

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

1525 e69d05fd Iustin Pop
  @type hypervisor_list: list
1526 e69d05fd Iustin Pop
  @param hypervisor_list: list of hypervisors to query for instance data
1527 0200a1af Helga Velroyen
  @type all_hvparams: dict of dict of strings
1528 0200a1af Helga Velroyen
  @param all_hvparams: mapping of hypervisor names to hvparams
1529 e69d05fd Iustin Pop

1530 955db481 Guido Trotter
  @rtype: dict
1531 e69d05fd Iustin Pop
  @return: dictionary of instance: data, with data having the following keys:
1532 e69d05fd Iustin Pop
      - memory: memory size of instance (int)
1533 e69d05fd Iustin Pop
      - state: xen state of instance (string)
1534 e69d05fd Iustin Pop
      - time: cpu time of instance (float)
1535 10c2650b Iustin Pop
      - vcpus: the number of vcpus
1536 a8083063 Iustin Pop

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

1567 b9e12624 Hrvoje Ribicic
  This function assumes that the caller already knows which instances are on
1568 b9e12624 Hrvoje Ribicic
  this node, by calling a function such as L{GetAllInstancesInfo} or
1569 b9e12624 Hrvoje Ribicic
  L{GetInstanceList}.
1570 b9e12624 Hrvoje Ribicic

1571 b9e12624 Hrvoje Ribicic
  For every instance, a large amount of configuration data needs to be
1572 b9e12624 Hrvoje Ribicic
  provided to the hypervisor interface in order to receive the console
1573 b9e12624 Hrvoje Ribicic
  information. Whether this could or should be cut down can be discussed.
1574 b9e12624 Hrvoje Ribicic
  The information is provided in a dictionary indexed by instance name,
1575 b9e12624 Hrvoje Ribicic
  allowing any number of instance queries to be done.
1576 b9e12624 Hrvoje Ribicic

1577 b9e12624 Hrvoje Ribicic
  @type instance_param_dict: dict of string to tuple of dictionaries, where the
1578 c42be2c0 Petr Pudlak
    dictionaries represent: L{objects.Instance}, L{objects.Node},
1579 c42be2c0 Petr Pudlak
    L{objects.NodeGroup}, HvParams, BeParams
1580 b9e12624 Hrvoje Ribicic
  @param instance_param_dict: mapping of instance name to parameters necessary
1581 b9e12624 Hrvoje Ribicic
    for console information retrieval
1582 b9e12624 Hrvoje Ribicic

1583 b9e12624 Hrvoje Ribicic
  @rtype: dict
1584 b9e12624 Hrvoje Ribicic
  @return: dictionary of instance: data, with data having the following keys:
1585 b9e12624 Hrvoje Ribicic
      - instance: instance name
1586 b9e12624 Hrvoje Ribicic
      - kind: console kind
1587 b9e12624 Hrvoje Ribicic
      - message: used with kind == CONS_MESSAGE, indicates console to be
1588 b9e12624 Hrvoje Ribicic
                 unavailable, supplies error message
1589 b9e12624 Hrvoje Ribicic
      - host: host to connect to
1590 b9e12624 Hrvoje Ribicic
      - port: port to use
1591 b9e12624 Hrvoje Ribicic
      - user: user for login
1592 b9e12624 Hrvoje Ribicic
      - command: the command, broken into parts as an array
1593 b9e12624 Hrvoje Ribicic
      - display: unknown, potentially unused?
1594 b9e12624 Hrvoje Ribicic

1595 b9e12624 Hrvoje Ribicic
  """
1596 b9e12624 Hrvoje Ribicic
1597 b9e12624 Hrvoje Ribicic
  output = {}
1598 b9e12624 Hrvoje Ribicic
  for inst_name in instance_param_dict:
1599 b9e12624 Hrvoje Ribicic
    instance = instance_param_dict[inst_name]["instance"]
1600 b9e12624 Hrvoje Ribicic
    pnode = instance_param_dict[inst_name]["node"]
1601 c42be2c0 Petr Pudlak
    group = instance_param_dict[inst_name]["group"]
1602 b9e12624 Hrvoje Ribicic
    hvparams = instance_param_dict[inst_name]["hvParams"]
1603 b9e12624 Hrvoje Ribicic
    beparams = instance_param_dict[inst_name]["beParams"]
1604 b9e12624 Hrvoje Ribicic
1605 b9e12624 Hrvoje Ribicic
    instance = objects.Instance.FromDict(instance)
1606 b9e12624 Hrvoje Ribicic
    pnode = objects.Node.FromDict(pnode)
1607 c42be2c0 Petr Pudlak
    group = objects.NodeGroup.FromDict(group)
1608 b9e12624 Hrvoje Ribicic
1609 b9e12624 Hrvoje Ribicic
    h = get_hv_fn(instance.hypervisor)
1610 c42be2c0 Petr Pudlak
    output[inst_name] = h.GetInstanceConsole(instance, pnode, group,
1611 c42be2c0 Petr Pudlak
                                             hvparams, beparams).ToDict()
1612 b9e12624 Hrvoje Ribicic
1613 b9e12624 Hrvoje Ribicic
  return output
1614 b9e12624 Hrvoje Ribicic
1615 b9e12624 Hrvoje Ribicic
1616 6aa7a354 Iustin Pop
def _InstanceLogName(kind, os_name, instance, component):
1617 81a3406c Iustin Pop
  """Compute the OS log filename for a given instance and operation.
1618 81a3406c Iustin Pop

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

1622 81a3406c Iustin Pop
  @type kind: string
1623 81a3406c Iustin Pop
  @param kind: the operation type (e.g. add, import, etc.)
1624 81a3406c Iustin Pop
  @type os_name: string
1625 81a3406c Iustin Pop
  @param os_name: the os name
1626 81a3406c Iustin Pop
  @type instance: string
1627 81a3406c Iustin Pop
  @param instance: the name of the instance being imported/added/etc.
1628 6aa7a354 Iustin Pop
  @type component: string or None
1629 6aa7a354 Iustin Pop
  @param component: the name of the component of the instance being
1630 6aa7a354 Iustin Pop
      transferred
1631 81a3406c Iustin Pop

1632 81a3406c Iustin Pop
  """
1633 1651d116 Michael Hanselmann
  # TODO: Use tempfile.mkstemp to create unique filename
1634 6aa7a354 Iustin Pop
  if component:
1635 6aa7a354 Iustin Pop
    assert "/" not in component
1636 6aa7a354 Iustin Pop
    c_msg = "-%s" % component
1637 6aa7a354 Iustin Pop
  else:
1638 6aa7a354 Iustin Pop
    c_msg = ""
1639 6aa7a354 Iustin Pop
  base = ("%s-%s-%s%s-%s.log" %
1640 6aa7a354 Iustin Pop
          (kind, os_name, instance, c_msg, utils.TimestampForFilename()))
1641 710f30ec Michael Hanselmann
  return utils.PathJoin(pathutils.LOG_OS_DIR, base)
1642 81a3406c Iustin Pop
1643 81a3406c Iustin Pop
1644 4a0e011f Iustin Pop
def InstanceOsAdd(instance, reinstall, debug):
1645 2f8598a5 Alexander Schreiber
  """Add an OS to an instance.
1646 a8083063 Iustin Pop

1647 d15a9ad3 Guido Trotter
  @type instance: L{objects.Instance}
1648 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1649 e557bae9 Guido Trotter
  @type reinstall: boolean
1650 e557bae9 Guido Trotter
  @param reinstall: whether this is an instance reinstall
1651 4a0e011f Iustin Pop
  @type debug: integer
1652 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1653 c26a6bd2 Iustin Pop
  @rtype: None
1654 a8083063 Iustin Pop

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

1679 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
1680 d15a9ad3 Guido Trotter
  @param instance: Instance whose OS is to be installed
1681 d15a9ad3 Guido Trotter
  @type old_name: string
1682 d15a9ad3 Guido Trotter
  @param old_name: previous instance name
1683 4a0e011f Iustin Pop
  @type debug: integer
1684 4a0e011f Iustin Pop
  @param debug: debug level, passed to the OS scripts
1685 10c2650b Iustin Pop
  @rtype: boolean
1686 10c2650b Iustin Pop
  @return: the success of the operation
1687 decd5f45 Iustin Pop

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

1712 3b721842 Michael Hanselmann
  """
1713 3b721842 Michael Hanselmann
  if _dir is None:
1714 3b721842 Michael Hanselmann
    _dir = pathutils.DISK_LINKS_DIR
1715 3b721842 Michael Hanselmann
1716 3b721842 Michael Hanselmann
  return utils.PathJoin(_dir,
1717 3b721842 Michael Hanselmann
                        ("%s%s%s" %
1718 3b721842 Michael Hanselmann
                         (instance_name, constants.DISK_SEPARATOR, idx)))
1719 5282084b Iustin Pop
1720 5282084b Iustin Pop
1721 5282084b Iustin Pop
def _SymlinkBlockDev(instance_name, device_path, idx):
1722 9332fd8a Iustin Pop
  """Set up symlinks to a instance's block device.
1723 9332fd8a Iustin Pop

1724 9332fd8a Iustin Pop
  This is an auxiliary function run when an instance is start (on the primary
1725 9332fd8a Iustin Pop
  node) or when an instance is migrated (on the target node).
1726 9332fd8a Iustin Pop

1727 9332fd8a Iustin Pop

1728 5282084b Iustin Pop
  @param instance_name: the name of the target instance
1729 5282084b Iustin Pop
  @param device_path: path of the physical block device, on the node
1730 5282084b Iustin Pop
  @param idx: the disk index
1731 5282084b Iustin Pop
  @return: absolute path to the disk's symlink
1732 9332fd8a Iustin Pop

1733 9332fd8a Iustin Pop
  """
1734 5282084b Iustin Pop
  link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1735 9332fd8a Iustin Pop
  try:
1736 9332fd8a Iustin Pop
    os.symlink(device_path, link_name)
1737 5282084b Iustin Pop
  except OSError, err:
1738 5282084b Iustin Pop
    if err.errno == errno.EEXIST:
1739 9332fd8a Iustin Pop
      if (not os.path.islink(link_name) or
1740 9332fd8a Iustin Pop
          os.readlink(link_name) != device_path):
1741 9332fd8a Iustin Pop
        os.remove(link_name)
1742 9332fd8a Iustin Pop
        os.symlink(device_path, link_name)
1743 9332fd8a Iustin Pop
    else:
1744 9332fd8a Iustin Pop
      raise
1745 9332fd8a Iustin Pop
1746 9332fd8a Iustin Pop
  return link_name
1747 9332fd8a Iustin Pop
1748 9332fd8a Iustin Pop
1749 5282084b Iustin Pop
def _RemoveBlockDevLinks(instance_name, disks):
1750 3c9c571d Iustin Pop
  """Remove the block device symlinks belonging to the given instance.
1751 3c9c571d Iustin Pop

1752 3c9c571d Iustin Pop
  """
1753 29921401 Iustin Pop
  for idx, _ in enumerate(disks):
1754 5282084b Iustin Pop
    link_name = _GetBlockDevSymlinkPath(instance_name, idx)
1755 5282084b Iustin Pop
    if os.path.islink(link_name):
1756 3c9c571d Iustin Pop
      try:
1757 03dfa658 Iustin Pop
        os.remove(link_name)
1758 03dfa658 Iustin Pop
      except OSError:
1759 03dfa658 Iustin Pop
        logging.exception("Can't remove symlink '%s'", link_name)
1760 3c9c571d Iustin Pop
1761 3c9c571d Iustin Pop
1762 66d3d195 Dimitris Aragiorgis
def _CalculateDeviceURI(instance, disk, device):
1763 66d3d195 Dimitris Aragiorgis
  """Get the URI for the device.
1764 66d3d195 Dimitris Aragiorgis

1765 66d3d195 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
1766 66d3d195 Dimitris Aragiorgis
  @param instance: the instance which disk belongs to
1767 66d3d195 Dimitris Aragiorgis
  @type disk: L{objects.Disk}
1768 66d3d195 Dimitris Aragiorgis
  @param disk: the target disk object
1769 66d3d195 Dimitris Aragiorgis
  @type device: L{bdev.BlockDev}
1770 66d3d195 Dimitris Aragiorgis
  @param device: the corresponding BlockDevice
1771 66d3d195 Dimitris Aragiorgis
  @rtype: string
1772 66d3d195 Dimitris Aragiorgis
  @return: the device uri if any else None
1773 66d3d195 Dimitris Aragiorgis

1774 66d3d195 Dimitris Aragiorgis
  """
1775 66d3d195 Dimitris Aragiorgis
  access_mode = disk.params.get(constants.LDP_ACCESS,
1776 66d3d195 Dimitris Aragiorgis
                                constants.DISK_KERNELSPACE)
1777 66d3d195 Dimitris Aragiorgis
  if access_mode == constants.DISK_USERSPACE:
1778 66d3d195 Dimitris Aragiorgis
    # This can raise errors.BlockDeviceError
1779 66d3d195 Dimitris Aragiorgis
    return device.GetUserspaceAccessUri(instance.hypervisor)
1780 66d3d195 Dimitris Aragiorgis
  else:
1781 66d3d195 Dimitris Aragiorgis
    return None
1782 66d3d195 Dimitris Aragiorgis
1783 66d3d195 Dimitris Aragiorgis
1784 9332fd8a Iustin Pop
def _GatherAndLinkBlockDevs(instance):
1785 a8083063 Iustin Pop
  """Set up an instance's block device(s).
1786 a8083063 Iustin Pop

1787 a8083063 Iustin Pop
  This is run on the primary node at instance startup. The block
1788 a8083063 Iustin Pop
  devices must be already assembled.
1789 a8083063 Iustin Pop

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

1795 a8083063 Iustin Pop
  """
1796 a8083063 Iustin Pop
  block_devices = []
1797 9332fd8a Iustin Pop
  for idx, disk in enumerate(instance.disks):
1798 a8083063 Iustin Pop
    device = _RecursiveFindBD(disk)
1799 a8083063 Iustin Pop
    if device is None:
1800 a8083063 Iustin Pop
      raise errors.BlockDeviceError("Block device '%s' is not set up." %
1801 a8083063 Iustin Pop
                                    str(disk))
1802 a8083063 Iustin Pop
    device.Open()
1803 9332fd8a Iustin Pop
    try:
1804 5282084b Iustin Pop
      link_name = _SymlinkBlockDev(instance.name, device.dev_path, idx)
1805 9332fd8a Iustin Pop
    except OSError, e:
1806 9332fd8a Iustin Pop
      raise errors.BlockDeviceError("Cannot create block device symlink: %s" %
1807 9332fd8a Iustin Pop
                                    e.strerror)
1808 66d3d195 Dimitris Aragiorgis
    uri = _CalculateDeviceURI(instance, disk, device)
1809 9332fd8a Iustin Pop
1810 66d3d195 Dimitris Aragiorgis
    block_devices.append((disk, link_name, uri))
1811 9332fd8a Iustin Pop
1812 a8083063 Iustin Pop
  return block_devices
1813 a8083063 Iustin Pop
1814 a8083063 Iustin Pop
1815 1fa6fcba Michele Tartara
def StartInstance(instance, startup_paused, reason, store_reason=True):
1816 a8083063 Iustin Pop
  """Start an instance.
1817 a8083063 Iustin Pop

1818 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1819 e69d05fd Iustin Pop
  @param instance: the instance object
1820 323f9095 Stephen Shirley
  @type startup_paused: bool
1821 323f9095 Stephen Shirley
  @param instance: pause instance at startup?
1822 1fa6fcba Michele Tartara
  @type reason: list of reasons
1823 1fa6fcba Michele Tartara
  @param reason: the reason trail for this startup
1824 1fa6fcba Michele Tartara
  @type store_reason: boolean
1825 1fa6fcba Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1826 c26a6bd2 Iustin Pop
  @rtype: None
1827 a8083063 Iustin Pop

1828 098c0958 Michael Hanselmann
  """
1829 3361ab37 Helga Velroyen
  running_instances = GetInstanceListForHypervisor(instance.hypervisor,
1830 3361ab37 Helga Velroyen
                                                   instance.hvparams)
1831 a8083063 Iustin Pop
1832 a8083063 Iustin Pop
  if instance.name in running_instances:
1833 c26a6bd2 Iustin Pop
    logging.info("Instance %s already running, not starting", instance.name)
1834 c26a6bd2 Iustin Pop
    return
1835 a8083063 Iustin Pop
1836 a8083063 Iustin Pop
  try:
1837 ec596c24 Iustin Pop
    block_devices = _GatherAndLinkBlockDevs(instance)
1838 ec596c24 Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
1839 323f9095 Stephen Shirley
    hyper.StartInstance(instance, block_devices, startup_paused)
1840 1fa6fcba Michele Tartara
    if store_reason:
1841 1fa6fcba Michele Tartara
      _StoreInstReasonTrail(instance.name, reason)
1842 ec596c24 Iustin Pop
  except errors.BlockDeviceError, err:
1843 2cc6781a Iustin Pop
    _Fail("Block device error: %s", err, exc=True)
1844 a8083063 Iustin Pop
  except errors.HypervisorError, err:
1845 5282084b Iustin Pop
    _RemoveBlockDevLinks(instance.name, instance.disks)
1846 2cc6781a Iustin Pop
    _Fail("Hypervisor error: %s", err, exc=True)
1847 a8083063 Iustin Pop
1848 a8083063 Iustin Pop
1849 1f350e0f Michele Tartara
def InstanceShutdown(instance, timeout, reason, store_reason=True):
1850 a8083063 Iustin Pop
  """Shut an instance down.
1851 a8083063 Iustin Pop

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

1854 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
1855 e69d05fd Iustin Pop
  @param instance: the instance object
1856 6263189c Guido Trotter
  @type timeout: integer
1857 6263189c Guido Trotter
  @param timeout: maximum timeout for soft shutdown
1858 1f350e0f Michele Tartara
  @type reason: list of reasons
1859 1f350e0f Michele Tartara
  @param reason: the reason trail for this shutdown
1860 1f350e0f Michele Tartara
  @type store_reason: boolean
1861 1f350e0f Michele Tartara
  @param store_reason: whether to store the shutdown reason trail on file
1862 c26a6bd2 Iustin Pop
  @rtype: None
1863 a8083063 Iustin Pop

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

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

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

1974 ebe466d8 Guido Trotter
  @type instance: L{objects.Instance}
1975 ebe466d8 Guido Trotter
  @param instance: the instance object
1976 ebe466d8 Guido Trotter
  @type memory: int
1977 ebe466d8 Guido Trotter
  @param memory: new memory amount in MB
1978 ebe466d8 Guido Trotter
  @rtype: None
1979 ebe466d8 Guido Trotter

1980 ebe466d8 Guido Trotter
  """
1981 ebe466d8 Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
1982 3361ab37 Helga Velroyen
  running = hyper.ListInstances(instance.hvparams)
1983 ebe466d8 Guido Trotter
  if instance.name not in running:
1984 ebe466d8 Guido Trotter
    logging.info("Instance %s is not running, cannot balloon", instance.name)
1985 ebe466d8 Guido Trotter
    return
1986 ebe466d8 Guido Trotter
  try:
1987 ebe466d8 Guido Trotter
    hyper.BalloonInstanceMemory(instance, memory)
1988 ebe466d8 Guido Trotter
  except errors.HypervisorError, err:
1989 ebe466d8 Guido Trotter
    _Fail("Failed to balloon instance memory: %s", err, exc=True)
1990 ebe466d8 Guido Trotter
1991 ebe466d8 Guido Trotter
1992 6906a9d8 Guido Trotter
def MigrationInfo(instance):
1993 6906a9d8 Guido Trotter
  """Gather information about an instance to be migrated.
1994 6906a9d8 Guido Trotter

1995 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
1996 6906a9d8 Guido Trotter
  @param instance: the instance definition
1997 6906a9d8 Guido Trotter

1998 6906a9d8 Guido Trotter
  """
1999 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2000 cd42d0ad Guido Trotter
  try:
2001 cd42d0ad Guido Trotter
    info = hyper.MigrationInfo(instance)
2002 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2003 2cc6781a Iustin Pop
    _Fail("Failed to fetch migration information: %s", err, exc=True)
2004 c26a6bd2 Iustin Pop
  return info
2005 6906a9d8 Guido Trotter
2006 6906a9d8 Guido Trotter
2007 6906a9d8 Guido Trotter
def AcceptInstance(instance, info, target):
2008 6906a9d8 Guido Trotter
  """Prepare the node to accept an instance.
2009 6906a9d8 Guido Trotter

2010 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2011 6906a9d8 Guido Trotter
  @param instance: the instance definition
2012 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
2013 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
2014 6906a9d8 Guido Trotter
  @type target: string
2015 6906a9d8 Guido Trotter
  @param target: target host (usually ip), on this node
2016 6906a9d8 Guido Trotter

2017 6906a9d8 Guido Trotter
  """
2018 77fcff4a Apollon Oikonomopoulos
  # TODO: why is this required only for DTS_EXT_MIRROR?
2019 77fcff4a Apollon Oikonomopoulos
  if instance.disk_template in constants.DTS_EXT_MIRROR:
2020 77fcff4a Apollon Oikonomopoulos
    # Create the symlinks, as the disks are not active
2021 77fcff4a Apollon Oikonomopoulos
    # in any way
2022 77fcff4a Apollon Oikonomopoulos
    try:
2023 77fcff4a Apollon Oikonomopoulos
      _GatherAndLinkBlockDevs(instance)
2024 77fcff4a Apollon Oikonomopoulos
    except errors.BlockDeviceError, err:
2025 77fcff4a Apollon Oikonomopoulos
      _Fail("Block device error: %s", err, exc=True)
2026 77fcff4a Apollon Oikonomopoulos
2027 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2028 cd42d0ad Guido Trotter
  try:
2029 cd42d0ad Guido Trotter
    hyper.AcceptInstance(instance, info, target)
2030 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2031 77fcff4a Apollon Oikonomopoulos
    if instance.disk_template in constants.DTS_EXT_MIRROR:
2032 77fcff4a Apollon Oikonomopoulos
      _RemoveBlockDevLinks(instance.name, instance.disks)
2033 2cc6781a Iustin Pop
    _Fail("Failed to accept instance: %s", err, exc=True)
2034 6906a9d8 Guido Trotter
2035 6906a9d8 Guido Trotter
2036 6a1434d7 Andrea Spadaccini
def FinalizeMigrationDst(instance, info, success):
2037 6906a9d8 Guido Trotter
  """Finalize any preparation to accept an instance.
2038 6906a9d8 Guido Trotter

2039 6906a9d8 Guido Trotter
  @type instance: L{objects.Instance}
2040 6906a9d8 Guido Trotter
  @param instance: the instance definition
2041 6906a9d8 Guido Trotter
  @type info: string/data (opaque)
2042 6906a9d8 Guido Trotter
  @param info: migration information, from the source node
2043 6906a9d8 Guido Trotter
  @type success: boolean
2044 6906a9d8 Guido Trotter
  @param success: whether the migration was a success or a failure
2045 6906a9d8 Guido Trotter

2046 6906a9d8 Guido Trotter
  """
2047 cd42d0ad Guido Trotter
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2048 cd42d0ad Guido Trotter
  try:
2049 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationDst(instance, info, success)
2050 cd42d0ad Guido Trotter
  except errors.HypervisorError, err:
2051 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize migration on the target node: %s", err, exc=True)
2052 6906a9d8 Guido Trotter
2053 6906a9d8 Guido Trotter
2054 bc0a2284 Helga Velroyen
def MigrateInstance(cluster_name, instance, target, live):
2055 2a10865c Iustin Pop
  """Migrates an instance to another node.
2056 2a10865c Iustin Pop

2057 bc0a2284 Helga Velroyen
  @type cluster_name: string
2058 bc0a2284 Helga Velroyen
  @param cluster_name: name of the cluster
2059 b1206984 Iustin Pop
  @type instance: L{objects.Instance}
2060 9f0e6b37 Iustin Pop
  @param instance: the instance definition
2061 9f0e6b37 Iustin Pop
  @type target: string
2062 9f0e6b37 Iustin Pop
  @param target: the target node name
2063 9f0e6b37 Iustin Pop
  @type live: boolean
2064 9f0e6b37 Iustin Pop
  @param live: whether the migration should be done live or not (the
2065 9f0e6b37 Iustin Pop
      interpretation of this parameter is left to the hypervisor)
2066 c03fe62b Andrea Spadaccini
  @raise RPCFail: if migration fails for some reason
2067 9f0e6b37 Iustin Pop

2068 2a10865c Iustin Pop
  """
2069 53c776b5 Iustin Pop
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2070 2a10865c Iustin Pop
2071 2a10865c Iustin Pop
  try:
2072 bc0a2284 Helga Velroyen
    hyper.MigrateInstance(cluster_name, instance, target, live)
2073 2a10865c Iustin Pop
  except errors.HypervisorError, err:
2074 2cc6781a Iustin Pop
    _Fail("Failed to migrate instance: %s", err, exc=True)
2075 2a10865c Iustin Pop
2076 2a10865c Iustin Pop
2077 6a1434d7 Andrea Spadaccini
def FinalizeMigrationSource(instance, success, live):
2078 6a1434d7 Andrea Spadaccini
  """Finalize the instance migration on the source node.
2079 6a1434d7 Andrea Spadaccini

2080 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2081 6a1434d7 Andrea Spadaccini
  @param instance: the instance definition of the migrated instance
2082 6a1434d7 Andrea Spadaccini
  @type success: bool
2083 6a1434d7 Andrea Spadaccini
  @param success: whether the migration succeeded or not
2084 6a1434d7 Andrea Spadaccini
  @type live: bool
2085 6a1434d7 Andrea Spadaccini
  @param live: whether the user requested a live migration or not
2086 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the execution fails for some reason
2087 6a1434d7 Andrea Spadaccini

2088 6a1434d7 Andrea Spadaccini
  """
2089 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2090 6a1434d7 Andrea Spadaccini
2091 6a1434d7 Andrea Spadaccini
  try:
2092 6a1434d7 Andrea Spadaccini
    hyper.FinalizeMigrationSource(instance, success, live)
2093 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2094 6a1434d7 Andrea Spadaccini
    _Fail("Failed to finalize the migration on the source node: %s", err,
2095 6a1434d7 Andrea Spadaccini
          exc=True)
2096 6a1434d7 Andrea Spadaccini
2097 6a1434d7 Andrea Spadaccini
2098 6a1434d7 Andrea Spadaccini
def GetMigrationStatus(instance):
2099 6a1434d7 Andrea Spadaccini
  """Get the migration status
2100 6a1434d7 Andrea Spadaccini

2101 6a1434d7 Andrea Spadaccini
  @type instance: L{objects.Instance}
2102 6a1434d7 Andrea Spadaccini
  @param instance: the instance that is being migrated
2103 6a1434d7 Andrea Spadaccini
  @rtype: L{objects.MigrationStatus}
2104 6a1434d7 Andrea Spadaccini
  @return: the status of the current migration (one of
2105 6a1434d7 Andrea Spadaccini
           L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2106 6a1434d7 Andrea Spadaccini
           progress info that can be retrieved from the hypervisor
2107 6a1434d7 Andrea Spadaccini
  @raise RPCFail: If the migration status cannot be retrieved
2108 6a1434d7 Andrea Spadaccini

2109 6a1434d7 Andrea Spadaccini
  """
2110 6a1434d7 Andrea Spadaccini
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2111 6a1434d7 Andrea Spadaccini
  try:
2112 6a1434d7 Andrea Spadaccini
    return hyper.GetMigrationStatus(instance)
2113 6a1434d7 Andrea Spadaccini
  except Exception, err:  # pylint: disable=W0703
2114 6a1434d7 Andrea Spadaccini
    _Fail("Failed to get migration status: %s", err, exc=True)
2115 6a1434d7 Andrea Spadaccini
2116 6a1434d7 Andrea Spadaccini
2117 c5708931 Dimitris Aragiorgis
def HotplugDevice(instance, action, dev_type, device, extra, seq):
2118 c5708931 Dimitris Aragiorgis
  """Hotplug a device
2119 c5708931 Dimitris Aragiorgis

2120 c5708931 Dimitris Aragiorgis
  Hotplug is currently supported only for KVM Hypervisor.
2121 c5708931 Dimitris Aragiorgis
  @type instance: L{objects.Instance}
2122 c5708931 Dimitris Aragiorgis
  @param instance: the instance to which we hotplug a device
2123 c5708931 Dimitris Aragiorgis
  @type action: string
2124 c5708931 Dimitris Aragiorgis
  @param action: the hotplug action to perform
2125 c5708931 Dimitris Aragiorgis
  @type dev_type: string
2126 c5708931 Dimitris Aragiorgis
  @param dev_type: the device type to hotplug
2127 c5708931 Dimitris Aragiorgis
  @type device: either L{objects.NIC} or L{objects.Disk}
2128 c5708931 Dimitris Aragiorgis
  @param device: the device object to hotplug
2129 c5708931 Dimitris Aragiorgis
  @type extra: string
2130 c5708931 Dimitris Aragiorgis
  @param extra: extra info used by hotplug code (e.g. disk link)
2131 c5708931 Dimitris Aragiorgis
  @type seq: int
2132 c5708931 Dimitris Aragiorgis
  @param seq: the index of the device from master perspective
2133 c5708931 Dimitris Aragiorgis
  @raise RPCFail: in case instance does not have KVM hypervisor
2134 c5708931 Dimitris Aragiorgis

2135 c5708931 Dimitris Aragiorgis
  """
2136 c5708931 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2137 c5708931 Dimitris Aragiorgis
  try:
2138 50e0f1d9 Dimitris Aragiorgis
    hyper.VerifyHotplugSupport(instance, action, dev_type)
2139 50e0f1d9 Dimitris Aragiorgis
  except errors.HotplugError, err:
2140 c5708931 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2141 c5708931 Dimitris Aragiorgis
2142 c5708931 Dimitris Aragiorgis
  if action == constants.HOTPLUG_ACTION_ADD:
2143 c5708931 Dimitris Aragiorgis
    fn = hyper.HotAddDevice
2144 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_REMOVE:
2145 c5708931 Dimitris Aragiorgis
    fn = hyper.HotDelDevice
2146 c5708931 Dimitris Aragiorgis
  elif action == constants.HOTPLUG_ACTION_MODIFY:
2147 c5708931 Dimitris Aragiorgis
    fn = hyper.HotModDevice
2148 c5708931 Dimitris Aragiorgis
  else:
2149 c5708931 Dimitris Aragiorgis
    assert action in constants.HOTPLUG_ALL_ACTIONS
2150 c5708931 Dimitris Aragiorgis
2151 c5708931 Dimitris Aragiorgis
  return fn(instance, dev_type, device, extra, seq)
2152 c5708931 Dimitris Aragiorgis
2153 c5708931 Dimitris Aragiorgis
2154 24711492 Dimitris Aragiorgis
def HotplugSupported(instance):
2155 24711492 Dimitris Aragiorgis
  """Checks if hotplug is generally supported.
2156 24711492 Dimitris Aragiorgis

2157 24711492 Dimitris Aragiorgis
  """
2158 24711492 Dimitris Aragiorgis
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2159 24711492 Dimitris Aragiorgis
  try:
2160 24711492 Dimitris Aragiorgis
    hyper.HotplugSupported(instance)
2161 24711492 Dimitris Aragiorgis
  except errors.HotplugError, err:
2162 24711492 Dimitris Aragiorgis
    _Fail("Hotplug is not supported: %s", err)
2163 24711492 Dimitris Aragiorgis
2164 24711492 Dimitris Aragiorgis
2165 ee1478e5 Bernardo Dal Seno
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
2166 a8083063 Iustin Pop
  """Creates a block device for an instance.
2167 a8083063 Iustin Pop

2168 b1206984 Iustin Pop
  @type disk: L{objects.Disk}
2169 b1206984 Iustin Pop
  @param disk: the object describing the disk we should create
2170 b1206984 Iustin Pop
  @type size: int
2171 b1206984 Iustin Pop
  @param size: the size of the physical underlying device, in MiB
2172 b1206984 Iustin Pop
  @type owner: str
2173 b1206984 Iustin Pop
  @param owner: the name of the instance for which disk is created,
2174 b1206984 Iustin Pop
      used for device cache data
2175 b1206984 Iustin Pop
  @type on_primary: boolean
2176 b1206984 Iustin Pop
  @param on_primary:  indicates if it is the primary node or not
2177 b1206984 Iustin Pop
  @type info: string
2178 b1206984 Iustin Pop
  @param info: string that will be sent to the physical device
2179 b1206984 Iustin Pop
      creation, used for example to set (LVM) tags on LVs
2180 ee1478e5 Bernardo Dal Seno
  @type excl_stor: boolean
2181 ee1478e5 Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
2182 b1206984 Iustin Pop

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

2187 a8083063 Iustin Pop
  """
2188 d0c8c01d Iustin Pop
  # TODO: remove the obsolete "size" argument
2189 b459a848 Andrea Spadaccini
  # pylint: disable=W0613
2190 a8083063 Iustin Pop
  clist = []
2191 a8083063 Iustin Pop
  if disk.children:
2192 a8083063 Iustin Pop
    for child in disk.children:
2193 1063abd1 Iustin Pop
      try:
2194 1063abd1 Iustin Pop
        crdev = _RecursiveAssembleBD(child, owner, on_primary)
2195 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2196 2cc6781a Iustin Pop
        _Fail("Can't assemble device %s: %s", child, err)
2197 a8083063 Iustin Pop
      if on_primary or disk.AssembleOnSecondary():
2198 a8083063 Iustin Pop
        # we need the children open in case the device itself has to
2199 a8083063 Iustin Pop
        # be assembled
2200 1063abd1 Iustin Pop
        try:
2201 b459a848 Andrea Spadaccini
          # pylint: disable=E1103
2202 1063abd1 Iustin Pop
          crdev.Open()
2203 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
2204 2cc6781a Iustin Pop
          _Fail("Can't make child '%s' read-write: %s", child, err)
2205 a8083063 Iustin Pop
      clist.append(crdev)
2206 a8083063 Iustin Pop
2207 dab69e97 Iustin Pop
  try:
2208 ee1478e5 Bernardo Dal Seno
    device = bdev.Create(disk, clist, excl_stor)
2209 1063abd1 Iustin Pop
  except errors.BlockDeviceError, err:
2210 2cc6781a Iustin Pop
    _Fail("Can't create block device: %s", err)
2211 6c626518 Iustin Pop
2212 a8083063 Iustin Pop
  if on_primary or disk.AssembleOnSecondary():
2213 1063abd1 Iustin Pop
    try:
2214 1063abd1 Iustin Pop
      device.Assemble()
2215 1063abd1 Iustin Pop
    except errors.BlockDeviceError, err:
2216 2cc6781a Iustin Pop
      _Fail("Can't assemble device after creation, unusual event: %s", err)
2217 a8083063 Iustin Pop
    if on_primary or disk.OpenOnSecondary():
2218 1063abd1 Iustin Pop
      try:
2219 1063abd1 Iustin Pop
        device.Open(force=True)
2220 1063abd1 Iustin Pop
      except errors.BlockDeviceError, err:
2221 2cc6781a Iustin Pop
        _Fail("Can't make device r/w after creation, unusual event: %s", err)
2222 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(device.dev_path, owner,
2223 3f78eef2 Iustin Pop
                                on_primary, disk.iv_name)
2224 a0c3fea1 Michael Hanselmann
2225 a0c3fea1 Michael Hanselmann
  device.SetInfo(info)
2226 a0c3fea1 Michael Hanselmann
2227 c26a6bd2 Iustin Pop
  return device.unique_id
2228 a8083063 Iustin Pop
2229 a8083063 Iustin Pop
2230 da63bb4e René Nussbaumer
def _WipeDevice(path, offset, size):
2231 69dd363f René Nussbaumer
  """This function actually wipes the device.
2232 69dd363f René Nussbaumer

2233 69dd363f René Nussbaumer
  @param path: The path to the device to wipe
2234 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
2235 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
2236 69dd363f René Nussbaumer

2237 69dd363f René Nussbaumer
  """
2238 0188611b Michael Hanselmann
  # Internal sizes are always in Mebibytes; if the following "dd" command
2239 0188611b Michael Hanselmann
  # should use a different block size the offset and size given to this
2240 0188611b Michael Hanselmann
  # function must be adjusted accordingly before being passed to "dd".
2241 0188611b Michael Hanselmann
  block_size = 1024 * 1024
2242 0188611b Michael Hanselmann
2243 da63bb4e René Nussbaumer
  cmd = [constants.DD_CMD, "if=/dev/zero", "seek=%d" % offset,
2244 0188611b Michael Hanselmann
         "bs=%s" % block_size, "oflag=direct", "of=%s" % path,
2245 da63bb4e René Nussbaumer
         "count=%d" % size]
2246 da63bb4e René Nussbaumer
  result = utils.RunCmd(cmd)
2247 69dd363f René Nussbaumer
2248 69dd363f René Nussbaumer
  if result.failed:
2249 69dd363f René Nussbaumer
    _Fail("Wipe command '%s' exited with error: %s; output: %s", result.cmd,
2250 69dd363f René Nussbaumer
          result.fail_reason, result.output)
2251 69dd363f René Nussbaumer
2252 69dd363f René Nussbaumer
2253 da63bb4e René Nussbaumer
def BlockdevWipe(disk, offset, size):
2254 69dd363f René Nussbaumer
  """Wipes a block device.
2255 69dd363f René Nussbaumer

2256 69dd363f René Nussbaumer
  @type disk: L{objects.Disk}
2257 69dd363f René Nussbaumer
  @param disk: the disk object we want to wipe
2258 da63bb4e René Nussbaumer
  @type offset: int
2259 da63bb4e René Nussbaumer
  @param offset: The offset in MiB in the file
2260 da63bb4e René Nussbaumer
  @type size: int
2261 da63bb4e René Nussbaumer
  @param size: The size in MiB to write
2262 69dd363f René Nussbaumer

2263 69dd363f René Nussbaumer
  """
2264 69dd363f René Nussbaumer
  try:
2265 69dd363f René Nussbaumer
    rdev = _RecursiveFindBD(disk)
2266 da63bb4e René Nussbaumer
  except errors.BlockDeviceError:
2267 da63bb4e René Nussbaumer
    rdev = None
2268 da63bb4e René Nussbaumer
2269 da63bb4e René Nussbaumer
  if not rdev:
2270 da63bb4e René Nussbaumer
    _Fail("Cannot execute wipe for device %s: device not found", disk.iv_name)
2271 da63bb4e René Nussbaumer
2272 da63bb4e René Nussbaumer
  # Do cross verify some of the parameters
2273 0188611b Michael Hanselmann
  if offset < 0:
2274 0188611b Michael Hanselmann
    _Fail("Negative offset")
2275 0188611b Michael Hanselmann
  if size < 0:
2276 0188611b Michael Hanselmann
    _Fail("Negative size")
2277 da63bb4e René Nussbaumer
  if offset > rdev.size:
2278 da63bb4e René Nussbaumer
    _Fail("Offset is bigger than device size")
2279 da63bb4e René Nussbaumer
  if (offset + size) > rdev.size:
2280 da63bb4e René Nussbaumer
    _Fail("The provided offset and size to wipe is bigger than device size")
2281 69dd363f René Nussbaumer
2282 da63bb4e René Nussbaumer
  _WipeDevice(rdev.dev_path, offset, size)
2283 69dd363f René Nussbaumer
2284 69dd363f René Nussbaumer
2285 5119c79e René Nussbaumer
def BlockdevPauseResumeSync(disks, pause):
2286 5119c79e René Nussbaumer
  """Pause or resume the sync of the block device.
2287 5119c79e René Nussbaumer

2288 0f39886a René Nussbaumer
  @type disks: list of L{objects.Disk}
2289 0f39886a René Nussbaumer
  @param disks: the disks object we want to pause/resume
2290 5119c79e René Nussbaumer
  @type pause: bool
2291 5119c79e René Nussbaumer
  @param pause: Wheater to pause or resume
2292 5119c79e René Nussbaumer

2293 5119c79e René Nussbaumer
  """
2294 5119c79e René Nussbaumer
  success = []
2295 5119c79e René Nussbaumer
  for disk in disks:
2296 5119c79e René Nussbaumer
    try:
2297 5119c79e René Nussbaumer
      rdev = _RecursiveFindBD(disk)
2298 5119c79e René Nussbaumer
    except errors.BlockDeviceError:
2299 5119c79e René Nussbaumer
      rdev = None
2300 5119c79e René Nussbaumer
2301 5119c79e René Nussbaumer
    if not rdev:
2302 5119c79e René Nussbaumer
      success.append((False, ("Cannot change sync for device %s:"
2303 5119c79e René Nussbaumer
                              " device not found" % disk.iv_name)))
2304 5119c79e René Nussbaumer
      continue
2305 5119c79e René Nussbaumer
2306 5119c79e René Nussbaumer
    result = rdev.PauseResumeSync(pause)
2307 5119c79e René Nussbaumer
2308 5119c79e René Nussbaumer
    if result:
2309 5119c79e René Nussbaumer
      success.append((result, None))
2310 5119c79e René Nussbaumer
    else:
2311 5119c79e René Nussbaumer
      if pause:
2312 5119c79e René Nussbaumer
        msg = "Pause"
2313 5119c79e René Nussbaumer
      else:
2314 5119c79e René Nussbaumer
        msg = "Resume"
2315 5119c79e René Nussbaumer
      success.append((result, "%s for device %s failed" % (msg, disk.iv_name)))
2316 5119c79e René Nussbaumer
2317 5119c79e René Nussbaumer
  return success
2318 5119c79e René Nussbaumer
2319 5119c79e René Nussbaumer
2320 821d1bd1 Iustin Pop
def BlockdevRemove(disk):
2321 a8083063 Iustin Pop
  """Remove a block device.
2322 a8083063 Iustin Pop

2323 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
2324 10c2650b Iustin Pop

2325 c41eea6e Iustin Pop
  @type disk: L{objects.Disk}
2326 10c2650b Iustin Pop
  @param disk: the disk object we should remove
2327 10c2650b Iustin Pop
  @rtype: boolean
2328 10c2650b Iustin Pop
  @return: the success of the operation
2329 a8083063 Iustin Pop

2330 a8083063 Iustin Pop
  """
2331 e1bc0878 Iustin Pop
  msgs = []
2332 a8083063 Iustin Pop
  try:
2333 bca2e7f4 Iustin Pop
    rdev = _RecursiveFindBD(disk)
2334 a8083063 Iustin Pop
  except errors.BlockDeviceError, err:
2335 a8083063 Iustin Pop
    # probably can't attach
2336 18682bca Iustin Pop
    logging.info("Can't attach to device %s in remove", disk)
2337 a8083063 Iustin Pop
    rdev = None
2338 a8083063 Iustin Pop
  if rdev is not None:
2339 3f78eef2 Iustin Pop
    r_path = rdev.dev_path
2340 b3ae67d7 Dimitris Aragiorgis
2341 b3ae67d7 Dimitris Aragiorgis
    def _TryRemove():
2342 b3ae67d7 Dimitris Aragiorgis
      try:
2343 b3ae67d7 Dimitris Aragiorgis
        rdev.Remove()
2344 b3ae67d7 Dimitris Aragiorgis
        return []
2345 b3ae67d7 Dimitris Aragiorgis
      except errors.BlockDeviceError, err:
2346 b3ae67d7 Dimitris Aragiorgis
        return [str(err)]
2347 b3ae67d7 Dimitris Aragiorgis
2348 b3ae67d7 Dimitris Aragiorgis
    msgs.extend(utils.SimpleRetry([], _TryRemove,
2349 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_INTERVAL,
2350 b3ae67d7 Dimitris Aragiorgis
                                  constants.DISK_REMOVE_RETRY_TIMEOUT))
2351 b3ae67d7 Dimitris Aragiorgis
2352 c26a6bd2 Iustin Pop
    if not msgs:
2353 3f78eef2 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2354 e1bc0878 Iustin Pop
2355 a8083063 Iustin Pop
  if disk.children:
2356 a8083063 Iustin Pop
    for child in disk.children:
2357 c26a6bd2 Iustin Pop
      try:
2358 c26a6bd2 Iustin Pop
        BlockdevRemove(child)
2359 c26a6bd2 Iustin Pop
      except RPCFail, err:
2360 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2361 e1bc0878 Iustin Pop
2362 c26a6bd2 Iustin Pop
  if msgs:
2363 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2364 afdc3985 Iustin Pop
2365 a8083063 Iustin Pop
2366 3f78eef2 Iustin Pop
def _RecursiveAssembleBD(disk, owner, as_primary):
2367 a8083063 Iustin Pop
  """Activate a block device for an instance.
2368 a8083063 Iustin Pop

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

2371 10c2650b Iustin Pop
  @note: this function is called recursively.
2372 a8083063 Iustin Pop

2373 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2374 10c2650b Iustin Pop
  @param disk: the disk we try to assemble
2375 10c2650b Iustin Pop
  @type owner: str
2376 10c2650b Iustin Pop
  @param owner: the name of the instance which owns the disk
2377 10c2650b Iustin Pop
  @type as_primary: boolean
2378 10c2650b Iustin Pop
  @param as_primary: if we should make the block device
2379 10c2650b Iustin Pop
      read/write
2380 a8083063 Iustin Pop

2381 10c2650b Iustin Pop
  @return: the assembled device or None (in case no device
2382 10c2650b Iustin Pop
      was assembled)
2383 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: in case there is an error
2384 10c2650b Iustin Pop
      during the activation of the children or the device
2385 10c2650b Iustin Pop
      itself
2386 a8083063 Iustin Pop

2387 a8083063 Iustin Pop
  """
2388 a8083063 Iustin Pop
  children = []
2389 a8083063 Iustin Pop
  if disk.children:
2390 fc1dc9d7 Iustin Pop
    mcn = disk.ChildrenNeeded()
2391 fc1dc9d7 Iustin Pop
    if mcn == -1:
2392 fc1dc9d7 Iustin Pop
      mcn = 0 # max number of Nones allowed
2393 fc1dc9d7 Iustin Pop
    else:
2394 fc1dc9d7 Iustin Pop
      mcn = len(disk.children) - mcn # max number of Nones
2395 a8083063 Iustin Pop
    for chld_disk in disk.children:
2396 fc1dc9d7 Iustin Pop
      try:
2397 fc1dc9d7 Iustin Pop
        cdev = _RecursiveAssembleBD(chld_disk, owner, as_primary)
2398 fc1dc9d7 Iustin Pop
      except errors.BlockDeviceError, err:
2399 7803d4d3 Iustin Pop
        if children.count(None) >= mcn:
2400 fc1dc9d7 Iustin Pop
          raise
2401 fc1dc9d7 Iustin Pop
        cdev = None
2402 1063abd1 Iustin Pop
        logging.error("Error in child activation (but continuing): %s",
2403 1063abd1 Iustin Pop
                      str(err))
2404 fc1dc9d7 Iustin Pop
      children.append(cdev)
2405 a8083063 Iustin Pop
2406 a8083063 Iustin Pop
  if as_primary or disk.AssembleOnSecondary():
2407 94dcbdb0 Andrea Spadaccini
    r_dev = bdev.Assemble(disk, children)
2408 a8083063 Iustin Pop
    result = r_dev
2409 a8083063 Iustin Pop
    if as_primary or disk.OpenOnSecondary():
2410 a8083063 Iustin Pop
      r_dev.Open()
2411 3f78eef2 Iustin Pop
    DevCacheManager.UpdateCache(r_dev.dev_path, owner,
2412 3f78eef2 Iustin Pop
                                as_primary, disk.iv_name)
2413 3f78eef2 Iustin Pop
2414 a8083063 Iustin Pop
  else:
2415 a8083063 Iustin Pop
    result = True
2416 a8083063 Iustin Pop
  return result
2417 a8083063 Iustin Pop
2418 a8083063 Iustin Pop
2419 c417e115 Iustin Pop
def BlockdevAssemble(disk, owner, as_primary, idx):
2420 a8083063 Iustin Pop
  """Activate a block device for an instance.
2421 a8083063 Iustin Pop

2422 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
2423 a8083063 Iustin Pop

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

2428 a8083063 Iustin Pop
  """
2429 53c14ef1 Iustin Pop
  try:
2430 53c14ef1 Iustin Pop
    result = _RecursiveAssembleBD(disk, owner, as_primary)
2431 89ff748d Thomas Thrainer
    if isinstance(result, BlockDev):
2432 b459a848 Andrea Spadaccini
      # pylint: disable=E1103
2433 ff5def9b Dimitris Aragiorgis
      dev_path = result.dev_path
2434 ff5def9b Dimitris Aragiorgis
      link_name = None
2435 c417e115 Iustin Pop
      if as_primary:
2436 ff5def9b Dimitris Aragiorgis
        link_name = _SymlinkBlockDev(owner, dev_path, idx)
2437 ff5def9b Dimitris Aragiorgis
    elif result:
2438 ff5def9b Dimitris Aragiorgis
      return result, result
2439 ff5def9b Dimitris Aragiorgis
    else:
2440 ff5def9b Dimitris Aragiorgis
      _Fail("Unexpected result from _RecursiveAssembleBD")
2441 53c14ef1 Iustin Pop
  except errors.BlockDeviceError, err:
2442 afdc3985 Iustin Pop
    _Fail("Error while assembling disk: %s", err, exc=True)
2443 c417e115 Iustin Pop
  except OSError, err:
2444 c417e115 Iustin Pop
    _Fail("Error while symlinking disk: %s", err, exc=True)
2445 afdc3985 Iustin Pop
2446 ff5def9b Dimitris Aragiorgis
  return dev_path, link_name
2447 a8083063 Iustin Pop
2448 a8083063 Iustin Pop
2449 821d1bd1 Iustin Pop
def BlockdevShutdown(disk):
2450 a8083063 Iustin Pop
  """Shut down a block device.
2451 a8083063 Iustin Pop

2452 5bbd3f7f Michael Hanselmann
  First, if the device is assembled (Attach() is successful), then
2453 c41eea6e Iustin Pop
  the device is shutdown. Then the children of the device are
2454 c41eea6e Iustin Pop
  shutdown.
2455 a8083063 Iustin Pop

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

2460 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2461 10c2650b Iustin Pop
  @param disk: the description of the disk we should
2462 10c2650b Iustin Pop
      shutdown
2463 c26a6bd2 Iustin Pop
  @rtype: None
2464 10c2650b Iustin Pop

2465 a8083063 Iustin Pop
  """
2466 cacfd1fd Iustin Pop
  msgs = []
2467 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2468 a8083063 Iustin Pop
  if r_dev is not None:
2469 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
2470 cacfd1fd Iustin Pop
    try:
2471 746f7476 Iustin Pop
      r_dev.Shutdown()
2472 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2473 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
2474 cacfd1fd Iustin Pop
      msgs.append(str(err))
2475 746f7476 Iustin Pop
2476 a8083063 Iustin Pop
  if disk.children:
2477 a8083063 Iustin Pop
    for child in disk.children:
2478 c26a6bd2 Iustin Pop
      try:
2479 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
2480 c26a6bd2 Iustin Pop
      except RPCFail, err:
2481 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2482 746f7476 Iustin Pop
2483 c26a6bd2 Iustin Pop
  if msgs:
2484 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2485 a8083063 Iustin Pop
2486 a8083063 Iustin Pop
2487 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
2488 153d9724 Iustin Pop
  """Extend 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 to which we should add 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 add
2494 c26a6bd2 Iustin Pop
  @rtype: None
2495 10c2650b Iustin Pop

2496 a8083063 Iustin Pop
  """
2497 bca2e7f4 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 add children", parent_cdev)
2500 153d9724 Iustin Pop
  new_bdevs = [_RecursiveFindBD(disk) for disk in new_cdevs]
2501 153d9724 Iustin Pop
  if new_bdevs.count(None) > 0:
2502 2cc6781a Iustin Pop
    _Fail("Can't find new device(s) to add: %s:%s", new_bdevs, new_cdevs)
2503 153d9724 Iustin Pop
  parent_bdev.AddChildren(new_bdevs)
2504 a8083063 Iustin Pop
2505 a8083063 Iustin Pop
2506 821d1bd1 Iustin Pop
def BlockdevRemovechildren(parent_cdev, new_cdevs):
2507 153d9724 Iustin Pop
  """Shrink a mirrored block device.
2508 a8083063 Iustin Pop

2509 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2510 10c2650b Iustin Pop
  @param parent_cdev: the disk from which we should remove children
2511 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2512 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should remove
2513 c26a6bd2 Iustin Pop
  @rtype: None
2514 10c2650b Iustin Pop

2515 a8083063 Iustin Pop
  """
2516 153d9724 Iustin Pop
  parent_bdev = _RecursiveFindBD(parent_cdev)
2517 153d9724 Iustin Pop
  if parent_bdev is None:
2518 2cc6781a Iustin Pop
    _Fail("Can't find parent device '%s' in remove children", parent_cdev)
2519 e739bd57 Iustin Pop
  devs = []
2520 e739bd57 Iustin Pop
  for disk in new_cdevs:
2521 e739bd57 Iustin Pop
    rpath = disk.StaticDevPath()
2522 e739bd57 Iustin Pop
    if rpath is None:
2523 e739bd57 Iustin Pop
      bd = _RecursiveFindBD(disk)
2524 e739bd57 Iustin Pop
      if bd is None:
2525 2cc6781a Iustin Pop
        _Fail("Can't find device %s while removing children", disk)
2526 e739bd57 Iustin Pop
      else:
2527 e739bd57 Iustin Pop
        devs.append(bd.dev_path)
2528 e739bd57 Iustin Pop
    else:
2529 e51db2a6 Iustin Pop
      if not utils.IsNormAbsPath(rpath):
2530 e51db2a6 Iustin Pop
        _Fail("Strange path returned from StaticDevPath: '%s'", rpath)
2531 e739bd57 Iustin Pop
      devs.append(rpath)
2532 e739bd57 Iustin Pop
  parent_bdev.RemoveChildren(devs)
2533 a8083063 Iustin Pop
2534 a8083063 Iustin Pop
2535 821d1bd1 Iustin Pop
def BlockdevGetmirrorstatus(disks):
2536 a8083063 Iustin Pop
  """Get the mirroring status of a list of devices.
2537 a8083063 Iustin Pop

2538 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
2539 10c2650b Iustin Pop
  @param disks: the list of disks which we should query
2540 10c2650b Iustin Pop
  @rtype: disk
2541 c6a9dffa Michael Hanselmann
  @return: List of L{objects.BlockDevStatus}, one for each disk
2542 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if any of the disks cannot be
2543 10c2650b Iustin Pop
      found
2544 a8083063 Iustin Pop

2545 a8083063 Iustin Pop
  """
2546 a8083063 Iustin Pop
  stats = []
2547 a8083063 Iustin Pop
  for dsk in disks:
2548 a8083063 Iustin Pop
    rbd = _RecursiveFindBD(dsk)
2549 a8083063 Iustin Pop
    if rbd is None:
2550 3efa9051 Iustin Pop
      _Fail("Can't find device %s", dsk)
2551 96acbc09 Michael Hanselmann
2552 36145b12 Michael Hanselmann
    stats.append(rbd.CombinedSyncStatus())
2553 96acbc09 Michael Hanselmann
2554 c26a6bd2 Iustin Pop
  return stats
2555 a8083063 Iustin Pop
2556 a8083063 Iustin Pop
2557 c6a9dffa Michael Hanselmann
def BlockdevGetmirrorstatusMulti(disks):
2558 c6a9dffa Michael Hanselmann
  """Get the mirroring status of a list of devices.
2559 c6a9dffa Michael Hanselmann

2560 c6a9dffa Michael Hanselmann
  @type disks: list of L{objects.Disk}
2561 c6a9dffa Michael Hanselmann
  @param disks: the list of disks which we should query
2562 c6a9dffa Michael Hanselmann
  @rtype: disk
2563 c6a9dffa Michael Hanselmann
  @return: List of tuples, (bool, status), one for each disk; bool denotes
2564 c6a9dffa Michael Hanselmann
    success/failure, status is L{objects.BlockDevStatus} on success, string
2565 c6a9dffa Michael Hanselmann
    otherwise
2566 c6a9dffa Michael Hanselmann

2567 c6a9dffa Michael Hanselmann
  """
2568 c6a9dffa Michael Hanselmann
  result = []
2569 c6a9dffa Michael Hanselmann
  for disk in disks:
2570 c6a9dffa Michael Hanselmann
    try:
2571 c6a9dffa Michael Hanselmann
      rbd = _RecursiveFindBD(disk)
2572 c6a9dffa Michael Hanselmann
      if rbd is None:
2573 c6a9dffa Michael Hanselmann
        result.append((False, "Can't find device %s" % disk))
2574 c6a9dffa Michael Hanselmann
        continue
2575 c6a9dffa Michael Hanselmann
2576 c6a9dffa Michael Hanselmann
      status = rbd.CombinedSyncStatus()
2577 c6a9dffa Michael Hanselmann
    except errors.BlockDeviceError, err:
2578 c6a9dffa Michael Hanselmann
      logging.exception("Error while getting disk status")
2579 c6a9dffa Michael Hanselmann
      result.append((False, str(err)))
2580 c6a9dffa Michael Hanselmann
    else:
2581 c6a9dffa Michael Hanselmann
      result.append((True, status))
2582 c6a9dffa Michael Hanselmann
2583 c6a9dffa Michael Hanselmann
  assert len(disks) == len(result)
2584 c6a9dffa Michael Hanselmann
2585 c6a9dffa Michael Hanselmann
  return result
2586 c6a9dffa Michael Hanselmann
2587 c6a9dffa Michael Hanselmann
2588 bca2e7f4 Iustin Pop
def _RecursiveFindBD(disk):
2589 a8083063 Iustin Pop
  """Check if a device is activated.
2590 a8083063 Iustin Pop

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

2593 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2594 10c2650b Iustin Pop
  @param disk: the disk object we need to find
2595 a8083063 Iustin Pop

2596 10c2650b Iustin Pop
  @return: None if the device can't be found,
2597 10c2650b Iustin Pop
      otherwise the device instance
2598 a8083063 Iustin Pop

2599 a8083063 Iustin Pop
  """
2600 a8083063 Iustin Pop
  children = []
2601 a8083063 Iustin Pop
  if disk.children:
2602 a8083063 Iustin Pop
    for chdisk in disk.children:
2603 a8083063 Iustin Pop
      children.append(_RecursiveFindBD(chdisk))
2604 a8083063 Iustin Pop
2605 94dcbdb0 Andrea Spadaccini
  return bdev.FindDevice(disk, children)
2606 a8083063 Iustin Pop
2607 a8083063 Iustin Pop
2608 f2e07bb4 Michael Hanselmann
def _OpenRealBD(disk):
2609 f2e07bb4 Michael Hanselmann
  """Opens the underlying block device of a disk.
2610 f2e07bb4 Michael Hanselmann

2611 f2e07bb4 Michael Hanselmann
  @type disk: L{objects.Disk}
2612 f2e07bb4 Michael Hanselmann
  @param disk: the disk object we want to open
2613 f2e07bb4 Michael Hanselmann

2614 f2e07bb4 Michael Hanselmann
  """
2615 f2e07bb4 Michael Hanselmann
  real_disk = _RecursiveFindBD(disk)
2616 f2e07bb4 Michael Hanselmann
  if real_disk is None:
2617 f2e07bb4 Michael Hanselmann
    _Fail("Block device '%s' is not set up", disk)
2618 f2e07bb4 Michael Hanselmann
2619 f2e07bb4 Michael Hanselmann
  real_disk.Open()
2620 f2e07bb4 Michael Hanselmann
2621 f2e07bb4 Michael Hanselmann
  return real_disk
2622 f2e07bb4 Michael Hanselmann
2623 f2e07bb4 Michael Hanselmann
2624 821d1bd1 Iustin Pop
def BlockdevFind(disk):
2625 a8083063 Iustin Pop
  """Check if a device is activated.
2626 a8083063 Iustin Pop

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

2629 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
2630 10c2650b Iustin Pop
  @param disk: the disk to find
2631 96acbc09 Michael Hanselmann
  @rtype: None or objects.BlockDevStatus
2632 96acbc09 Michael Hanselmann
  @return: None if the disk cannot be found, otherwise a the current
2633 96acbc09 Michael Hanselmann
           information
2634 a8083063 Iustin Pop

2635 a8083063 Iustin Pop
  """
2636 23829f6f Iustin Pop
  try:
2637 23829f6f Iustin Pop
    rbd = _RecursiveFindBD(disk)
2638 23829f6f Iustin Pop
  except errors.BlockDeviceError, err:
2639 2cc6781a Iustin Pop
    _Fail("Failed to find device: %s", err, exc=True)
2640 96acbc09 Michael Hanselmann
2641 a8083063 Iustin Pop
  if rbd is None:
2642 c26a6bd2 Iustin Pop
    return None
2643 96acbc09 Michael Hanselmann
2644 96acbc09 Michael Hanselmann
  return rbd.GetSyncStatus()
2645 a8083063 Iustin Pop
2646 a8083063 Iustin Pop
2647 6ef8077e Bernardo Dal Seno
def BlockdevGetdimensions(disks):
2648 968a7623 Iustin Pop
  """Computes the size of the given disks.
2649 968a7623 Iustin Pop

2650 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
2651 968a7623 Iustin Pop

2652 968a7623 Iustin Pop
  @type disks: list of L{objects.Disk}
2653 968a7623 Iustin Pop
  @param disks: the list of disk to compute the size for
2654 968a7623 Iustin Pop
  @rtype: list
2655 968a7623 Iustin Pop
  @return: list with elements None if the disk cannot be found,
2656 6ef8077e Bernardo Dal Seno
      otherwise the pair (size, spindles), where spindles is None if the
2657 6ef8077e Bernardo Dal Seno
      device doesn't support that
2658 968a7623 Iustin Pop

2659 968a7623 Iustin Pop
  """
2660 968a7623 Iustin Pop
  result = []
2661 968a7623 Iustin Pop
  for cf in disks:
2662 968a7623 Iustin Pop
    try:
2663 968a7623 Iustin Pop
      rbd = _RecursiveFindBD(cf)
2664 1122eb25 Iustin Pop
    except errors.BlockDeviceError:
2665 968a7623 Iustin Pop
      result.append(None)
2666 968a7623 Iustin Pop
      continue
2667 968a7623 Iustin Pop
    if rbd is None:
2668 968a7623 Iustin Pop
      result.append(None)
2669 968a7623 Iustin Pop
    else:
2670 6ef8077e Bernardo Dal Seno
      result.append(rbd.GetActualDimensions())
2671 968a7623 Iustin Pop
  return result
2672 968a7623 Iustin Pop
2673 968a7623 Iustin Pop
2674 a8083063 Iustin Pop
def UploadFile(file_name, data, mode, uid, gid, atime, mtime):
2675 a8083063 Iustin Pop
  """Write a file to the filesystem.
2676 a8083063 Iustin Pop

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

2680 10c2650b Iustin Pop
  @type file_name: str
2681 10c2650b Iustin Pop
  @param file_name: the target file name
2682 10c2650b Iustin Pop
  @type data: str
2683 10c2650b Iustin Pop
  @param data: the new contents of the file
2684 10c2650b Iustin Pop
  @type mode: int
2685 10c2650b Iustin Pop
  @param mode: the mode to give the file (can be None)
2686 9a914f7a René Nussbaumer
  @type uid: string
2687 9a914f7a René Nussbaumer
  @param uid: the owner of the file
2688 9a914f7a René Nussbaumer
  @type gid: string
2689 9a914f7a René Nussbaumer
  @param gid: the group of the file
2690 10c2650b Iustin Pop
  @type atime: float
2691 10c2650b Iustin Pop
  @param atime: the atime to set on the file (can be None)
2692 10c2650b Iustin Pop
  @type mtime: float
2693 10c2650b Iustin Pop
  @param mtime: the mtime to set on the file (can be None)
2694 c26a6bd2 Iustin Pop
  @rtype: None
2695 10c2650b Iustin Pop

2696 a8083063 Iustin Pop
  """
2697 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
2698 cffbbae7 Michael Hanselmann
2699 a8083063 Iustin Pop
  if not os.path.isabs(file_name):
2700 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile is not absolute: '%s'", file_name)
2701 a8083063 Iustin Pop
2702 360b0dc2 Iustin Pop
  if file_name not in _ALLOWED_UPLOAD_FILES:
2703 2cc6781a Iustin Pop
    _Fail("Filename passed to UploadFile not in allowed upload targets: '%s'",
2704 2cc6781a Iustin Pop
          file_name)
2705 a8083063 Iustin Pop
2706 12bce260 Michael Hanselmann
  raw_data = _Decompress(data)
2707 12bce260 Michael Hanselmann
2708 9a914f7a René Nussbaumer
  if not (isinstance(uid, basestring) and isinstance(gid, basestring)):
2709 9a914f7a René Nussbaumer
    _Fail("Invalid username/groupname type")
2710 9a914f7a René Nussbaumer
2711 9a914f7a René Nussbaumer
  getents = runtime.GetEnts()
2712 9a914f7a René Nussbaumer
  uid = getents.LookupUser(uid)
2713 9a914f7a René Nussbaumer
  gid = getents.LookupGroup(gid)
2714 9a914f7a René Nussbaumer
2715 8f065ae2 Iustin Pop
  utils.SafeWriteFile(file_name, None,
2716 8f065ae2 Iustin Pop
                      data=raw_data, mode=mode, uid=uid, gid=gid,
2717 8f065ae2 Iustin Pop
                      atime=atime, mtime=mtime)
2718 a8083063 Iustin Pop
2719 386b57af Iustin Pop
2720 b2f29800 René Nussbaumer
def RunOob(oob_program, command, node, timeout):
2721 b2f29800 René Nussbaumer
  """Executes oob_program with given command on given node.
2722 b2f29800 René Nussbaumer

2723 b2f29800 René Nussbaumer
  @param oob_program: The path to the executable oob_program
2724 b2f29800 René Nussbaumer
  @param command: The command to invoke on oob_program
2725 b2f29800 René Nussbaumer
  @param node: The node given as an argument to the program
2726 b2f29800 René Nussbaumer
  @param timeout: Timeout after which we kill the oob program
2727 b2f29800 René Nussbaumer

2728 b2f29800 René Nussbaumer
  @return: stdout
2729 b2f29800 René Nussbaumer
  @raise RPCFail: If execution fails for some reason
2730 b2f29800 René Nussbaumer

2731 b2f29800 René Nussbaumer
  """
2732 b2f29800 René Nussbaumer
  result = utils.RunCmd([oob_program, command, node], timeout=timeout)
2733 b2f29800 René Nussbaumer
2734 b2f29800 René Nussbaumer
  if result.failed:
2735 b2f29800 René Nussbaumer
    _Fail("'%s' failed with reason '%s'; output: %s", result.cmd,
2736 b2f29800 René Nussbaumer
          result.fail_reason, result.output)
2737 b2f29800 René Nussbaumer
2738 b2f29800 René Nussbaumer
  return result.stdout
2739 b2f29800 René Nussbaumer
2740 b2f29800 René Nussbaumer
2741 c19f9810 Iustin Pop
def _OSOndiskAPIVersion(os_dir):
2742 2f8598a5 Alexander Schreiber
  """Compute and return the API version of a given OS.
2743 a8083063 Iustin Pop

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

2747 10c2650b Iustin Pop
  @type os_dir: str
2748 c19f9810 Iustin Pop
  @param os_dir: the directory in which we should look for the OS
2749 8e70b181 Iustin Pop
  @rtype: tuple
2750 8e70b181 Iustin Pop
  @return: tuple (status, data) with status denoting the validity and
2751 8e70b181 Iustin Pop
      data holding either the vaid versions or an error message
2752 a8083063 Iustin Pop

2753 a8083063 Iustin Pop
  """
2754 e02b9114 Iustin Pop
  api_file = utils.PathJoin(os_dir, constants.OS_API_FILE)
2755 a8083063 Iustin Pop
2756 a8083063 Iustin Pop
  try:
2757 a8083063 Iustin Pop
    st = os.stat(api_file)
2758 a8083063 Iustin Pop
  except EnvironmentError, err:
2759 b6b45e0d Guido Trotter
    return False, ("Required file '%s' not found under path %s: %s" %
2760 eb93b673 Guido Trotter
                   (constants.OS_API_FILE, os_dir, utils.ErrnoOrStr(err)))
2761 a8083063 Iustin Pop
2762 a8083063 Iustin Pop
  if not stat.S_ISREG(stat.S_IFMT(st.st_mode)):
2763 b6b45e0d Guido Trotter
    return False, ("File '%s' in %s is not a regular file" %
2764 b6b45e0d Guido Trotter
                   (constants.OS_API_FILE, os_dir))
2765 a8083063 Iustin Pop
2766 a8083063 Iustin Pop
  try:
2767 3374afa9 Guido Trotter
    api_versions = utils.ReadFile(api_file).splitlines()
2768 a8083063 Iustin Pop
  except EnvironmentError, err:
2769 255dcebd Iustin Pop
    return False, ("Error while reading the API version file at %s: %s" %
2770 eb93b673 Guido Trotter
                   (api_file, utils.ErrnoOrStr(err)))
2771 a8083063 Iustin Pop
2772 a8083063 Iustin Pop
  try:
2773 63b9b186 Guido Trotter
    api_versions = [int(version.strip()) for version in api_versions]
2774 a8083063 Iustin Pop
  except (TypeError, ValueError), err:
2775 255dcebd Iustin Pop
    return False, ("API version(s) can't be converted to integer: %s" %
2776 255dcebd Iustin Pop
                   str(err))
2777 a8083063 Iustin Pop
2778 255dcebd Iustin Pop
  return True, api_versions
2779 a8083063 Iustin Pop
2780 386b57af Iustin Pop
2781 7c3d51d4 Guido Trotter
def DiagnoseOS(top_dirs=None):
2782 a8083063 Iustin Pop
  """Compute the validity for all OSes.
2783 a8083063 Iustin Pop

2784 10c2650b Iustin Pop
  @type top_dirs: list
2785 10c2650b Iustin Pop
  @param top_dirs: the list of directories in which to
2786 10c2650b Iustin Pop
      search (if not given defaults to
2787 3329f4de Michael Hanselmann
      L{pathutils.OS_SEARCH_PATH})
2788 10c2650b Iustin Pop
  @rtype: list of L{objects.OS}
2789 bad78e66 Iustin Pop
  @return: a list of tuples (name, path, status, diagnose, variants,
2790 bad78e66 Iustin Pop
      parameters, api_version) for all (potential) OSes under all
2791 bad78e66 Iustin Pop
      search paths, where:
2792 255dcebd Iustin Pop
          - name is the (potential) OS name
2793 255dcebd Iustin Pop
          - path is the full path to the OS
2794 255dcebd Iustin Pop
          - status True/False is the validity of the OS
2795 255dcebd Iustin Pop
          - diagnose is the error message for an invalid OS, otherwise empty
2796 ba00557a Guido Trotter
          - variants is a list of supported OS variants, if any
2797 c7d04a6b Iustin Pop
          - parameters is a list of (name, help) parameters, if any
2798 bad78e66 Iustin Pop
          - api_version is a list of support OS API versions
2799 a8083063 Iustin Pop

2800 a8083063 Iustin Pop
  """
2801 7c3d51d4 Guido Trotter
  if top_dirs is None:
2802 710f30ec Michael Hanselmann
    top_dirs = pathutils.OS_SEARCH_PATH
2803 a8083063 Iustin Pop
2804 a8083063 Iustin Pop
  result = []
2805 65fe4693 Iustin Pop
  for dir_name in top_dirs:
2806 65fe4693 Iustin Pop
    if os.path.isdir(dir_name):
2807 7c3d51d4 Guido Trotter
      try:
2808 65fe4693 Iustin Pop
        f_names = utils.ListVisibleFiles(dir_name)
2809 7c3d51d4 Guido Trotter
      except EnvironmentError, err:
2810 29921401 Iustin Pop
        logging.exception("Can't list the OS directory %s: %s", dir_name, err)
2811 7c3d51d4 Guido Trotter
        break
2812 7c3d51d4 Guido Trotter
      for name in f_names:
2813 e02b9114 Iustin Pop
        os_path = utils.PathJoin(dir_name, name)
2814 255dcebd Iustin Pop
        status, os_inst = _TryOSFromDisk(name, base_dir=dir_name)
2815 255dcebd Iustin Pop
        if status:
2816 255dcebd Iustin Pop
          diagnose = ""
2817 ba00557a Guido Trotter
          variants = os_inst.supported_variants
2818 c7d04a6b Iustin Pop
          parameters = os_inst.supported_parameters
2819 bad78e66 Iustin Pop
          api_versions = os_inst.api_versions
2820 255dcebd Iustin Pop
        else:
2821 255dcebd Iustin Pop
          diagnose = os_inst
2822 bad78e66 Iustin Pop
          variants = parameters = api_versions = []
2823 bad78e66 Iustin Pop
        result.append((name, os_path, status, diagnose, variants,
2824 bad78e66 Iustin Pop
                       parameters, api_versions))
2825 a8083063 Iustin Pop
2826 c26a6bd2 Iustin Pop
  return result
2827 a8083063 Iustin Pop
2828 a8083063 Iustin Pop
2829 255dcebd Iustin Pop
def _TryOSFromDisk(name, base_dir=None):
2830 a8083063 Iustin Pop
  """Create an OS instance from disk.
2831 a8083063 Iustin Pop

2832 a8083063 Iustin Pop
  This function will return an OS instance if the given name is a
2833 8e70b181 Iustin Pop
  valid OS name.
2834 a8083063 Iustin Pop

2835 8ee4dc80 Guido Trotter
  @type base_dir: string
2836 8ee4dc80 Guido Trotter
  @keyword base_dir: Base directory containing OS installations.
2837 8ee4dc80 Guido Trotter
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2838 255dcebd Iustin Pop
  @rtype: tuple
2839 255dcebd Iustin Pop
  @return: success and either the OS instance if we find a valid one,
2840 255dcebd Iustin Pop
      or error message
2841 7c3d51d4 Guido Trotter

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

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

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

2939 255dcebd Iustin Pop
  @type base_dir: string
2940 255dcebd Iustin Pop
  @keyword base_dir: Base directory containing OS installations.
2941 255dcebd Iustin Pop
                     Defaults to a search in all the OS_SEARCH_PATH dirs.
2942 255dcebd Iustin Pop
  @rtype: L{objects.OS}
2943 255dcebd Iustin Pop
  @return: the OS instance if we find a valid one
2944 255dcebd Iustin Pop
  @raise RPCFail: if we don't find a valid OS
2945 255dcebd Iustin Pop

2946 255dcebd Iustin Pop
  """
2947 870dc44c Iustin Pop
  name_only = objects.OS.GetName(name)
2948 6ee7102a Guido Trotter
  status, payload = _TryOSFromDisk(name_only, base_dir)
2949 255dcebd Iustin Pop
2950 255dcebd Iustin Pop
  if not status:
2951 255dcebd Iustin Pop
    _Fail(payload)
2952 a8083063 Iustin Pop
2953 255dcebd Iustin Pop
  return payload
2954 a8083063 Iustin Pop
2955 a8083063 Iustin Pop
2956 a025e535 Vitaly Kuznetsov
def OSCoreEnv(os_name, inst_os, os_params, debug=0):
2957 efaa9b06 Iustin Pop
  """Calculate the basic environment for an os script.
2958 2266edb2 Guido Trotter

2959 a025e535 Vitaly Kuznetsov
  @type os_name: str
2960 a025e535 Vitaly Kuznetsov
  @param os_name: full operating system name (including variant)
2961 099c52ad Iustin Pop
  @type inst_os: L{objects.OS}
2962 099c52ad Iustin Pop
  @param inst_os: operating system for which the environment is being built
2963 1bdcbbab Iustin Pop
  @type os_params: dict
2964 1bdcbbab Iustin Pop
  @param os_params: the OS parameters
2965 2266edb2 Guido Trotter
  @type debug: integer
2966 10c2650b Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
2967 2266edb2 Guido Trotter
  @rtype: dict
2968 2266edb2 Guido Trotter
  @return: dict of environment variables
2969 10c2650b Iustin Pop
  @raise errors.BlockDeviceError: if the block device
2970 10c2650b Iustin Pop
      cannot be found
2971 2266edb2 Guido Trotter

2972 2266edb2 Guido Trotter
  """
2973 2266edb2 Guido Trotter
  result = {}
2974 099c52ad Iustin Pop
  api_version = \
2975 099c52ad Iustin Pop
    max(constants.OS_API_VERSIONS.intersection(inst_os.api_versions))
2976 d0c8c01d Iustin Pop
  result["OS_API_VERSION"] = "%d" % api_version
2977 d0c8c01d Iustin Pop
  result["OS_NAME"] = inst_os.name
2978 d0c8c01d Iustin Pop
  result["DEBUG_LEVEL"] = "%d" % debug
2979 efaa9b06 Iustin Pop
2980 efaa9b06 Iustin Pop
  # OS variants
2981 35007011 Iustin Pop
  if api_version >= constants.OS_API_V15 and inst_os.supported_variants:
2982 870dc44c Iustin Pop
    variant = objects.OS.GetVariant(os_name)
2983 870dc44c Iustin Pop
    if not variant:
2984 099c52ad Iustin Pop
      variant = inst_os.supported_variants[0]
2985 35007011 Iustin Pop
  else:
2986 35007011 Iustin Pop
    variant = ""
2987 35007011 Iustin Pop
  result["OS_VARIANT"] = variant
2988 efaa9b06 Iustin Pop
2989 1bdcbbab Iustin Pop
  # OS params
2990 1bdcbbab Iustin Pop
  for pname, pvalue in os_params.items():
2991 d0c8c01d Iustin Pop
    result["OSP_%s" % pname.upper()] = pvalue
2992 1bdcbbab Iustin Pop
2993 9a6ade06 Iustin Pop
  # Set a default path otherwise programs called by OS scripts (or
2994 9a6ade06 Iustin Pop
  # even hooks called from OS scripts) might break, and we don't want
2995 9a6ade06 Iustin Pop
  # to have each script require setting a PATH variable
2996 9a6ade06 Iustin Pop
  result["PATH"] = constants.HOOKS_PATH
2997 9a6ade06 Iustin Pop
2998 efaa9b06 Iustin Pop
  return result
2999 efaa9b06 Iustin Pop
3000 efaa9b06 Iustin Pop
3001 efaa9b06 Iustin Pop
def OSEnvironment(instance, inst_os, debug=0):
3002 efaa9b06 Iustin Pop
  """Calculate the environment for an os script.
3003 efaa9b06 Iustin Pop

3004 efaa9b06 Iustin Pop
  @type instance: L{objects.Instance}
3005 efaa9b06 Iustin Pop
  @param instance: target instance for the os script run
3006 efaa9b06 Iustin Pop
  @type inst_os: L{objects.OS}
3007 efaa9b06 Iustin Pop
  @param inst_os: operating system for which the environment is being built
3008 efaa9b06 Iustin Pop
  @type debug: integer
3009 efaa9b06 Iustin Pop
  @param debug: debug level (0 or 1, for OS Api 10)
3010 efaa9b06 Iustin Pop
  @rtype: dict
3011 efaa9b06 Iustin Pop
  @return: dict of environment variables
3012 efaa9b06 Iustin Pop
  @raise errors.BlockDeviceError: if the block device
3013 efaa9b06 Iustin Pop
      cannot be found
3014 efaa9b06 Iustin Pop

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

3075 b954f097 Constantinos Venetsanopoulos
  @type top_dirs: list
3076 b954f097 Constantinos Venetsanopoulos
  @param top_dirs: the list of directories in which to
3077 b954f097 Constantinos Venetsanopoulos
      search (if not given defaults to
3078 b954f097 Constantinos Venetsanopoulos
      L{pathutils.ES_SEARCH_PATH})
3079 b954f097 Constantinos Venetsanopoulos
  @rtype: list of L{objects.ExtStorage}
3080 b954f097 Constantinos Venetsanopoulos
  @return: a list of tuples (name, path, status, diagnose, parameters)
3081 b954f097 Constantinos Venetsanopoulos
      for all (potential) ExtStorage Providers under all
3082 b954f097 Constantinos Venetsanopoulos
      search paths, where:
3083 b954f097 Constantinos Venetsanopoulos
          - name is the (potential) ExtStorage Provider
3084 b954f097 Constantinos Venetsanopoulos
          - path is the full path to the ExtStorage Provider
3085 b954f097 Constantinos Venetsanopoulos
          - status True/False is the validity of the ExtStorage Provider
3086 b954f097 Constantinos Venetsanopoulos
          - diagnose is the error message for an invalid ExtStorage Provider,
3087 b954f097 Constantinos Venetsanopoulos
            otherwise empty
3088 b954f097 Constantinos Venetsanopoulos
          - parameters is a list of (name, help) parameters, if any
3089 b954f097 Constantinos Venetsanopoulos

3090 b954f097 Constantinos Venetsanopoulos
  """
3091 b954f097 Constantinos Venetsanopoulos
  if top_dirs is None:
3092 b954f097 Constantinos Venetsanopoulos
    top_dirs = pathutils.ES_SEARCH_PATH
3093 b954f097 Constantinos Venetsanopoulos
3094 b954f097 Constantinos Venetsanopoulos
  result = []
3095 b954f097 Constantinos Venetsanopoulos
  for dir_name in top_dirs:
3096 b954f097 Constantinos Venetsanopoulos
    if os.path.isdir(dir_name):
3097 b954f097 Constantinos Venetsanopoulos
      try:
3098 b954f097 Constantinos Venetsanopoulos
        f_names = utils.ListVisibleFiles(dir_name)
3099 b954f097 Constantinos Venetsanopoulos
      except EnvironmentError, err:
3100 b954f097 Constantinos Venetsanopoulos
        logging.exception("Can't list the ExtStorage directory %s: %s",
3101 b954f097 Constantinos Venetsanopoulos
                          dir_name, err)
3102 b954f097 Constantinos Venetsanopoulos
        break
3103 b954f097 Constantinos Venetsanopoulos
      for name in f_names:
3104 b954f097 Constantinos Venetsanopoulos
        es_path = utils.PathJoin(dir_name, name)
3105 b954f097 Constantinos Venetsanopoulos
        status, es_inst = bdev.ExtStorageFromDisk(name, base_dir=dir_name)
3106 b954f097 Constantinos Venetsanopoulos
        if status:
3107 b954f097 Constantinos Venetsanopoulos
          diagnose = ""
3108 b954f097 Constantinos Venetsanopoulos
          parameters = es_inst.supported_parameters
3109 b954f097 Constantinos Venetsanopoulos
        else:
3110 b954f097 Constantinos Venetsanopoulos
          diagnose = es_inst
3111 b954f097 Constantinos Venetsanopoulos
          parameters = []
3112 b954f097 Constantinos Venetsanopoulos
        result.append((name, es_path, status, diagnose, parameters))
3113 b954f097 Constantinos Venetsanopoulos
3114 b954f097 Constantinos Venetsanopoulos
  return result
3115 b954f097 Constantinos Venetsanopoulos
3116 b954f097 Constantinos Venetsanopoulos
3117 be9150ea Bernardo Dal Seno
def BlockdevGrow(disk, amount, dryrun, backingstore, excl_stor):
3118 594609c0 Iustin Pop
  """Grow a stack of block devices.
3119 594609c0 Iustin Pop

3120 594609c0 Iustin Pop
  This function is called recursively, with the childrens being the
3121 10c2650b Iustin Pop
  first ones to resize.
3122 594609c0 Iustin Pop

3123 10c2650b Iustin Pop
  @type disk: L{objects.Disk}
3124 10c2650b Iustin Pop
  @param disk: the disk to be grown
3125 a59faf4b Iustin Pop
  @type amount: integer
3126 a59faf4b Iustin Pop
  @param amount: the amount (in mebibytes) to grow with
3127 a59faf4b Iustin Pop
  @type dryrun: boolean
3128 a59faf4b Iustin Pop
  @param dryrun: whether to execute the operation in simulation mode
3129 a59faf4b Iustin Pop
      only, without actually increasing the size
3130 cad0723b Iustin Pop
  @param backingstore: whether to execute the operation on backing storage
3131 cad0723b Iustin Pop
      only, or on "logical" storage only; e.g. DRBD is logical storage,
3132 cad0723b Iustin Pop
      whereas LVM, file, RBD are backing storage
3133 10c2650b Iustin Pop
  @rtype: (status, result)
3134 be9150ea Bernardo Dal Seno
  @type excl_stor: boolean
3135 be9150ea Bernardo Dal Seno
  @param excl_stor: Whether exclusive_storage is active
3136 a59faf4b Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3137 a59faf4b Iustin Pop
      the errors message if status is False
3138 594609c0 Iustin Pop

3139 594609c0 Iustin Pop
  """
3140 594609c0 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3141 594609c0 Iustin Pop
  if r_dev is None:
3142 afdc3985 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3143 594609c0 Iustin Pop
3144 594609c0 Iustin Pop
  try:
3145 be9150ea Bernardo Dal Seno
    r_dev.Grow(amount, dryrun, backingstore, excl_stor)
3146 594609c0 Iustin Pop
  except errors.BlockDeviceError, err:
3147 2cc6781a Iustin Pop
    _Fail("Failed to grow block device: %s", err, exc=True)
3148 594609c0 Iustin Pop
3149 594609c0 Iustin Pop
3150 821d1bd1 Iustin Pop
def BlockdevSnapshot(disk):
3151 a8083063 Iustin Pop
  """Create a snapshot copy of a block device.
3152 a8083063 Iustin Pop

3153 a8083063 Iustin Pop
  This function is called recursively, and the snapshot is actually created
3154 a8083063 Iustin Pop
  just for the leaf lvm backend device.
3155 a8083063 Iustin Pop

3156 e9e9263d Guido Trotter
  @type disk: L{objects.Disk}
3157 e9e9263d Guido Trotter
  @param disk: the disk to be snapshotted
3158 e9e9263d Guido Trotter
  @rtype: string
3159 800ac399 Iustin Pop
  @return: snapshot disk ID as (vg, lv)
3160 a8083063 Iustin Pop

3161 098c0958 Michael Hanselmann
  """
3162 cd3b4ff4 Helga Velroyen
  if disk.dev_type == constants.DT_DRBD8:
3163 433c63aa Iustin Pop
    if not disk.children:
3164 433c63aa Iustin Pop
      _Fail("DRBD device '%s' without backing storage cannot be snapshotted",
3165 433c63aa Iustin Pop
            disk.unique_id)
3166 433c63aa Iustin Pop
    return BlockdevSnapshot(disk.children[0])
3167 cd3b4ff4 Helga Velroyen
  elif disk.dev_type == constants.DT_PLAIN:
3168 a8083063 Iustin Pop
    r_dev = _RecursiveFindBD(disk)
3169 a8083063 Iustin Pop
    if r_dev is not None:
3170 433c63aa Iustin Pop
      # FIXME: choose a saner value for the snapshot size
3171 a8083063 Iustin Pop
      # let's stay on the safe side and ask for the full size, for now
3172 c26a6bd2 Iustin Pop
      return r_dev.Snapshot(disk.size)
3173 a8083063 Iustin Pop
    else:
3174 87812fd3 Iustin Pop
      _Fail("Cannot find block device %s", disk)
3175 a8083063 Iustin Pop
  else:
3176 87812fd3 Iustin Pop
    _Fail("Cannot snapshot non-lvm block device '%s' of type '%s'",
3177 87812fd3 Iustin Pop
          disk.unique_id, disk.dev_type)
3178 a8083063 Iustin Pop
3179 a8083063 Iustin Pop
3180 48e175a2 Iustin Pop
def BlockdevSetInfo(disk, info):
3181 48e175a2 Iustin Pop
  """Sets 'metadata' information on block devices.
3182 48e175a2 Iustin Pop

3183 48e175a2 Iustin Pop
  This function sets 'info' metadata on block devices. Initial
3184 48e175a2 Iustin Pop
  information is set at device creation; this function should be used
3185 48e175a2 Iustin Pop
  for example after renames.
3186 48e175a2 Iustin Pop

3187 48e175a2 Iustin Pop
  @type disk: L{objects.Disk}
3188 48e175a2 Iustin Pop
  @param disk: the disk to be grown
3189 48e175a2 Iustin Pop
  @type info: string
3190 48e175a2 Iustin Pop
  @param info: new 'info' metadata
3191 48e175a2 Iustin Pop
  @rtype: (status, result)
3192 48e175a2 Iustin Pop
  @return: a tuple with the status of the operation (True/False), and
3193 48e175a2 Iustin Pop
      the errors message if status is False
3194 48e175a2 Iustin Pop

3195 48e175a2 Iustin Pop
  """
3196 48e175a2 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
3197 48e175a2 Iustin Pop
  if r_dev is None:
3198 48e175a2 Iustin Pop
    _Fail("Cannot find block device %s", disk)
3199 48e175a2 Iustin Pop
3200 48e175a2 Iustin Pop
  try:
3201 48e175a2 Iustin Pop
    r_dev.SetInfo(info)
3202 48e175a2 Iustin Pop
  except errors.BlockDeviceError, err:
3203 48e175a2 Iustin Pop
    _Fail("Failed to set information on block device: %s", err, exc=True)
3204 48e175a2 Iustin Pop
3205 48e175a2 Iustin Pop
3206 a8083063 Iustin Pop
def FinalizeExport(instance, snap_disks):
3207 a8083063 Iustin Pop
  """Write out the export configuration information.
3208 a8083063 Iustin Pop

3209 10c2650b Iustin Pop
  @type instance: L{objects.Instance}
3210 10c2650b Iustin Pop
  @param instance: the instance which we export, used for
3211 10c2650b Iustin Pop
      saving configuration
3212 10c2650b Iustin Pop
  @type snap_disks: list of L{objects.Disk}
3213 10c2650b Iustin Pop
  @param snap_disks: list of snapshot block devices, which
3214 10c2650b Iustin Pop
      will be used to get the actual name of the dump file
3215 a8083063 Iustin Pop

3216 c26a6bd2 Iustin Pop
  @rtype: None
3217 a8083063 Iustin Pop

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

3301 10c2650b Iustin Pop
  @type dest: str
3302 10c2650b Iustin Pop
  @param dest: directory containing the export
3303 a8083063 Iustin Pop

3304 10c2650b Iustin Pop
  @rtype: L{objects.SerializableConfigParser}
3305 10c2650b Iustin Pop
  @return: a serializable config file containing the
3306 10c2650b Iustin Pop
      export info
3307 a8083063 Iustin Pop

3308 a8083063 Iustin Pop
  """
3309 c4feafe8 Iustin Pop
  cff = utils.PathJoin(dest, constants.EXPORT_CONF_FILE)
3310 a8083063 Iustin Pop
3311 a8083063 Iustin Pop
  config = objects.SerializableConfigParser()
3312 a8083063 Iustin Pop
  config.read(cff)
3313 a8083063 Iustin Pop
3314 a8083063 Iustin Pop
  if (not config.has_section(constants.INISECT_EXP) or
3315 a8083063 Iustin Pop
      not config.has_section(constants.INISECT_INS)):
3316 3eccac06 Iustin Pop
    _Fail("Export info file doesn't have the required fields")
3317 a8083063 Iustin Pop
3318 c26a6bd2 Iustin Pop
  return config.Dumps()
3319 a8083063 Iustin Pop
3320 a8083063 Iustin Pop
3321 a8083063 Iustin Pop
def ListExports():
3322 a8083063 Iustin Pop
  """Return a list of exports currently available on this machine.
3323 098c0958 Michael Hanselmann

3324 10c2650b Iustin Pop
  @rtype: list
3325 10c2650b Iustin Pop
  @return: list of the exports
3326 10c2650b Iustin Pop

3327 a8083063 Iustin Pop
  """
3328 710f30ec Michael Hanselmann
  if os.path.isdir(pathutils.EXPORT_DIR):
3329 710f30ec Michael Hanselmann
    return sorted(utils.ListVisibleFiles(pathutils.EXPORT_DIR))
3330 a8083063 Iustin Pop
  else:
3331 afdc3985 Iustin Pop
    _Fail("No exports directory")
3332 a8083063 Iustin Pop
3333 a8083063 Iustin Pop
3334 a8083063 Iustin Pop
def RemoveExport(export):
3335 a8083063 Iustin Pop
  """Remove an existing export from the node.
3336 a8083063 Iustin Pop

3337 10c2650b Iustin Pop
  @type export: str
3338 10c2650b Iustin Pop
  @param export: the name of the export to remove
3339 c26a6bd2 Iustin Pop
  @rtype: None
3340 a8083063 Iustin Pop

3341 098c0958 Michael Hanselmann
  """
3342 710f30ec Michael Hanselmann
  target = utils.PathJoin(pathutils.EXPORT_DIR, export)
3343 a8083063 Iustin Pop
3344 35fbcd11 Iustin Pop
  try:
3345 35fbcd11 Iustin Pop
    shutil.rmtree(target)
3346 35fbcd11 Iustin Pop
  except EnvironmentError, err:
3347 35fbcd11 Iustin Pop
    _Fail("Error while removing the export: %s", err, exc=True)
3348 a8083063 Iustin Pop
3349 a8083063 Iustin Pop
3350 821d1bd1 Iustin Pop
def BlockdevRename(devlist):
3351 f3e513ad Iustin Pop
  """Rename a list of block devices.
3352 f3e513ad Iustin Pop

3353 10c2650b Iustin Pop
  @type devlist: list of tuples
3354 a57e502a Thomas Thrainer
  @param devlist: list of tuples of the form  (disk, new_unique_id); disk is
3355 a57e502a Thomas Thrainer
      an L{objects.Disk} object describing the current disk, and new
3356 a57e502a Thomas Thrainer
      unique_id is the name we rename it to
3357 10c2650b Iustin Pop
  @rtype: boolean
3358 10c2650b Iustin Pop
  @return: True if all renames succeeded, False otherwise
3359 f3e513ad Iustin Pop

3360 f3e513ad Iustin Pop
  """
3361 6b5e3f70 Iustin Pop
  msgs = []
3362 f3e513ad Iustin Pop
  result = True
3363 f3e513ad Iustin Pop
  for disk, unique_id in devlist:
3364 f3e513ad Iustin Pop
    dev = _RecursiveFindBD(disk)
3365 f3e513ad Iustin Pop
    if dev is None:
3366 6b5e3f70 Iustin Pop
      msgs.append("Can't find device %s in rename" % str(disk))
3367 f3e513ad Iustin Pop
      result = False
3368 f3e513ad Iustin Pop
      continue
3369 f3e513ad Iustin Pop
    try:
3370 3f78eef2 Iustin Pop
      old_rpath = dev.dev_path
3371 f3e513ad Iustin Pop
      dev.Rename(unique_id)
3372 3f78eef2 Iustin Pop
      new_rpath = dev.dev_path
3373 3f78eef2 Iustin Pop
      if old_rpath != new_rpath:
3374 3f78eef2 Iustin Pop
        DevCacheManager.RemoveCache(old_rpath)
3375 3f78eef2 Iustin Pop
        # FIXME: we should add the new cache information here, like:
3376 3f78eef2 Iustin Pop
        # DevCacheManager.UpdateCache(new_rpath, owner, ...)
3377 3f78eef2 Iustin Pop
        # but we don't have the owner here - maybe parse from existing
3378 3f78eef2 Iustin Pop
        # cache? for now, we only lose lvm data when we rename, which
3379 3f78eef2 Iustin Pop
        # is less critical than DRBD or MD
3380 f3e513ad Iustin Pop
    except errors.BlockDeviceError, err:
3381 6b5e3f70 Iustin Pop
      msgs.append("Can't rename device '%s' to '%s': %s" %
3382 6b5e3f70 Iustin Pop
                  (dev, unique_id, err))
3383 18682bca Iustin Pop
      logging.exception("Can't rename device '%s' to '%s'", dev, unique_id)
3384 f3e513ad Iustin Pop
      result = False
3385 afdc3985 Iustin Pop
  if not result:
3386 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
3387 f3e513ad Iustin Pop
3388 f3e513ad Iustin Pop
3389 4b97f902 Apollon Oikonomopoulos
def _TransformFileStorageDir(fs_dir):
3390 778b75bb Manuel Franceschini
  """Checks whether given file_storage_dir is valid.
3391 778b75bb Manuel Franceschini

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

3396 4b97f902 Apollon Oikonomopoulos
  @type fs_dir: str
3397 4b97f902 Apollon Oikonomopoulos
  @param fs_dir: the path to check
3398 d61cbe76 Iustin Pop

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

3401 778b75bb Manuel Franceschini
  """
3402 13a6c760 Helga Velroyen
  filestorage.CheckFileStoragePath(fs_dir)
3403 5e09a309 Michael Hanselmann
3404 5e09a309 Michael Hanselmann
  return os.path.normpath(fs_dir)
3405 778b75bb Manuel Franceschini
3406 778b75bb Manuel Franceschini
3407 778b75bb Manuel Franceschini
def CreateFileStorageDir(file_storage_dir):
3408 778b75bb Manuel Franceschini
  """Create file storage directory.
3409 778b75bb Manuel Franceschini

3410 b1206984 Iustin Pop
  @type file_storage_dir: str
3411 b1206984 Iustin Pop
  @param file_storage_dir: directory to create
3412 778b75bb Manuel Franceschini

3413 b1206984 Iustin Pop
  @rtype: tuple
3414 b1206984 Iustin Pop
  @return: tuple with first element a boolean indicating wheter dir
3415 b1206984 Iustin Pop
      creation was successful or not
3416 778b75bb Manuel Franceschini

3417 778b75bb Manuel Franceschini
  """
3418 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3419 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3420 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3421 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3422 b2b8bcce Iustin Pop
            file_storage_dir)
3423 778b75bb Manuel Franceschini
  else:
3424 b2b8bcce Iustin Pop
    try:
3425 b2b8bcce Iustin Pop
      os.makedirs(file_storage_dir, 0750)
3426 b2b8bcce Iustin Pop
    except OSError, err:
3427 b2b8bcce Iustin Pop
      _Fail("Cannot create file storage directory '%s': %s",
3428 b2b8bcce Iustin Pop
            file_storage_dir, err, exc=True)
3429 778b75bb Manuel Franceschini
3430 778b75bb Manuel Franceschini
3431 778b75bb Manuel Franceschini
def RemoveFileStorageDir(file_storage_dir):
3432 778b75bb Manuel Franceschini
  """Remove file storage directory.
3433 778b75bb Manuel Franceschini

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

3436 10c2650b Iustin Pop
  @type file_storage_dir: str
3437 10c2650b Iustin Pop
  @param file_storage_dir: the directory we should cleanup
3438 10c2650b Iustin Pop
  @rtype: tuple (success,)
3439 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3440 5bbd3f7f Michael Hanselmann
      whether the operation was successful
3441 778b75bb Manuel Franceschini

3442 778b75bb Manuel Franceschini
  """
3443 778b75bb Manuel Franceschini
  file_storage_dir = _TransformFileStorageDir(file_storage_dir)
3444 b2b8bcce Iustin Pop
  if os.path.exists(file_storage_dir):
3445 b2b8bcce Iustin Pop
    if not os.path.isdir(file_storage_dir):
3446 b2b8bcce Iustin Pop
      _Fail("Specified Storage directory '%s' is not a directory",
3447 b2b8bcce Iustin Pop
            file_storage_dir)
3448 afdc3985 Iustin Pop
    # deletes dir only if empty, otherwise we want to fail the rpc call
3449 b2b8bcce Iustin Pop
    try:
3450 b2b8bcce Iustin Pop
      os.rmdir(file_storage_dir)
3451 b2b8bcce Iustin Pop
    except OSError, err:
3452 b2b8bcce Iustin Pop
      _Fail("Cannot remove file storage directory '%s': %s",
3453 b2b8bcce Iustin Pop
            file_storage_dir, err)
3454 b2b8bcce Iustin Pop
3455 778b75bb Manuel Franceschini
3456 778b75bb Manuel Franceschini
def RenameFileStorageDir(old_file_storage_dir, new_file_storage_dir):
3457 778b75bb Manuel Franceschini
  """Rename the file storage directory.
3458 778b75bb Manuel Franceschini

3459 10c2650b Iustin Pop
  @type old_file_storage_dir: str
3460 10c2650b Iustin Pop
  @param old_file_storage_dir: the current path
3461 10c2650b Iustin Pop
  @type new_file_storage_dir: str
3462 10c2650b Iustin Pop
  @param new_file_storage_dir: the name we should rename to
3463 10c2650b Iustin Pop
  @rtype: tuple (success,)
3464 10c2650b Iustin Pop
  @return: tuple of one element, C{success}, denoting
3465 10c2650b Iustin Pop
      whether the operation was successful
3466 778b75bb Manuel Franceschini

3467 778b75bb Manuel Franceschini
  """
3468 778b75bb Manuel Franceschini
  old_file_storage_dir = _TransformFileStorageDir(old_file_storage_dir)
3469 778b75bb Manuel Franceschini
  new_file_storage_dir = _TransformFileStorageDir(new_file_storage_dir)
3470 b2b8bcce Iustin Pop
  if not os.path.exists(new_file_storage_dir):
3471 b2b8bcce Iustin Pop
    if os.path.isdir(old_file_storage_dir):
3472 b2b8bcce Iustin Pop
      try:
3473 b2b8bcce Iustin Pop
        os.rename(old_file_storage_dir, new_file_storage_dir)
3474 b2b8bcce Iustin Pop
      except OSError, err:
3475 b2b8bcce Iustin Pop
        _Fail("Cannot rename '%s' to '%s': %s",
3476 b2b8bcce Iustin Pop
              old_file_storage_dir, new_file_storage_dir, err)
3477 778b75bb Manuel Franceschini
    else:
3478 b2b8bcce Iustin Pop
      _Fail("Specified storage dir '%s' is not a directory",
3479 b2b8bcce Iustin Pop
            old_file_storage_dir)
3480 b2b8bcce Iustin Pop
  else:
3481 b2b8bcce Iustin Pop
    if os.path.exists(old_file_storage_dir):
3482 b2b8bcce Iustin Pop
      _Fail("Cannot rename '%s' to '%s': both locations exist",
3483 b2b8bcce Iustin Pop
            old_file_storage_dir, new_file_storage_dir)
3484 778b75bb Manuel Franceschini
3485 778b75bb Manuel Franceschini
3486 c8457ce7 Iustin Pop
def _EnsureJobQueueFile(file_name):
3487 dc31eae3 Michael Hanselmann
  """Checks whether the given filename is in the queue directory.
3488 ca52cdeb Michael Hanselmann

3489 10c2650b Iustin Pop
  @type file_name: str
3490 10c2650b Iustin Pop
  @param file_name: the file name we should check
3491 c8457ce7 Iustin Pop
  @rtype: None
3492 c8457ce7 Iustin Pop
  @raises RPCFail: if the file is not valid
3493 10c2650b Iustin Pop

3494 ca52cdeb Michael Hanselmann
  """
3495 b3589802 Michael Hanselmann
  if not utils.IsBelowDir(pathutils.QUEUE_DIR, file_name):
3496 c8457ce7 Iustin Pop
    _Fail("Passed job queue file '%s' does not belong to"
3497 b3589802 Michael Hanselmann
          " the queue directory '%s'", file_name, pathutils.QUEUE_DIR)
3498 dc31eae3 Michael Hanselmann
3499 dc31eae3 Michael Hanselmann
3500 dc31eae3 Michael Hanselmann
def JobQueueUpdate(file_name, content):
3501 dc31eae3 Michael Hanselmann
  """Updates a file in the queue directory.
3502 dc31eae3 Michael Hanselmann

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

3506 10c2650b Iustin Pop
  @type file_name: str
3507 10c2650b Iustin Pop
  @param file_name: the job file name
3508 10c2650b Iustin Pop
  @type content: str
3509 10c2650b Iustin Pop
  @param content: the new job contents
3510 10c2650b Iustin Pop
  @rtype: boolean
3511 10c2650b Iustin Pop
  @return: the success of the operation
3512 10c2650b Iustin Pop

3513 dc31eae3 Michael Hanselmann
  """
3514 cffbbae7 Michael Hanselmann
  file_name = vcluster.LocalizeVirtualPath(file_name)
3515 cffbbae7 Michael Hanselmann
3516 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(file_name)
3517 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
3518 ca52cdeb Michael Hanselmann
3519 ca52cdeb Michael Hanselmann
  # Write and replace the file atomically
3520 82b22e19 René Nussbaumer
  utils.WriteFile(file_name, data=_Decompress(content), uid=getents.masterd_uid,
3521 fe05a931 Michele Tartara
                  gid=getents.daemons_gid, mode=constants.JOB_QUEUE_FILES_PERMS)
3522 ca52cdeb Michael Hanselmann
3523 ca52cdeb Michael Hanselmann
3524 af5ebcb1 Michael Hanselmann
def JobQueueRename(old, new):
3525 af5ebcb1 Michael Hanselmann
  """Renames a job queue file.
3526 af5ebcb1 Michael Hanselmann

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

3529 10c2650b Iustin Pop
  @type old: str
3530 10c2650b Iustin Pop
  @param old: the old (actual) file name
3531 10c2650b Iustin Pop
  @type new: str
3532 10c2650b Iustin Pop
  @param new: the desired file name
3533 c8457ce7 Iustin Pop
  @rtype: tuple
3534 c8457ce7 Iustin Pop
  @return: the success of the operation and payload
3535 10c2650b Iustin Pop

3536 af5ebcb1 Michael Hanselmann
  """
3537 cffbbae7 Michael Hanselmann
  old = vcluster.LocalizeVirtualPath(old)
3538 cffbbae7 Michael Hanselmann
  new = vcluster.LocalizeVirtualPath(new)
3539 cffbbae7 Michael Hanselmann
3540 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(old)
3541 c8457ce7 Iustin Pop
  _EnsureJobQueueFile(new)
3542 af5ebcb1 Michael Hanselmann
3543 8e5a705d René Nussbaumer
  getents = runtime.GetEnts()
3544 8e5a705d René Nussbaumer
3545 fe05a931 Michele Tartara
  utils.RenameFile(old, new, mkdir=True, mkdir_mode=0750,
3546 fe05a931 Michele Tartara
                   dir_uid=getents.masterd_uid, dir_gid=getents.daemons_gid)
3547 af5ebcb1 Michael Hanselmann
3548 af5ebcb1 Michael Hanselmann
3549 821d1bd1 Iustin Pop
def BlockdevClose(instance_name, disks):
3550 d61cbe76 Iustin Pop
  """Closes the given block devices.
3551 d61cbe76 Iustin Pop

3552 10c2650b Iustin Pop
  This means they will be switched to secondary mode (in case of
3553 10c2650b Iustin Pop
  DRBD).
3554 10c2650b Iustin Pop

3555 b2e7666a Iustin Pop
  @param instance_name: if the argument is not empty, the symlinks
3556 b2e7666a Iustin Pop
      of this instance will be removed
3557 10c2650b Iustin Pop
  @type disks: list of L{objects.Disk}
3558 10c2650b Iustin Pop
  @param disks: the list of disks to be closed
3559 10c2650b Iustin Pop
  @rtype: tuple (success, message)
3560 10c2650b Iustin Pop
  @return: a tuple of success and message, where success
3561 10c2650b Iustin Pop
      indicates the succes of the operation, and message
3562 10c2650b Iustin Pop
      which will contain the error details in case we
3563 10c2650b Iustin Pop
      failed
3564 d61cbe76 Iustin Pop

3565 d61cbe76 Iustin Pop
  """
3566 d61cbe76 Iustin Pop
  bdevs = []
3567 d61cbe76 Iustin Pop
  for cf in disks:
3568 d61cbe76 Iustin Pop
    rd = _RecursiveFindBD(cf)
3569 d61cbe76 Iustin Pop
    if rd is None:
3570 2cc6781a Iustin Pop
      _Fail("Can't find device %s", cf)
3571 d61cbe76 Iustin Pop
    bdevs.append(rd)
3572 d61cbe76 Iustin Pop
3573 d61cbe76 Iustin Pop
  msg = []
3574 d61cbe76 Iustin Pop
  for rd in bdevs:
3575 d61cbe76 Iustin Pop
    try:
3576 d61cbe76 Iustin Pop
      rd.Close()
3577 d61cbe76 Iustin Pop
    except errors.BlockDeviceError, err:
3578 d61cbe76 Iustin Pop
      msg.append(str(err))
3579 d61cbe76 Iustin Pop
  if msg:
3580 afdc3985 Iustin Pop
    _Fail("Can't make devices secondary: %s", ",".join(msg))
3581 d61cbe76 Iustin Pop
  else:
3582 b2e7666a Iustin Pop
    if instance_name:
3583 5282084b Iustin Pop
      _RemoveBlockDevLinks(instance_name, disks)
3584 d61cbe76 Iustin Pop
3585 d61cbe76 Iustin Pop
3586 6217e295 Iustin Pop
def ValidateHVParams(hvname, hvparams):
3587 6217e295 Iustin Pop
  """Validates the given hypervisor parameters.
3588 6217e295 Iustin Pop

3589 6217e295 Iustin Pop
  @type hvname: string
3590 6217e295 Iustin Pop
  @param hvname: the hypervisor name
3591 6217e295 Iustin Pop
  @type hvparams: dict
3592 6217e295 Iustin Pop
  @param hvparams: the hypervisor parameters to be validated
3593 c26a6bd2 Iustin Pop
  @rtype: None
3594 6217e295 Iustin Pop

3595 6217e295 Iustin Pop
  """
3596 6217e295 Iustin Pop
  try:
3597 6217e295 Iustin Pop
    hv_type = hypervisor.GetHypervisor(hvname)
3598 6217e295 Iustin Pop
    hv_type.ValidateParameters(hvparams)
3599 6217e295 Iustin Pop
  except errors.HypervisorError, err:
3600 afdc3985 Iustin Pop
    _Fail(str(err), log=False)
3601 6217e295 Iustin Pop
3602 6217e295 Iustin Pop
3603 acd9ff9e Iustin Pop
def _CheckOSPList(os_obj, parameters):
3604 acd9ff9e Iustin Pop
  """Check whether a list of parameters is supported by the OS.
3605 acd9ff9e Iustin Pop

3606 acd9ff9e Iustin Pop
  @type os_obj: L{objects.OS}
3607 acd9ff9e Iustin Pop
  @param os_obj: OS object to check
3608 acd9ff9e Iustin Pop
  @type parameters: list
3609 acd9ff9e Iustin Pop
  @param parameters: the list of parameters to check
3610 acd9ff9e Iustin Pop

3611 acd9ff9e Iustin Pop
  """
3612 acd9ff9e Iustin Pop
  supported = [v[0] for v in os_obj.supported_parameters]
3613 acd9ff9e Iustin Pop
  delta = frozenset(parameters).difference(supported)
3614 acd9ff9e Iustin Pop
  if delta:
3615 acd9ff9e Iustin Pop
    _Fail("The following parameters are not supported"
3616 acd9ff9e Iustin Pop
          " by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
3617 acd9ff9e Iustin Pop
3618 acd9ff9e Iustin Pop
3619 acd9ff9e Iustin Pop
def ValidateOS(required, osname, checks, osparams):
3620 acd9ff9e Iustin Pop
  """Validate the given OS' parameters.
3621 acd9ff9e Iustin Pop

3622 acd9ff9e Iustin Pop
  @type required: boolean
3623 acd9ff9e Iustin Pop
  @param required: whether absence of the OS should translate into
3624 acd9ff9e Iustin Pop
      failure or not
3625 acd9ff9e Iustin Pop
  @type osname: string
3626 acd9ff9e Iustin Pop
  @param osname: the OS to be validated
3627 acd9ff9e Iustin Pop
  @type checks: list
3628 acd9ff9e Iustin Pop
  @param checks: list of the checks to run (currently only 'parameters')
3629 acd9ff9e Iustin Pop
  @type osparams: dict
3630 acd9ff9e Iustin Pop
  @param osparams: dictionary with OS parameters
3631 acd9ff9e Iustin Pop
  @rtype: boolean
3632 acd9ff9e Iustin Pop
  @return: True if the validation passed, or False if the OS was not
3633 acd9ff9e Iustin Pop
      found and L{required} was false
3634 acd9ff9e Iustin Pop

3635 acd9ff9e Iustin Pop
  """
3636 acd9ff9e Iustin Pop
  if not constants.OS_VALIDATE_CALLS.issuperset(checks):
3637 acd9ff9e Iustin Pop
    _Fail("Unknown checks required for OS %s: %s", osname,
3638 acd9ff9e Iustin Pop
          set(checks).difference(constants.OS_VALIDATE_CALLS))
3639 acd9ff9e Iustin Pop
3640 870dc44c Iustin Pop
  name_only = objects.OS.GetName(osname)
3641 acd9ff9e Iustin Pop
  status, tbv = _TryOSFromDisk(name_only, None)
3642 acd9ff9e Iustin Pop
3643 acd9ff9e Iustin Pop
  if not status:
3644 acd9ff9e Iustin Pop
    if required:
3645 acd9ff9e Iustin Pop
      _Fail(tbv)
3646 acd9ff9e Iustin Pop
    else:
3647 acd9ff9e Iustin Pop
      return False
3648 acd9ff9e Iustin Pop
3649 72db3fd7 Iustin Pop
  if max(tbv.api_versions) < constants.OS_API_V20:
3650 72db3fd7 Iustin Pop
    return True
3651 72db3fd7 Iustin Pop
3652 acd9ff9e Iustin Pop
  if constants.OS_VALIDATE_PARAMETERS in checks:
3653 acd9ff9e Iustin Pop
    _CheckOSPList(tbv, osparams.keys())
3654 acd9ff9e Iustin Pop
3655 a025e535 Vitaly Kuznetsov
  validate_env = OSCoreEnv(osname, tbv, osparams)
3656 acd9ff9e Iustin Pop
  result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
3657 896a03f6 Iustin Pop
                        cwd=tbv.path, reset_env=True)
3658 acd9ff9e Iustin Pop
  if result.failed:
3659 acd9ff9e Iustin Pop
    logging.error("os validate command '%s' returned error: %s output: %s",
3660 acd9ff9e Iustin Pop
                  result.cmd, result.fail_reason, result.output)
3661 acd9ff9e Iustin Pop
    _Fail("OS validation script failed (%s), output: %s",
3662 acd9ff9e Iustin Pop
          result.fail_reason, result.output, log=False)
3663 acd9ff9e Iustin Pop
3664 acd9ff9e Iustin Pop
  return True
3665 acd9ff9e Iustin Pop
3666 acd9ff9e Iustin Pop
3667 56aa9fd5 Iustin Pop
def DemoteFromMC():
3668 56aa9fd5 Iustin Pop
  """Demotes the current node from master candidate role.
3669 56aa9fd5 Iustin Pop

3670 56aa9fd5 Iustin Pop
  """
3671 56aa9fd5 Iustin Pop
  # try to ensure we're not the master by mistake
3672 56aa9fd5 Iustin Pop
  master, myself = ssconf.GetMasterAndMyself()
3673 56aa9fd5 Iustin Pop
  if master == myself:
3674 afdc3985 Iustin Pop
    _Fail("ssconf status shows I'm the master node, will not demote")
3675 f154a7a3 Michael Hanselmann
3676 710f30ec Michael Hanselmann
  result = utils.RunCmd([pathutils.DAEMON_UTIL, "check", constants.MASTERD])
3677 f154a7a3 Michael Hanselmann
  if not result.failed:
3678 afdc3985 Iustin Pop
    _Fail("The master daemon is running, will not demote")
3679 f154a7a3 Michael Hanselmann
3680 56aa9fd5 Iustin Pop
  try:
3681 710f30ec Michael Hanselmann
    if os.path.isfile(pathutils.CLUSTER_CONF_FILE):
3682 710f30ec Michael Hanselmann
      utils.CreateBackup(pathutils.CLUSTER_CONF_FILE)
3683 56aa9fd5 Iustin Pop
  except EnvironmentError, err:
3684 56aa9fd5 Iustin Pop
    if err.errno != errno.ENOENT:
3685 afdc3985 Iustin Pop
      _Fail("Error while backing up cluster file: %s", err, exc=True)
3686 f154a7a3 Michael Hanselmann
3687 710f30ec Michael Hanselmann
  utils.RemoveFile(pathutils.CLUSTER_CONF_FILE)
3688 56aa9fd5 Iustin Pop
3689 56aa9fd5 Iustin Pop
3690 f942a838 Michael Hanselmann
def _GetX509Filenames(cryptodir, name):
3691 f942a838 Michael Hanselmann
  """Returns the full paths for the private key and certificate.
3692 f942a838 Michael Hanselmann

3693 f942a838 Michael Hanselmann
  """
3694 f942a838 Michael Hanselmann
  return (utils.PathJoin(cryptodir, name),
3695 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_KEY_FILE),
3696 f942a838 Michael Hanselmann
          utils.PathJoin(cryptodir, name, _X509_CERT_FILE))
3697 f942a838 Michael Hanselmann
3698 f942a838 Michael Hanselmann
3699 710f30ec Michael Hanselmann
def CreateX509Certificate(validity, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3700 f942a838 Michael Hanselmann
  """Creates a new X509 certificate for SSL/TLS.
3701 f942a838 Michael Hanselmann

3702 f942a838 Michael Hanselmann
  @type validity: int
3703 f942a838 Michael Hanselmann
  @param validity: Validity in seconds
3704 f942a838 Michael Hanselmann
  @rtype: tuple; (string, string)
3705 f942a838 Michael Hanselmann
  @return: Certificate name and public part
3706 f942a838 Michael Hanselmann

3707 f942a838 Michael Hanselmann
  """
3708 f942a838 Michael Hanselmann
  (key_pem, cert_pem) = \
3709 b705c7a6 Manuel Franceschini
    utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
3710 ab4b1cf2 Helga Velroyen
                                     min(validity, _MAX_SSL_CERT_VALIDITY), 1)
3711 f942a838 Michael Hanselmann
3712 f942a838 Michael Hanselmann
  cert_dir = tempfile.mkdtemp(dir=cryptodir,
3713 f942a838 Michael Hanselmann
                              prefix="x509-%s-" % utils.TimestampForFilename())
3714 f942a838 Michael Hanselmann
  try:
3715 f942a838 Michael Hanselmann
    name = os.path.basename(cert_dir)
3716 f942a838 Michael Hanselmann
    assert len(name) > 5
3717 f942a838 Michael Hanselmann
3718 f942a838 Michael Hanselmann
    (_, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3719 f942a838 Michael Hanselmann
3720 f942a838 Michael Hanselmann
    utils.WriteFile(key_file, mode=0400, data=key_pem)
3721 f942a838 Michael Hanselmann
    utils.WriteFile(cert_file, mode=0400, data=cert_pem)
3722 f942a838 Michael Hanselmann
3723 f942a838 Michael Hanselmann
    # Never return private key as it shouldn't leave the node
3724 f942a838 Michael Hanselmann
    return (name, cert_pem)
3725 f942a838 Michael Hanselmann
  except Exception:
3726 f942a838 Michael Hanselmann
    shutil.rmtree(cert_dir, ignore_errors=True)
3727 f942a838 Michael Hanselmann
    raise
3728 f942a838 Michael Hanselmann
3729 f942a838 Michael Hanselmann
3730 710f30ec Michael Hanselmann
def RemoveX509Certificate(name, cryptodir=pathutils.CRYPTO_KEYS_DIR):
3731 f942a838 Michael Hanselmann
  """Removes a X509 certificate.
3732 f942a838 Michael Hanselmann

3733 f942a838 Michael Hanselmann
  @type name: string
3734 f942a838 Michael Hanselmann
  @param name: Certificate name
3735 f942a838 Michael Hanselmann

3736 f942a838 Michael Hanselmann
  """
3737 f942a838 Michael Hanselmann
  (cert_dir, key_file, cert_file) = _GetX509Filenames(cryptodir, name)
3738 f942a838 Michael Hanselmann
3739 f942a838 Michael Hanselmann
  utils.RemoveFile(key_file)
3740 f942a838 Michael Hanselmann
  utils.RemoveFile(cert_file)
3741 f942a838 Michael Hanselmann
3742 f942a838 Michael Hanselmann
  try:
3743 f942a838 Michael Hanselmann
    os.rmdir(cert_dir)
3744 f942a838 Michael Hanselmann
  except EnvironmentError, err:
3745 f942a838 Michael Hanselmann
    _Fail("Cannot remove certificate directory '%s': %s",
3746 f942a838 Michael Hanselmann
          cert_dir, err)
3747 f942a838 Michael Hanselmann
3748 f942a838 Michael Hanselmann
3749 1651d116 Michael Hanselmann
def _GetImportExportIoCommand(instance, mode, ieio, ieargs):
3750 1651d116 Michael Hanselmann
  """Returns the command for the requested input/output.
3751 1651d116 Michael Hanselmann

3752 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
3753 1651d116 Michael Hanselmann
  @param instance: The instance object
3754 1651d116 Michael Hanselmann
  @param mode: Import/export mode
3755 1651d116 Michael Hanselmann
  @param ieio: Input/output type
3756 1651d116 Michael Hanselmann
  @param ieargs: Input/output arguments
3757 1651d116 Michael Hanselmann

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

3857 1651d116 Michael Hanselmann
  """
3858 710f30ec Michael Hanselmann
  return tempfile.mkdtemp(dir=pathutils.IMPORT_EXPORT_DIR,
3859 1651d116 Michael Hanselmann
                          prefix=("%s-%s-" %
3860 1651d116 Michael Hanselmann
                                  (prefix, utils.TimestampForFilename())))
3861 1651d116 Michael Hanselmann
3862 1651d116 Michael Hanselmann
3863 6613661a Iustin Pop
def StartImportExportDaemon(mode, opts, host, port, instance, component,
3864 6613661a Iustin Pop
                            ieio, ieioargs):
3865 1651d116 Michael Hanselmann
  """Starts an import or export daemon.
3866 1651d116 Michael Hanselmann

3867 1651d116 Michael Hanselmann
  @param mode: Import/output mode
3868 eb630f50 Michael Hanselmann
  @type opts: L{objects.ImportExportOptions}
3869 eb630f50 Michael Hanselmann
  @param opts: Daemon options
3870 1651d116 Michael Hanselmann
  @type host: string
3871 1651d116 Michael Hanselmann
  @param host: Remote host for export (None for import)
3872 1651d116 Michael Hanselmann
  @type port: int
3873 1651d116 Michael Hanselmann
  @param port: Remote port for export (None for import)
3874 1651d116 Michael Hanselmann
  @type instance: L{objects.Instance}
3875 1651d116 Michael Hanselmann
  @param instance: Instance object
3876 6613661a Iustin Pop
  @type component: string
3877 6613661a Iustin Pop
  @param component: which part of the instance is transferred now,
3878 6613661a Iustin Pop
      e.g. 'disk/0'
3879 1651d116 Michael Hanselmann
  @param ieio: Input/output type
3880 1651d116 Michael Hanselmann
  @param ieioargs: Input/output arguments
3881 1651d116 Michael Hanselmann

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

3994 1651d116 Michael Hanselmann
  @type names: sequence
3995 1651d116 Michael Hanselmann
  @param names: List of names
3996 1651d116 Michael Hanselmann
  @rtype: List of dicts
3997 1651d116 Michael Hanselmann
  @return: Returns a list of the state of each named import/export or None if a
3998 1651d116 Michael Hanselmann
           status couldn't be read
3999 1651d116 Michael Hanselmann

4000 1651d116 Michael Hanselmann
  """
4001 1651d116 Michael Hanselmann
  result = []
4002 1651d116 Michael Hanselmann
4003 1651d116 Michael Hanselmann
  for name in names:
4004 710f30ec Michael Hanselmann
    status_file = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name,
4005 1651d116 Michael Hanselmann
                                 _IES_STATUS_FILE)
4006 1651d116 Michael Hanselmann
4007 1651d116 Michael Hanselmann
    try:
4008 1651d116 Michael Hanselmann
      data = utils.ReadFile(status_file)
4009 1651d116 Michael Hanselmann
    except EnvironmentError, err:
4010 1651d116 Michael Hanselmann
      if err.errno != errno.ENOENT:
4011 1651d116 Michael Hanselmann
        raise
4012 1651d116 Michael Hanselmann
      data = None
4013 1651d116 Michael Hanselmann
4014 1651d116 Michael Hanselmann
    if not data:
4015 1651d116 Michael Hanselmann
      result.append(None)
4016 1651d116 Michael Hanselmann
      continue
4017 1651d116 Michael Hanselmann
4018 1651d116 Michael Hanselmann
    result.append(serializer.LoadJson(data))
4019 1651d116 Michael Hanselmann
4020 1651d116 Michael Hanselmann
  return result
4021 1651d116 Michael Hanselmann
4022 1651d116 Michael Hanselmann
4023 f81c4737 Michael Hanselmann
def AbortImportExport(name):
4024 f81c4737 Michael Hanselmann
  """Sends SIGTERM to a running import/export daemon.
4025 f81c4737 Michael Hanselmann

4026 f81c4737 Michael Hanselmann
  """
4027 f81c4737 Michael Hanselmann
  logging.info("Abort import/export %s", name)
4028 f81c4737 Michael Hanselmann
4029 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4030 f81c4737 Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4031 f81c4737 Michael Hanselmann
4032 f81c4737 Michael Hanselmann
  if pid:
4033 f81c4737 Michael Hanselmann
    logging.info("Import/export %s is running with PID %s, sending SIGTERM",
4034 f81c4737 Michael Hanselmann
                 name, pid)
4035 560cbec1 Michael Hanselmann
    utils.IgnoreProcessNotFound(os.kill, pid, signal.SIGTERM)
4036 f81c4737 Michael Hanselmann
4037 f81c4737 Michael Hanselmann
4038 1651d116 Michael Hanselmann
def CleanupImportExport(name):
4039 1651d116 Michael Hanselmann
  """Cleanup after an import or export.
4040 1651d116 Michael Hanselmann

4041 1651d116 Michael Hanselmann
  If the import/export daemon is still running it's killed. Afterwards the
4042 1651d116 Michael Hanselmann
  whole status directory is removed.
4043 1651d116 Michael Hanselmann

4044 1651d116 Michael Hanselmann
  """
4045 1651d116 Michael Hanselmann
  logging.info("Finalizing import/export %s", name)
4046 1651d116 Michael Hanselmann
4047 710f30ec Michael Hanselmann
  status_dir = utils.PathJoin(pathutils.IMPORT_EXPORT_DIR, name)
4048 1651d116 Michael Hanselmann
4049 debed9ae Michael Hanselmann
  pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE))
4050 1651d116 Michael Hanselmann
4051 1651d116 Michael Hanselmann
  if pid:
4052 1651d116 Michael Hanselmann
    logging.info("Import/export %s is still running with PID %s",
4053 1651d116 Michael Hanselmann
                 name, pid)
4054 1651d116 Michael Hanselmann
    utils.KillProcess(pid, waitpid=False)
4055 1651d116 Michael Hanselmann
4056 1651d116 Michael Hanselmann
  shutil.rmtree(status_dir, ignore_errors=True)
4057 1651d116 Michael Hanselmann
4058 1651d116 Michael Hanselmann
4059 0c3d9c7c Thomas Thrainer
def _FindDisks(disks):
4060 0c3d9c7c Thomas Thrainer
  """Finds attached L{BlockDev}s for the given disks.
4061 6b93ec9d Iustin Pop

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

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

4068 235a6b29 Thomas Thrainer
  """
4069 6b93ec9d Iustin Pop
  bdevs = []
4070 6b93ec9d Iustin Pop
4071 0c3d9c7c Thomas Thrainer
  for disk in disks:
4072 0c3d9c7c Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4073 6b93ec9d Iustin Pop
    if rd is None:
4074 0c3d9c7c Thomas Thrainer
      _Fail("Can't find device %s", disk)
4075 6b93ec9d Iustin Pop
    bdevs.append(rd)
4076 5a533f8a Iustin Pop
  return bdevs
4077 6b93ec9d Iustin Pop
4078 6b93ec9d Iustin Pop
4079 0c3d9c7c Thomas Thrainer
def DrbdDisconnectNet(disks):
4080 6b93ec9d Iustin Pop
  """Disconnects the network on a list of drbd devices.
4081 6b93ec9d Iustin Pop

4082 6b93ec9d Iustin Pop
  """
4083 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4084 6b93ec9d Iustin Pop
4085 6b93ec9d Iustin Pop
  # disconnect disks
4086 6b93ec9d Iustin Pop
  for rd in bdevs:
4087 6b93ec9d Iustin Pop
    try:
4088 6b93ec9d Iustin Pop
      rd.DisconnectNet()
4089 6b93ec9d Iustin Pop
    except errors.BlockDeviceError, err:
4090 2cc6781a Iustin Pop
      _Fail("Can't change network configuration to standalone mode: %s",
4091 2cc6781a Iustin Pop
            err, exc=True)
4092 6b93ec9d Iustin Pop
4093 6b93ec9d Iustin Pop
4094 0c3d9c7c Thomas Thrainer
def DrbdAttachNet(disks, instance_name, multimaster):
4095 6b93ec9d Iustin Pop
  """Attaches the network on a list of drbd devices.
4096 6b93ec9d Iustin Pop

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

4171 6b93ec9d Iustin Pop
  """
4172 db8667b7 Iustin Pop
  def _helper(rd):
4173 db8667b7 Iustin Pop
    stats = rd.GetProcStatus()
4174 db8667b7 Iustin Pop
    if not (stats.is_connected or stats.is_in_resync):
4175 db8667b7 Iustin Pop
      raise utils.RetryAgain()
4176 db8667b7 Iustin Pop
    return stats
4177 db8667b7 Iustin Pop
4178 0c3d9c7c Thomas Thrainer
  bdevs = _FindDisks(disks)
4179 6b93ec9d Iustin Pop
4180 6b93ec9d Iustin Pop
  min_resync = 100
4181 6b93ec9d Iustin Pop
  alldone = True
4182 6b93ec9d Iustin Pop
  for rd in bdevs:
4183 db8667b7 Iustin Pop
    try:
4184 db8667b7 Iustin Pop
      # poll each second for 15 seconds
4185 db8667b7 Iustin Pop
      stats = utils.Retry(_helper, 1, 15, args=[rd])
4186 db8667b7 Iustin Pop
    except utils.RetryTimeout:
4187 db8667b7 Iustin Pop
      stats = rd.GetProcStatus()
4188 db8667b7 Iustin Pop
      # last check
4189 db8667b7 Iustin Pop
      if not (stats.is_connected or stats.is_in_resync):
4190 db8667b7 Iustin Pop
        _Fail("DRBD device %s is not in sync: stats=%s", rd, stats)
4191 6b93ec9d Iustin Pop
    alldone = alldone and (not stats.is_in_resync)
4192 6b93ec9d Iustin Pop
    if stats.sync_percent is not None:
4193 6b93ec9d Iustin Pop
      min_resync = min(min_resync, stats.sync_percent)
4194 afdc3985 Iustin Pop
4195 c26a6bd2 Iustin Pop
  return (alldone, min_resync)
4196 6b93ec9d Iustin Pop
4197 6b93ec9d Iustin Pop
4198 0c3d9c7c Thomas Thrainer
def DrbdNeedsActivation(disks):
4199 235a6b29 Thomas Thrainer
  """Checks which of the passed disks needs activation and returns their UUIDs.
4200 235a6b29 Thomas Thrainer

4201 235a6b29 Thomas Thrainer
  """
4202 235a6b29 Thomas Thrainer
  faulty_disks = []
4203 235a6b29 Thomas Thrainer
4204 235a6b29 Thomas Thrainer
  for disk in disks:
4205 235a6b29 Thomas Thrainer
    rd = _RecursiveFindBD(disk)
4206 235a6b29 Thomas Thrainer
    if rd is None:
4207 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4208 235a6b29 Thomas Thrainer
      continue
4209 235a6b29 Thomas Thrainer
4210 235a6b29 Thomas Thrainer
    stats = rd.GetProcStatus()
4211 235a6b29 Thomas Thrainer
    if stats.is_standalone or stats.is_diskless:
4212 235a6b29 Thomas Thrainer
      faulty_disks.append(disk)
4213 235a6b29 Thomas Thrainer
4214 235a6b29 Thomas Thrainer
  return [disk.uuid for disk in faulty_disks]
4215 235a6b29 Thomas Thrainer
4216 235a6b29 Thomas Thrainer
4217 c46b9782 Luca Bigliardi
def GetDrbdUsermodeHelper():
4218 c46b9782 Luca Bigliardi
  """Returns DRBD usermode helper currently configured.
4219 c46b9782 Luca Bigliardi

4220 c46b9782 Luca Bigliardi
  """
4221 c46b9782 Luca Bigliardi
  try:
4222 47e0abee Thomas Thrainer
    return drbd.DRBD8.GetUsermodeHelper()
4223 c46b9782 Luca Bigliardi
  except errors.BlockDeviceError, err:
4224 c46b9782 Luca Bigliardi
    _Fail(str(err))
4225 c46b9782 Luca Bigliardi
4226 c46b9782 Luca Bigliardi
4227 8ef418bb Helga Velroyen
def PowercycleNode(hypervisor_type, hvparams=None):
4228 f5118ade Iustin Pop
  """Hard-powercycle the node.
4229 f5118ade Iustin Pop

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

4233 f5118ade Iustin Pop
  """
4234 f5118ade Iustin Pop
  hyper = hypervisor.GetHypervisor(hypervisor_type)
4235 f5118ade Iustin Pop
  try:
4236 f5118ade Iustin Pop
    pid = os.fork()
4237 29921401 Iustin Pop
  except OSError:
4238 f5118ade Iustin Pop
    # if we can't fork, we'll pretend that we're in the child process
4239 f5118ade Iustin Pop
    pid = 0
4240 f5118ade Iustin Pop
  if pid > 0:
4241 c26a6bd2 Iustin Pop
    return "Reboot scheduled in 5 seconds"
4242 1af6ac0f Luca Bigliardi
  # ensure the child is running on ram
4243 1af6ac0f Luca Bigliardi
  try:
4244 1af6ac0f Luca Bigliardi
    utils.Mlockall()
4245 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
4246 1af6ac0f Luca Bigliardi
    pass
4247 f5118ade Iustin Pop
  time.sleep(5)
4248 8ef418bb Helga Velroyen
  hyper.PowercycleNode(hvparams=hvparams)
4249 f5118ade Iustin Pop
4250 f5118ade Iustin Pop
4251 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdName(cmd):
4252 45bc4635 Iustin Pop
  """Verifies a restricted command name.
4253 1a2eb2dc Michael Hanselmann

4254 1a2eb2dc Michael Hanselmann
  @type cmd: string
4255 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4256 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4257 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4258 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4259 1a2eb2dc Michael Hanselmann

4260 1a2eb2dc Michael Hanselmann
  """
4261 1a2eb2dc Michael Hanselmann
  if not cmd.strip():
4262 1a2eb2dc Michael Hanselmann
    return (False, "Missing command name")
4263 1a2eb2dc Michael Hanselmann
4264 1a2eb2dc Michael Hanselmann
  if os.path.basename(cmd) != cmd:
4265 1a2eb2dc Michael Hanselmann
    return (False, "Invalid command name")
4266 1a2eb2dc Michael Hanselmann
4267 1a2eb2dc Michael Hanselmann
  if not constants.EXT_PLUGIN_MASK.match(cmd):
4268 1a2eb2dc Michael Hanselmann
    return (False, "Command name contains forbidden characters")
4269 1a2eb2dc Michael Hanselmann
4270 1a2eb2dc Michael Hanselmann
  return (True, None)
4271 1a2eb2dc Michael Hanselmann
4272 1a2eb2dc Michael Hanselmann
4273 405bffe2 Michael Hanselmann
def _CommonRestrictedCmdCheck(path, owner):
4274 45bc4635 Iustin Pop
  """Common checks for restricted command file system directories and files.
4275 1a2eb2dc Michael Hanselmann

4276 1a2eb2dc Michael Hanselmann
  @type path: string
4277 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4278 1a2eb2dc Michael Hanselmann
  @param owner: C{None} or tuple containing UID and GID
4279 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or C{os.stat} result)
4280 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4281 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's the result of C{os.stat}
4282 1a2eb2dc Michael Hanselmann

4283 1a2eb2dc Michael Hanselmann
  """
4284 1a2eb2dc Michael Hanselmann
  if owner is None:
4285 1a2eb2dc Michael Hanselmann
    # Default to root as owner
4286 1a2eb2dc Michael Hanselmann
    owner = (0, 0)
4287 1a2eb2dc Michael Hanselmann
4288 1a2eb2dc Michael Hanselmann
  try:
4289 1a2eb2dc Michael Hanselmann
    st = os.stat(path)
4290 1a2eb2dc Michael Hanselmann
  except EnvironmentError, err:
4291 1a2eb2dc Michael Hanselmann
    return (False, "Can't stat(2) '%s': %s" % (path, err))
4292 1a2eb2dc Michael Hanselmann
4293 1a2eb2dc Michael Hanselmann
  if stat.S_IMODE(st.st_mode) & (~_RCMD_MAX_MODE):
4294 1a2eb2dc Michael Hanselmann
    return (False, "Permissions on '%s' are too permissive" % path)
4295 1a2eb2dc Michael Hanselmann
4296 1a2eb2dc Michael Hanselmann
  if (st.st_uid, st.st_gid) != owner:
4297 1a2eb2dc Michael Hanselmann
    (owner_uid, owner_gid) = owner
4298 1a2eb2dc Michael Hanselmann
    return (False, "'%s' is not owned by %s:%s" % (path, owner_uid, owner_gid))
4299 1a2eb2dc Michael Hanselmann
4300 1a2eb2dc Michael Hanselmann
  return (True, st)
4301 1a2eb2dc Michael Hanselmann
4302 1a2eb2dc Michael Hanselmann
4303 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmdDirectory(path, _owner=None):
4304 45bc4635 Iustin Pop
  """Verifies restricted command directory.
4305 1a2eb2dc Michael Hanselmann

4306 1a2eb2dc Michael Hanselmann
  @type path: string
4307 1a2eb2dc Michael Hanselmann
  @param path: Path to check
4308 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string or None)
4309 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4310 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise it's C{None}
4311 1a2eb2dc Michael Hanselmann

4312 1a2eb2dc Michael Hanselmann
  """
4313 405bffe2 Michael Hanselmann
  (status, value) = _CommonRestrictedCmdCheck(path, _owner)
4314 1a2eb2dc Michael Hanselmann
4315 1a2eb2dc Michael Hanselmann
  if not status:
4316 1a2eb2dc Michael Hanselmann
    return (False, value)
4317 1a2eb2dc Michael Hanselmann
4318 1a2eb2dc Michael Hanselmann
  if not stat.S_ISDIR(value.st_mode):
4319 1a2eb2dc Michael Hanselmann
    return (False, "Path '%s' is not a directory" % path)
4320 1a2eb2dc Michael Hanselmann
4321 1a2eb2dc Michael Hanselmann
  return (True, None)
4322 1a2eb2dc Michael Hanselmann
4323 1a2eb2dc Michael Hanselmann
4324 405bffe2 Michael Hanselmann
def _VerifyRestrictedCmd(path, cmd, _owner=None):
4325 45bc4635 Iustin Pop
  """Verifies a whole restricted command and returns its executable filename.
4326 1a2eb2dc Michael Hanselmann

4327 1a2eb2dc Michael Hanselmann
  @type path: string
4328 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4329 1a2eb2dc Michael Hanselmann
  @type cmd: string
4330 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4331 1a2eb2dc Michael Hanselmann
  @rtype: tuple; (boolean, string)
4332 1a2eb2dc Michael Hanselmann
  @return: The tuple's first element is the status; if C{False}, the second
4333 1a2eb2dc Michael Hanselmann
    element is an error message string, otherwise the second element is the
4334 1a2eb2dc Michael Hanselmann
    absolute path to the executable
4335 1a2eb2dc Michael Hanselmann

4336 1a2eb2dc Michael Hanselmann
  """
4337 1a2eb2dc Michael Hanselmann
  executable = utils.PathJoin(path, cmd)
4338 1a2eb2dc Michael Hanselmann
4339 405bffe2 Michael Hanselmann
  (status, msg) = _CommonRestrictedCmdCheck(executable, _owner)
4340 1a2eb2dc Michael Hanselmann
4341 1a2eb2dc Michael Hanselmann
  if not status:
4342 1a2eb2dc Michael Hanselmann
    return (False, msg)
4343 1a2eb2dc Michael Hanselmann
4344 1a2eb2dc Michael Hanselmann
  if not utils.IsExecutable(executable):
4345 1a2eb2dc Michael Hanselmann
    return (False, "access(2) thinks '%s' can't be executed" % executable)
4346 1a2eb2dc Michael Hanselmann
4347 1a2eb2dc Michael Hanselmann
  return (True, executable)
4348 1a2eb2dc Michael Hanselmann
4349 1a2eb2dc Michael Hanselmann
4350 405bffe2 Michael Hanselmann
def _PrepareRestrictedCmd(path, cmd,
4351 405bffe2 Michael Hanselmann
                          _verify_dir=_VerifyRestrictedCmdDirectory,
4352 405bffe2 Michael Hanselmann
                          _verify_name=_VerifyRestrictedCmdName,
4353 405bffe2 Michael Hanselmann
                          _verify_cmd=_VerifyRestrictedCmd):
4354 45bc4635 Iustin Pop
  """Performs a number of tests on a restricted command.
4355 1a2eb2dc Michael Hanselmann

4356 1a2eb2dc Michael Hanselmann
  @type path: string
4357 45bc4635 Iustin Pop
  @param path: Directory containing restricted commands
4358 1a2eb2dc Michael Hanselmann
  @type cmd: string
4359 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4360 405bffe2 Michael Hanselmann
  @return: Same as L{_VerifyRestrictedCmd}
4361 1a2eb2dc Michael Hanselmann

4362 1a2eb2dc Michael Hanselmann
  """
4363 1a2eb2dc Michael Hanselmann
  # Verify the directory first
4364 1a2eb2dc Michael Hanselmann
  (status, msg) = _verify_dir(path)
4365 1a2eb2dc Michael Hanselmann
  if status:
4366 1a2eb2dc Michael Hanselmann
    # Check command if everything was alright
4367 1a2eb2dc Michael Hanselmann
    (status, msg) = _verify_name(cmd)
4368 1a2eb2dc Michael Hanselmann
4369 1a2eb2dc Michael Hanselmann
  if not status:
4370 1a2eb2dc Michael Hanselmann
    return (False, msg)
4371 1a2eb2dc Michael Hanselmann
4372 1a2eb2dc Michael Hanselmann
  # Check actual executable
4373 1a2eb2dc Michael Hanselmann
  return _verify_cmd(path, cmd)
4374 1a2eb2dc Michael Hanselmann
4375 1a2eb2dc Michael Hanselmann
4376 42bd26e8 Michael Hanselmann
def RunRestrictedCmd(cmd,
4377 1a2eb2dc Michael Hanselmann
                     _lock_timeout=_RCMD_LOCK_TIMEOUT,
4378 878c42ae Michael Hanselmann
                     _lock_file=pathutils.RESTRICTED_COMMANDS_LOCK_FILE,
4379 878c42ae Michael Hanselmann
                     _path=pathutils.RESTRICTED_COMMANDS_DIR,
4380 1a2eb2dc Michael Hanselmann
                     _sleep_fn=time.sleep,
4381 405bffe2 Michael Hanselmann
                     _prepare_fn=_PrepareRestrictedCmd,
4382 1a2eb2dc Michael Hanselmann
                     _runcmd_fn=utils.RunCmd,
4383 1fdeb284 Michael Hanselmann
                     _enabled=constants.ENABLE_RESTRICTED_COMMANDS):
4384 45bc4635 Iustin Pop
  """Executes a restricted command after performing strict tests.
4385 1a2eb2dc Michael Hanselmann

4386 1a2eb2dc Michael Hanselmann
  @type cmd: string
4387 1a2eb2dc Michael Hanselmann
  @param cmd: Command name
4388 1a2eb2dc Michael Hanselmann
  @rtype: string
4389 1a2eb2dc Michael Hanselmann
  @return: Command output
4390 1a2eb2dc Michael Hanselmann
  @raise RPCFail: In case of an error
4391 1a2eb2dc Michael Hanselmann

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

4438 99e222b1 Michael Hanselmann
  @type until: None or number
4439 99e222b1 Michael Hanselmann
  @param until: Unix timestamp saying until when the watcher shouldn't run
4440 99e222b1 Michael Hanselmann

4441 99e222b1 Michael Hanselmann
  """
4442 99e222b1 Michael Hanselmann
  if until is None:
4443 99e222b1 Michael Hanselmann
    logging.info("Received request to no longer pause watcher")
4444 99e222b1 Michael Hanselmann
    utils.RemoveFile(_filename)
4445 99e222b1 Michael Hanselmann
  else:
4446 99e222b1 Michael Hanselmann
    logging.info("Received request to pause watcher until %s", until)
4447 99e222b1 Michael Hanselmann
4448 99e222b1 Michael Hanselmann
    if not ht.TNumber(until):
4449 99e222b1 Michael Hanselmann
      _Fail("Duration must be numeric")
4450 99e222b1 Michael Hanselmann
4451 99e222b1 Michael Hanselmann
    utils.WriteFile(_filename, data="%d\n" % (until, ), mode=0644)
4452 99e222b1 Michael Hanselmann
4453 99e222b1 Michael Hanselmann
4454 4daa5eb9 Sebastian Gebhard
def ConfigureOVS(ovs_name, ovs_link):
4455 4daa5eb9 Sebastian Gebhard
  """Creates a OpenvSwitch on the node.
4456 4daa5eb9 Sebastian Gebhard

4457 4daa5eb9 Sebastian Gebhard
  This function sets up a OpenvSwitch on the node with given name nad
4458 4daa5eb9 Sebastian Gebhard
  connects it via a given eth device.
4459 4daa5eb9 Sebastian Gebhard

4460 4daa5eb9 Sebastian Gebhard
  @type ovs_name: string
4461 4daa5eb9 Sebastian Gebhard
  @param ovs_name: Name of the OpenvSwitch to create.
4462 4daa5eb9 Sebastian Gebhard
  @type ovs_link: None or string
4463 4daa5eb9 Sebastian Gebhard
  @param ovs_link: Ethernet device for outside connection (can be missing)
4464 4daa5eb9 Sebastian Gebhard

4465 4daa5eb9 Sebastian Gebhard
  """
4466 4daa5eb9 Sebastian Gebhard
  # Initialize the OpenvSwitch
4467 4daa5eb9 Sebastian Gebhard
  result = utils.RunCmd(["ovs-vsctl", "add-br", ovs_name])
4468 4daa5eb9 Sebastian Gebhard
  if result.failed:
4469 a1578ccf Sebastian Gebhard
    _Fail("Failed to create openvswitch. Script return value: %s, output: '%s'"
4470 a1578ccf Sebastian Gebhard
          % (result.exit_code, result.output), log=True)
4471 4daa5eb9 Sebastian Gebhard
4472 4daa5eb9 Sebastian Gebhard
  # And connect it to a physical interface, if given
4473 4daa5eb9 Sebastian Gebhard
  if ovs_link:
4474 4daa5eb9 Sebastian Gebhard
    result = utils.RunCmd(["ovs-vsctl", "add-port", ovs_name, ovs_link])
4475 4daa5eb9 Sebastian Gebhard
    if result.failed:
4476 4daa5eb9 Sebastian Gebhard
      _Fail("Failed to connect openvswitch to  interface %s. Script return"
4477 a1578ccf Sebastian Gebhard
            " value: %s, output: '%s'" % (ovs_link, result.exit_code,
4478 a1578ccf Sebastian Gebhard
            result.output), log=True)
4479 4daa5eb9 Sebastian Gebhard
4480 4daa5eb9 Sebastian Gebhard
4481 a8083063 Iustin Pop
class HooksRunner(object):
4482 a8083063 Iustin Pop
  """Hook runner.
4483 a8083063 Iustin Pop

4484 10c2650b Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not
4485 10c2650b Iustin Pop
  on the master side.
4486 a8083063 Iustin Pop

4487 a8083063 Iustin Pop
  """
4488 a8083063 Iustin Pop
  def __init__(self, hooks_base_dir=None):
4489 a8083063 Iustin Pop
    """Constructor for hooks runner.
4490 a8083063 Iustin Pop

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

4495 a8083063 Iustin Pop
    """
4496 a8083063 Iustin Pop
    if hooks_base_dir is None:
4497 710f30ec Michael Hanselmann
      hooks_base_dir = pathutils.HOOKS_BASE_DIR
4498 fe267188 Iustin Pop
    # yeah, _BASE_DIR is not valid for attributes, we use it like a
4499 fe267188 Iustin Pop
    # constant
4500 b459a848 Andrea Spadaccini
    self._BASE_DIR = hooks_base_dir # pylint: disable=C0103
4501 a8083063 Iustin Pop
4502 0fa481f5 Andrea Spadaccini
  def RunLocalHooks(self, node_list, hpath, phase, env):
4503 0fa481f5 Andrea Spadaccini
    """Check that the hooks will be run only locally and then run them.
4504 0fa481f5 Andrea Spadaccini

4505 0fa481f5 Andrea Spadaccini
    """
4506 0fa481f5 Andrea Spadaccini
    assert len(node_list) == 1
4507 0fa481f5 Andrea Spadaccini
    node = node_list[0]
4508 0fa481f5 Andrea Spadaccini
    _, myself = ssconf.GetMasterAndMyself()
4509 0fa481f5 Andrea Spadaccini
    assert node == myself
4510 0fa481f5 Andrea Spadaccini
4511 0fa481f5 Andrea Spadaccini
    results = self.RunHooks(hpath, phase, env)
4512 0fa481f5 Andrea Spadaccini
4513 0fa481f5 Andrea Spadaccini
    # Return values in the form expected by HooksMaster
4514 0fa481f5 Andrea Spadaccini
    return {node: (None, False, results)}
4515 0fa481f5 Andrea Spadaccini
4516 a8083063 Iustin Pop
  def RunHooks(self, hpath, phase, env):
4517 a8083063 Iustin Pop
    """Run the scripts in the hooks directory.
4518 a8083063 Iustin Pop

4519 10c2650b Iustin Pop
    @type hpath: str
4520 10c2650b Iustin Pop
    @param hpath: the path to the hooks directory which
4521 10c2650b Iustin Pop
        holds the scripts
4522 10c2650b Iustin Pop
    @type phase: str
4523 10c2650b Iustin Pop
    @param phase: either L{constants.HOOKS_PHASE_PRE} or
4524 10c2650b Iustin Pop
        L{constants.HOOKS_PHASE_POST}
4525 10c2650b Iustin Pop
    @type env: dict
4526 10c2650b Iustin Pop
    @param env: dictionary with the environment for the hook
4527 10c2650b Iustin Pop
    @rtype: list
4528 10c2650b Iustin Pop
    @return: list of 3-element tuples:
4529 10c2650b Iustin Pop
      - script path
4530 10c2650b Iustin Pop
      - script result, either L{constants.HKR_SUCCESS} or
4531 10c2650b Iustin Pop
        L{constants.HKR_FAIL}
4532 10c2650b Iustin Pop
      - output of the script
4533 10c2650b Iustin Pop

4534 10c2650b Iustin Pop
    @raise errors.ProgrammerError: for invalid input
4535 10c2650b Iustin Pop
        parameters
4536 a8083063 Iustin Pop

4537 a8083063 Iustin Pop
    """
4538 a8083063 Iustin Pop
    if phase == constants.HOOKS_PHASE_PRE:
4539 a8083063 Iustin Pop
      suffix = "pre"
4540 a8083063 Iustin Pop
    elif phase == constants.HOOKS_PHASE_POST:
4541 a8083063 Iustin Pop
      suffix = "post"
4542 a8083063 Iustin Pop
    else:
4543 3fb4f740 Iustin Pop
      _Fail("Unknown hooks phase '%s'", phase)
4544 3fb4f740 Iustin Pop
4545 a8083063 Iustin Pop
    subdir = "%s-%s.d" % (hpath, suffix)
4546 0411c011 Iustin Pop
    dir_name = utils.PathJoin(self._BASE_DIR, subdir)
4547 6bb65e3a Guido Trotter
4548 6bb65e3a Guido Trotter
    results = []
4549 a9b7e346 Iustin Pop
4550 a9b7e346 Iustin Pop
    if not os.path.isdir(dir_name):
4551 a9b7e346 Iustin Pop
      # for non-existing/non-dirs, we simply exit instead of logging a
4552 a9b7e346 Iustin Pop
      # warning at every operation
4553 a9b7e346 Iustin Pop
      return results
4554 a9b7e346 Iustin Pop
4555 a9b7e346 Iustin Pop
    runparts_results = utils.RunParts(dir_name, env=env, reset_env=True)
4556 a9b7e346 Iustin Pop
4557 5ae4945a Iustin Pop
    for (relname, relstatus, runresult) in runparts_results:
4558 6bb65e3a Guido Trotter
      if relstatus == constants.RUNPARTS_SKIP:
4559 a8083063 Iustin Pop
        rrval = constants.HKR_SKIP
4560 a8083063 Iustin Pop
        output = ""
4561 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_ERR:
4562 6bb65e3a Guido Trotter
        rrval = constants.HKR_FAIL
4563 6bb65e3a Guido Trotter
        output = "Hook script execution error: %s" % runresult
4564 6bb65e3a Guido Trotter
      elif relstatus == constants.RUNPARTS_RUN:
4565 6bb65e3a Guido Trotter
        if runresult.failed:
4566 a8083063 Iustin Pop
          rrval = constants.HKR_FAIL
4567 a8083063 Iustin Pop
        else:
4568 6bb65e3a Guido Trotter
          rrval = constants.HKR_SUCCESS
4569 6bb65e3a Guido Trotter
        output = utils.SafeEncode(runresult.output.strip())
4570 6bb65e3a Guido Trotter
      results.append(("%s/%s" % (subdir, relname), rrval, output))
4571 6bb65e3a Guido Trotter
4572 6bb65e3a Guido Trotter
    return results
4573 3f78eef2 Iustin Pop
4574 3f78eef2 Iustin Pop
4575 8d528b7c Iustin Pop
class IAllocatorRunner(object):
4576 8d528b7c Iustin Pop
  """IAllocator runner.
4577 8d528b7c Iustin Pop

4578 8d528b7c Iustin Pop
  This class is instantiated on the node side (ganeti-noded) and not on
4579 8d528b7c Iustin Pop
  the master side.
4580 8d528b7c Iustin Pop

4581 8d528b7c Iustin Pop
  """
4582 7e950d31 Iustin Pop
  @staticmethod
4583 0359e5d0 Spyros Trigazis
  def Run(name, idata, ial_params):
4584 8d528b7c Iustin Pop
    """Run an iallocator script.
4585 8d528b7c Iustin Pop

4586 10c2650b Iustin Pop
    @type name: str
4587 10c2650b Iustin Pop
    @param name: the iallocator script name
4588 10c2650b Iustin Pop
    @type idata: str
4589 10c2650b Iustin Pop
    @param idata: the allocator input data
4590 0359e5d0 Spyros Trigazis
    @type ial_params: list
4591 0359e5d0 Spyros Trigazis
    @param ial_params: the iallocator parameters
4592 10c2650b Iustin Pop

4593 10c2650b Iustin Pop
    @rtype: tuple
4594 87f5c298 Iustin Pop
    @return: two element tuple of:
4595 87f5c298 Iustin Pop
       - status
4596 87f5c298 Iustin Pop
       - either error message or stdout of allocator (for success)
4597 8d528b7c Iustin Pop

4598 8d528b7c Iustin Pop
    """
4599 8d528b7c Iustin Pop
    alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
4600 8d528b7c Iustin Pop
                                  os.path.isfile)
4601 8d528b7c Iustin Pop
    if alloc_script is None:
4602 87f5c298 Iustin Pop
      _Fail("iallocator module '%s' not found in the search path", name)
4603 8d528b7c Iustin Pop
4604 8d528b7c Iustin Pop
    fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
4605 8d528b7c Iustin Pop
    try:
4606 8d528b7c Iustin Pop
      os.write(fd, idata)
4607 8d528b7c Iustin Pop
      os.close(fd)
4608 0359e5d0 Spyros Trigazis
      result = utils.RunCmd([alloc_script, fin_name] + ial_params)
4609 8d528b7c Iustin Pop
      if result.failed:
4610 87f5c298 Iustin Pop
        _Fail("iallocator module '%s' failed: %s, output '%s'",
4611 87f5c298 Iustin Pop
              name, result.fail_reason, result.output)
4612 8d528b7c Iustin Pop
    finally:
4613 8d528b7c Iustin Pop
      os.unlink(fin_name)
4614 8d528b7c Iustin Pop
4615 c26a6bd2 Iustin Pop
    return result.stdout
4616 8d528b7c Iustin Pop
4617 8d528b7c Iustin Pop
4618 3f78eef2 Iustin Pop
class DevCacheManager(object):
4619 c99a3cc0 Manuel Franceschini
  """Simple class for managing a cache of block device information.
4620 3f78eef2 Iustin Pop

4621 3f78eef2 Iustin Pop
  """
4622 3f78eef2 Iustin Pop
  _DEV_PREFIX = "/dev/"
4623 710f30ec Michael Hanselmann
  _ROOT_DIR = pathutils.BDEV_CACHE_DIR
4624 3f78eef2 Iustin Pop
4625 3f78eef2 Iustin Pop
  @classmethod
4626 3f78eef2 Iustin Pop
  def _ConvertPath(cls, dev_path):
4627 3f78eef2 Iustin Pop
    """Converts a /dev/name path to the cache file name.
4628 3f78eef2 Iustin Pop

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

4632 10c2650b Iustin Pop
    @type dev_path: str
4633 10c2650b Iustin Pop
    @param dev_path: the C{/dev/} path name
4634 10c2650b Iustin Pop
    @rtype: str
4635 10c2650b Iustin Pop
    @return: the converted path name
4636 3f78eef2 Iustin Pop

4637 3f78eef2 Iustin Pop
    """
4638 3f78eef2 Iustin Pop
    if dev_path.startswith(cls._DEV_PREFIX):
4639 3f78eef2 Iustin Pop
      dev_path = dev_path[len(cls._DEV_PREFIX):]
4640 3f78eef2 Iustin Pop
    dev_path = dev_path.replace("/", "_")
4641 0411c011 Iustin Pop
    fpath = utils.PathJoin(cls._ROOT_DIR, "bdev_%s" % dev_path)
4642 3f78eef2 Iustin Pop
    return fpath
4643 3f78eef2 Iustin Pop
4644 3f78eef2 Iustin Pop
  @classmethod
4645 3f78eef2 Iustin Pop
  def UpdateCache(cls, dev_path, owner, on_primary, iv_name):
4646 3f78eef2 Iustin Pop
    """Updates the cache information for a given device.
4647 3f78eef2 Iustin Pop

4648 10c2650b Iustin Pop
    @type dev_path: str
4649 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4650 10c2650b Iustin Pop
    @type owner: str
4651 10c2650b Iustin Pop
    @param owner: the owner (instance name) of the device
4652 10c2650b Iustin Pop
    @type on_primary: bool
4653 10c2650b Iustin Pop
    @param on_primary: whether this is the primary
4654 10c2650b Iustin Pop
        node nor not
4655 10c2650b Iustin Pop
    @type iv_name: str
4656 10c2650b Iustin Pop
    @param iv_name: the instance-visible name of the
4657 c41eea6e Iustin Pop
        device, as in objects.Disk.iv_name
4658 10c2650b Iustin Pop

4659 10c2650b Iustin Pop
    @rtype: None
4660 10c2650b Iustin Pop

4661 3f78eef2 Iustin Pop
    """
4662 cf5a8306 Iustin Pop
    if dev_path is None:
4663 18682bca Iustin Pop
      logging.error("DevCacheManager.UpdateCache got a None dev_path")
4664 cf5a8306 Iustin Pop
      return
4665 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4666 3f78eef2 Iustin Pop
    if on_primary:
4667 3f78eef2 Iustin Pop
      state = "primary"
4668 3f78eef2 Iustin Pop
    else:
4669 3f78eef2 Iustin Pop
      state = "secondary"
4670 3f78eef2 Iustin Pop
    if iv_name is None:
4671 3f78eef2 Iustin Pop
      iv_name = "not_visible"
4672 3f78eef2 Iustin Pop
    fdata = "%s %s %s\n" % (str(owner), state, iv_name)
4673 3f78eef2 Iustin Pop
    try:
4674 3f78eef2 Iustin Pop
      utils.WriteFile(fpath, data=fdata)
4675 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4676 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)
4677 3f78eef2 Iustin Pop
4678 3f78eef2 Iustin Pop
  @classmethod
4679 3f78eef2 Iustin Pop
  def RemoveCache(cls, dev_path):
4680 3f78eef2 Iustin Pop
    """Remove data for a dev_path.
4681 3f78eef2 Iustin Pop

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

4685 10c2650b Iustin Pop
    @type dev_path: str
4686 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4687 10c2650b Iustin Pop

4688 10c2650b Iustin Pop
    @rtype: None
4689 10c2650b Iustin Pop

4690 3f78eef2 Iustin Pop
    """
4691 cf5a8306 Iustin Pop
    if dev_path is None:
4692 18682bca Iustin Pop
      logging.error("DevCacheManager.RemoveCache got a None dev_path")
4693 cf5a8306 Iustin Pop
      return
4694 3f78eef2 Iustin Pop
    fpath = cls._ConvertPath(dev_path)
4695 3f78eef2 Iustin Pop
    try:
4696 3f78eef2 Iustin Pop
      utils.RemoveFile(fpath)
4697 3f78eef2 Iustin Pop
    except EnvironmentError, err:
4698 29921401 Iustin Pop
      logging.exception("Can't update bdev cache for %s: %s", dev_path, err)