Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / common.py @ 4665b94f

History | View | Annotate | Download (36.4 kB)

1 1a732a74 Thomas Thrainer
#
2 1a732a74 Thomas Thrainer
#
3 1a732a74 Thomas Thrainer
4 1a732a74 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 1a732a74 Thomas Thrainer
#
6 1a732a74 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 1a732a74 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 1a732a74 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 1a732a74 Thomas Thrainer
# (at your option) any later version.
10 1a732a74 Thomas Thrainer
#
11 1a732a74 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 1a732a74 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 1a732a74 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 1a732a74 Thomas Thrainer
# General Public License for more details.
15 1a732a74 Thomas Thrainer
#
16 1a732a74 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 1a732a74 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 1a732a74 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 1a732a74 Thomas Thrainer
# 02110-1301, USA.
20 1a732a74 Thomas Thrainer
21 1a732a74 Thomas Thrainer
22 1a732a74 Thomas Thrainer
"""Common functions used by multiple logical units."""
23 f380d53c Thomas Thrainer
24 7352d33b Thomas Thrainer
import copy
25 7352d33b Thomas Thrainer
import os
26 1a732a74 Thomas Thrainer
27 f380d53c Thomas Thrainer
from ganeti import compat
28 7352d33b Thomas Thrainer
from ganeti import constants
29 1a732a74 Thomas Thrainer
from ganeti import errors
30 7352d33b Thomas Thrainer
from ganeti import hypervisor
31 fb3891d0 Thomas Thrainer
from ganeti import locking
32 7352d33b Thomas Thrainer
from ganeti import objects
33 f380d53c Thomas Thrainer
from ganeti import opcodes
34 7352d33b Thomas Thrainer
from ganeti import pathutils
35 7352d33b Thomas Thrainer
from ganeti import rpc
36 7352d33b Thomas Thrainer
from ganeti import ssconf
37 37dc17e3 Thomas Thrainer
from ganeti import utils
38 1a732a74 Thomas Thrainer
39 1a732a74 Thomas Thrainer
40 31b836b8 Thomas Thrainer
# States of instance
41 31b836b8 Thomas Thrainer
INSTANCE_DOWN = [constants.ADMINST_DOWN]
42 31b836b8 Thomas Thrainer
INSTANCE_ONLINE = [constants.ADMINST_DOWN, constants.ADMINST_UP]
43 31b836b8 Thomas Thrainer
INSTANCE_NOT_RUNNING = [constants.ADMINST_DOWN, constants.ADMINST_OFFLINE]
44 31b836b8 Thomas Thrainer
45 31b836b8 Thomas Thrainer
#: Instance status in which an instance can be marked as offline/online
46 31b836b8 Thomas Thrainer
CAN_CHANGE_INSTANCE_OFFLINE = (frozenset(INSTANCE_DOWN) | frozenset([
47 31b836b8 Thomas Thrainer
  constants.ADMINST_OFFLINE,
48 31b836b8 Thomas Thrainer
  ]))
49 31b836b8 Thomas Thrainer
50 31b836b8 Thomas Thrainer
51 1c3231aa Thomas Thrainer
def _ExpandItemName(expand_fn, name, kind):
52 1a732a74 Thomas Thrainer
  """Expand an item name.
53 1a732a74 Thomas Thrainer

54 1c3231aa Thomas Thrainer
  @param expand_fn: the function to use for expansion
55 1a732a74 Thomas Thrainer
  @param name: requested item name
56 1a732a74 Thomas Thrainer
  @param kind: text description ('Node' or 'Instance')
57 1c3231aa Thomas Thrainer
  @return: the result of the expand_fn, if successful
58 1a732a74 Thomas Thrainer
  @raise errors.OpPrereqError: if the item is not found
59 1a732a74 Thomas Thrainer

60 1a732a74 Thomas Thrainer
  """
61 1c3231aa Thomas Thrainer
  full_name = expand_fn(name)
62 1a732a74 Thomas Thrainer
  if full_name is None:
63 1a732a74 Thomas Thrainer
    raise errors.OpPrereqError("%s '%s' not known" % (kind, name),
64 1a732a74 Thomas Thrainer
                               errors.ECODE_NOENT)
65 1a732a74 Thomas Thrainer
  return full_name
66 1a732a74 Thomas Thrainer
67 1a732a74 Thomas Thrainer
68 5eacbcae Thomas Thrainer
def ExpandInstanceName(cfg, name):
69 1a732a74 Thomas Thrainer
  """Wrapper over L{_ExpandItemName} for instance."""
70 1a732a74 Thomas Thrainer
  return _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
71 1a732a74 Thomas Thrainer
72 1a732a74 Thomas Thrainer
73 1c3231aa Thomas Thrainer
def ExpandNodeUuidAndName(cfg, expected_uuid, name):
74 1c3231aa Thomas Thrainer
  """Expand a short node name into the node UUID and full name.
75 1c3231aa Thomas Thrainer

76 1c3231aa Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
77 1c3231aa Thomas Thrainer
  @param cfg: The cluster configuration
78 1c3231aa Thomas Thrainer
  @type expected_uuid: string
79 1c3231aa Thomas Thrainer
  @param expected_uuid: expected UUID for the node (or None if there is no
80 1c3231aa Thomas Thrainer
        expectation). If it does not match, a L{errors.OpPrereqError} is
81 1c3231aa Thomas Thrainer
        raised.
82 1c3231aa Thomas Thrainer
  @type name: string
83 1c3231aa Thomas Thrainer
  @param name: the short node name
84 1c3231aa Thomas Thrainer

85 1c3231aa Thomas Thrainer
  """
86 1c3231aa Thomas Thrainer
  (uuid, full_name) = _ExpandItemName(cfg.ExpandNodeName, name, "Node")
87 1c3231aa Thomas Thrainer
  if expected_uuid is not None and uuid != expected_uuid:
88 1c3231aa Thomas Thrainer
    raise errors.OpPrereqError(
89 1c3231aa Thomas Thrainer
      "The nodes UUID '%s' does not match the expected UUID '%s' for node"
90 1c3231aa Thomas Thrainer
      " '%s'. Maybe the node changed since you submitted this job." %
91 1c3231aa Thomas Thrainer
      (uuid, expected_uuid, full_name), errors.ECODE_NOTUNIQUE)
92 1c3231aa Thomas Thrainer
  return (uuid, full_name)
93 fb3891d0 Thomas Thrainer
94 fb3891d0 Thomas Thrainer
95 5eacbcae Thomas Thrainer
def ShareAll():
96 fb3891d0 Thomas Thrainer
  """Returns a dict declaring all lock levels shared.
97 fb3891d0 Thomas Thrainer

98 fb3891d0 Thomas Thrainer
  """
99 fb3891d0 Thomas Thrainer
  return dict.fromkeys(locking.LEVELS, 1)
100 37dc17e3 Thomas Thrainer
101 37dc17e3 Thomas Thrainer
102 5eacbcae Thomas Thrainer
def CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
103 37dc17e3 Thomas Thrainer
  """Checks if the instances in a node group are still correct.
104 37dc17e3 Thomas Thrainer

105 37dc17e3 Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
106 37dc17e3 Thomas Thrainer
  @param cfg: The cluster configuration
107 37dc17e3 Thomas Thrainer
  @type group_uuid: string
108 37dc17e3 Thomas Thrainer
  @param group_uuid: Node group UUID
109 37dc17e3 Thomas Thrainer
  @type owned_instances: set or frozenset
110 37dc17e3 Thomas Thrainer
  @param owned_instances: List of currently owned instances
111 37dc17e3 Thomas Thrainer

112 37dc17e3 Thomas Thrainer
  """
113 37dc17e3 Thomas Thrainer
  wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
114 37dc17e3 Thomas Thrainer
  if owned_instances != wanted_instances:
115 37dc17e3 Thomas Thrainer
    raise errors.OpPrereqError("Instances in node group '%s' changed since"
116 37dc17e3 Thomas Thrainer
                               " locks were acquired, wanted '%s', have '%s';"
117 37dc17e3 Thomas Thrainer
                               " retry the operation" %
118 37dc17e3 Thomas Thrainer
                               (group_uuid,
119 37dc17e3 Thomas Thrainer
                                utils.CommaJoin(wanted_instances),
120 37dc17e3 Thomas Thrainer
                                utils.CommaJoin(owned_instances)),
121 37dc17e3 Thomas Thrainer
                               errors.ECODE_STATE)
122 37dc17e3 Thomas Thrainer
123 37dc17e3 Thomas Thrainer
  return wanted_instances
124 1d870e0d Thomas Thrainer
125 1d870e0d Thomas Thrainer
126 1c3231aa Thomas Thrainer
def GetWantedNodes(lu, short_node_names):
127 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded node names.
128 1d870e0d Thomas Thrainer

129 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
130 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
131 1c3231aa Thomas Thrainer
  @type short_node_names: list
132 1c3231aa Thomas Thrainer
  @param short_node_names: list of node names or None for all nodes
133 1c3231aa Thomas Thrainer
  @rtype: tuple of lists
134 1c3231aa Thomas Thrainer
  @return: tupe with (list of node UUIDs, list of node names)
135 1d870e0d Thomas Thrainer
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
136 1d870e0d Thomas Thrainer

