Statistics
| Branch: | Tag: | Revision:

root / lib / backend.py @ 22114677

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1729 9332fd8a Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2325 10c2650b Iustin Pop
  @note: This is intended to be called recursively.
2326 10c2650b Iustin Pop

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

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

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

2373 10c2650b Iustin Pop
  @note: this function is called recursively.
2374 a8083063 Iustin Pop

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

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

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

2424 a8083063 Iustin Pop
  This is a wrapper over _RecursiveAssembleBD.
2425 a8083063 Iustin Pop

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

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

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

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

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

2467 a8083063 Iustin Pop
  """
2468 cacfd1fd Iustin Pop
  msgs = []
2469 a8083063 Iustin Pop
  r_dev = _RecursiveFindBD(disk)
2470 a8083063 Iustin Pop
  if r_dev is not None:
2471 3f78eef2 Iustin Pop
    r_path = r_dev.dev_path
2472 cacfd1fd Iustin Pop
    try:
2473 746f7476 Iustin Pop
      r_dev.Shutdown()
2474 746f7476 Iustin Pop
      DevCacheManager.RemoveCache(r_path)
2475 cacfd1fd Iustin Pop
    except errors.BlockDeviceError, err:
2476 cacfd1fd Iustin Pop
      msgs.append(str(err))
2477 746f7476 Iustin Pop
2478 a8083063 Iustin Pop
  if disk.children:
2479 a8083063 Iustin Pop
    for child in disk.children:
2480 c26a6bd2 Iustin Pop
      try:
2481 c26a6bd2 Iustin Pop
        BlockdevShutdown(child)
2482 c26a6bd2 Iustin Pop
      except RPCFail, err:
2483 c26a6bd2 Iustin Pop
        msgs.append(str(err))
2484 746f7476 Iustin Pop
2485 c26a6bd2 Iustin Pop
  if msgs:
2486 afdc3985 Iustin Pop
    _Fail("; ".join(msgs))
2487 a8083063 Iustin Pop
2488 a8083063 Iustin Pop
2489 821d1bd1 Iustin Pop
def BlockdevAddchildren(parent_cdev, new_cdevs):
2490 153d9724 Iustin Pop
  """Extend a mirrored block device.
2491 a8083063 Iustin Pop

2492 10c2650b Iustin Pop
  @type parent_cdev: L{objects.Disk}
2493 10c2650b Iustin Pop
  @param parent_cdev: the disk to which we should add children
2494 10c2650b Iustin Pop
  @type new_cdevs: list of L{objects.Disk}
2495 10c2650b Iustin Pop
  @param new_cdevs: the list of children which we should add
2496 c26a6bd2 Iustin Pop
  @rtype: None
2497 10c2650b Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2652 968a7623 Iustin Pop
  If a disk is not found, returns None instead.
2653 968a7623 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3218 c26a6bd2 Iustin Pop
  @rtype: None
3219 a8083063 Iustin Pop

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

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

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

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

3326 10c2650b Iustin Pop
  @rtype: list
3327 10c2650b Iustin Pop
  @return: list of the exports
3328 10c2650b Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3735 f942a838 Michael Hanselmann
  @type name: string
3736 f942a838 Michael Hanselmann
  @param name: Certificate name
3737 f942a838 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4661 10c2650b Iustin Pop
    @rtype: None
4662 10c2650b Iustin Pop

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

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

4687 10c2650b Iustin Pop
    @type dev_path: str
4688 10c2650b Iustin Pop
    @param dev_path: the pathname of the device
4689 10c2650b Iustin Pop

4690 10c2650b Iustin Pop
    @rtype: None
4691 10c2650b Iustin Pop

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