Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / common.py @ 7352d33b

History | View | Annotate | Download (24.2 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 7352d33b Thomas Thrainer
import copy
24 7352d33b Thomas Thrainer
import os
25 1a732a74 Thomas Thrainer
26 7352d33b Thomas Thrainer
from ganeti import constants
27 1a732a74 Thomas Thrainer
from ganeti import errors
28 7352d33b Thomas Thrainer
from ganeti import hypervisor
29 fb3891d0 Thomas Thrainer
from ganeti import locking
30 7352d33b Thomas Thrainer
from ganeti import objects
31 7352d33b Thomas Thrainer
from ganeti import pathutils
32 7352d33b Thomas Thrainer
from ganeti import rpc
33 7352d33b Thomas Thrainer
from ganeti import ssconf
34 37dc17e3 Thomas Thrainer
from ganeti import utils
35 1a732a74 Thomas Thrainer
36 1a732a74 Thomas Thrainer
37 1a732a74 Thomas Thrainer
def _ExpandItemName(fn, name, kind):
38 1a732a74 Thomas Thrainer
  """Expand an item name.
39 1a732a74 Thomas Thrainer

40 1a732a74 Thomas Thrainer
  @param fn: the function to use for expansion
41 1a732a74 Thomas Thrainer
  @param name: requested item name
42 1a732a74 Thomas Thrainer
  @param kind: text description ('Node' or 'Instance')
43 1a732a74 Thomas Thrainer
  @return: the resolved (full) name
44 1a732a74 Thomas Thrainer
  @raise errors.OpPrereqError: if the item is not found
45 1a732a74 Thomas Thrainer

46 1a732a74 Thomas Thrainer
  """
47 1a732a74 Thomas Thrainer
  full_name = fn(name)
48 1a732a74 Thomas Thrainer
  if full_name is None:
49 1a732a74 Thomas Thrainer
    raise errors.OpPrereqError("%s '%s' not known" % (kind, name),
50 1a732a74 Thomas Thrainer
                               errors.ECODE_NOENT)
51 1a732a74 Thomas Thrainer
  return full_name
52 1a732a74 Thomas Thrainer
53 1a732a74 Thomas Thrainer
54 1a732a74 Thomas Thrainer
def _ExpandInstanceName(cfg, name):
55 1a732a74 Thomas Thrainer
  """Wrapper over L{_ExpandItemName} for instance."""
56 1a732a74 Thomas Thrainer
  return _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
57 1a732a74 Thomas Thrainer
58 1a732a74 Thomas Thrainer
59 1a732a74 Thomas Thrainer
def _ExpandNodeName(cfg, name):
60 1a732a74 Thomas Thrainer
  """Wrapper over L{_ExpandItemName} for nodes."""
61 1a732a74 Thomas Thrainer
  return _ExpandItemName(cfg.ExpandNodeName, name, "Node")
62 fb3891d0 Thomas Thrainer
63 fb3891d0 Thomas Thrainer
64 fb3891d0 Thomas Thrainer
def _ShareAll():
65 fb3891d0 Thomas Thrainer
  """Returns a dict declaring all lock levels shared.
66 fb3891d0 Thomas Thrainer

67 fb3891d0 Thomas Thrainer
  """
68 fb3891d0 Thomas Thrainer
  return dict.fromkeys(locking.LEVELS, 1)
69 37dc17e3 Thomas Thrainer
70 37dc17e3 Thomas Thrainer
71 37dc17e3 Thomas Thrainer
def _CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
72 37dc17e3 Thomas Thrainer
  """Checks if the instances in a node group are still correct.
73 37dc17e3 Thomas Thrainer

74 37dc17e3 Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
75 37dc17e3 Thomas Thrainer
  @param cfg: The cluster configuration
76 37dc17e3 Thomas Thrainer
  @type group_uuid: string
77 37dc17e3 Thomas Thrainer
  @param group_uuid: Node group UUID
78 37dc17e3 Thomas Thrainer
  @type owned_instances: set or frozenset
79 37dc17e3 Thomas Thrainer
  @param owned_instances: List of currently owned instances
80 37dc17e3 Thomas Thrainer

81 37dc17e3 Thomas Thrainer
  """
82 37dc17e3 Thomas Thrainer
  wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
83 37dc17e3 Thomas Thrainer
  if owned_instances != wanted_instances:
84 37dc17e3 Thomas Thrainer
    raise errors.OpPrereqError("Instances in node group '%s' changed since"
85 37dc17e3 Thomas Thrainer
                               " locks were acquired, wanted '%s', have '%s';"
86 37dc17e3 Thomas Thrainer
                               " retry the operation" %
87 37dc17e3 Thomas Thrainer
                               (group_uuid,
88 37dc17e3 Thomas Thrainer
                                utils.CommaJoin(wanted_instances),
89 37dc17e3 Thomas Thrainer
                                utils.CommaJoin(owned_instances)),
90 37dc17e3 Thomas Thrainer
                               errors.ECODE_STATE)
91 37dc17e3 Thomas Thrainer
92 37dc17e3 Thomas Thrainer
  return wanted_instances
93 1d870e0d Thomas Thrainer
94 1d870e0d Thomas Thrainer
95 1d870e0d Thomas Thrainer
def _GetWantedNodes(lu, nodes):
96 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded node names.
97 1d870e0d Thomas Thrainer

98 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
99 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
100 1d870e0d Thomas Thrainer
  @type nodes: list
101 1d870e0d Thomas Thrainer
  @param nodes: list of node names or None for all nodes
102 1d870e0d Thomas Thrainer
  @rtype: list
103 1d870e0d Thomas Thrainer
  @return: the list of nodes, sorted
104 1d870e0d Thomas Thrainer
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
105 1d870e0d Thomas Thrainer

106 1d870e0d Thomas Thrainer
  """
107 1d870e0d Thomas Thrainer
  if nodes:
108 1d870e0d Thomas Thrainer
    return [_ExpandNodeName(lu.cfg, name) for name in nodes]
109 1d870e0d Thomas Thrainer
110 1d870e0d Thomas Thrainer
  return utils.NiceSort(lu.cfg.GetNodeList())
111 1d870e0d Thomas Thrainer
112 1d870e0d Thomas Thrainer
113 1d870e0d Thomas Thrainer
def _GetWantedInstances(lu, instances):
114 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded instance names.
115 1d870e0d Thomas Thrainer

116 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
117 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
118 1d870e0d Thomas Thrainer
  @type instances: list
119 1d870e0d Thomas Thrainer
  @param instances: list of instance names or None for all instances
120 1d870e0d Thomas Thrainer
  @rtype: list
121 1d870e0d Thomas Thrainer
  @return: the list of instances, sorted
122 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if the instances parameter is wrong type
123 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if any of the passed instances is not found
124 1d870e0d Thomas Thrainer

125 1d870e0d Thomas Thrainer
  """
126 1d870e0d Thomas Thrainer
  if instances:
127 1d870e0d Thomas Thrainer
    wanted = [_ExpandInstanceName(lu.cfg, name) for name in instances]
128 1d870e0d Thomas Thrainer
  else:
129 1d870e0d Thomas Thrainer
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
130 1d870e0d Thomas Thrainer
  return wanted
131 7352d33b Thomas Thrainer
132 7352d33b Thomas Thrainer
133 7352d33b Thomas Thrainer
def _RunPostHook(lu, node_name):
134 7352d33b Thomas Thrainer
  """Runs the post-hook for an opcode on a single node.
135 7352d33b Thomas Thrainer

136 7352d33b Thomas Thrainer
  """
137 7352d33b Thomas Thrainer
  hm = lu.proc.BuildHooksManager(lu)
138 7352d33b Thomas Thrainer
  try:
139 7352d33b Thomas Thrainer
    hm.RunPhase(constants.HOOKS_PHASE_POST, nodes=[node_name])
140 7352d33b Thomas Thrainer
  except Exception, err: # pylint: disable=W0703
141 7352d33b Thomas Thrainer
    lu.LogWarning("Errors occurred running hooks on %s: %s",
142 7352d33b Thomas Thrainer
                  node_name, err)
143 7352d33b Thomas Thrainer
144 7352d33b Thomas Thrainer
145 7352d33b Thomas Thrainer
def _RedistributeAncillaryFiles(lu, additional_nodes=None, additional_vm=True):
146 7352d33b Thomas Thrainer
  """Distribute additional files which are part of the cluster configuration.
147 7352d33b Thomas Thrainer

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

152 7352d33b Thomas Thrainer
  @param lu: calling logical unit
153 7352d33b Thomas Thrainer
  @param additional_nodes: list of nodes not in the config to distribute to
154 7352d33b Thomas Thrainer
  @type additional_vm: boolean
155 7352d33b Thomas Thrainer
  @param additional_vm: whether the additional nodes are vm-capable or not
156 7352d33b Thomas Thrainer

157 7352d33b Thomas Thrainer
  """
158 7352d33b Thomas Thrainer
  # Gather target nodes
159 7352d33b Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
160 7352d33b Thomas Thrainer
  master_info = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
161 7352d33b Thomas Thrainer
162 7352d33b Thomas Thrainer
  online_nodes = lu.cfg.GetOnlineNodeList()
163 7352d33b Thomas Thrainer
  online_set = frozenset(online_nodes)
164 7352d33b Thomas Thrainer
  vm_nodes = list(online_set.intersection(lu.cfg.GetVmCapableNodeList()))
165 7352d33b Thomas Thrainer
166 7352d33b Thomas Thrainer
  if additional_nodes is not None:
167 7352d33b Thomas Thrainer
    online_nodes.extend(additional_nodes)
168 7352d33b Thomas Thrainer
    if additional_vm:
169 7352d33b Thomas Thrainer
      vm_nodes.extend(additional_nodes)
170 7352d33b Thomas Thrainer
171 7352d33b Thomas Thrainer
  # Never distribute to master node
172 7352d33b Thomas Thrainer
  for nodelist in [online_nodes, vm_nodes]:
173 7352d33b Thomas Thrainer
    if master_info.name in nodelist:
174 7352d33b Thomas Thrainer
      nodelist.remove(master_info.name)
175 7352d33b Thomas Thrainer
176 7352d33b Thomas Thrainer
  # Gather file lists
177 7352d33b Thomas Thrainer
  (files_all, _, files_mc, files_vm) = \
178 7352d33b Thomas Thrainer
    _ComputeAncillaryFiles(cluster, True)
179 7352d33b Thomas Thrainer
180 7352d33b Thomas Thrainer
  # Never re-distribute configuration file from here
181 7352d33b Thomas Thrainer
  assert not (pathutils.CLUSTER_CONF_FILE in files_all or
182 7352d33b Thomas Thrainer
              pathutils.CLUSTER_CONF_FILE in files_vm)
183 7352d33b Thomas Thrainer
  assert not files_mc, "Master candidates not handled in this function"
184 7352d33b Thomas Thrainer
185 7352d33b Thomas Thrainer
  filemap = [
186 7352d33b Thomas Thrainer
    (online_nodes, files_all),
187 7352d33b Thomas Thrainer
    (vm_nodes, files_vm),
188 7352d33b Thomas Thrainer
    ]
189 7352d33b Thomas Thrainer
190 7352d33b Thomas Thrainer
  # Upload the files
191 7352d33b Thomas Thrainer
  for (node_list, files) in filemap:
192 7352d33b Thomas Thrainer
    for fname in files:
193 7352d33b Thomas Thrainer
      _UploadHelper(lu, node_list, fname)
194 7352d33b Thomas Thrainer
195 7352d33b Thomas Thrainer
196 7352d33b Thomas Thrainer
def _ComputeAncillaryFiles(cluster, redist):
197 7352d33b Thomas Thrainer
  """Compute files external to Ganeti which need to be consistent.
198 7352d33b Thomas Thrainer

199 7352d33b Thomas Thrainer
  @type redist: boolean
200 7352d33b Thomas Thrainer
  @param redist: Whether to include files which need to be redistributed
201 7352d33b Thomas Thrainer

202 7352d33b Thomas Thrainer
  """
203 7352d33b Thomas Thrainer
  # Compute files for all nodes
204 7352d33b Thomas Thrainer
  files_all = set([
205 7352d33b Thomas Thrainer
    pathutils.SSH_KNOWN_HOSTS_FILE,
206 7352d33b Thomas Thrainer
    pathutils.CONFD_HMAC_KEY,
207 7352d33b Thomas Thrainer
    pathutils.CLUSTER_DOMAIN_SECRET_FILE,
208 7352d33b Thomas Thrainer
    pathutils.SPICE_CERT_FILE,
209 7352d33b Thomas Thrainer
    pathutils.SPICE_CACERT_FILE,
210 7352d33b Thomas Thrainer
    pathutils.RAPI_USERS_FILE,
211 7352d33b Thomas Thrainer
    ])
212 7352d33b Thomas Thrainer
213 7352d33b Thomas Thrainer
  if redist:
214 7352d33b Thomas Thrainer
    # we need to ship at least the RAPI certificate
215 7352d33b Thomas Thrainer
    files_all.add(pathutils.RAPI_CERT_FILE)
216 7352d33b Thomas Thrainer
  else:
217 7352d33b Thomas Thrainer
    files_all.update(pathutils.ALL_CERT_FILES)
218 7352d33b Thomas Thrainer
    files_all.update(ssconf.SimpleStore().GetFileList())
219 7352d33b Thomas Thrainer
220 7352d33b Thomas Thrainer
  if cluster.modify_etc_hosts:
221 7352d33b Thomas Thrainer
    files_all.add(pathutils.ETC_HOSTS)
222 7352d33b Thomas Thrainer
223 7352d33b Thomas Thrainer
  if cluster.use_external_mip_script:
224 7352d33b Thomas Thrainer
    files_all.add(pathutils.EXTERNAL_MASTER_SETUP_SCRIPT)
225 7352d33b Thomas Thrainer
226 7352d33b Thomas Thrainer
  # Files which are optional, these must:
227 7352d33b Thomas Thrainer
  # - be present in one other category as well
228 7352d33b Thomas Thrainer
  # - either exist or not exist on all nodes of that category (mc, vm all)
229 7352d33b Thomas Thrainer
  files_opt = set([
230 7352d33b Thomas Thrainer
    pathutils.RAPI_USERS_FILE,
231 7352d33b Thomas Thrainer
    ])
232 7352d33b Thomas Thrainer
233 7352d33b Thomas Thrainer
  # Files which should only be on master candidates
234 7352d33b Thomas Thrainer
  files_mc = set()
235 7352d33b Thomas Thrainer
236 7352d33b Thomas Thrainer
  if not redist:
237 7352d33b Thomas Thrainer
    files_mc.add(pathutils.CLUSTER_CONF_FILE)
238 7352d33b Thomas Thrainer
239 7352d33b Thomas Thrainer
  # File storage
240 7352d33b Thomas Thrainer
  if (not redist and (constants.ENABLE_FILE_STORAGE or
241 7352d33b Thomas Thrainer
                        constants.ENABLE_SHARED_FILE_STORAGE)):
242 7352d33b Thomas Thrainer
    files_all.add(pathutils.FILE_STORAGE_PATHS_FILE)
243 7352d33b Thomas Thrainer
    files_opt.add(pathutils.FILE_STORAGE_PATHS_FILE)
244 7352d33b Thomas Thrainer
245 7352d33b Thomas Thrainer
  # Files which should only be on VM-capable nodes
246 7352d33b Thomas Thrainer
  files_vm = set(
247 7352d33b Thomas Thrainer
    filename
248 7352d33b Thomas Thrainer
    for hv_name in cluster.enabled_hypervisors
249 7352d33b Thomas Thrainer
    for filename in
250 7352d33b Thomas Thrainer
    hypervisor.GetHypervisorClass(hv_name).GetAncillaryFiles()[0])
251 7352d33b Thomas Thrainer
252 7352d33b Thomas Thrainer
  files_opt |= set(
253 7352d33b Thomas Thrainer
    filename
254 7352d33b Thomas Thrainer
    for hv_name in cluster.enabled_hypervisors
255 7352d33b Thomas Thrainer
    for filename in
256 7352d33b Thomas Thrainer
    hypervisor.GetHypervisorClass(hv_name).GetAncillaryFiles()[1])
257 7352d33b Thomas Thrainer
258 7352d33b Thomas Thrainer
  # Filenames in each category must be unique
259 7352d33b Thomas Thrainer
  all_files_set = files_all | files_mc | files_vm
260 7352d33b Thomas Thrainer
  assert (len(all_files_set) ==
261 7352d33b Thomas Thrainer
          sum(map(len, [files_all, files_mc, files_vm]))), \
262 7352d33b Thomas Thrainer
    "Found file listed in more than one file list"
263 7352d33b Thomas Thrainer
264 7352d33b Thomas Thrainer
  # Optional files must be present in one other category
265 7352d33b Thomas Thrainer
  assert all_files_set.issuperset(files_opt), \
266 7352d33b Thomas Thrainer
    "Optional file not in a different required list"
267 7352d33b Thomas Thrainer
268 7352d33b Thomas Thrainer
  # This one file should never ever be re-distributed via RPC
269 7352d33b Thomas Thrainer
  assert not (redist and
270 7352d33b Thomas Thrainer
              pathutils.FILE_STORAGE_PATHS_FILE in all_files_set)
271 7352d33b Thomas Thrainer
272 7352d33b Thomas Thrainer
  return (files_all, files_opt, files_mc, files_vm)
273 7352d33b Thomas Thrainer
274 7352d33b Thomas Thrainer
275 7352d33b Thomas Thrainer
def _UploadHelper(lu, nodes, fname):
276 7352d33b Thomas Thrainer
  """Helper for uploading a file and showing warnings.
277 7352d33b Thomas Thrainer

278 7352d33b Thomas Thrainer
  """
279 7352d33b Thomas Thrainer
  if os.path.exists(fname):
280 7352d33b Thomas Thrainer
    result = lu.rpc.call_upload_file(nodes, fname)
281 7352d33b Thomas Thrainer
    for to_node, to_result in result.items():
282 7352d33b Thomas Thrainer
      msg = to_result.fail_msg
283 7352d33b Thomas Thrainer
      if msg:
284 7352d33b Thomas Thrainer
        msg = ("Copy of file %s to node %s failed: %s" %
285 7352d33b Thomas Thrainer
               (fname, to_node, msg))
286 7352d33b Thomas Thrainer
        lu.LogWarning(msg)
287 7352d33b Thomas Thrainer
288 7352d33b Thomas Thrainer
289 7352d33b Thomas Thrainer
def _MergeAndVerifyHvState(op_input, obj_input):
290 7352d33b Thomas Thrainer
  """Combines the hv state from an opcode with the one of the object
291 7352d33b Thomas Thrainer

292 7352d33b Thomas Thrainer
  @param op_input: The input dict from the opcode
293 7352d33b Thomas Thrainer
  @param obj_input: The input dict from the objects
294 7352d33b Thomas Thrainer
  @return: The verified and updated dict
295 7352d33b Thomas Thrainer

296 7352d33b Thomas Thrainer
  """
297 7352d33b Thomas Thrainer
  if op_input:
298 7352d33b Thomas Thrainer
    invalid_hvs = set(op_input) - constants.HYPER_TYPES
299 7352d33b Thomas Thrainer
    if invalid_hvs:
300 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid hypervisor(s) in hypervisor state:"
301 7352d33b Thomas Thrainer
                                 " %s" % utils.CommaJoin(invalid_hvs),
302 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
303 7352d33b Thomas Thrainer
    if obj_input is None:
304 7352d33b Thomas Thrainer
      obj_input = {}
305 7352d33b Thomas Thrainer
    type_check = constants.HVSTS_PARAMETER_TYPES
306 7352d33b Thomas Thrainer
    return _UpdateAndVerifySubDict(obj_input, op_input, type_check)
307 7352d33b Thomas Thrainer
308 7352d33b Thomas Thrainer
  return None
309 7352d33b Thomas Thrainer
310 7352d33b Thomas Thrainer
311 7352d33b Thomas Thrainer
def _MergeAndVerifyDiskState(op_input, obj_input):
312 7352d33b Thomas Thrainer
  """Combines the disk state from an opcode with the one of the object
313 7352d33b Thomas Thrainer

314 7352d33b Thomas Thrainer
  @param op_input: The input dict from the opcode
315 7352d33b Thomas Thrainer
  @param obj_input: The input dict from the objects
316 7352d33b Thomas Thrainer
  @return: The verified and updated dict
317 7352d33b Thomas Thrainer
  """
318 7352d33b Thomas Thrainer
  if op_input:
319 7352d33b Thomas Thrainer
    invalid_dst = set(op_input) - constants.DS_VALID_TYPES
320 7352d33b Thomas Thrainer
    if invalid_dst:
321 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid storage type(s) in disk state: %s" %
322 7352d33b Thomas Thrainer
                                 utils.CommaJoin(invalid_dst),
323 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
324 7352d33b Thomas Thrainer
    type_check = constants.DSS_PARAMETER_TYPES
325 7352d33b Thomas Thrainer
    if obj_input is None:
326 7352d33b Thomas Thrainer
      obj_input = {}
327 7352d33b Thomas Thrainer
    return dict((key, _UpdateAndVerifySubDict(obj_input.get(key, {}), value,
328 7352d33b Thomas Thrainer
                                              type_check))
329 7352d33b Thomas Thrainer
                for key, value in op_input.items())
330 7352d33b Thomas Thrainer
331 7352d33b Thomas Thrainer
  return None
332 7352d33b Thomas Thrainer
333 7352d33b Thomas Thrainer
334 7352d33b Thomas Thrainer
def _CheckOSParams(lu, required, nodenames, osname, osparams):
335 7352d33b Thomas Thrainer
  """OS parameters validation.
336 7352d33b Thomas Thrainer

337 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
338 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
339 7352d33b Thomas Thrainer
  @type required: boolean
340 7352d33b Thomas Thrainer
  @param required: whether the validation should fail if the OS is not
341 7352d33b Thomas Thrainer
      found
342 7352d33b Thomas Thrainer
  @type nodenames: list
343 7352d33b Thomas Thrainer
  @param nodenames: the list of nodes on which we should check
344 7352d33b Thomas Thrainer
  @type osname: string
345 7352d33b Thomas Thrainer
  @param osname: the name of the hypervisor we should use
346 7352d33b Thomas Thrainer
  @type osparams: dict
347 7352d33b Thomas Thrainer
  @param osparams: the parameters which we need to check
348 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
349 7352d33b Thomas Thrainer

350 7352d33b Thomas Thrainer
  """
351 7352d33b Thomas Thrainer
  nodenames = _FilterVmNodes(lu, nodenames)
352 7352d33b Thomas Thrainer
  result = lu.rpc.call_os_validate(nodenames, required, osname,
353 7352d33b Thomas Thrainer
                                   [constants.OS_VALIDATE_PARAMETERS],
354 7352d33b Thomas Thrainer
                                   osparams)
355 7352d33b Thomas Thrainer
  for node, nres in result.items():
356 7352d33b Thomas Thrainer
    # we don't check for offline cases since this should be run only
357 7352d33b Thomas Thrainer
    # against the master node and/or an instance's nodes
358 7352d33b Thomas Thrainer
    nres.Raise("OS Parameters validation failed on node %s" % node)
359 7352d33b Thomas Thrainer
    if not nres.payload:
360 7352d33b Thomas Thrainer
      lu.LogInfo("OS %s not found on node %s, validation skipped",
361 7352d33b Thomas Thrainer
                 osname, node)
362 7352d33b Thomas Thrainer
363 7352d33b Thomas Thrainer
364 7352d33b Thomas Thrainer
def _CheckHVParams(lu, nodenames, hvname, hvparams):
365 7352d33b Thomas Thrainer
  """Hypervisor parameter validation.
366 7352d33b Thomas Thrainer

367 7352d33b Thomas Thrainer
  This function abstract the hypervisor parameter validation to be
368 7352d33b Thomas Thrainer
  used in both instance create and instance modify.
369 7352d33b Thomas Thrainer

370 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
371 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
372 7352d33b Thomas Thrainer
  @type nodenames: list
373 7352d33b Thomas Thrainer
  @param nodenames: the list of nodes on which we should check
374 7352d33b Thomas Thrainer
  @type hvname: string
375 7352d33b Thomas Thrainer
  @param hvname: the name of the hypervisor we should use
376 7352d33b Thomas Thrainer
  @type hvparams: dict
377 7352d33b Thomas Thrainer
  @param hvparams: the parameters which we need to check
378 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
379 7352d33b Thomas Thrainer

380 7352d33b Thomas Thrainer
  """
381 7352d33b Thomas Thrainer
  nodenames = _FilterVmNodes(lu, nodenames)
382 7352d33b Thomas Thrainer
383 7352d33b Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
384 7352d33b Thomas Thrainer
  hvfull = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
385 7352d33b Thomas Thrainer
386 7352d33b Thomas Thrainer
  hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames, hvname, hvfull)