137 1d870e0d Thomas Thrainer
  """
138 1c3231aa Thomas Thrainer
  if short_node_names:
139 1c3231aa Thomas Thrainer
    node_uuids = [ExpandNodeUuidAndName(lu.cfg, None, name)[0]
140 1c3231aa Thomas Thrainer
                  for name in short_node_names]
141 1c3231aa Thomas Thrainer
  else:
142 1c3231aa Thomas Thrainer
    node_uuids = lu.cfg.GetNodeList()
143 1d870e0d Thomas Thrainer
144 1c3231aa Thomas Thrainer
  return (node_uuids, [lu.cfg.GetNodeInfo(uuid).name for uuid in node_uuids])
145 1d870e0d Thomas Thrainer
146 1d870e0d Thomas Thrainer
147 5eacbcae Thomas Thrainer
def GetWantedInstances(lu, instances):
148 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded instance names.
149 1d870e0d Thomas Thrainer

150 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
151 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
152 1d870e0d Thomas Thrainer
  @type instances: list
153 1d870e0d Thomas Thrainer
  @param instances: list of instance names or None for all instances
154 1d870e0d Thomas Thrainer
  @rtype: list
155 1d870e0d Thomas Thrainer
  @return: the list of instances, sorted
156 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if the instances parameter is wrong type
157 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if any of the passed instances is not found
158 1d870e0d Thomas Thrainer

159 1d870e0d Thomas Thrainer
  """
160 1d870e0d Thomas Thrainer
  if instances:
161 5eacbcae Thomas Thrainer
    wanted = [ExpandInstanceName(lu.cfg, name) for name in instances]
162 1d870e0d Thomas Thrainer
  else:
163 1d870e0d Thomas Thrainer
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
164 1d870e0d Thomas Thrainer
  return wanted
165 7352d33b Thomas Thrainer
166 7352d33b Thomas Thrainer
167 5eacbcae Thomas Thrainer
def RunPostHook(lu, node_name):
168 7352d33b Thomas Thrainer
  """Runs the post-hook for an opcode on a single node.
169 7352d33b Thomas Thrainer

170 7352d33b Thomas Thrainer
  """
171 7352d33b Thomas Thrainer
  hm = lu.proc.BuildHooksManager(lu)
172 7352d33b Thomas Thrainer
  try:
173 d0d7d7cf Thomas Thrainer
    hm.RunPhase(constants.HOOKS_PHASE_POST, node_names=[node_name])
174 7352d33b Thomas Thrainer
  except Exception, err: # pylint: disable=W0703
175 7352d33b Thomas Thrainer
    lu.LogWarning("Errors occurred running hooks on %s: %s",
176 7352d33b Thomas Thrainer
                  node_name, err)
177 7352d33b Thomas Thrainer
178 7352d33b Thomas Thrainer
179 1c3231aa Thomas Thrainer
def RedistributeAncillaryFiles(lu):
180 7352d33b Thomas Thrainer
  """Distribute additional files which are part of the cluster configuration.
181 7352d33b Thomas Thrainer

182 7352d33b Thomas Thrainer
  ConfigWriter takes care of distributing the config and ssconf files, but
183 7352d33b Thomas Thrainer
  there are more files which should be distributed to all nodes. This function
184 7352d33b Thomas Thrainer
  makes sure those are copied.
185 7352d33b Thomas Thrainer

186 7352d33b Thomas Thrainer
  """
187 7352d33b Thomas Thrainer
  # Gather target nodes
188 7352d33b Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
189 7352d33b Thomas Thrainer
  master_info = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
190 7352d33b Thomas Thrainer
191 1c3231aa Thomas Thrainer
  online_node_uuids = lu.cfg.GetOnlineNodeList()
192 1c3231aa Thomas Thrainer
  online_node_uuid_set = frozenset(online_node_uuids)
193 1c3231aa Thomas Thrainer
  vm_node_uuids = list(online_node_uuid_set.intersection(
194 1c3231aa Thomas Thrainer
                         lu.cfg.GetVmCapableNodeList()))
195 7352d33b Thomas Thrainer
196 7352d33b Thomas Thrainer
  # Never distribute to master node
197 1c3231aa Thomas Thrainer
  for node_uuids in [online_node_uuids, vm_node_uuids]:
198 1c3231aa Thomas Thrainer
    if master_info.uuid in node_uuids:
199 1c3231aa Thomas Thrainer
      node_uuids.remove(master_info.uuid)
200 7352d33b Thomas Thrainer
201 7352d33b Thomas Thrainer
  # Gather file lists
202 7352d33b Thomas Thrainer
  (files_all, _, files_mc, files_vm) = \
203 5eacbcae Thomas Thrainer
    ComputeAncillaryFiles(cluster, True)
204 7352d33b Thomas Thrainer
205 7352d33b Thomas Thrainer
  # Never re-distribute configuration file from here
206 7352d33b Thomas Thrainer
  assert not (pathutils.CLUSTER_CONF_FILE in files_all or
207 7352d33b Thomas Thrainer
              pathutils.CLUSTER_CONF_FILE in files_vm)
208 7352d33b Thomas Thrainer
  assert not files_mc, "Master candidates not handled in this function"
209 7352d33b Thomas Thrainer
210 7352d33b Thomas Thrainer
  filemap = [
211 1c3231aa Thomas Thrainer
    (online_node_uuids, files_all),
212 1c3231aa Thomas Thrainer
    (vm_node_uuids, files_vm),
213 7352d33b Thomas Thrainer
    ]
214 7352d33b Thomas Thrainer
215 7352d33b Thomas Thrainer
  # Upload the files
216 1c3231aa Thomas Thrainer
  for (node_uuids, files) in filemap:
217 7352d33b Thomas Thrainer
    for fname in files:
218 1c3231aa Thomas Thrainer
      UploadHelper(lu, node_uuids, fname)
219 7352d33b Thomas Thrainer
220 7352d33b Thomas Thrainer
221 5eacbcae Thomas Thrainer
def ComputeAncillaryFiles(cluster, redist):
222 7352d33b Thomas Thrainer
  """Compute files external to Ganeti which need to be consistent.
223 7352d33b Thomas Thrainer

224 7352d33b Thomas Thrainer
  @type redist: boolean
225 7352d33b Thomas Thrainer
  @param redist: Whether to include files which need to be redistributed
226 7352d33b Thomas Thrainer

227 7352d33b Thomas Thrainer
  """
228 7352d33b Thomas Thrainer
  # Compute files for all nodes
229 7352d33b Thomas Thrainer
  files_all = set([
230 7352d33b Thomas Thrainer
    pathutils.SSH_KNOWN_HOSTS_FILE,
231 7352d33b Thomas Thrainer
    pathutils.CONFD_HMAC_KEY,
232 7352d33b Thomas Thrainer
    pathutils.CLUSTER_DOMAIN_SECRET_FILE,
233 7352d33b Thomas Thrainer
    pathutils.SPICE_CERT_FILE,
234 7352d33b Thomas Thrainer
    pathutils.SPICE_CACERT_FILE,
235 7352d33b Thomas Thrainer
    pathutils.RAPI_USERS_FILE,
236 7352d33b Thomas Thrainer
    ])
237 7352d33b Thomas Thrainer
238 7352d33b Thomas Thrainer
  if redist:
239 7352d33b Thomas Thrainer
    # we need to ship at least the RAPI certificate
240 7352d33b Thomas Thrainer
    files_all.add(pathutils.RAPI_CERT_FILE)
241 7352d33b Thomas Thrainer
  else:
242 7352d33b Thomas Thrainer
    files_all.update(pathutils.ALL_CERT_FILES)
243 7352d33b Thomas Thrainer
    files_all.update(ssconf.SimpleStore().GetFileList())
244 7352d33b Thomas Thrainer
245 7352d33b Thomas Thrainer
  if cluster.modify_etc_hosts:
246 7352d33b Thomas Thrainer
    files_all.add(pathutils.ETC_HOSTS)
247 7352d33b Thomas Thrainer
248 7352d33b Thomas Thrainer
  if cluster.use_external_mip_script:
249 7352d33b Thomas Thrainer
    files_all.add(pathutils.EXTERNAL_MASTER_SETUP_SCRIPT)
250 7352d33b Thomas Thrainer
251 7352d33b Thomas Thrainer
  # Files which are optional, these must:
252 7352d33b Thomas Thrainer
  # - be present in one other category as well
253 7352d33b Thomas Thrainer
  # - either exist or not exist on all nodes of that category (mc, vm all)
254 7352d33b Thomas Thrainer
  files_opt = set([
255 7352d33b Thomas Thrainer
    pathutils.RAPI_USERS_FILE,
256 7352d33b Thomas Thrainer
    ])
257 7352d33b Thomas Thrainer
258 7352d33b Thomas Thrainer
  # Files which should only be on master candidates
259 7352d33b Thomas Thrainer
  files_mc = set()
260 7352d33b Thomas Thrainer
261 7352d33b Thomas Thrainer
  if not redist:
262 7352d33b Thomas Thrainer
    files_mc.add(pathutils.CLUSTER_CONF_FILE)
263 7352d33b Thomas Thrainer
264 7352d33b Thomas Thrainer
  # File storage
265 7352d33b Thomas Thrainer
  if (not redist and (constants.ENABLE_FILE_STORAGE or
266 7352d33b Thomas Thrainer
                        constants.ENABLE_SHARED_FILE_STORAGE)):
267 7352d33b Thomas Thrainer
    files_all.add(pathutils.FILE_STORAGE_PATHS_FILE)
268 7352d33b Thomas Thrainer
    files_opt.add(pathutils.FILE_STORAGE_PATHS_FILE)
269 7352d33b Thomas Thrainer
270 7352d33b Thomas Thrainer
  # Files which should only be on VM-capable nodes
271 7352d33b Thomas Thrainer
  files_vm = set(
272 7352d33b Thomas Thrainer
    filename
273 7352d33b Thomas Thrainer
    for hv_name in cluster.enabled_hypervisors
274 7352d33b Thomas Thrainer
    for filename in
275 7352d33b Thomas Thrainer
    hypervisor.GetHypervisorClass(hv_name).GetAncillaryFiles()[0])