387 7352d33b Thomas Thrainer
  for node in nodenames:
388 7352d33b Thomas Thrainer
    info = hvinfo[node]
389 7352d33b Thomas Thrainer
    if info.offline:
390 7352d33b Thomas Thrainer
      continue
391 7352d33b Thomas Thrainer
    info.Raise("Hypervisor parameter validation failed on node %s" % node)
392 7352d33b Thomas Thrainer
393 7352d33b Thomas Thrainer
394 7352d33b Thomas Thrainer
def _AdjustCandidatePool(lu, exceptions):
395 7352d33b Thomas Thrainer
  """Adjust the candidate pool after node operations.
396 7352d33b Thomas Thrainer

397 7352d33b Thomas Thrainer
  """
398 7352d33b Thomas Thrainer
  mod_list = lu.cfg.MaintainCandidatePool(exceptions)
399 7352d33b Thomas Thrainer
  if mod_list:
400 7352d33b Thomas Thrainer
    lu.LogInfo("Promoted nodes to master candidate role: %s",
401 7352d33b Thomas Thrainer
               utils.CommaJoin(node.name for node in mod_list))
402 7352d33b Thomas Thrainer
    for name in mod_list:
403 7352d33b Thomas Thrainer
      lu.context.ReaddNode(name)
404 7352d33b Thomas Thrainer
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
405 7352d33b Thomas Thrainer
  if mc_now > mc_max:
406 7352d33b Thomas Thrainer
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
407 7352d33b Thomas Thrainer
               (mc_now, mc_max))
408 7352d33b Thomas Thrainer
409 7352d33b Thomas Thrainer
410 7352d33b Thomas Thrainer
def _CheckNodePVs(nresult, exclusive_storage):
411 7352d33b Thomas Thrainer
  """Check node PVs.
412 7352d33b Thomas Thrainer

413 7352d33b Thomas Thrainer
  """
414 7352d33b Thomas Thrainer
  pvlist_dict = nresult.get(constants.NV_PVLIST, None)
415 7352d33b Thomas Thrainer
  if pvlist_dict is None:
416 7352d33b Thomas Thrainer
    return (["Can't get PV list from node"], None)
417 7352d33b Thomas Thrainer
  pvlist = map(objects.LvmPvInfo.FromDict, pvlist_dict)
418 7352d33b Thomas Thrainer
  errlist = []
419 7352d33b Thomas Thrainer
  # check that ':' is not present in PV names, since it's a
420 7352d33b Thomas Thrainer
  # special character for lvcreate (denotes the range of PEs to
421 7352d33b Thomas Thrainer
  # use on the PV)
422 7352d33b Thomas Thrainer
  for pv in pvlist:
423 7352d33b Thomas Thrainer
    if ":" in pv.name:
424 7352d33b Thomas Thrainer
      errlist.append("Invalid character ':' in PV '%s' of VG '%s'" %
425 7352d33b Thomas Thrainer
                     (pv.name, pv.vg_name))
426 7352d33b Thomas Thrainer
  es_pvinfo = None
427 7352d33b Thomas Thrainer
  if exclusive_storage:
428 7352d33b Thomas Thrainer
    (errmsgs, es_pvinfo) = utils.LvmExclusiveCheckNodePvs(pvlist)
429 7352d33b Thomas Thrainer
    errlist.extend(errmsgs)
430 7352d33b Thomas Thrainer
    shared_pvs = nresult.get(constants.NV_EXCLUSIVEPVS, None)
431 7352d33b Thomas Thrainer
    if shared_pvs:
432 7352d33b Thomas Thrainer
      for (pvname, lvlist) in shared_pvs:
433 7352d33b Thomas Thrainer
        # TODO: Check that LVs are really unrelated (snapshots, DRBD meta...)
434 7352d33b Thomas Thrainer
        errlist.append("PV %s is shared among unrelated LVs (%s)" %
435 7352d33b Thomas Thrainer
                       (pvname, utils.CommaJoin(lvlist)))
436 7352d33b Thomas Thrainer
  return (errlist, es_pvinfo)