276 7352d33b Thomas Thrainer
277 7352d33b Thomas Thrainer
  files_opt |= set(
278 7352d33b Thomas Thrainer
    filename
279 7352d33b Thomas Thrainer
    for hv_name in cluster.enabled_hypervisors
280 7352d33b Thomas Thrainer
    for filename in
281 7352d33b Thomas Thrainer
    hypervisor.GetHypervisorClass(hv_name).GetAncillaryFiles()[1])
282 7352d33b Thomas Thrainer
283 7352d33b Thomas Thrainer
  # Filenames in each category must be unique
284 7352d33b Thomas Thrainer
  all_files_set = files_all | files_mc | files_vm
285 7352d33b Thomas Thrainer
  assert (len(all_files_set) ==
286 7352d33b Thomas Thrainer
          sum(map(len, [files_all, files_mc, files_vm]))), \
287 7352d33b Thomas Thrainer
    "Found file listed in more than one file list"
288 7352d33b Thomas Thrainer
289 7352d33b Thomas Thrainer
  # Optional files must be present in one other category
290 7352d33b Thomas Thrainer
  assert all_files_set.issuperset(files_opt), \
291 7352d33b Thomas Thrainer
    "Optional file not in a different required list"
292 7352d33b Thomas Thrainer
293 7352d33b Thomas Thrainer
  # This one file should never ever be re-distributed via RPC
294 7352d33b Thomas Thrainer
  assert not (redist and
295 7352d33b Thomas Thrainer
              pathutils.FILE_STORAGE_PATHS_FILE in all_files_set)
296 7352d33b Thomas Thrainer
297 7352d33b Thomas Thrainer
  return (files_all, files_opt, files_mc, files_vm)
298 7352d33b Thomas Thrainer
299 7352d33b Thomas Thrainer
300 1c3231aa Thomas Thrainer
def UploadHelper(lu, node_uuids, fname):
301 7352d33b Thomas Thrainer
  """Helper for uploading a file and showing warnings.
302 7352d33b Thomas Thrainer

303 7352d33b Thomas Thrainer
  """
304 7352d33b Thomas Thrainer
  if os.path.exists(fname):
305 1c3231aa Thomas Thrainer
    result = lu.rpc.call_upload_file(node_uuids, fname)
306 1c3231aa Thomas Thrainer
    for to_node_uuids, to_result in result.items():
307 7352d33b Thomas Thrainer
      msg = to_result.fail_msg
308 7352d33b Thomas Thrainer
      if msg:
309 7352d33b Thomas Thrainer
        msg = ("Copy of file %s to node %s failed: %s" %
310 1c3231aa Thomas Thrainer
               (fname, lu.cfg.GetNodeName(to_node_uuids), msg))
311 7352d33b Thomas Thrainer
        lu.LogWarning(msg)
312 7352d33b Thomas Thrainer
313 7352d33b Thomas Thrainer
314 5eacbcae Thomas Thrainer
def MergeAndVerifyHvState(op_input, obj_input):
315 7352d33b Thomas Thrainer
  """Combines the hv state from an opcode with the one of the object
316 7352d33b Thomas Thrainer

317 7352d33b Thomas Thrainer
  @param op_input: The input dict from the opcode
318 7352d33b Thomas Thrainer
  @param obj_input: The input dict from the objects
319 7352d33b Thomas Thrainer
  @return: The verified and updated dict
320 7352d33b Thomas Thrainer

321 7352d33b Thomas Thrainer
  """
322 7352d33b Thomas Thrainer
  if op_input:
323 7352d33b Thomas Thrainer
    invalid_hvs = set(op_input) - constants.HYPER_TYPES
324 7352d33b Thomas Thrainer
    if invalid_hvs:
325 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid hypervisor(s) in hypervisor state:"
326 7352d33b Thomas Thrainer
                                 " %s" % utils.CommaJoin(invalid_hvs),
327 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
328 7352d33b Thomas Thrainer
    if obj_input is None:
329 7352d33b Thomas Thrainer
      obj_input = {}
330 7352d33b Thomas Thrainer
    type_check = constants.HVSTS_PARAMETER_TYPES
331 7352d33b Thomas Thrainer
    return _UpdateAndVerifySubDict(obj_input, op_input, type_check)
332 7352d33b Thomas Thrainer
333 7352d33b Thomas Thrainer
  return None
334 7352d33b Thomas Thrainer
335 7352d33b Thomas Thrainer
336 5eacbcae Thomas Thrainer
def MergeAndVerifyDiskState(op_input, obj_input):
337 7352d33b Thomas Thrainer
  """Combines the disk state from an opcode with the one of the object
338 7352d33b Thomas Thrainer

339 7352d33b Thomas Thrainer
  @param op_input: The input dict from the opcode
340 7352d33b Thomas Thrainer
  @param obj_input: The input dict from the objects
341 7352d33b Thomas Thrainer
  @return: The verified and updated dict
342 7352d33b Thomas Thrainer
  """
343 7352d33b Thomas Thrainer
  if op_input:
344 7352d33b Thomas Thrainer
    invalid_dst = set(op_input) - constants.DS_VALID_TYPES
345 7352d33b Thomas Thrainer
    if invalid_dst:
346 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid storage type(s) in disk state: %s" %
347 7352d33b Thomas Thrainer
                                 utils.CommaJoin(invalid_dst),
348 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
349 7352d33b Thomas Thrainer
    type_check = constants.DSS_PARAMETER_TYPES
350 7352d33b Thomas Thrainer
    if obj_input is None:
351 7352d33b Thomas Thrainer
      obj_input = {}
352 7352d33b Thomas Thrainer
    return dict((key, _UpdateAndVerifySubDict(obj_input.get(key, {}), value,
353 7352d33b Thomas Thrainer
                                              type_check))
354 7352d33b Thomas Thrainer
                for key, value in op_input.items())
355 7352d33b Thomas Thrainer
356 7352d33b Thomas Thrainer
  return None
357 7352d33b Thomas Thrainer
358 7352d33b Thomas Thrainer
359 1c3231aa Thomas Thrainer
def CheckOSParams(lu, required, node_uuids, osname, osparams):
360 7352d33b Thomas Thrainer
  """OS parameters validation.
361 7352d33b Thomas Thrainer

362 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
363 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
364 7352d33b Thomas Thrainer
  @type required: boolean
365 7352d33b Thomas Thrainer
  @param required: whether the validation should fail if the OS is not
366 7352d33b Thomas Thrainer
      found
367 1c3231aa Thomas Thrainer
  @type node_uuids: list
368 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
369 7352d33b Thomas Thrainer
  @type osname: string
370 7352d33b Thomas Thrainer
  @param osname: the name of the hypervisor we should use
371 7352d33b Thomas Thrainer
  @type osparams: dict
372 7352d33b Thomas Thrainer
  @param osparams: the parameters which we need to check
373 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
374 7352d33b Thomas Thrainer

375 7352d33b Thomas Thrainer
  """
376 1c3231aa Thomas Thrainer
  node_uuids = _FilterVmNodes(lu, node_uuids)
377 1c3231aa Thomas Thrainer
  result = lu.rpc.call_os_validate(node_uuids, required, osname,
378 7352d33b Thomas Thrainer
                                   [constants.OS_VALIDATE_PARAMETERS],
379 7352d33b Thomas Thrainer
                                   osparams)
380 1c3231aa Thomas Thrainer
  for node_uuid, nres in result.items():
381 7352d33b Thomas Thrainer
    # we don't check for offline cases since this should be run only
382 7352d33b Thomas Thrainer
    # against the master node and/or an instance's nodes
383 1c3231aa Thomas Thrainer
    nres.Raise("OS Parameters validation failed on node %s" %
384 1c3231aa Thomas Thrainer
               lu.cfg.GetNodeName(node_uuid))
385 7352d33b Thomas Thrainer
    if not nres.payload:
386 7352d33b Thomas Thrainer
      lu.LogInfo("OS %s not found on node %s, validation skipped",
387 1c3231aa Thomas Thrainer
                 osname, lu.cfg.GetNodeName(node_uuid))
388 7352d33b Thomas Thrainer
389 7352d33b Thomas Thrainer
390 1c3231aa Thomas Thrainer
def CheckHVParams(lu, node_uuids, hvname, hvparams):
391 7352d33b Thomas Thrainer
  """Hypervisor parameter validation.
392 7352d33b Thomas Thrainer

393 7352d33b Thomas Thrainer
  This function abstract the hypervisor parameter validation to be
394 7352d33b Thomas Thrainer
  used in both instance create and instance modify.
395 7352d33b Thomas Thrainer

396 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
397 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
398 1c3231aa Thomas Thrainer
  @type node_uuids: list
399 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
400 7352d33b Thomas Thrainer
  @type hvname: string
401 7352d33b Thomas Thrainer
  @param hvname: the name of the hypervisor we should use
402 7352d33b Thomas Thrainer
  @type hvparams: dict
403 7352d33b Thomas Thrainer
  @param hvparams: the parameters which we need to check
404 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
405 7352d33b Thomas Thrainer

406 7352d33b Thomas Thrainer
  """
407 1c3231aa Thomas Thrainer
  node_uuids = _FilterVmNodes(lu, node_uuids)
408 7352d33b Thomas Thrainer
409 7352d33b Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
410 7352d33b Thomas Thrainer
  hvfull = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
411 7352d33b Thomas Thrainer
412 1c3231aa Thomas Thrainer
  hvinfo = lu.rpc.call_hypervisor_validate_params(node_uuids, hvname, hvfull)
413 1c3231aa Thomas Thrainer
  for node_uuid in node_uuids:
414 1c3231aa Thomas Thrainer
    info = hvinfo[node_uuid]
415 7352d33b Thomas Thrainer
    if info.offline:
416 7352d33b Thomas Thrainer
      continue