437 7352d33b Thomas Thrainer
438 7352d33b Thomas Thrainer
439 7352d33b Thomas Thrainer
def _ComputeMinMaxSpec(name, qualifier, ispecs, value):
440 7352d33b Thomas Thrainer
  """Computes if value is in the desired range.
441 7352d33b Thomas Thrainer

442 7352d33b Thomas Thrainer
  @param name: name of the parameter for which we perform the check
443 7352d33b Thomas Thrainer
  @param qualifier: a qualifier used in the error message (e.g. 'disk/1',
444 7352d33b Thomas Thrainer
      not just 'disk')
445 7352d33b Thomas Thrainer
  @param ispecs: dictionary containing min and max values
446 7352d33b Thomas Thrainer
  @param value: actual value that we want to use
447 7352d33b Thomas Thrainer
  @return: None or an error string
448 7352d33b Thomas Thrainer

449 7352d33b Thomas Thrainer
  """
450 7352d33b Thomas Thrainer
  if value in [None, constants.VALUE_AUTO]:
451 7352d33b Thomas Thrainer
    return None
452 7352d33b Thomas Thrainer
  max_v = ispecs[constants.ISPECS_MAX].get(name, value)
453 7352d33b Thomas Thrainer
  min_v = ispecs[constants.ISPECS_MIN].get(name, value)
454 7352d33b Thomas Thrainer
  if value > max_v or min_v > value:
455 7352d33b Thomas Thrainer
    if qualifier:
456 7352d33b Thomas Thrainer
      fqn = "%s/%s" % (name, qualifier)
457 7352d33b Thomas Thrainer
    else:
458 7352d33b Thomas Thrainer
      fqn = name
459 7352d33b Thomas Thrainer
    return ("%s value %s is not in range [%s, %s]" %
460 7352d33b Thomas Thrainer
            (fqn, value, min_v, max_v))
461 7352d33b Thomas Thrainer
  return None
462 7352d33b Thomas Thrainer
463 7352d33b Thomas Thrainer
464 7352d33b Thomas Thrainer
def _ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
465 7352d33b Thomas Thrainer
                                 nic_count, disk_sizes, spindle_use,
466 7352d33b Thomas Thrainer
                                 disk_template,