417 1c3231aa Thomas Thrainer
    info.Raise("Hypervisor parameter validation failed on node %s" %
418 1c3231aa Thomas Thrainer
               lu.cfg.GetNodeName(node_uuid))
419 7352d33b Thomas Thrainer
420 7352d33b Thomas Thrainer
421 5eacbcae Thomas Thrainer
def AdjustCandidatePool(lu, exceptions):
422 7352d33b Thomas Thrainer
  """Adjust the candidate pool after node operations.
423 7352d33b Thomas Thrainer

424 7352d33b Thomas Thrainer
  """
425 7352d33b Thomas Thrainer
  mod_list = lu.cfg.MaintainCandidatePool(exceptions)
426 7352d33b Thomas Thrainer
  if mod_list:
427 7352d33b Thomas Thrainer
    lu.LogInfo("Promoted nodes to master candidate role: %s",
428 7352d33b Thomas Thrainer
               utils.CommaJoin(node.name for node in mod_list))
429 1c3231aa Thomas Thrainer
    for node in mod_list:
430 1c3231aa Thomas Thrainer
      lu.context.ReaddNode(node)
431 7352d33b Thomas Thrainer
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
432 7352d33b Thomas Thrainer
  if mc_now > mc_max:
433 7352d33b Thomas Thrainer
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
434 7352d33b Thomas Thrainer
               (mc_now, mc_max))
435 7352d33b Thomas Thrainer
436 7352d33b Thomas Thrainer
437 5eacbcae Thomas Thrainer
def CheckNodePVs(nresult, exclusive_storage):
438 7352d33b Thomas Thrainer
  """Check node PVs.
439 7352d33b Thomas Thrainer

440 7352d33b Thomas Thrainer
  """
441 7352d33b Thomas Thrainer
  pvlist_dict = nresult.get(constants.NV_PVLIST, None)
442 7352d33b Thomas Thrainer
  if pvlist_dict is None:
443 7352d33b Thomas Thrainer
    return (["Can't get PV list from node"], None)
444 7352d33b Thomas Thrainer
  pvlist = map(objects.LvmPvInfo.FromDict, pvlist_dict)
445 7352d33b Thomas Thrainer
  errlist = []
446 7352d33b Thomas Thrainer
  # check that ':' is not present in PV names, since it's a
447 7352d33b Thomas Thrainer
  # special character for lvcreate (denotes the range of PEs to
448 7352d33b Thomas Thrainer
  # use on the PV)
449 7352d33b Thomas Thrainer
  for pv in pvlist:
450 7352d33b Thomas Thrainer
    if ":" in pv.name:
451 7352d33b Thomas Thrainer
      errlist.append("Invalid character ':' in PV '%s' of VG '%s'" %
452 7352d33b Thomas Thrainer
                     (pv.name, pv.vg_name))
453 7352d33b Thomas Thrainer
  es_pvinfo = None
454 7352d33b Thomas Thrainer
  if exclusive_storage:
455 7352d33b Thomas Thrainer
    (errmsgs, es_pvinfo) = utils.LvmExclusiveCheckNodePvs(pvlist)
456 7352d33b Thomas Thrainer
    errlist.extend(errmsgs)
457 7352d33b Thomas Thrainer
    shared_pvs = nresult.get(constants.NV_EXCLUSIVEPVS, None)
458 7352d33b Thomas Thrainer
    if shared_pvs:
459 7352d33b Thomas Thrainer
      for (pvname, lvlist) in shared_pvs:
460 7352d33b Thomas Thrainer
        # TODO: Check that LVs are really unrelated (snapshots, DRBD meta...)
461 7352d33b Thomas Thrainer
        errlist.append("PV %s is shared among unrelated LVs (%s)" %
462 7352d33b Thomas Thrainer
                       (pvname, utils.CommaJoin(lvlist)))
463 7352d33b Thomas Thrainer
  return (errlist, es_pvinfo)
464 7352d33b Thomas Thrainer
465 7352d33b Thomas Thrainer
466 7352d33b Thomas Thrainer
def _ComputeMinMaxSpec(name, qualifier, ispecs, value):
467 7352d33b Thomas Thrainer
  """Computes if value is in the desired range.
468 7352d33b Thomas Thrainer

469 7352d33b Thomas Thrainer
  @param name: name of the parameter for which we perform the check
470 7352d33b Thomas Thrainer
  @param qualifier: a qualifier used in the error message (e.g. 'disk/1',
471 7352d33b Thomas Thrainer
      not just 'disk')
472 7352d33b Thomas Thrainer
  @param ispecs: dictionary containing min and max values
473 7352d33b Thomas Thrainer
  @param value: actual value that we want to use
474 7352d33b Thomas Thrainer
  @return: None or an error string
475 7352d33b Thomas Thrainer

476 7352d33b Thomas Thrainer
  """
477 7352d33b Thomas Thrainer
  if value in [None, constants.VALUE_AUTO]:
478 7352d33b Thomas Thrainer
    return None
479 7352d33b Thomas Thrainer
  max_v = ispecs[constants.ISPECS_MAX].get(name, value)
480 7352d33b Thomas Thrainer
  min_v = ispecs[constants.ISPECS_MIN].get(name, value)
481 7352d33b Thomas Thrainer
  if value > max_v or min_v > value:
482 7352d33b Thomas Thrainer
    if qualifier:
483 7352d33b Thomas Thrainer
      fqn = "%s/%s" % (name, qualifier)
484 7352d33b Thomas Thrainer
    else:
485 7352d33b Thomas Thrainer
      fqn = name
486 7352d33b Thomas Thrainer
    return ("%s value %s is not in range [%s, %s]" %
487 7352d33b Thomas Thrainer
            (fqn, value, min_v, max_v))
488 7352d33b Thomas Thrainer
  return None
489 7352d33b Thomas Thrainer
490 7352d33b Thomas Thrainer
491 5eacbcae Thomas Thrainer
def ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
492 5eacbcae Thomas Thrainer
                                nic_count, disk_sizes, spindle_use,
493 5eacbcae Thomas Thrainer
                                disk_template,
494 5eacbcae Thomas Thrainer
                                _compute_fn=_ComputeMinMaxSpec):
495 7352d33b Thomas Thrainer
  """Verifies ipolicy against provided specs.
496 7352d33b Thomas Thrainer

497 7352d33b Thomas Thrainer
  @type ipolicy: dict
498 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy
499 7352d33b Thomas Thrainer
  @type mem_size: int
500 7352d33b Thomas Thrainer
  @param mem_size: The memory size
501 7352d33b Thomas Thrainer
  @type cpu_count: int
502 7352d33b Thomas Thrainer
  @param cpu_count: Used cpu cores
503 7352d33b Thomas Thrainer
  @type disk_count: int
504 7352d33b Thomas Thrainer
  @param disk_count: Number of disks used
505 7352d33b Thomas Thrainer
  @type nic_count: int
506 7352d33b Thomas Thrainer
  @param nic_count: Number of nics used
507 7352d33b Thomas Thrainer
  @type disk_sizes: list of ints
508 7352d33b Thomas Thrainer
  @param disk_sizes: Disk sizes of used disk (len must match C{disk_count})
509 7352d33b Thomas Thrainer
  @type spindle_use: int
510 7352d33b Thomas Thrainer
  @param spindle_use: The number of spindles this instance uses
511 7352d33b Thomas Thrainer
  @type disk_template: string
512 7352d33b Thomas Thrainer
  @param disk_template: The disk template of the instance
513 7352d33b Thomas Thrainer
  @param _compute_fn: The compute function (unittest only)
514 7352d33b Thomas Thrainer
  @return: A list of violations, or an empty list of no violations are found
515 7352d33b Thomas Thrainer

516 7352d33b Thomas Thrainer
  """
517 7352d33b Thomas Thrainer
  assert disk_count == len(disk_sizes)
518 7352d33b Thomas Thrainer
519 7352d33b Thomas Thrainer
  test_settings = [
520 7352d33b Thomas Thrainer
    (constants.ISPEC_MEM_SIZE, "", mem_size),
521 7352d33b Thomas Thrainer
    (constants.ISPEC_CPU_COUNT, "", cpu_count),
522 7352d33b Thomas Thrainer
    (constants.ISPEC_NIC_COUNT, "", nic_count),
523 7352d33b Thomas Thrainer
    (constants.ISPEC_SPINDLE_USE, "", spindle_use),
524 7352d33b Thomas Thrainer
    ] + [(constants.ISPEC_DISK_SIZE, str(idx), d)
525 7352d33b Thomas Thrainer
         for idx, d in enumerate(disk_sizes)]
526 7352d33b Thomas Thrainer
  if disk_template != constants.DT_DISKLESS:
527 7352d33b Thomas Thrainer
    # This check doesn't make sense for diskless instances
528 7352d33b Thomas Thrainer
    test_settings.append((constants.ISPEC_DISK_COUNT, "", disk_count))
529 7352d33b Thomas Thrainer
  ret = []
530 7352d33b Thomas Thrainer
  allowed_dts = ipolicy[constants.IPOLICY_DTS]
531 7352d33b Thomas Thrainer
  if disk_template not in allowed_dts:
532 7352d33b Thomas Thrainer
    ret.append("Disk template %s is not allowed (allowed templates: %s)" %
533 7352d33b Thomas Thrainer
               (disk_template, utils.CommaJoin(allowed_dts)))
534 7352d33b Thomas Thrainer
535 7352d33b Thomas Thrainer
  min_errs = None
536 7352d33b Thomas Thrainer
  for minmax in ipolicy[constants.ISPECS_MINMAX]:
537 7352d33b Thomas Thrainer
    errs = filter(None,
538 7352d33b Thomas Thrainer
                  (_compute_fn(name, qualifier, minmax, value)
539 7352d33b Thomas Thrainer
                   for (name, qualifier, value) in test_settings))