467 7352d33b Thomas Thrainer
                                 _compute_fn=_ComputeMinMaxSpec):
468 7352d33b Thomas Thrainer
  """Verifies ipolicy against provided specs.
469 7352d33b Thomas Thrainer

470 7352d33b Thomas Thrainer
  @type ipolicy: dict
471 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy
472 7352d33b Thomas Thrainer
  @type mem_size: int
473 7352d33b Thomas Thrainer
  @param mem_size: The memory size
474 7352d33b Thomas Thrainer
  @type cpu_count: int
475 7352d33b Thomas Thrainer
  @param cpu_count: Used cpu cores
476 7352d33b Thomas Thrainer
  @type disk_count: int
477 7352d33b Thomas Thrainer
  @param disk_count: Number of disks used
478 7352d33b Thomas Thrainer
  @type nic_count: int
479 7352d33b Thomas Thrainer
  @param nic_count: Number of nics used
480 7352d33b Thomas Thrainer
  @type disk_sizes: list of ints
481 7352d33b Thomas Thrainer
  @param disk_sizes: Disk sizes of used disk (len must match C{disk_count})
482 7352d33b Thomas Thrainer
  @type spindle_use: int
483 7352d33b Thomas Thrainer
  @param spindle_use: The number of spindles this instance uses
484 7352d33b Thomas Thrainer
  @type disk_template: string
485 7352d33b Thomas Thrainer
  @param disk_template: The disk template of the instance
486 7352d33b Thomas Thrainer
  @param _compute_fn: The compute function (unittest only)
487 7352d33b Thomas Thrainer
  @return: A list of violations, or an empty list of no violations are found
488 7352d33b Thomas Thrainer

489 7352d33b Thomas Thrainer
  """
490 7352d33b Thomas Thrainer
  assert disk_count == len(disk_sizes)
491 7352d33b Thomas Thrainer
492 7352d33b Thomas Thrainer
  test_settings = [
493 7352d33b Thomas Thrainer
    (constants.ISPEC_MEM_SIZE, "", mem_size),
494 7352d33b Thomas Thrainer
    (constants.ISPEC_CPU_COUNT, "", cpu_count),
495 7352d33b Thomas Thrainer
    (constants.ISPEC_NIC_COUNT, "", nic_count),
496 7352d33b Thomas Thrainer
    (constants.ISPEC_SPINDLE_USE, "", spindle_use),
497 7352d33b Thomas Thrainer
    ] + [(constants.ISPEC_DISK_SIZE, str(idx), d)
498 7352d33b Thomas Thrainer
         for idx, d in enumerate(disk_sizes)]
499 7352d33b Thomas Thrainer
  if disk_template != constants.DT_DISKLESS:
500 7352d33b Thomas Thrainer
    # This check doesn't make sense for diskless instances
501 7352d33b Thomas Thrainer
    test_settings.append((constants.ISPEC_DISK_COUNT, "", disk_count))
502 7352d33b Thomas Thrainer
  ret = []
503 7352d33b Thomas Thrainer
  allowed_dts = ipolicy[constants.IPOLICY_DTS]
504 7352d33b Thomas Thrainer
  if disk_template not in allowed_dts:
505 7352d33b Thomas Thrainer
    ret.append("Disk template %s is not allowed (allowed templates: %s)" %
506 7352d33b Thomas Thrainer
               (disk_template, utils.CommaJoin(allowed_dts)))
507 7352d33b Thomas Thrainer
508 7352d33b Thomas Thrainer
  min_errs = None
509 7352d33b Thomas Thrainer
  for minmax in ipolicy[constants.ISPECS_MINMAX]:
510 7352d33b Thomas Thrainer
    errs = filter(None,
511 7352d33b Thomas Thrainer
                  (_compute_fn(name, qualifier, minmax, value)
512 7352d33b Thomas Thrainer
                   for (name, qualifier, value) in test_settings))
513 7352d33b Thomas Thrainer
    if min_errs is None or len(errs) < len(min_errs):
514 7352d33b Thomas Thrainer
      min_errs = errs
515 7352d33b Thomas Thrainer
  assert min_errs is not None
516 7352d33b Thomas Thrainer
  return ret + min_errs
517 7352d33b Thomas Thrainer
518 7352d33b Thomas Thrainer
519 7352d33b Thomas Thrainer
def _ComputeIPolicyInstanceViolation(ipolicy, instance, cfg,
520 7352d33b Thomas Thrainer
                                     _compute_fn=_ComputeIPolicySpecViolation):
521 7352d33b Thomas Thrainer
  """Compute if instance meets the specs of ipolicy.
522 7352d33b Thomas Thrainer

523 7352d33b Thomas Thrainer
  @type ipolicy: dict
524 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify against
525 7352d33b Thomas Thrainer
  @type instance: L{objects.Instance}
526 7352d33b Thomas Thrainer
  @param instance: The instance to verify
527 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
528 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
529 7352d33b Thomas Thrainer
  @param _compute_fn: The function to verify ipolicy (unittest only)
530 7352d33b Thomas Thrainer
  @see: L{_ComputeIPolicySpecViolation}
531 7352d33b Thomas Thrainer

532 7352d33b Thomas Thrainer
  """
533 7352d33b Thomas Thrainer
  be_full = cfg.GetClusterInfo().FillBE(instance)
534 7352d33b Thomas Thrainer
  mem_size = be_full[constants.BE_MAXMEM]
535 7352d33b Thomas Thrainer
  cpu_count = be_full[constants.BE_VCPUS]
536 7352d33b Thomas Thrainer
  spindle_use = be_full[constants.BE_SPINDLE_USE]
537 7352d33b Thomas Thrainer
  disk_count = len(instance.disks)
538 7352d33b Thomas Thrainer
  disk_sizes = [disk.size for disk in instance.disks]
539 7352d33b Thomas Thrainer
  nic_count = len(instance.nics)
540 7352d33b Thomas Thrainer
  disk_template = instance.disk_template
541 7352d33b Thomas Thrainer
542 7352d33b Thomas Thrainer
  return _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
543 7352d33b Thomas Thrainer
                     disk_sizes, spindle_use, disk_template)