540 7352d33b Thomas Thrainer
    if min_errs is None or len(errs) < len(min_errs):
541 7352d33b Thomas Thrainer
      min_errs = errs
542 7352d33b Thomas Thrainer
  assert min_errs is not None
543 7352d33b Thomas Thrainer
  return ret + min_errs
544 7352d33b Thomas Thrainer
545 7352d33b Thomas Thrainer
546 5eacbcae Thomas Thrainer
def ComputeIPolicyInstanceViolation(ipolicy, instance, cfg,
547 5eacbcae Thomas Thrainer
                                    _compute_fn=ComputeIPolicySpecViolation):
548 7352d33b Thomas Thrainer
  """Compute if instance meets the specs of ipolicy.
549 7352d33b Thomas Thrainer

550 7352d33b Thomas Thrainer
  @type ipolicy: dict
551 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify against
552 7352d33b Thomas Thrainer
  @type instance: L{objects.Instance}
553 7352d33b Thomas Thrainer
  @param instance: The instance to verify
554 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
555 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
556 7352d33b Thomas Thrainer
  @param _compute_fn: The function to verify ipolicy (unittest only)
557 5eacbcae Thomas Thrainer
  @see: L{ComputeIPolicySpecViolation}
558 7352d33b Thomas Thrainer

559 7352d33b Thomas Thrainer
  """
560 5a13489b Bernardo Dal Seno
  ret = []
561 7352d33b Thomas Thrainer
  be_full = cfg.GetClusterInfo().FillBE(instance)
562 7352d33b Thomas Thrainer
  mem_size = be_full[constants.BE_MAXMEM]
563 7352d33b Thomas Thrainer
  cpu_count = be_full[constants.BE_VCPUS]
564 1c3231aa Thomas Thrainer
  es_flags = rpc.GetExclusiveStorageForNodes(cfg, instance.all_nodes)
565 5a13489b Bernardo Dal Seno
  if any(es_flags.values()):
566 5a13489b Bernardo Dal Seno
    # With exclusive storage use the actual spindles
567 5a13489b Bernardo Dal Seno
    try:
568 5a13489b Bernardo Dal Seno
      spindle_use = sum([disk.spindles for disk in instance.disks])
569 5a13489b Bernardo Dal Seno
    except TypeError:
570 5a13489b Bernardo Dal Seno
      ret.append("Number of spindles not configured for disks of instance %s"
571 5a13489b Bernardo Dal Seno
                 " while exclusive storage is enabled, try running gnt-cluster"
572 5a13489b Bernardo Dal Seno
                 " repair-disk-sizes" % instance.name)
573 5a13489b Bernardo Dal Seno
      # _ComputeMinMaxSpec ignores 'None's
574 5a13489b Bernardo Dal Seno
      spindle_use = None
575 5a13489b Bernardo Dal Seno
  else:
576 5a13489b Bernardo Dal Seno
    spindle_use = be_full[constants.BE_SPINDLE_USE]
577 7352d33b Thomas Thrainer
  disk_count = len(instance.disks)
578 7352d33b Thomas Thrainer
  disk_sizes = [disk.size for disk in instance.disks]
579 7352d33b Thomas Thrainer
  nic_count = len(instance.nics)
580 7352d33b Thomas Thrainer
  disk_template = instance.disk_template
581 7352d33b Thomas Thrainer
582 5a13489b Bernardo Dal Seno
  return ret + _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
583 5a13489b Bernardo Dal Seno
                           disk_sizes, spindle_use, disk_template)
584 7352d33b Thomas Thrainer
585 7352d33b Thomas Thrainer
586 7352d33b Thomas Thrainer
def _ComputeViolatingInstances(ipolicy, instances, cfg):
587 7352d33b Thomas Thrainer
  """Computes a set of instances who violates given ipolicy.
588 7352d33b Thomas Thrainer

589 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify
590 7352d33b Thomas Thrainer
  @type instances: L{objects.Instance}
591 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
592 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
593 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
594 7352d33b Thomas Thrainer
  @return: A frozenset of instance names violating the ipolicy
595 7352d33b Thomas Thrainer

596 7352d33b Thomas Thrainer
  """
597 7352d33b Thomas Thrainer
  return frozenset([inst.name for inst in instances
598 5eacbcae Thomas Thrainer
                    if ComputeIPolicyInstanceViolation(ipolicy, inst, cfg)])
599 7352d33b Thomas Thrainer
600 7352d33b Thomas Thrainer
601 5eacbcae Thomas Thrainer
def ComputeNewInstanceViolations(old_ipolicy, new_ipolicy, instances, cfg):
602 7352d33b Thomas Thrainer
  """Computes a set of any instances that would violate the new ipolicy.
603 7352d33b Thomas Thrainer

604 7352d33b Thomas Thrainer
  @param old_ipolicy: The current (still in-place) ipolicy
605 7352d33b Thomas Thrainer
  @param new_ipolicy: The new (to become) ipolicy
606 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
607 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
608 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
609 7352d33b Thomas Thrainer
  @return: A list of instances which violates the new ipolicy but
610 7352d33b Thomas Thrainer
      did not before
611 7352d33b Thomas Thrainer

612 7352d33b Thomas Thrainer
  """
613 7352d33b Thomas Thrainer
  return (_ComputeViolatingInstances(new_ipolicy, instances, cfg) -
614 7352d33b Thomas Thrainer
          _ComputeViolatingInstances(old_ipolicy, instances, cfg))
615 7352d33b Thomas Thrainer
616 7352d33b Thomas Thrainer
617 5eacbcae Thomas Thrainer
def GetUpdatedParams(old_params, update_dict,
618 7352d33b Thomas Thrainer
                      use_default=True, use_none=False):
619 7352d33b Thomas Thrainer
  """Return the new version of a parameter dictionary.
620 7352d33b Thomas Thrainer

621 7352d33b Thomas Thrainer
  @type old_params: dict
622 7352d33b Thomas Thrainer
  @param old_params: old parameters
623 7352d33b Thomas Thrainer
  @type update_dict: dict
624 7352d33b Thomas Thrainer
  @param update_dict: dict containing new parameter values, or
625 7352d33b Thomas Thrainer
      constants.VALUE_DEFAULT to reset the parameter to its default
626 7352d33b Thomas Thrainer
      value
627 7352d33b Thomas Thrainer
  @param use_default: boolean
628 7352d33b Thomas Thrainer
  @type use_default: whether to recognise L{constants.VALUE_DEFAULT}
629 7352d33b Thomas Thrainer
      values as 'to be deleted' values
630 7352d33b Thomas Thrainer
  @param use_none: boolean
631 7352d33b Thomas Thrainer
  @type use_none: whether to recognise C{None} values as 'to be
632 7352d33b Thomas Thrainer
      deleted' values
633 7352d33b Thomas Thrainer
  @rtype: dict
634 7352d33b Thomas Thrainer
  @return: the new parameter dictionary
635 7352d33b Thomas Thrainer

636 7352d33b Thomas Thrainer
  """
637 7352d33b Thomas Thrainer
  params_copy = copy.deepcopy(old_params)
638 7352d33b Thomas Thrainer
  for key, val in update_dict.iteritems():
639 7352d33b Thomas Thrainer
    if ((use_default and val == constants.VALUE_DEFAULT) or
640 7352d33b Thomas Thrainer
          (use_none and val is None)):
641 7352d33b Thomas Thrainer
      try:
642 7352d33b Thomas Thrainer
        del params_copy[key]
643 7352d33b Thomas Thrainer
      except KeyError:
644 7352d33b Thomas Thrainer
        pass
645 7352d33b Thomas Thrainer
    else:
646 7352d33b Thomas Thrainer
      params_copy[key] = val
647 7352d33b Thomas Thrainer
  return params_copy
648 7352d33b Thomas Thrainer
649 7352d33b Thomas Thrainer
650 5eacbcae Thomas Thrainer
def GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
651 7352d33b Thomas Thrainer
  """Return the new version of an instance policy.
652 7352d33b Thomas Thrainer

653 7352d33b Thomas Thrainer
  @param group_policy: whether this policy applies to a group and thus
654 7352d33b Thomas Thrainer
    we should support removal of policy entries
655 7352d33b Thomas Thrainer

656 7352d33b Thomas Thrainer
  """
657 7352d33b Thomas Thrainer
  ipolicy = copy.deepcopy(old_ipolicy)
658 7352d33b Thomas Thrainer
  for key, value in new_ipolicy.items():
659 7352d33b Thomas Thrainer
    if key not in constants.IPOLICY_ALL_KEYS:
660 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid key in new ipolicy: %s" % key,
661 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
662 7352d33b Thomas Thrainer
    if (not value or value == [constants.VALUE_DEFAULT] or
663 7352d33b Thomas Thrainer
            value == constants.VALUE_DEFAULT):
664 7352d33b Thomas Thrainer
      if group_policy:
665 7352d33b Thomas Thrainer
        if key in ipolicy:
666 7352d33b Thomas Thrainer
          del ipolicy[key]
667 7352d33b Thomas Thrainer
      else:
668 7352d33b Thomas Thrainer
        raise errors.OpPrereqError("Can't unset ipolicy attribute '%s'"
669 7352d33b Thomas Thrainer
                                   " on the cluster'" % key,
670 7352d33b Thomas Thrainer
                                   errors.ECODE_INVAL)
671 7352d33b Thomas Thrainer
    else:
672 7352d33b Thomas Thrainer
      if key in constants.IPOLICY_PARAMETERS:
673 7352d33b Thomas Thrainer
        # FIXME: we assume all such values are float
674 7352d33b Thomas Thrainer
        try:
675 7352d33b Thomas Thrainer
          ipolicy[key] = float(value)
676 7352d33b Thomas Thrainer
        except (TypeError, ValueError), err:
677 7352d33b Thomas Thrainer
          raise errors.OpPrereqError("Invalid value for attribute"
678 7352d33b Thomas Thrainer
                                     " '%s': '%s', error: %s" %
679 7352d33b Thomas Thrainer
                                     (key, value, err), errors.ECODE_INVAL)
680 7352d33b Thomas Thrainer
      elif key == constants.ISPECS_MINMAX:
681 7352d33b Thomas Thrainer
        for minmax in value:
682 7352d33b Thomas Thrainer
          for k in minmax.keys():
683 7352d33b Thomas Thrainer
            utils.ForceDictType(minmax[k], constants.ISPECS_PARAMETER_TYPES)
684 7352d33b Thomas Thrainer
        ipolicy[key] = value
685 7352d33b Thomas Thrainer
      elif key == constants.ISPECS_STD:
686 7352d33b Thomas Thrainer
        if group_policy:
687 7352d33b Thomas Thrainer
          msg = "%s cannot appear in group instance specs" % key
688 7352d33b Thomas Thrainer
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
689 5eacbcae Thomas Thrainer
        ipolicy[key] = GetUpdatedParams(old_ipolicy.get(key, {}), value,
690 5eacbcae Thomas Thrainer
                                        use_none=False, use_default=False)
691 7352d33b Thomas Thrainer
        utils.ForceDictType(ipolicy[key], constants.ISPECS_PARAMETER_TYPES)
692 7352d33b Thomas Thrainer
      else:
693 7352d33b Thomas Thrainer
        # FIXME: we assume all others are lists; this should be redone
694 7352d33b Thomas Thrainer
        # in a nicer way
695 7352d33b Thomas Thrainer
        ipolicy[key] = list(value)
696 7352d33b Thomas Thrainer
  try:
697 7352d33b Thomas Thrainer
    objects.InstancePolicy.CheckParameterSyntax(ipolicy, not group_policy)
698 7352d33b Thomas Thrainer
  except errors.ConfigurationError, err:
699 7352d33b Thomas Thrainer
    raise errors.OpPrereqError("Invalid instance policy: %s" % err,
700 7352d33b Thomas Thrainer
                               errors.ECODE_INVAL)
701 7352d33b Thomas Thrainer
  return ipolicy
702 7352d33b Thomas Thrainer
703 7352d33b Thomas Thrainer
704 5eacbcae Thomas Thrainer
def AnnotateDiskParams(instance, devs, cfg):
705 7352d33b Thomas Thrainer
  """Little helper wrapper to the rpc annotation method.
706 7352d33b Thomas Thrainer

707 7352d33b Thomas Thrainer
  @param instance: The instance object
708 7352d33b Thomas Thrainer
  @type devs: List of L{objects.Disk}
709 7352d33b Thomas Thrainer
  @param devs: The root devices (not any of its children!)
710 7352d33b Thomas Thrainer
  @param cfg: The config object
711 7352d33b Thomas Thrainer
  @returns The annotated disk copies
712 7352d33b Thomas Thrainer
  @see L{rpc.AnnotateDiskParams}
713 7352d33b Thomas Thrainer

714 7352d33b Thomas Thrainer
  """
715 7352d33b Thomas Thrainer
  return rpc.AnnotateDiskParams(instance.disk_template, devs,
716 7352d33b Thomas Thrainer
                                cfg.GetInstanceDiskParams(instance))
717 7352d33b Thomas Thrainer
718 7352d33b Thomas Thrainer
719 5eacbcae Thomas Thrainer
def SupportsOob(cfg, node):
720 7352d33b Thomas Thrainer
  """Tells if node supports OOB.
721 7352d33b Thomas Thrainer

722 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
723 7352d33b Thomas Thrainer
  @param cfg: The cluster configuration
724 7352d33b Thomas Thrainer
  @type node: L{objects.Node}
725 7352d33b Thomas Thrainer
  @param node: The node
726 7352d33b Thomas Thrainer
  @return: The OOB script if supported or an empty string otherwise
727 7352d33b Thomas Thrainer

728 7352d33b Thomas Thrainer
  """
729 7352d33b Thomas Thrainer
  return cfg.GetNdParams(node)[constants.ND_OOB_PROGRAM]
730 7352d33b Thomas Thrainer
731 7352d33b Thomas Thrainer
732 7352d33b Thomas Thrainer
def _UpdateAndVerifySubDict(base, updates, type_check):
733 7352d33b Thomas Thrainer
  """Updates and verifies a dict with sub dicts of the same type.
734 7352d33b Thomas Thrainer

735 7352d33b Thomas Thrainer
  @param base: The dict with the old data
736 7352d33b Thomas Thrainer
  @param updates: The dict with the new data
737 7352d33b Thomas Thrainer
  @param type_check: Dict suitable to ForceDictType to verify correct types
738 7352d33b Thomas Thrainer
  @returns: A new dict with updated and verified values
739 7352d33b Thomas Thrainer

740 7352d33b Thomas Thrainer
  """
741 7352d33b Thomas Thrainer
  def fn(old, value):
742 5eacbcae Thomas Thrainer
    new = GetUpdatedParams(old, value)
743 7352d33b Thomas Thrainer
    utils.ForceDictType(new, type_check)
744 7352d33b Thomas Thrainer
    return new
745 7352d33b Thomas Thrainer
746 7352d33b Thomas Thrainer
  ret = copy.deepcopy(base)
747 7352d33b Thomas Thrainer
  ret.update(dict((key, fn(base.get(key, {}), value))
748 7352d33b Thomas Thrainer
                  for key, value in updates.items()))
749 7352d33b Thomas Thrainer
  return ret
750 7352d33b Thomas Thrainer
751 7352d33b Thomas Thrainer
752 1c3231aa Thomas Thrainer
def _FilterVmNodes(lu, node_uuids):
753 7352d33b Thomas Thrainer
  """Filters out non-vm_capable nodes from a list.
754 7352d33b Thomas Thrainer

755 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
756 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
757 1c3231aa Thomas Thrainer
  @type node_uuids: list
758 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
759 7352d33b Thomas Thrainer
  @rtype: list
760 7352d33b Thomas Thrainer
  @return: the list of vm-capable nodes
761 7352d33b Thomas Thrainer

762 7352d33b Thomas Thrainer
  """
763 7352d33b Thomas Thrainer
  vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList())
764 1c3231aa Thomas Thrainer
  return [uuid for uuid in node_uuids if uuid not in vm_nodes]
765 f380d53c Thomas Thrainer
766 f380d53c Thomas Thrainer
767 5eacbcae Thomas Thrainer
def GetDefaultIAllocator(cfg, ialloc):
768 f380d53c Thomas Thrainer
  """Decides on which iallocator to use.
769 f380d53c Thomas Thrainer

770 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
771 f380d53c Thomas Thrainer
  @param cfg: Cluster configuration object
772 f380d53c Thomas Thrainer
  @type ialloc: string or None
773 f380d53c Thomas Thrainer
  @param ialloc: Iallocator specified in opcode
774 f380d53c Thomas Thrainer
  @rtype: string
775 f380d53c Thomas Thrainer
  @return: Iallocator name
776 f380d53c Thomas Thrainer

777 f380d53c Thomas Thrainer
  """
778 f380d53c Thomas Thrainer
  if not ialloc:
779 f380d53c Thomas Thrainer
    # Use default iallocator
780 f380d53c Thomas Thrainer
    ialloc = cfg.GetDefaultIAllocator()
781 f380d53c Thomas Thrainer
782 f380d53c Thomas Thrainer
  if not ialloc:
783 f380d53c Thomas Thrainer
    raise errors.OpPrereqError("No iallocator was specified, neither in the"
784 f380d53c Thomas Thrainer
                               " opcode nor as a cluster-wide default",
785 f380d53c Thomas Thrainer
                               errors.ECODE_INVAL)
786 f380d53c Thomas Thrainer
787 f380d53c Thomas Thrainer
  return ialloc
788 f380d53c Thomas Thrainer
789 f380d53c Thomas Thrainer
790 1c3231aa Thomas Thrainer
def CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_node_uuids,
791 5eacbcae Thomas Thrainer
                             cur_group_uuid):
792 f380d53c Thomas Thrainer
  """Checks if node groups for locked instances are still correct.
793 f380d53c Thomas Thrainer

794 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
795 f380d53c Thomas Thrainer
  @param cfg: Cluster configuration
796 f380d53c Thomas Thrainer
  @type instances: dict; string as key, L{objects.Instance} as value
797 f380d53c Thomas Thrainer
  @param instances: Dictionary, instance name as key, instance object as value
798 f380d53c Thomas Thrainer
  @type owned_groups: iterable of string
799 f380d53c Thomas Thrainer
  @param owned_groups: List of owned groups
800 1c3231aa Thomas Thrainer
  @type owned_node_uuids: iterable of string
801 1c3231aa Thomas Thrainer
  @param owned_node_uuids: List of owned nodes
802 f380d53c Thomas Thrainer
  @type cur_group_uuid: string or None
803 f380d53c Thomas Thrainer
  @param cur_group_uuid: Optional group UUID to check against instance's groups
804 f380d53c Thomas Thrainer

805 f380d53c Thomas Thrainer
  """
806 f380d53c Thomas Thrainer
  for (name, inst) in instances.items():
807 1c3231aa Thomas Thrainer
    assert owned_node_uuids.issuperset(inst.all_nodes), \
808 f380d53c Thomas Thrainer
      "Instance %s's nodes changed while we kept the lock" % name
809 f380d53c Thomas Thrainer
810 5eacbcae Thomas Thrainer
    inst_groups = CheckInstanceNodeGroups(cfg, name, owned_groups)
811 f380d53c Thomas Thrainer
812 f380d53c Thomas Thrainer
    assert cur_group_uuid is None or cur_group_uuid in inst_groups, \
813 f380d53c Thomas Thrainer
      "Instance %s has no node in group %s" % (name, cur_group_uuid)
814 f380d53c Thomas Thrainer
815 f380d53c Thomas Thrainer
816 5eacbcae Thomas Thrainer
def CheckInstanceNodeGroups(cfg, instance_name, owned_groups,
817 5eacbcae Thomas Thrainer
                            primary_only=False):
818 f380d53c Thomas Thrainer
  """Checks if the owned node groups are still correct for an instance.
819 f380d53c Thomas Thrainer

820 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
821 f380d53c Thomas Thrainer
  @param cfg: The cluster configuration
822 f380d53c Thomas Thrainer
  @type instance_name: string
823 f380d53c Thomas Thrainer
  @param instance_name: Instance name
824 f380d53c Thomas Thrainer
  @type owned_groups: set or frozenset
825 f380d53c Thomas Thrainer
  @param owned_groups: List of currently owned node groups
826 f380d53c Thomas Thrainer
  @type primary_only: boolean
827 f380d53c Thomas Thrainer
  @param primary_only: Whether to check node groups for only the primary node
828 f380d53c Thomas Thrainer

829 f380d53c Thomas Thrainer
  """
830 f380d53c Thomas Thrainer
  inst_groups = cfg.GetInstanceNodeGroups(instance_name, primary_only)
831 f380d53c Thomas Thrainer
832 f380d53c Thomas Thrainer
  if not owned_groups.issuperset(inst_groups):
833 f380d53c Thomas Thrainer
    raise errors.OpPrereqError("Instance %s's node groups changed since"
834 f380d53c Thomas Thrainer
                               " locks were acquired, current groups are"
835 f380d53c Thomas Thrainer
                               " are '%s', owning groups '%s'; retry the"
836 f380d53c Thomas Thrainer
                               " operation" %
837 f380d53c Thomas Thrainer
                               (instance_name,
838 f380d53c Thomas Thrainer
                                utils.CommaJoin(inst_groups),
839 f380d53c Thomas Thrainer
                                utils.CommaJoin(owned_groups)),
840 f380d53c Thomas Thrainer
                               errors.ECODE_STATE)
841 f380d53c Thomas Thrainer
842 f380d53c Thomas Thrainer
  return inst_groups
843 f380d53c Thomas Thrainer
844 f380d53c Thomas Thrainer
845 5eacbcae Thomas Thrainer
def LoadNodeEvacResult(lu, alloc_result, early_release, use_nodes):
846 f380d53c Thomas Thrainer
  """Unpacks the result of change-group and node-evacuate iallocator requests.
847 f380d53c Thomas Thrainer

848 f380d53c Thomas Thrainer
  Iallocator modes L{constants.IALLOCATOR_MODE_NODE_EVAC} and
849 f380d53c Thomas Thrainer
  L{constants.IALLOCATOR_MODE_CHG_GROUP}.
850 f380d53c Thomas Thrainer

851 f380d53c Thomas Thrainer
  @type lu: L{LogicalUnit}
852 f380d53c Thomas Thrainer
  @param lu: Logical unit instance
853 f380d53c Thomas Thrainer
  @type alloc_result: tuple/list
854 f380d53c Thomas Thrainer
  @param alloc_result: Result from iallocator
855 f380d53c Thomas Thrainer
  @type early_release: bool
856 f380d53c Thomas Thrainer
  @param early_release: Whether to release locks early if possible
857 f380d53c Thomas Thrainer
  @type use_nodes: bool
858 f380d53c Thomas Thrainer
  @param use_nodes: Whether to display node names instead of groups
859 f380d53c Thomas Thrainer

860 f380d53c Thomas Thrainer
  """
861 f380d53c Thomas Thrainer
  (moved, failed, jobs) = alloc_result
862 f380d53c Thomas Thrainer
863 f380d53c Thomas Thrainer
  if failed:
864 f380d53c Thomas Thrainer
    failreason = utils.CommaJoin("%s (%s)" % (name, reason)
865 f380d53c Thomas Thrainer
                                 for (name, reason) in failed)
866 f380d53c Thomas Thrainer
    lu.LogWarning("Unable to evacuate instances %s", failreason)
867 f380d53c Thomas Thrainer
    raise errors.OpExecError("Unable to evacuate instances %s" % failreason)
868 f380d53c Thomas Thrainer
869 f380d53c Thomas Thrainer
  if moved:
870 f380d53c Thomas Thrainer
    lu.LogInfo("Instances to be moved: %s",
871 1c3231aa Thomas Thrainer
               utils.CommaJoin(
872 1c3231aa Thomas Thrainer
                 "%s (to %s)" %
873 1c3231aa Thomas Thrainer
                 (name, _NodeEvacDest(use_nodes, group, node_names))
874 1c3231aa Thomas Thrainer
                 for (name, group, node_names) in moved))
875 f380d53c Thomas Thrainer
876 f380d53c Thomas Thrainer
  return [map(compat.partial(_SetOpEarlyRelease, early_release),
877 f380d53c Thomas Thrainer
              map(opcodes.OpCode.LoadOpCode, ops))
878 f380d53c Thomas Thrainer
          for ops in jobs]
879 f380d53c Thomas Thrainer
880 f380d53c Thomas Thrainer
881 1c3231aa Thomas Thrainer
def _NodeEvacDest(use_nodes, group, node_names):
882 f380d53c Thomas Thrainer
  """Returns group or nodes depending on caller's choice.
883 f380d53c Thomas Thrainer

884 f380d53c Thomas Thrainer
  """
885 f380d53c Thomas Thrainer
  if use_nodes:
886 1c3231aa Thomas Thrainer
    return utils.CommaJoin(node_names)
887 f380d53c Thomas Thrainer
  else:
888 f380d53c Thomas Thrainer
    return group
889 f380d53c Thomas Thrainer
890 f380d53c Thomas Thrainer
891 f380d53c Thomas Thrainer
def _SetOpEarlyRelease(early_release, op):
892 f380d53c Thomas Thrainer
  """Sets C{early_release} flag on opcodes if available.
893 f380d53c Thomas Thrainer

894 f380d53c Thomas Thrainer
  """
895 f380d53c Thomas Thrainer
  try:
896 f380d53c Thomas Thrainer
    op.early_release = early_release
897 f380d53c Thomas Thrainer
  except AttributeError:
898 f380d53c Thomas Thrainer
    assert not isinstance(op, opcodes.OpInstanceReplaceDisks)
899 f380d53c Thomas Thrainer
900 f380d53c Thomas Thrainer
  return op
901 f380d53c Thomas Thrainer
902 f380d53c Thomas Thrainer
903 5eacbcae Thomas Thrainer
def MapInstanceDisksToNodes(instances):
904 f380d53c Thomas Thrainer
  """Creates a map from (node, volume) to instance name.
905 f380d53c Thomas Thrainer

906 f380d53c Thomas Thrainer
  @type instances: list of L{objects.Instance}
907 1c3231aa Thomas Thrainer
  @rtype: dict; tuple of (node uuid, volume name) as key, instance name as value
908 f380d53c Thomas Thrainer

909 f380d53c Thomas Thrainer
  """
910 1c3231aa Thomas Thrainer
  return dict(((node_uuid, vol), inst.name)
911 f380d53c Thomas Thrainer
              for inst in instances
912 1c3231aa Thomas Thrainer
              for (node_uuid, vols) in inst.MapLVsByNode().items()
913 f380d53c Thomas Thrainer
              for vol in vols)
914 31b836b8 Thomas Thrainer
915 31b836b8 Thomas Thrainer
916 5eacbcae Thomas Thrainer
def CheckParamsNotGlobal(params, glob_pars, kind, bad_levels, good_levels):
917 31b836b8 Thomas Thrainer
  """Make sure that none of the given paramters is global.
918 31b836b8 Thomas Thrainer

919 31b836b8 Thomas Thrainer
  If a global parameter is found, an L{errors.OpPrereqError} exception is
920 31b836b8 Thomas Thrainer
  raised. This is used to avoid setting global parameters for individual nodes.
921 31b836b8 Thomas Thrainer

922 31b836b8 Thomas Thrainer
  @type params: dictionary
923 31b836b8 Thomas Thrainer
  @param params: Parameters to check
924 31b836b8 Thomas Thrainer
  @type glob_pars: dictionary
925 31b836b8 Thomas Thrainer
  @param glob_pars: Forbidden parameters
926 31b836b8 Thomas Thrainer
  @type kind: string
927 31b836b8 Thomas Thrainer
  @param kind: Kind of parameters (e.g. "node")
928 31b836b8 Thomas Thrainer
  @type bad_levels: string
929 31b836b8 Thomas Thrainer
  @param bad_levels: Level(s) at which the parameters are forbidden (e.g.
930 31b836b8 Thomas Thrainer
      "instance")
931 31b836b8 Thomas Thrainer
  @type good_levels: strings
932 31b836b8 Thomas Thrainer
  @param good_levels: Level(s) at which the parameters are allowed (e.g.
933 31b836b8 Thomas Thrainer
      "cluster or group")
934 31b836b8 Thomas Thrainer

935 31b836b8 Thomas Thrainer
  """
936 31b836b8 Thomas Thrainer
  used_globals = glob_pars.intersection(params)
937 31b836b8 Thomas Thrainer
  if used_globals:
938 31b836b8 Thomas Thrainer
    msg = ("The following %s parameters are global and cannot"
939 31b836b8 Thomas Thrainer
           " be customized at %s level, please modify them at"
940 31b836b8 Thomas Thrainer
           " %s level: %s" %
941 31b836b8 Thomas Thrainer
           (kind, bad_levels, good_levels, utils.CommaJoin(used_globals)))