544 7352d33b Thomas Thrainer
545 7352d33b Thomas Thrainer
546 7352d33b Thomas Thrainer
def _ComputeViolatingInstances(ipolicy, instances, cfg):
547 7352d33b Thomas Thrainer
  """Computes a set of instances who violates given ipolicy.
548 7352d33b Thomas Thrainer

549 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify
550 7352d33b Thomas Thrainer
  @type instances: L{objects.Instance}
551 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
552 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
553 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
554 7352d33b Thomas Thrainer
  @return: A frozenset of instance names violating the ipolicy
555 7352d33b Thomas Thrainer

556 7352d33b Thomas Thrainer
  """
557 7352d33b Thomas Thrainer
  return frozenset([inst.name for inst in instances
558 7352d33b Thomas Thrainer
                    if _ComputeIPolicyInstanceViolation(ipolicy, inst, cfg)])
559 7352d33b Thomas Thrainer
560 7352d33b Thomas Thrainer
561 7352d33b Thomas Thrainer
def _ComputeNewInstanceViolations(old_ipolicy, new_ipolicy, instances, cfg):
562 7352d33b Thomas Thrainer
  """Computes a set of any instances that would violate the new ipolicy.
563 7352d33b Thomas Thrainer

564 7352d33b Thomas Thrainer
  @param old_ipolicy: The current (still in-place) ipolicy
565 7352d33b Thomas Thrainer
  @param new_ipolicy: The new (to become) ipolicy
566 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
567 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
568 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
569 7352d33b Thomas Thrainer
  @return: A list of instances which violates the new ipolicy but
570 7352d33b Thomas Thrainer
      did not before
571 7352d33b Thomas Thrainer

572 7352d33b Thomas Thrainer
  """
573 7352d33b Thomas Thrainer
  return (_ComputeViolatingInstances(new_ipolicy, instances, cfg) -
574 7352d33b Thomas Thrainer
          _ComputeViolatingInstances(old_ipolicy, instances, cfg))
575 7352d33b Thomas Thrainer
576 7352d33b Thomas Thrainer
577 7352d33b Thomas Thrainer
def _GetUpdatedParams(old_params, update_dict,
578 7352d33b Thomas Thrainer
                      use_default=True, use_none=False):
579 7352d33b Thomas Thrainer
  """Return the new version of a parameter dictionary.
580 7352d33b Thomas Thrainer

581 7352d33b Thomas Thrainer
  @type old_params: dict
582 7352d33b Thomas Thrainer
  @param old_params: old parameters
583 7352d33b Thomas Thrainer
  @type update_dict: dict
584 7352d33b Thomas Thrainer
  @param update_dict: dict containing new parameter values, or
585 7352d33b Thomas Thrainer
      constants.VALUE_DEFAULT to reset the parameter to its default
586 7352d33b Thomas Thrainer
      value
587 7352d33b Thomas Thrainer
  @param use_default: boolean
588 7352d33b Thomas Thrainer
  @type use_default: whether to recognise L{constants.VALUE_DEFAULT}
589 7352d33b Thomas Thrainer
      values as 'to be deleted' values
590 7352d33b Thomas Thrainer
  @param use_none: boolean
591 7352d33b Thomas Thrainer
  @type use_none: whether to recognise C{None} values as 'to be
592 7352d33b Thomas Thrainer
      deleted' values
593 7352d33b Thomas Thrainer
  @rtype: dict
594 7352d33b Thomas Thrainer
  @return: the new parameter dictionary
595 7352d33b Thomas Thrainer

596 7352d33b Thomas Thrainer
  """
597 7352d33b Thomas Thrainer
  params_copy = copy.deepcopy(old_params)
598 7352d33b Thomas Thrainer
  for key, val in update_dict.iteritems():
599 7352d33b Thomas Thrainer
    if ((use_default and val == constants.VALUE_DEFAULT) or
600 7352d33b Thomas Thrainer
          (use_none and val is None)):
601 7352d33b Thomas Thrainer
      try:
602 7352d33b Thomas Thrainer
        del params_copy[key]
603 7352d33b Thomas Thrainer
      except KeyError:
604 7352d33b Thomas Thrainer
        pass
605 7352d33b Thomas Thrainer
    else:
606 7352d33b Thomas Thrainer
      params_copy[key] = val
607 7352d33b Thomas Thrainer
  return params_copy
608 7352d33b Thomas Thrainer
609 7352d33b Thomas Thrainer
610 7352d33b Thomas Thrainer
def _GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
611 7352d33b Thomas Thrainer
  """Return the new version of an instance policy.
612 7352d33b Thomas Thrainer

613 7352d33b Thomas Thrainer
  @param group_policy: whether this policy applies to a group and thus
614 7352d33b Thomas Thrainer
    we should support removal of policy entries
615 7352d33b Thomas Thrainer

616 7352d33b Thomas Thrainer
  """
617 7352d33b Thomas Thrainer
  ipolicy = copy.deepcopy(old_ipolicy)
618 7352d33b Thomas Thrainer
  for key, value in new_ipolicy.items():
619 7352d33b Thomas Thrainer
    if key not in constants.IPOLICY_ALL_KEYS:
620 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid key in new ipolicy: %s" % key,
621 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
622 7352d33b Thomas Thrainer
    if (not value or value == [constants.VALUE_DEFAULT] or
623 7352d33b Thomas Thrainer
            value == constants.VALUE_DEFAULT):
624 7352d33b Thomas Thrainer
      if group_policy:
625 7352d33b Thomas Thrainer
        if key in ipolicy:
626 7352d33b Thomas Thrainer
          del ipolicy[key]
627 7352d33b Thomas Thrainer
      else:
628 7352d33b Thomas Thrainer
        raise errors.OpPrereqError("Can't unset ipolicy attribute '%s'"
629 7352d33b Thomas Thrainer
                                   " on the cluster'" % key,
630 7352d33b Thomas Thrainer
                                   errors.ECODE_INVAL)
631 7352d33b Thomas Thrainer
    else:
632 7352d33b Thomas Thrainer
      if key in constants.IPOLICY_PARAMETERS:
633 7352d33b Thomas Thrainer
        # FIXME: we assume all such values are float
634 7352d33b Thomas Thrainer
        try:
635 7352d33b Thomas Thrainer
          ipolicy[key] = float(value)
636 7352d33b Thomas Thrainer
        except (TypeError, ValueError), err:
637 7352d33b Thomas Thrainer
          raise errors.OpPrereqError("Invalid value for attribute"
638 7352d33b Thomas Thrainer
                                     " '%s': '%s', error: %s" %
639 7352d33b Thomas Thrainer
                                     (key, value, err), errors.ECODE_INVAL)