942 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
943 31b836b8 Thomas Thrainer
944 31b836b8 Thomas Thrainer
945 5eacbcae Thomas Thrainer
def IsExclusiveStorageEnabledNode(cfg, node):
946 31b836b8 Thomas Thrainer
  """Whether exclusive_storage is in effect for the given node.
947 31b836b8 Thomas Thrainer

948 31b836b8 Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
949 31b836b8 Thomas Thrainer
  @param cfg: The cluster configuration
950 31b836b8 Thomas Thrainer
  @type node: L{objects.Node}
951 31b836b8 Thomas Thrainer
  @param node: The node
952 31b836b8 Thomas Thrainer
  @rtype: bool
953 31b836b8 Thomas Thrainer
  @return: The effective value of exclusive_storage
954 31b836b8 Thomas Thrainer

955 31b836b8 Thomas Thrainer
  """
956 31b836b8 Thomas Thrainer
  return cfg.GetNdParams(node)[constants.ND_EXCLUSIVE_STORAGE]
957 31b836b8 Thomas Thrainer
958 31b836b8 Thomas Thrainer
959 5eacbcae Thomas Thrainer
def CheckInstanceState(lu, instance, req_states, msg=None):
960 31b836b8 Thomas Thrainer
  """Ensure that an instance is in one of the required states.
961 31b836b8 Thomas Thrainer

962 31b836b8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
963 31b836b8 Thomas Thrainer
  @param instance: the instance to check
964 31b836b8 Thomas Thrainer
  @param msg: if passed, should be a message to replace the default one
965 31b836b8 Thomas Thrainer
  @raise errors.OpPrereqError: if the instance is not in the required state
966 31b836b8 Thomas Thrainer

967 31b836b8 Thomas Thrainer
  """
968 31b836b8 Thomas Thrainer
  if msg is None:
969 31b836b8 Thomas Thrainer
    msg = ("can't use instance from outside %s states" %
970 31b836b8 Thomas Thrainer
           utils.CommaJoin(req_states))
971 31b836b8 Thomas Thrainer
  if instance.admin_state not in req_states:
972 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError("Instance '%s' is marked to be %s, %s" %
973 31b836b8 Thomas Thrainer
                               (instance.name, instance.admin_state, msg),
974 31b836b8 Thomas Thrainer
                               errors.ECODE_STATE)
975 31b836b8 Thomas Thrainer
976 31b836b8 Thomas Thrainer
  if constants.ADMINST_UP not in req_states:
977 1c3231aa Thomas Thrainer
    pnode_uuid = instance.primary_node
978 1c3231aa Thomas Thrainer
    if not lu.cfg.GetNodeInfo(pnode_uuid).offline:
979 8ac806e6 Helga Velroyen
      all_hvparams = lu.cfg.GetClusterInfo().hvparams
980 1c3231aa Thomas Thrainer
      ins_l = lu.rpc.call_instance_list(
981 1c3231aa Thomas Thrainer
                [pnode_uuid], [instance.hypervisor], all_hvparams)[pnode_uuid]
982 1c3231aa Thomas Thrainer
      ins_l.Raise("Can't contact node %s for instance information" %
983 1c3231aa Thomas Thrainer
                  lu.cfg.GetNodeName(pnode_uuid),
984 31b836b8 Thomas Thrainer
                  prereq=True, ecode=errors.ECODE_ENVIRON)
985 31b836b8 Thomas Thrainer
      if instance.name in ins_l.payload:
986 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Instance %s is running, %s" %
987 31b836b8 Thomas Thrainer
                                   (instance.name, msg), errors.ECODE_STATE)
988 31b836b8 Thomas Thrainer
    else:
989 31b836b8 Thomas Thrainer
      lu.LogWarning("Primary node offline, ignoring check that instance"
990 31b836b8 Thomas Thrainer
                     " is down")
991 31b836b8 Thomas Thrainer
992 31b836b8 Thomas Thrainer
993 5eacbcae Thomas Thrainer
def CheckIAllocatorOrNode(lu, iallocator_slot, node_slot):
994 31b836b8 Thomas Thrainer
  """Check the sanity of iallocator and node arguments and use the
995 31b836b8 Thomas Thrainer
  cluster-wide iallocator if appropriate.
996 31b836b8 Thomas Thrainer

997 31b836b8 Thomas Thrainer
  Check that at most one of (iallocator, node) is specified. If none is
998 31b836b8 Thomas Thrainer
  specified, or the iallocator is L{constants.DEFAULT_IALLOCATOR_SHORTCUT},
999 31b836b8 Thomas Thrainer
  then the LU's opcode's iallocator slot is filled with the cluster-wide
1000 31b836b8 Thomas Thrainer
  default iallocator.
1001 31b836b8 Thomas Thrainer

1002 31b836b8 Thomas Thrainer
  @type iallocator_slot: string
1003 31b836b8 Thomas Thrainer
  @param iallocator_slot: the name of the opcode iallocator slot
1004 31b836b8 Thomas Thrainer
  @type node_slot: string
1005 31b836b8 Thomas Thrainer
  @param node_slot: the name of the opcode target node slot
1006 31b836b8 Thomas Thrainer

1007 31b836b8 Thomas Thrainer
  """
1008 31b836b8 Thomas Thrainer
  node = getattr(lu.op, node_slot, None)
1009 31b836b8 Thomas Thrainer
  ialloc = getattr(lu.op, iallocator_slot, None)
1010 31b836b8 Thomas Thrainer
  if node == []:
1011 31b836b8 Thomas Thrainer
    node = None
1012 31b836b8 Thomas Thrainer
1013 31b836b8 Thomas Thrainer
  if node is not None and ialloc is not None:
1014 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError("Do not specify both, iallocator and node",
1015 31b836b8 Thomas Thrainer
                               errors.ECODE_INVAL)
1016 31b836b8 Thomas Thrainer
  elif ((node is None and ialloc is None) or
1017 31b836b8 Thomas Thrainer
        ialloc == constants.DEFAULT_IALLOCATOR_SHORTCUT):
1018 31b836b8 Thomas Thrainer
    default_iallocator = lu.cfg.GetDefaultIAllocator()
1019 31b836b8 Thomas Thrainer
    if default_iallocator:
1020 31b836b8 Thomas Thrainer
      setattr(lu.op, iallocator_slot, default_iallocator)
1021 31b836b8 Thomas Thrainer
    else:
1022 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("No iallocator or node given and no"
1023 31b836b8 Thomas Thrainer
                                 " cluster-wide default iallocator found;"
1024 31b836b8 Thomas Thrainer
                                 " please specify either an iallocator or a"
1025 31b836b8 Thomas Thrainer
                                 " node, or set a cluster-wide default"
1026 31b836b8 Thomas Thrainer
                                 " iallocator", errors.ECODE_INVAL)
1027 31b836b8 Thomas Thrainer
1028 31b836b8 Thomas Thrainer
1029 1c3231aa Thomas Thrainer
def FindFaultyInstanceDisks(cfg, rpc_runner, instance, node_uuid, prereq):
1030 31b836b8 Thomas Thrainer
  faulty = []
1031 31b836b8 Thomas Thrainer
1032 31b836b8 Thomas Thrainer
  for dev in instance.disks:
1033 1c3231aa Thomas Thrainer
    cfg.SetDiskID(dev, node_uuid)
1034 31b836b8 Thomas Thrainer
1035 1c3231aa Thomas Thrainer
  result = rpc_runner.call_blockdev_getmirrorstatus(
1036 1c3231aa Thomas Thrainer
             node_uuid, (instance.disks, instance))
1037 1c3231aa Thomas Thrainer
  result.Raise("Failed to get disk status from node %s" %
1038 1c3231aa Thomas Thrainer
               cfg.GetNodeName(node_uuid),
1039 31b836b8 Thomas Thrainer
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
1040 31b836b8 Thomas Thrainer
1041 31b836b8 Thomas Thrainer
  for idx, bdev_status in enumerate(result.payload):
1042 31b836b8 Thomas Thrainer
    if bdev_status and bdev_status.ldisk_status == constants.LDS_FAULTY:
1043 31b836b8 Thomas Thrainer
      faulty.append(idx)
1044 31b836b8 Thomas Thrainer
1045 31b836b8 Thomas Thrainer
  return faulty
1046 22b7f6f8 Thomas Thrainer
1047 22b7f6f8 Thomas Thrainer
1048 1c3231aa Thomas Thrainer
def CheckNodeOnline(lu, node_uuid, msg=None):
1049 22b7f6f8 Thomas Thrainer
  """Ensure that a given node is online.
1050 22b7f6f8 Thomas Thrainer

1051 22b7f6f8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
1052 1c3231aa Thomas Thrainer
  @param node_uuid: the node to check
1053 22b7f6f8 Thomas Thrainer
  @param msg: if passed, should be a message to replace the default one
1054 22b7f6f8 Thomas Thrainer
  @raise errors.OpPrereqError: if the node is offline
1055 22b7f6f8 Thomas Thrainer

1056 22b7f6f8 Thomas Thrainer
  """
1057 22b7f6f8 Thomas Thrainer
  if msg is None:
1058 22b7f6f8 Thomas Thrainer
    msg = "Can't use offline node"
1059 1c3231aa Thomas Thrainer
  if lu.cfg.GetNodeInfo(node_uuid).offline:
1060 1c3231aa Thomas Thrainer
    raise errors.OpPrereqError("%s: %s" % (msg, lu.cfg.GetNodeName(node_uuid)),
1061 1c3231aa Thomas Thrainer
                               errors.ECODE_STATE)