640 7352d33b Thomas Thrainer
      elif key == constants.ISPECS_MINMAX:
641 7352d33b Thomas Thrainer
        for minmax in value:
642 7352d33b Thomas Thrainer
          for k in minmax.keys():
643 7352d33b Thomas Thrainer
            utils.ForceDictType(minmax[k], constants.ISPECS_PARAMETER_TYPES)
644 7352d33b Thomas Thrainer
        ipolicy[key] = value
645 7352d33b Thomas Thrainer
      elif key == constants.ISPECS_STD:
646 7352d33b Thomas Thrainer
        if group_policy:
647 7352d33b Thomas Thrainer
          msg = "%s cannot appear in group instance specs" % key
648 7352d33b Thomas Thrainer
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
649 7352d33b Thomas Thrainer
        ipolicy[key] = _GetUpdatedParams(old_ipolicy.get(key, {}), value,
650 7352d33b Thomas Thrainer
                                         use_none=False, use_default=False)
651 7352d33b Thomas Thrainer
        utils.ForceDictType(ipolicy[key], constants.ISPECS_PARAMETER_TYPES)
652 7352d33b Thomas Thrainer
      else:
653 7352d33b Thomas Thrainer
        # FIXME: we assume all others are lists; this should be redone
654 7352d33b Thomas Thrainer
        # in a nicer way
655 7352d33b Thomas Thrainer
        ipolicy[key] = list(value)
656 7352d33b Thomas Thrainer
  try:
657 7352d33b Thomas Thrainer
    objects.InstancePolicy.CheckParameterSyntax(ipolicy, not group_policy)
658 7352d33b Thomas Thrainer
  except errors.ConfigurationError, err:
659 7352d33b Thomas Thrainer
    raise errors.OpPrereqError("Invalid instance policy: %s" % err,
660 7352d33b Thomas Thrainer
                               errors.ECODE_INVAL)
661 7352d33b Thomas Thrainer
  return ipolicy
662 7352d33b Thomas Thrainer
663 7352d33b Thomas Thrainer
664 7352d33b Thomas Thrainer
def _AnnotateDiskParams(instance, devs, cfg):
665 7352d33b Thomas Thrainer
  """Little helper wrapper to the rpc annotation method.
666 7352d33b Thomas Thrainer

667 7352d33b Thomas Thrainer
  @param instance: The instance object
668 7352d33b Thomas Thrainer
  @type devs: List of L{objects.Disk}
669 7352d33b Thomas Thrainer
  @param devs: The root devices (not any of its children!)
670 7352d33b Thomas Thrainer
  @param cfg: The config object
671 7352d33b Thomas Thrainer
  @returns The annotated disk copies
672 7352d33b Thomas Thrainer
  @see L{rpc.AnnotateDiskParams}
673 7352d33b Thomas Thrainer

674 7352d33b Thomas Thrainer
  """
675 7352d33b Thomas Thrainer
  return rpc.AnnotateDiskParams(instance.disk_template, devs,
676 7352d33b Thomas Thrainer
                                cfg.GetInstanceDiskParams(instance))
677 7352d33b Thomas Thrainer
678 7352d33b Thomas Thrainer
679 7352d33b Thomas Thrainer
def _SupportsOob(cfg, node):
680 7352d33b Thomas Thrainer
  """Tells if node supports OOB.
681 7352d33b Thomas Thrainer

682 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
683 7352d33b Thomas Thrainer
  @param cfg: The cluster configuration
684 7352d33b Thomas Thrainer
  @type node: L{objects.Node}
685 7352d33b Thomas Thrainer
  @param node: The node
686 7352d33b Thomas Thrainer
  @return: The OOB script if supported or an empty string otherwise
687 7352d33b Thomas Thrainer

688 7352d33b Thomas Thrainer
  """
689 7352d33b Thomas Thrainer
  return cfg.GetNdParams(node)[constants.ND_OOB_PROGRAM]
690 7352d33b Thomas Thrainer
691 7352d33b Thomas Thrainer
692 7352d33b Thomas Thrainer
def _UpdateAndVerifySubDict(base, updates, type_check):
693 7352d33b Thomas Thrainer
  """Updates and verifies a dict with sub dicts of the same type.
694 7352d33b Thomas Thrainer

695 7352d33b Thomas Thrainer
  @param base: The dict with the old data
696 7352d33b Thomas Thrainer
  @param updates: The dict with the new data
697 7352d33b Thomas Thrainer
  @param type_check: Dict suitable to ForceDictType to verify correct types
698 7352d33b Thomas Thrainer
  @returns: A new dict with updated and verified values
699 7352d33b Thomas Thrainer

700 7352d33b Thomas Thrainer
  """
701 7352d33b Thomas Thrainer
  def fn(old, value):
702 7352d33b Thomas Thrainer
    new = _GetUpdatedParams(old, value)
703 7352d33b Thomas Thrainer
    utils.ForceDictType(new, type_check)
704 7352d33b Thomas Thrainer
    return new
705 7352d33b Thomas Thrainer
706 7352d33b Thomas Thrainer
  ret = copy.deepcopy(base)
707 7352d33b Thomas Thrainer
  ret.update(dict((key, fn(base.get(key, {}), value))
708 7352d33b Thomas Thrainer
                  for key, value in updates.items()))
709 7352d33b Thomas Thrainer
  return ret
710 7352d33b Thomas Thrainer
711 7352d33b Thomas Thrainer
712 7352d33b Thomas Thrainer
def _FilterVmNodes(lu, nodenames):
713 7352d33b Thomas Thrainer
  """Filters out non-vm_capable nodes from a list.
714 7352d33b Thomas Thrainer

715 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
716 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
717 7352d33b Thomas Thrainer
  @type nodenames: list
718 7352d33b Thomas Thrainer
  @param nodenames: the list of nodes on which we should check
719 7352d33b Thomas Thrainer
  @rtype: list
720 7352d33b Thomas Thrainer
  @return: the list of vm-capable nodes
721 7352d33b Thomas Thrainer

722 7352d33b Thomas Thrainer
  """
723 7352d33b Thomas Thrainer
  vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList())
724 7352d33b Thomas Thrainer
  return [name for name in nodenames if name not in vm_nodes]