Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / common.py @ 2ff6426b

History | View | Annotate | Download (46.7 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 07e3c124 Santi Raffa
from ganeti.serializer import Private
36 4869595d Petr Pudlak
import ganeti.rpc.node as rpc
37 7352d33b Thomas Thrainer
from ganeti import ssconf
38 37dc17e3 Thomas Thrainer
from ganeti import utils
39 1a732a74 Thomas Thrainer
40 1a732a74 Thomas Thrainer
41 31b836b8 Thomas Thrainer
# States of instance
42 31b836b8 Thomas Thrainer
INSTANCE_DOWN = [constants.ADMINST_DOWN]
43 31b836b8 Thomas Thrainer
INSTANCE_ONLINE = [constants.ADMINST_DOWN, constants.ADMINST_UP]
44 31b836b8 Thomas Thrainer
INSTANCE_NOT_RUNNING = [constants.ADMINST_DOWN, constants.ADMINST_OFFLINE]
45 31b836b8 Thomas Thrainer
46 31b836b8 Thomas Thrainer
#: Instance status in which an instance can be marked as offline/online
47 31b836b8 Thomas Thrainer
CAN_CHANGE_INSTANCE_OFFLINE = (frozenset(INSTANCE_DOWN) | frozenset([
48 31b836b8 Thomas Thrainer
  constants.ADMINST_OFFLINE,
49 31b836b8 Thomas Thrainer
  ]))
50 31b836b8 Thomas Thrainer
51 31b836b8 Thomas Thrainer
52 1c3231aa Thomas Thrainer
def _ExpandItemName(expand_fn, name, kind):
53 1a732a74 Thomas Thrainer
  """Expand an item name.
54 1a732a74 Thomas Thrainer

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

61 1a732a74 Thomas Thrainer
  """
62 738436bf Thomas Thrainer
  (uuid, full_name) = expand_fn(name)
63 738436bf Thomas Thrainer
  if uuid is None or full_name is None:
64 1a732a74 Thomas Thrainer
    raise errors.OpPrereqError("%s '%s' not known" % (kind, name),
65 1a732a74 Thomas Thrainer
                               errors.ECODE_NOENT)
66 738436bf Thomas Thrainer
  return (uuid, full_name)
67 1a732a74 Thomas Thrainer
68 1a732a74 Thomas Thrainer
69 da4a52a3 Thomas Thrainer
def ExpandInstanceUuidAndName(cfg, expected_uuid, name):
70 1a732a74 Thomas Thrainer
  """Wrapper over L{_ExpandItemName} for instance."""
71 da4a52a3 Thomas Thrainer
  (uuid, full_name) = _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
72 da4a52a3 Thomas Thrainer
  if expected_uuid is not None and uuid != expected_uuid:
73 da4a52a3 Thomas Thrainer
    raise errors.OpPrereqError(
74 da4a52a3 Thomas Thrainer
      "The instances UUID '%s' does not match the expected UUID '%s' for"
75 da4a52a3 Thomas Thrainer
      " instance '%s'. Maybe the instance changed since you submitted this"
76 da4a52a3 Thomas Thrainer
      " job." % (uuid, expected_uuid, full_name), errors.ECODE_NOTUNIQUE)
77 da4a52a3 Thomas Thrainer
  return (uuid, full_name)
78 1a732a74 Thomas Thrainer
79 1a732a74 Thomas Thrainer
80 1c3231aa Thomas Thrainer
def ExpandNodeUuidAndName(cfg, expected_uuid, name):
81 1c3231aa Thomas Thrainer
  """Expand a short node name into the node UUID and full name.
82 1c3231aa Thomas Thrainer

83 1c3231aa Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
84 1c3231aa Thomas Thrainer
  @param cfg: The cluster configuration
85 1c3231aa Thomas Thrainer
  @type expected_uuid: string
86 1c3231aa Thomas Thrainer
  @param expected_uuid: expected UUID for the node (or None if there is no
87 1c3231aa Thomas Thrainer
        expectation). If it does not match, a L{errors.OpPrereqError} is
88 1c3231aa Thomas Thrainer
        raised.
89 1c3231aa Thomas Thrainer
  @type name: string
90 1c3231aa Thomas Thrainer
  @param name: the short node name
91 1c3231aa Thomas Thrainer

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

105 fb3891d0 Thomas Thrainer
  """
106 fb3891d0 Thomas Thrainer
  return dict.fromkeys(locking.LEVELS, 1)
107 37dc17e3 Thomas Thrainer
108 37dc17e3 Thomas Thrainer
109 da4a52a3 Thomas Thrainer
def CheckNodeGroupInstances(cfg, group_uuid, owned_instance_names):
110 37dc17e3 Thomas Thrainer
  """Checks if the instances in a node group are still correct.
111 37dc17e3 Thomas Thrainer

112 37dc17e3 Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
113 37dc17e3 Thomas Thrainer
  @param cfg: The cluster configuration
114 37dc17e3 Thomas Thrainer
  @type group_uuid: string
115 37dc17e3 Thomas Thrainer
  @param group_uuid: Node group UUID
116 da4a52a3 Thomas Thrainer
  @type owned_instance_names: set or frozenset
117 da4a52a3 Thomas Thrainer
  @param owned_instance_names: List of currently owned instances
118 37dc17e3 Thomas Thrainer

119 37dc17e3 Thomas Thrainer
  """
120 da4a52a3 Thomas Thrainer
  wanted_instances = frozenset(cfg.GetInstanceNames(
121 da4a52a3 Thomas Thrainer
                                 cfg.GetNodeGroupInstances(group_uuid)))
122 da4a52a3 Thomas Thrainer
  if owned_instance_names != wanted_instances:
123 37dc17e3 Thomas Thrainer
    raise errors.OpPrereqError("Instances in node group '%s' changed since"
124 37dc17e3 Thomas Thrainer
                               " locks were acquired, wanted '%s', have '%s';"
125 37dc17e3 Thomas Thrainer
                               " retry the operation" %
126 37dc17e3 Thomas Thrainer
                               (group_uuid,
127 37dc17e3 Thomas Thrainer
                                utils.CommaJoin(wanted_instances),
128 da4a52a3 Thomas Thrainer
                                utils.CommaJoin(owned_instance_names)),
129 37dc17e3 Thomas Thrainer
                               errors.ECODE_STATE)
130 37dc17e3 Thomas Thrainer
131 37dc17e3 Thomas Thrainer
  return wanted_instances
132 1d870e0d Thomas Thrainer
133 1d870e0d Thomas Thrainer
134 1c3231aa Thomas Thrainer
def GetWantedNodes(lu, short_node_names):
135 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded node names.
136 1d870e0d Thomas Thrainer

137 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
138 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
139 1c3231aa Thomas Thrainer
  @type short_node_names: list
140 1c3231aa Thomas Thrainer
  @param short_node_names: list of node names or None for all nodes
141 1c3231aa Thomas Thrainer
  @rtype: tuple of lists
142 1c3231aa Thomas Thrainer
  @return: tupe with (list of node UUIDs, list of node names)
143 1d870e0d Thomas Thrainer
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
144 1d870e0d Thomas Thrainer

145 1d870e0d Thomas Thrainer
  """
146 1c3231aa Thomas Thrainer
  if short_node_names:
147 1c3231aa Thomas Thrainer
    node_uuids = [ExpandNodeUuidAndName(lu.cfg, None, name)[0]
148 1c3231aa Thomas Thrainer
                  for name in short_node_names]
149 1c3231aa Thomas Thrainer
  else:
150 1c3231aa Thomas Thrainer
    node_uuids = lu.cfg.GetNodeList()
151 1d870e0d Thomas Thrainer
152 b691385f Thomas Thrainer
  return (node_uuids, [lu.cfg.GetNodeName(uuid) for uuid in node_uuids])
153 1d870e0d Thomas Thrainer
154 1d870e0d Thomas Thrainer
155 da4a52a3 Thomas Thrainer
def GetWantedInstances(lu, short_inst_names):
156 1d870e0d Thomas Thrainer
  """Returns list of checked and expanded instance names.
157 1d870e0d Thomas Thrainer

158 1d870e0d Thomas Thrainer
  @type lu: L{LogicalUnit}
159 1d870e0d Thomas Thrainer
  @param lu: the logical unit on whose behalf we execute
160 da4a52a3 Thomas Thrainer
  @type short_inst_names: list
161 da4a52a3 Thomas Thrainer
  @param short_inst_names: list of instance names or None for all instances
162 da4a52a3 Thomas Thrainer
  @rtype: tuple of lists
163 da4a52a3 Thomas Thrainer
  @return: tuple of (instance UUIDs, instance names)
164 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if the instances parameter is wrong type
165 1d870e0d Thomas Thrainer
  @raise errors.OpPrereqError: if any of the passed instances is not found
166 1d870e0d Thomas Thrainer

167 1d870e0d Thomas Thrainer
  """
168 da4a52a3 Thomas Thrainer
  if short_inst_names:
169 da4a52a3 Thomas Thrainer
    inst_uuids = [ExpandInstanceUuidAndName(lu.cfg, None, name)[0]
170 da4a52a3 Thomas Thrainer
                  for name in short_inst_names]
171 1d870e0d Thomas Thrainer
  else:
172 da4a52a3 Thomas Thrainer
    inst_uuids = lu.cfg.GetInstanceList()
173 da4a52a3 Thomas Thrainer
  return (inst_uuids, [lu.cfg.GetInstanceName(uuid) for uuid in inst_uuids])
174 7352d33b Thomas Thrainer
175 7352d33b Thomas Thrainer
176 5eacbcae Thomas Thrainer
def RunPostHook(lu, node_name):
177 7352d33b Thomas Thrainer
  """Runs the post-hook for an opcode on a single node.
178 7352d33b Thomas Thrainer

179 7352d33b Thomas Thrainer
  """
180 7352d33b Thomas Thrainer
  hm = lu.proc.BuildHooksManager(lu)
181 7352d33b Thomas Thrainer
  try:
182 d0d7d7cf Thomas Thrainer
    hm.RunPhase(constants.HOOKS_PHASE_POST, node_names=[node_name])
183 7352d33b Thomas Thrainer
  except Exception, err: # pylint: disable=W0703
184 7352d33b Thomas Thrainer
    lu.LogWarning("Errors occurred running hooks on %s: %s",
185 7352d33b Thomas Thrainer
                  node_name, err)
186 7352d33b Thomas Thrainer
187 7352d33b Thomas Thrainer
188 1c3231aa Thomas Thrainer
def RedistributeAncillaryFiles(lu):
189 7352d33b Thomas Thrainer
  """Distribute additional files which are part of the cluster configuration.
190 7352d33b Thomas Thrainer

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

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

233 7352d33b Thomas Thrainer
  @type redist: boolean
234 7352d33b Thomas Thrainer
  @param redist: Whether to include files which need to be redistributed
235 7352d33b Thomas Thrainer

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

312 7352d33b Thomas Thrainer
  """
313 7352d33b Thomas Thrainer
  if os.path.exists(fname):
314 1c3231aa Thomas Thrainer
    result = lu.rpc.call_upload_file(node_uuids, fname)
315 1c3231aa Thomas Thrainer
    for to_node_uuids, to_result in result.items():
316 7352d33b Thomas Thrainer
      msg = to_result.fail_msg
317 7352d33b Thomas Thrainer
      if msg:
318 7352d33b Thomas Thrainer
        msg = ("Copy of file %s to node %s failed: %s" %
319 1c3231aa Thomas Thrainer
               (fname, lu.cfg.GetNodeName(to_node_uuids), msg))
320 7352d33b Thomas Thrainer
        lu.LogWarning(msg)
321 7352d33b Thomas Thrainer
322 7352d33b Thomas Thrainer
323 5eacbcae Thomas Thrainer
def MergeAndVerifyHvState(op_input, obj_input):
324 7352d33b Thomas Thrainer
  """Combines the hv state from an opcode with the one of the object
325 7352d33b Thomas Thrainer

326 7352d33b Thomas Thrainer
  @param op_input: The input dict from the opcode
327 7352d33b Thomas Thrainer
  @param obj_input: The input dict from the objects
328 7352d33b Thomas Thrainer
  @return: The verified and updated dict
329 7352d33b Thomas Thrainer

330 7352d33b Thomas Thrainer
  """
331 7352d33b Thomas Thrainer
  if op_input:
332 7352d33b Thomas Thrainer
    invalid_hvs = set(op_input) - constants.HYPER_TYPES
333 7352d33b Thomas Thrainer
    if invalid_hvs:
334 7352d33b Thomas Thrainer
      raise errors.OpPrereqError("Invalid hypervisor(s) in hypervisor state:"
335 7352d33b Thomas Thrainer
                                 " %s" % utils.CommaJoin(invalid_hvs),
336 7352d33b Thomas Thrainer
                                 errors.ECODE_INVAL)
337 7352d33b Thomas Thrainer
    if obj_input is None:
338 7352d33b Thomas Thrainer
      obj_input = {}
339 7352d33b Thomas Thrainer
    type_check = constants.HVSTS_PARAMETER_TYPES
340 7352d33b Thomas Thrainer
    return _UpdateAndVerifySubDict(obj_input, op_input, type_check)
341 7352d33b Thomas Thrainer
342 7352d33b Thomas Thrainer
  return None
343 7352d33b Thomas Thrainer
344 7352d33b Thomas Thrainer
345 5eacbcae Thomas Thrainer
def MergeAndVerifyDiskState(op_input, obj_input):
346 7352d33b Thomas Thrainer
  """Combines the disk state from an opcode with the one of the object
347 7352d33b Thomas Thrainer

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

371 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
372 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
373 7352d33b Thomas Thrainer
  @type required: boolean
374 7352d33b Thomas Thrainer
  @param required: whether the validation should fail if the OS is not
375 7352d33b Thomas Thrainer
      found
376 1c3231aa Thomas Thrainer
  @type node_uuids: list
377 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
378 7352d33b Thomas Thrainer
  @type osname: string
379 7352d33b Thomas Thrainer
  @param osname: the name of the hypervisor we should use
380 7352d33b Thomas Thrainer
  @type osparams: dict
381 7352d33b Thomas Thrainer
  @param osparams: the parameters which we need to check
382 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
383 7352d33b Thomas Thrainer

384 7352d33b Thomas Thrainer
  """
385 1c3231aa Thomas Thrainer
  node_uuids = _FilterVmNodes(lu, node_uuids)
386 07e3c124 Santi Raffa
387 07e3c124 Santi Raffa
  # Last chance to unwrap private elements.
388 07e3c124 Santi Raffa
  for key in osparams:
389 07e3c124 Santi Raffa
    if isinstance(osparams[key], Private):
390 07e3c124 Santi Raffa
      osparams[key] = osparams[key].Get()
391 07e3c124 Santi Raffa
392 1c3231aa Thomas Thrainer
  result = lu.rpc.call_os_validate(node_uuids, required, osname,
393 7352d33b Thomas Thrainer
                                   [constants.OS_VALIDATE_PARAMETERS],
394 7352d33b Thomas Thrainer
                                   osparams)
395 1c3231aa Thomas Thrainer
  for node_uuid, nres in result.items():
396 7352d33b Thomas Thrainer
    # we don't check for offline cases since this should be run only
397 7352d33b Thomas Thrainer
    # against the master node and/or an instance's nodes
398 1c3231aa Thomas Thrainer
    nres.Raise("OS Parameters validation failed on node %s" %
399 1c3231aa Thomas Thrainer
               lu.cfg.GetNodeName(node_uuid))
400 7352d33b Thomas Thrainer
    if not nres.payload:
401 7352d33b Thomas Thrainer
      lu.LogInfo("OS %s not found on node %s, validation skipped",
402 1c3231aa Thomas Thrainer
                 osname, lu.cfg.GetNodeName(node_uuid))
403 7352d33b Thomas Thrainer
404 7352d33b Thomas Thrainer
405 1c3231aa Thomas Thrainer
def CheckHVParams(lu, node_uuids, hvname, hvparams):
406 7352d33b Thomas Thrainer
  """Hypervisor parameter validation.
407 7352d33b Thomas Thrainer

408 7352d33b Thomas Thrainer
  This function abstract the hypervisor parameter validation to be
409 7352d33b Thomas Thrainer
  used in both instance create and instance modify.
410 7352d33b Thomas Thrainer

411 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
412 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
413 1c3231aa Thomas Thrainer
  @type node_uuids: list
414 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
415 7352d33b Thomas Thrainer
  @type hvname: string
416 7352d33b Thomas Thrainer
  @param hvname: the name of the hypervisor we should use
417 7352d33b Thomas Thrainer
  @type hvparams: dict
418 7352d33b Thomas Thrainer
  @param hvparams: the parameters which we need to check
419 7352d33b Thomas Thrainer
  @raise errors.OpPrereqError: if the parameters are not valid
420 7352d33b Thomas Thrainer

421 7352d33b Thomas Thrainer
  """
422 1c3231aa Thomas Thrainer
  node_uuids = _FilterVmNodes(lu, node_uuids)
423 7352d33b Thomas Thrainer
424 7352d33b Thomas Thrainer
  cluster = lu.cfg.GetClusterInfo()
425 7352d33b Thomas Thrainer
  hvfull = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
426 7352d33b Thomas Thrainer
427 1c3231aa Thomas Thrainer
  hvinfo = lu.rpc.call_hypervisor_validate_params(node_uuids, hvname, hvfull)
428 1c3231aa Thomas Thrainer
  for node_uuid in node_uuids:
429 1c3231aa Thomas Thrainer
    info = hvinfo[node_uuid]
430 7352d33b Thomas Thrainer
    if info.offline:
431 7352d33b Thomas Thrainer
      continue
432 1c3231aa Thomas Thrainer
    info.Raise("Hypervisor parameter validation failed on node %s" %
433 1c3231aa Thomas Thrainer
               lu.cfg.GetNodeName(node_uuid))
434 7352d33b Thomas Thrainer
435 7352d33b Thomas Thrainer
436 c1410048 Helga Velroyen
def AdjustCandidatePool(lu, exceptions, feedback_fn):
437 7352d33b Thomas Thrainer
  """Adjust the candidate pool after node operations.
438 7352d33b Thomas Thrainer

439 7352d33b Thomas Thrainer
  """
440 7352d33b Thomas Thrainer
  mod_list = lu.cfg.MaintainCandidatePool(exceptions)
441 7352d33b Thomas Thrainer
  if mod_list:
442 7352d33b Thomas Thrainer
    lu.LogInfo("Promoted nodes to master candidate role: %s",
443 7352d33b Thomas Thrainer
               utils.CommaJoin(node.name for node in mod_list))
444 1c3231aa Thomas Thrainer
    for node in mod_list:
445 1c3231aa Thomas Thrainer
      lu.context.ReaddNode(node)
446 c1410048 Helga Velroyen
      cluster = lu.cfg.GetClusterInfo()
447 c1410048 Helga Velroyen
      AddNodeCertToCandidateCerts(lu, node.uuid, cluster)
448 c1410048 Helga Velroyen
      lu.cfg.Update(cluster, feedback_fn)
449 7352d33b Thomas Thrainer
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
450 7352d33b Thomas Thrainer
  if mc_now > mc_max:
451 7352d33b Thomas Thrainer
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
452 7352d33b Thomas Thrainer
               (mc_now, mc_max))
453 7352d33b Thomas Thrainer
454 7352d33b Thomas Thrainer
455 5eacbcae Thomas Thrainer
def CheckNodePVs(nresult, exclusive_storage):
456 7352d33b Thomas Thrainer
  """Check node PVs.
457 7352d33b Thomas Thrainer

458 7352d33b Thomas Thrainer
  """
459 7352d33b Thomas Thrainer
  pvlist_dict = nresult.get(constants.NV_PVLIST, None)
460 7352d33b Thomas Thrainer
  if pvlist_dict is None:
461 7352d33b Thomas Thrainer
    return (["Can't get PV list from node"], None)
462 7352d33b Thomas Thrainer
  pvlist = map(objects.LvmPvInfo.FromDict, pvlist_dict)
463 7352d33b Thomas Thrainer
  errlist = []
464 7352d33b Thomas Thrainer
  # check that ':' is not present in PV names, since it's a
465 7352d33b Thomas Thrainer
  # special character for lvcreate (denotes the range of PEs to
466 7352d33b Thomas Thrainer
  # use on the PV)
467 7352d33b Thomas Thrainer
  for pv in pvlist:
468 7352d33b Thomas Thrainer
    if ":" in pv.name:
469 7352d33b Thomas Thrainer
      errlist.append("Invalid character ':' in PV '%s' of VG '%s'" %
470 7352d33b Thomas Thrainer
                     (pv.name, pv.vg_name))
471 7352d33b Thomas Thrainer
  es_pvinfo = None
472 7352d33b Thomas Thrainer
  if exclusive_storage:
473 7352d33b Thomas Thrainer
    (errmsgs, es_pvinfo) = utils.LvmExclusiveCheckNodePvs(pvlist)
474 7352d33b Thomas Thrainer
    errlist.extend(errmsgs)
475 7352d33b Thomas Thrainer
    shared_pvs = nresult.get(constants.NV_EXCLUSIVEPVS, None)
476 7352d33b Thomas Thrainer
    if shared_pvs:
477 7352d33b Thomas Thrainer
      for (pvname, lvlist) in shared_pvs:
478 7352d33b Thomas Thrainer
        # TODO: Check that LVs are really unrelated (snapshots, DRBD meta...)
479 7352d33b Thomas Thrainer
        errlist.append("PV %s is shared among unrelated LVs (%s)" %
480 7352d33b Thomas Thrainer
                       (pvname, utils.CommaJoin(lvlist)))
481 7352d33b Thomas Thrainer
  return (errlist, es_pvinfo)
482 7352d33b Thomas Thrainer
483 7352d33b Thomas Thrainer
484 7352d33b Thomas Thrainer
def _ComputeMinMaxSpec(name, qualifier, ispecs, value):
485 7352d33b Thomas Thrainer
  """Computes if value is in the desired range.
486 7352d33b Thomas Thrainer

487 7352d33b Thomas Thrainer
  @param name: name of the parameter for which we perform the check
488 7352d33b Thomas Thrainer
  @param qualifier: a qualifier used in the error message (e.g. 'disk/1',
489 7352d33b Thomas Thrainer
      not just 'disk')
490 7352d33b Thomas Thrainer
  @param ispecs: dictionary containing min and max values
491 7352d33b Thomas Thrainer
  @param value: actual value that we want to use
492 7352d33b Thomas Thrainer
  @return: None or an error string
493 7352d33b Thomas Thrainer

494 7352d33b Thomas Thrainer
  """
495 7352d33b Thomas Thrainer
  if value in [None, constants.VALUE_AUTO]:
496 7352d33b Thomas Thrainer
    return None
497 7352d33b Thomas Thrainer
  max_v = ispecs[constants.ISPECS_MAX].get(name, value)
498 7352d33b Thomas Thrainer
  min_v = ispecs[constants.ISPECS_MIN].get(name, value)
499 7352d33b Thomas Thrainer
  if value > max_v or min_v > value:
500 7352d33b Thomas Thrainer
    if qualifier:
501 7352d33b Thomas Thrainer
      fqn = "%s/%s" % (name, qualifier)
502 7352d33b Thomas Thrainer
    else:
503 7352d33b Thomas Thrainer
      fqn = name
504 7352d33b Thomas Thrainer
    return ("%s value %s is not in range [%s, %s]" %
505 7352d33b Thomas Thrainer
            (fqn, value, min_v, max_v))
506 7352d33b Thomas Thrainer
  return None
507 7352d33b Thomas Thrainer
508 7352d33b Thomas Thrainer
509 5eacbcae Thomas Thrainer
def ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
510 5eacbcae Thomas Thrainer
                                nic_count, disk_sizes, spindle_use,
511 5eacbcae Thomas Thrainer
                                disk_template,
512 5eacbcae Thomas Thrainer
                                _compute_fn=_ComputeMinMaxSpec):
513 7352d33b Thomas Thrainer
  """Verifies ipolicy against provided specs.
514 7352d33b Thomas Thrainer

515 7352d33b Thomas Thrainer
  @type ipolicy: dict
516 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy
517 7352d33b Thomas Thrainer
  @type mem_size: int
518 7352d33b Thomas Thrainer
  @param mem_size: The memory size
519 7352d33b Thomas Thrainer
  @type cpu_count: int
520 7352d33b Thomas Thrainer
  @param cpu_count: Used cpu cores
521 7352d33b Thomas Thrainer
  @type disk_count: int
522 7352d33b Thomas Thrainer
  @param disk_count: Number of disks used
523 7352d33b Thomas Thrainer
  @type nic_count: int
524 7352d33b Thomas Thrainer
  @param nic_count: Number of nics used
525 7352d33b Thomas Thrainer
  @type disk_sizes: list of ints
526 7352d33b Thomas Thrainer
  @param disk_sizes: Disk sizes of used disk (len must match C{disk_count})
527 7352d33b Thomas Thrainer
  @type spindle_use: int
528 7352d33b Thomas Thrainer
  @param spindle_use: The number of spindles this instance uses
529 7352d33b Thomas Thrainer
  @type disk_template: string
530 7352d33b Thomas Thrainer
  @param disk_template: The disk template of the instance
531 7352d33b Thomas Thrainer
  @param _compute_fn: The compute function (unittest only)
532 7352d33b Thomas Thrainer
  @return: A list of violations, or an empty list of no violations are found
533 7352d33b Thomas Thrainer

534 7352d33b Thomas Thrainer
  """
535 7352d33b Thomas Thrainer
  assert disk_count == len(disk_sizes)
536 7352d33b Thomas Thrainer
537 7352d33b Thomas Thrainer
  test_settings = [
538 7352d33b Thomas Thrainer
    (constants.ISPEC_MEM_SIZE, "", mem_size),
539 7352d33b Thomas Thrainer
    (constants.ISPEC_CPU_COUNT, "", cpu_count),
540 7352d33b Thomas Thrainer
    (constants.ISPEC_NIC_COUNT, "", nic_count),
541 7352d33b Thomas Thrainer
    (constants.ISPEC_SPINDLE_USE, "", spindle_use),
542 7352d33b Thomas Thrainer
    ] + [(constants.ISPEC_DISK_SIZE, str(idx), d)
543 7352d33b Thomas Thrainer
         for idx, d in enumerate(disk_sizes)]
544 7352d33b Thomas Thrainer
  if disk_template != constants.DT_DISKLESS:
545 7352d33b Thomas Thrainer
    # This check doesn't make sense for diskless instances
546 7352d33b Thomas Thrainer
    test_settings.append((constants.ISPEC_DISK_COUNT, "", disk_count))
547 7352d33b Thomas Thrainer
  ret = []
548 7352d33b Thomas Thrainer
  allowed_dts = ipolicy[constants.IPOLICY_DTS]
549 7352d33b Thomas Thrainer
  if disk_template not in allowed_dts:
550 7352d33b Thomas Thrainer
    ret.append("Disk template %s is not allowed (allowed templates: %s)" %
551 7352d33b Thomas Thrainer
               (disk_template, utils.CommaJoin(allowed_dts)))
552 7352d33b Thomas Thrainer
553 7352d33b Thomas Thrainer
  min_errs = None
554 7352d33b Thomas Thrainer
  for minmax in ipolicy[constants.ISPECS_MINMAX]:
555 7352d33b Thomas Thrainer
    errs = filter(None,
556 7352d33b Thomas Thrainer
                  (_compute_fn(name, qualifier, minmax, value)
557 7352d33b Thomas Thrainer
                   for (name, qualifier, value) in test_settings))
558 7352d33b Thomas Thrainer
    if min_errs is None or len(errs) < len(min_errs):
559 7352d33b Thomas Thrainer
      min_errs = errs
560 7352d33b Thomas Thrainer
  assert min_errs is not None
561 7352d33b Thomas Thrainer
  return ret + min_errs
562 7352d33b Thomas Thrainer
563 7352d33b Thomas Thrainer
564 5eacbcae Thomas Thrainer
def ComputeIPolicyInstanceViolation(ipolicy, instance, cfg,
565 5eacbcae Thomas Thrainer
                                    _compute_fn=ComputeIPolicySpecViolation):
566 7352d33b Thomas Thrainer
  """Compute if instance meets the specs of ipolicy.
567 7352d33b Thomas Thrainer

568 7352d33b Thomas Thrainer
  @type ipolicy: dict
569 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify against
570 7352d33b Thomas Thrainer
  @type instance: L{objects.Instance}
571 7352d33b Thomas Thrainer
  @param instance: The instance to verify
572 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
573 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
574 7352d33b Thomas Thrainer
  @param _compute_fn: The function to verify ipolicy (unittest only)
575 5eacbcae Thomas Thrainer
  @see: L{ComputeIPolicySpecViolation}
576 7352d33b Thomas Thrainer

577 7352d33b Thomas Thrainer
  """
578 5a13489b Bernardo Dal Seno
  ret = []
579 7352d33b Thomas Thrainer
  be_full = cfg.GetClusterInfo().FillBE(instance)
580 7352d33b Thomas Thrainer
  mem_size = be_full[constants.BE_MAXMEM]
581 7352d33b Thomas Thrainer
  cpu_count = be_full[constants.BE_VCPUS]
582 1c3231aa Thomas Thrainer
  es_flags = rpc.GetExclusiveStorageForNodes(cfg, instance.all_nodes)
583 5a13489b Bernardo Dal Seno
  if any(es_flags.values()):
584 5a13489b Bernardo Dal Seno
    # With exclusive storage use the actual spindles
585 5a13489b Bernardo Dal Seno
    try:
586 5a13489b Bernardo Dal Seno
      spindle_use = sum([disk.spindles for disk in instance.disks])
587 5a13489b Bernardo Dal Seno
    except TypeError:
588 5a13489b Bernardo Dal Seno
      ret.append("Number of spindles not configured for disks of instance %s"
589 5a13489b Bernardo Dal Seno
                 " while exclusive storage is enabled, try running gnt-cluster"
590 5a13489b Bernardo Dal Seno
                 " repair-disk-sizes" % instance.name)
591 5a13489b Bernardo Dal Seno
      # _ComputeMinMaxSpec ignores 'None's
592 5a13489b Bernardo Dal Seno
      spindle_use = None
593 5a13489b Bernardo Dal Seno
  else:
594 5a13489b Bernardo Dal Seno
    spindle_use = be_full[constants.BE_SPINDLE_USE]
595 7352d33b Thomas Thrainer
  disk_count = len(instance.disks)
596 7352d33b Thomas Thrainer
  disk_sizes = [disk.size for disk in instance.disks]
597 7352d33b Thomas Thrainer
  nic_count = len(instance.nics)
598 7352d33b Thomas Thrainer
  disk_template = instance.disk_template
599 7352d33b Thomas Thrainer
600 5a13489b Bernardo Dal Seno
  return ret + _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
601 5a13489b Bernardo Dal Seno
                           disk_sizes, spindle_use, disk_template)
602 7352d33b Thomas Thrainer
603 7352d33b Thomas Thrainer
604 7352d33b Thomas Thrainer
def _ComputeViolatingInstances(ipolicy, instances, cfg):
605 7352d33b Thomas Thrainer
  """Computes a set of instances who violates given ipolicy.
606 7352d33b Thomas Thrainer

607 7352d33b Thomas Thrainer
  @param ipolicy: The ipolicy to verify
608 7352d33b Thomas Thrainer
  @type instances: L{objects.Instance}
609 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
610 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
611 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
612 7352d33b Thomas Thrainer
  @return: A frozenset of instance names violating the ipolicy
613 7352d33b Thomas Thrainer

614 7352d33b Thomas Thrainer
  """
615 7352d33b Thomas Thrainer
  return frozenset([inst.name for inst in instances
616 5eacbcae Thomas Thrainer
                    if ComputeIPolicyInstanceViolation(ipolicy, inst, cfg)])
617 7352d33b Thomas Thrainer
618 7352d33b Thomas Thrainer
619 5eacbcae Thomas Thrainer
def ComputeNewInstanceViolations(old_ipolicy, new_ipolicy, instances, cfg):
620 7352d33b Thomas Thrainer
  """Computes a set of any instances that would violate the new ipolicy.
621 7352d33b Thomas Thrainer

622 7352d33b Thomas Thrainer
  @param old_ipolicy: The current (still in-place) ipolicy
623 7352d33b Thomas Thrainer
  @param new_ipolicy: The new (to become) ipolicy
624 7352d33b Thomas Thrainer
  @param instances: List of instances to verify
625 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
626 7352d33b Thomas Thrainer
  @param cfg: Cluster configuration
627 7352d33b Thomas Thrainer
  @return: A list of instances which violates the new ipolicy but
628 7352d33b Thomas Thrainer
      did not before
629 7352d33b Thomas Thrainer

630 7352d33b Thomas Thrainer
  """
631 7352d33b Thomas Thrainer
  return (_ComputeViolatingInstances(new_ipolicy, instances, cfg) -
632 7352d33b Thomas Thrainer
          _ComputeViolatingInstances(old_ipolicy, instances, cfg))
633 7352d33b Thomas Thrainer
634 7352d33b Thomas Thrainer
635 5eacbcae Thomas Thrainer
def GetUpdatedParams(old_params, update_dict,
636 7352d33b Thomas Thrainer
                      use_default=True, use_none=False):
637 7352d33b Thomas Thrainer
  """Return the new version of a parameter dictionary.
638 7352d33b Thomas Thrainer

639 7352d33b Thomas Thrainer
  @type old_params: dict
640 7352d33b Thomas Thrainer
  @param old_params: old parameters
641 7352d33b Thomas Thrainer
  @type update_dict: dict
642 7352d33b Thomas Thrainer
  @param update_dict: dict containing new parameter values, or
643 7352d33b Thomas Thrainer
      constants.VALUE_DEFAULT to reset the parameter to its default
644 7352d33b Thomas Thrainer
      value
645 7352d33b Thomas Thrainer
  @param use_default: boolean
646 7352d33b Thomas Thrainer
  @type use_default: whether to recognise L{constants.VALUE_DEFAULT}
647 7352d33b Thomas Thrainer
      values as 'to be deleted' values
648 7352d33b Thomas Thrainer
  @param use_none: boolean
649 7352d33b Thomas Thrainer
  @type use_none: whether to recognise C{None} values as 'to be
650 7352d33b Thomas Thrainer
      deleted' values
651 7352d33b Thomas Thrainer
  @rtype: dict
652 7352d33b Thomas Thrainer
  @return: the new parameter dictionary
653 7352d33b Thomas Thrainer

654 7352d33b Thomas Thrainer
  """
655 7352d33b Thomas Thrainer
  params_copy = copy.deepcopy(old_params)
656 7352d33b Thomas Thrainer
  for key, val in update_dict.iteritems():
657 7352d33b Thomas Thrainer
    if ((use_default and val == constants.VALUE_DEFAULT) or
658 7352d33b Thomas Thrainer
          (use_none and val is None)):
659 7352d33b Thomas Thrainer
      try:
660 7352d33b Thomas Thrainer
        del params_copy[key]
661 7352d33b Thomas Thrainer
      except KeyError:
662 7352d33b Thomas Thrainer
        pass
663 7352d33b Thomas Thrainer
    else:
664 7352d33b Thomas Thrainer
      params_copy[key] = val
665 7352d33b Thomas Thrainer
  return params_copy
666 7352d33b Thomas Thrainer
667 7352d33b Thomas Thrainer
668 5eacbcae Thomas Thrainer
def GetUpdatedIPolicy(old_ipolicy, new_ipolicy, group_policy=False):
669 7352d33b Thomas Thrainer
  """Return the new version of an instance policy.
670 7352d33b Thomas Thrainer

671 7352d33b Thomas Thrainer
  @param group_policy: whether this policy applies to a group and thus
672 7352d33b Thomas Thrainer
    we should support removal of policy entries
673 7352d33b Thomas Thrainer

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

725 7352d33b Thomas Thrainer
  @param instance: The instance object
726 7352d33b Thomas Thrainer
  @type devs: List of L{objects.Disk}
727 7352d33b Thomas Thrainer
  @param devs: The root devices (not any of its children!)
728 7352d33b Thomas Thrainer
  @param cfg: The config object
729 7352d33b Thomas Thrainer
  @returns The annotated disk copies
730 4e745e62 Santi Raffa
  @see L{rpc.node.AnnotateDiskParams}
731 7352d33b Thomas Thrainer

732 7352d33b Thomas Thrainer
  """
733 0c3d9c7c Thomas Thrainer
  return rpc.AnnotateDiskParams(devs, cfg.GetInstanceDiskParams(instance))
734 7352d33b Thomas Thrainer
735 7352d33b Thomas Thrainer
736 5eacbcae Thomas Thrainer
def SupportsOob(cfg, node):
737 7352d33b Thomas Thrainer
  """Tells if node supports OOB.
738 7352d33b Thomas Thrainer

739 7352d33b Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
740 7352d33b Thomas Thrainer
  @param cfg: The cluster configuration
741 7352d33b Thomas Thrainer
  @type node: L{objects.Node}
742 7352d33b Thomas Thrainer
  @param node: The node
743 7352d33b Thomas Thrainer
  @return: The OOB script if supported or an empty string otherwise
744 7352d33b Thomas Thrainer

745 7352d33b Thomas Thrainer
  """
746 7352d33b Thomas Thrainer
  return cfg.GetNdParams(node)[constants.ND_OOB_PROGRAM]
747 7352d33b Thomas Thrainer
748 7352d33b Thomas Thrainer
749 7352d33b Thomas Thrainer
def _UpdateAndVerifySubDict(base, updates, type_check):
750 7352d33b Thomas Thrainer
  """Updates and verifies a dict with sub dicts of the same type.
751 7352d33b Thomas Thrainer

752 7352d33b Thomas Thrainer
  @param base: The dict with the old data
753 7352d33b Thomas Thrainer
  @param updates: The dict with the new data
754 7352d33b Thomas Thrainer
  @param type_check: Dict suitable to ForceDictType to verify correct types
755 7352d33b Thomas Thrainer
  @returns: A new dict with updated and verified values
756 7352d33b Thomas Thrainer

757 7352d33b Thomas Thrainer
  """
758 7352d33b Thomas Thrainer
  def fn(old, value):
759 5eacbcae Thomas Thrainer
    new = GetUpdatedParams(old, value)
760 7352d33b Thomas Thrainer
    utils.ForceDictType(new, type_check)
761 7352d33b Thomas Thrainer
    return new
762 7352d33b Thomas Thrainer
763 7352d33b Thomas Thrainer
  ret = copy.deepcopy(base)
764 7352d33b Thomas Thrainer
  ret.update(dict((key, fn(base.get(key, {}), value))
765 7352d33b Thomas Thrainer
                  for key, value in updates.items()))
766 7352d33b Thomas Thrainer
  return ret
767 7352d33b Thomas Thrainer
768 7352d33b Thomas Thrainer
769 1c3231aa Thomas Thrainer
def _FilterVmNodes(lu, node_uuids):
770 7352d33b Thomas Thrainer
  """Filters out non-vm_capable nodes from a list.
771 7352d33b Thomas Thrainer

772 7352d33b Thomas Thrainer
  @type lu: L{LogicalUnit}
773 7352d33b Thomas Thrainer
  @param lu: the logical unit for which we check
774 1c3231aa Thomas Thrainer
  @type node_uuids: list
775 1c3231aa Thomas Thrainer
  @param node_uuids: the list of nodes on which we should check
776 7352d33b Thomas Thrainer
  @rtype: list
777 7352d33b Thomas Thrainer
  @return: the list of vm-capable nodes
778 7352d33b Thomas Thrainer

779 7352d33b Thomas Thrainer
  """
780 7352d33b Thomas Thrainer
  vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList())
781 1c3231aa Thomas Thrainer
  return [uuid for uuid in node_uuids if uuid not in vm_nodes]
782 f380d53c Thomas Thrainer
783 f380d53c Thomas Thrainer
784 5eacbcae Thomas Thrainer
def GetDefaultIAllocator(cfg, ialloc):
785 f380d53c Thomas Thrainer
  """Decides on which iallocator to use.
786 f380d53c Thomas Thrainer

787 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
788 f380d53c Thomas Thrainer
  @param cfg: Cluster configuration object
789 f380d53c Thomas Thrainer
  @type ialloc: string or None
790 f380d53c Thomas Thrainer
  @param ialloc: Iallocator specified in opcode
791 f380d53c Thomas Thrainer
  @rtype: string
792 f380d53c Thomas Thrainer
  @return: Iallocator name
793 f380d53c Thomas Thrainer

794 f380d53c Thomas Thrainer
  """
795 f380d53c Thomas Thrainer
  if not ialloc:
796 f380d53c Thomas Thrainer
    # Use default iallocator
797 f380d53c Thomas Thrainer
    ialloc = cfg.GetDefaultIAllocator()
798 f380d53c Thomas Thrainer
799 f380d53c Thomas Thrainer
  if not ialloc:
800 f380d53c Thomas Thrainer
    raise errors.OpPrereqError("No iallocator was specified, neither in the"
801 f380d53c Thomas Thrainer
                               " opcode nor as a cluster-wide default",
802 f380d53c Thomas Thrainer
                               errors.ECODE_INVAL)
803 f380d53c Thomas Thrainer
804 f380d53c Thomas Thrainer
  return ialloc
805 f380d53c Thomas Thrainer
806 f380d53c Thomas Thrainer
807 1c3231aa Thomas Thrainer
def CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_node_uuids,
808 5eacbcae Thomas Thrainer
                             cur_group_uuid):
809 f380d53c Thomas Thrainer
  """Checks if node groups for locked instances are still correct.
810 f380d53c Thomas Thrainer

811 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
812 f380d53c Thomas Thrainer
  @param cfg: Cluster configuration
813 f380d53c Thomas Thrainer
  @type instances: dict; string as key, L{objects.Instance} as value
814 da4a52a3 Thomas Thrainer
  @param instances: Dictionary, instance UUID as key, instance object as value
815 f380d53c Thomas Thrainer
  @type owned_groups: iterable of string
816 f380d53c Thomas Thrainer
  @param owned_groups: List of owned groups
817 1c3231aa Thomas Thrainer
  @type owned_node_uuids: iterable of string
818 1c3231aa Thomas Thrainer
  @param owned_node_uuids: List of owned nodes
819 f380d53c Thomas Thrainer
  @type cur_group_uuid: string or None
820 f380d53c Thomas Thrainer
  @param cur_group_uuid: Optional group UUID to check against instance's groups
821 f380d53c Thomas Thrainer

822 f380d53c Thomas Thrainer
  """
823 da4a52a3 Thomas Thrainer
  for (uuid, inst) in instances.items():
824 1c3231aa Thomas Thrainer
    assert owned_node_uuids.issuperset(inst.all_nodes), \
825 da4a52a3 Thomas Thrainer
      "Instance %s's nodes changed while we kept the lock" % inst.name
826 f380d53c Thomas Thrainer
827 da4a52a3 Thomas Thrainer
    inst_groups = CheckInstanceNodeGroups(cfg, uuid, owned_groups)
828 f380d53c Thomas Thrainer
829 f380d53c Thomas Thrainer
    assert cur_group_uuid is None or cur_group_uuid in inst_groups, \
830 da4a52a3 Thomas Thrainer
      "Instance %s has no node in group %s" % (inst.name, cur_group_uuid)
831 f380d53c Thomas Thrainer
832 f380d53c Thomas Thrainer
833 da4a52a3 Thomas Thrainer
def CheckInstanceNodeGroups(cfg, inst_uuid, owned_groups, primary_only=False):
834 f380d53c Thomas Thrainer
  """Checks if the owned node groups are still correct for an instance.
835 f380d53c Thomas Thrainer

836 f380d53c Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
837 f380d53c Thomas Thrainer
  @param cfg: The cluster configuration
838 da4a52a3 Thomas Thrainer
  @type inst_uuid: string
839 da4a52a3 Thomas Thrainer
  @param inst_uuid: Instance UUID
840 f380d53c Thomas Thrainer
  @type owned_groups: set or frozenset
841 f380d53c Thomas Thrainer
  @param owned_groups: List of currently owned node groups
842 f380d53c Thomas Thrainer
  @type primary_only: boolean
843 f380d53c Thomas Thrainer
  @param primary_only: Whether to check node groups for only the primary node
844 f380d53c Thomas Thrainer

845 f380d53c Thomas Thrainer
  """
846 da4a52a3 Thomas Thrainer
  inst_groups = cfg.GetInstanceNodeGroups(inst_uuid, primary_only)
847 f380d53c Thomas Thrainer
848 f380d53c Thomas Thrainer
  if not owned_groups.issuperset(inst_groups):
849 f380d53c Thomas Thrainer
    raise errors.OpPrereqError("Instance %s's node groups changed since"
850 f380d53c Thomas Thrainer
                               " locks were acquired, current groups are"
851 f380d53c Thomas Thrainer
                               " are '%s', owning groups '%s'; retry the"
852 f380d53c Thomas Thrainer
                               " operation" %
853 da4a52a3 Thomas Thrainer
                               (cfg.GetInstanceName(inst_uuid),
854 f380d53c Thomas Thrainer
                                utils.CommaJoin(inst_groups),
855 f380d53c Thomas Thrainer
                                utils.CommaJoin(owned_groups)),
856 f380d53c Thomas Thrainer
                               errors.ECODE_STATE)
857 f380d53c Thomas Thrainer
858 f380d53c Thomas Thrainer
  return inst_groups
859 f380d53c Thomas Thrainer
860 f380d53c Thomas Thrainer
861 5eacbcae Thomas Thrainer
def LoadNodeEvacResult(lu, alloc_result, early_release, use_nodes):
862 f380d53c Thomas Thrainer
  """Unpacks the result of change-group and node-evacuate iallocator requests.
863 f380d53c Thomas Thrainer

864 f380d53c Thomas Thrainer
  Iallocator modes L{constants.IALLOCATOR_MODE_NODE_EVAC} and
865 f380d53c Thomas Thrainer
  L{constants.IALLOCATOR_MODE_CHG_GROUP}.
866 f380d53c Thomas Thrainer

867 f380d53c Thomas Thrainer
  @type lu: L{LogicalUnit}
868 f380d53c Thomas Thrainer
  @param lu: Logical unit instance
869 f380d53c Thomas Thrainer
  @type alloc_result: tuple/list
870 f380d53c Thomas Thrainer
  @param alloc_result: Result from iallocator
871 f380d53c Thomas Thrainer
  @type early_release: bool
872 f380d53c Thomas Thrainer
  @param early_release: Whether to release locks early if possible
873 f380d53c Thomas Thrainer
  @type use_nodes: bool
874 f380d53c Thomas Thrainer
  @param use_nodes: Whether to display node names instead of groups
875 f380d53c Thomas Thrainer

876 f380d53c Thomas Thrainer
  """
877 f380d53c Thomas Thrainer
  (moved, failed, jobs) = alloc_result
878 f380d53c Thomas Thrainer
879 f380d53c Thomas Thrainer
  if failed:
880 f380d53c Thomas Thrainer
    failreason = utils.CommaJoin("%s (%s)" % (name, reason)
881 f380d53c Thomas Thrainer
                                 for (name, reason) in failed)
882 f380d53c Thomas Thrainer
    lu.LogWarning("Unable to evacuate instances %s", failreason)
883 f380d53c Thomas Thrainer
    raise errors.OpExecError("Unable to evacuate instances %s" % failreason)
884 f380d53c Thomas Thrainer
885 f380d53c Thomas Thrainer
  if moved:
886 f380d53c Thomas Thrainer
    lu.LogInfo("Instances to be moved: %s",
887 1c3231aa Thomas Thrainer
               utils.CommaJoin(
888 1c3231aa Thomas Thrainer
                 "%s (to %s)" %
889 1c3231aa Thomas Thrainer
                 (name, _NodeEvacDest(use_nodes, group, node_names))
890 1c3231aa Thomas Thrainer
                 for (name, group, node_names) in moved))
891 f380d53c Thomas Thrainer
892 f380d53c Thomas Thrainer
  return [map(compat.partial(_SetOpEarlyRelease, early_release),
893 f380d53c Thomas Thrainer
              map(opcodes.OpCode.LoadOpCode, ops))
894 f380d53c Thomas Thrainer
          for ops in jobs]
895 f380d53c Thomas Thrainer
896 f380d53c Thomas Thrainer
897 1c3231aa Thomas Thrainer
def _NodeEvacDest(use_nodes, group, node_names):
898 f380d53c Thomas Thrainer
  """Returns group or nodes depending on caller's choice.
899 f380d53c Thomas Thrainer

900 f380d53c Thomas Thrainer
  """
901 f380d53c Thomas Thrainer
  if use_nodes:
902 1c3231aa Thomas Thrainer
    return utils.CommaJoin(node_names)
903 f380d53c Thomas Thrainer
  else:
904 f380d53c Thomas Thrainer
    return group
905 f380d53c Thomas Thrainer
906 f380d53c Thomas Thrainer
907 f380d53c Thomas Thrainer
def _SetOpEarlyRelease(early_release, op):
908 f380d53c Thomas Thrainer
  """Sets C{early_release} flag on opcodes if available.
909 f380d53c Thomas Thrainer

910 f380d53c Thomas Thrainer
  """
911 f380d53c Thomas Thrainer
  try:
912 f380d53c Thomas Thrainer
    op.early_release = early_release
913 f380d53c Thomas Thrainer
  except AttributeError:
914 f380d53c Thomas Thrainer
    assert not isinstance(op, opcodes.OpInstanceReplaceDisks)
915 f380d53c Thomas Thrainer
916 f380d53c Thomas Thrainer
  return op
917 f380d53c Thomas Thrainer
918 f380d53c Thomas Thrainer
919 843094ad Thomas Thrainer
def MapInstanceLvsToNodes(instances):
920 f380d53c Thomas Thrainer
  """Creates a map from (node, volume) to instance name.
921 f380d53c Thomas Thrainer

922 f380d53c Thomas Thrainer
  @type instances: list of L{objects.Instance}
923 843094ad Thomas Thrainer
  @rtype: dict; tuple of (node uuid, volume name) as key, L{objects.Instance}
924 843094ad Thomas Thrainer
          object as value
925 f380d53c Thomas Thrainer

926 f380d53c Thomas Thrainer
  """
927 843094ad Thomas Thrainer
  return dict(((node_uuid, vol), inst)
928 f380d53c Thomas Thrainer
              for inst in instances
929 1c3231aa Thomas Thrainer
              for (node_uuid, vols) in inst.MapLVsByNode().items()
930 f380d53c Thomas Thrainer
              for vol in vols)
931 31b836b8 Thomas Thrainer
932 31b836b8 Thomas Thrainer
933 5eacbcae Thomas Thrainer
def CheckParamsNotGlobal(params, glob_pars, kind, bad_levels, good_levels):
934 31b836b8 Thomas Thrainer
  """Make sure that none of the given paramters is global.
935 31b836b8 Thomas Thrainer

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

939 31b836b8 Thomas Thrainer
  @type params: dictionary
940 31b836b8 Thomas Thrainer
  @param params: Parameters to check
941 31b836b8 Thomas Thrainer
  @type glob_pars: dictionary
942 31b836b8 Thomas Thrainer
  @param glob_pars: Forbidden parameters
943 31b836b8 Thomas Thrainer
  @type kind: string
944 31b836b8 Thomas Thrainer
  @param kind: Kind of parameters (e.g. "node")
945 31b836b8 Thomas Thrainer
  @type bad_levels: string
946 31b836b8 Thomas Thrainer
  @param bad_levels: Level(s) at which the parameters are forbidden (e.g.
947 31b836b8 Thomas Thrainer
      "instance")
948 31b836b8 Thomas Thrainer
  @type good_levels: strings
949 31b836b8 Thomas Thrainer
  @param good_levels: Level(s) at which the parameters are allowed (e.g.
950 31b836b8 Thomas Thrainer
      "cluster or group")
951 31b836b8 Thomas Thrainer

952 31b836b8 Thomas Thrainer
  """
953 31b836b8 Thomas Thrainer
  used_globals = glob_pars.intersection(params)
954 31b836b8 Thomas Thrainer
  if used_globals:
955 31b836b8 Thomas Thrainer
    msg = ("The following %s parameters are global and cannot"
956 31b836b8 Thomas Thrainer
           " be customized at %s level, please modify them at"
957 31b836b8 Thomas Thrainer
           " %s level: %s" %
958 31b836b8 Thomas Thrainer
           (kind, bad_levels, good_levels, utils.CommaJoin(used_globals)))
959 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
960 31b836b8 Thomas Thrainer
961 31b836b8 Thomas Thrainer
962 5eacbcae Thomas Thrainer
def IsExclusiveStorageEnabledNode(cfg, node):
963 31b836b8 Thomas Thrainer
  """Whether exclusive_storage is in effect for the given node.
964 31b836b8 Thomas Thrainer

965 31b836b8 Thomas Thrainer
  @type cfg: L{config.ConfigWriter}
966 31b836b8 Thomas Thrainer
  @param cfg: The cluster configuration
967 31b836b8 Thomas Thrainer
  @type node: L{objects.Node}
968 31b836b8 Thomas Thrainer
  @param node: The node
969 31b836b8 Thomas Thrainer
  @rtype: bool
970 31b836b8 Thomas Thrainer
  @return: The effective value of exclusive_storage
971 31b836b8 Thomas Thrainer

972 31b836b8 Thomas Thrainer
  """
973 31b836b8 Thomas Thrainer
  return cfg.GetNdParams(node)[constants.ND_EXCLUSIVE_STORAGE]
974 31b836b8 Thomas Thrainer
975 31b836b8 Thomas Thrainer
976 5eacbcae Thomas Thrainer
def CheckInstanceState(lu, instance, req_states, msg=None):
977 31b836b8 Thomas Thrainer
  """Ensure that an instance is in one of the required states.
978 31b836b8 Thomas Thrainer

979 31b836b8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
980 31b836b8 Thomas Thrainer
  @param instance: the instance to check
981 31b836b8 Thomas Thrainer
  @param msg: if passed, should be a message to replace the default one
982 31b836b8 Thomas Thrainer
  @raise errors.OpPrereqError: if the instance is not in the required state
983 31b836b8 Thomas Thrainer

984 31b836b8 Thomas Thrainer
  """
985 31b836b8 Thomas Thrainer
  if msg is None:
986 31b836b8 Thomas Thrainer
    msg = ("can't use instance from outside %s states" %
987 31b836b8 Thomas Thrainer
           utils.CommaJoin(req_states))
988 31b836b8 Thomas Thrainer
  if instance.admin_state not in req_states:
989 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError("Instance '%s' is marked to be %s, %s" %
990 31b836b8 Thomas Thrainer
                               (instance.name, instance.admin_state, msg),
991 31b836b8 Thomas Thrainer
                               errors.ECODE_STATE)
992 31b836b8 Thomas Thrainer
993 31b836b8 Thomas Thrainer
  if constants.ADMINST_UP not in req_states:
994 1c3231aa Thomas Thrainer
    pnode_uuid = instance.primary_node
995 1c3231aa Thomas Thrainer
    if not lu.cfg.GetNodeInfo(pnode_uuid).offline:
996 8ac806e6 Helga Velroyen
      all_hvparams = lu.cfg.GetClusterInfo().hvparams
997 1c3231aa Thomas Thrainer
      ins_l = lu.rpc.call_instance_list(
998 1c3231aa Thomas Thrainer
                [pnode_uuid], [instance.hypervisor], all_hvparams)[pnode_uuid]
999 1c3231aa Thomas Thrainer
      ins_l.Raise("Can't contact node %s for instance information" %
1000 1c3231aa Thomas Thrainer
                  lu.cfg.GetNodeName(pnode_uuid),
1001 31b836b8 Thomas Thrainer
                  prereq=True, ecode=errors.ECODE_ENVIRON)
1002 31b836b8 Thomas Thrainer
      if instance.name in ins_l.payload:
1003 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Instance %s is running, %s" %
1004 31b836b8 Thomas Thrainer
                                   (instance.name, msg), errors.ECODE_STATE)
1005 31b836b8 Thomas Thrainer
    else:
1006 31b836b8 Thomas Thrainer
      lu.LogWarning("Primary node offline, ignoring check that instance"
1007 31b836b8 Thomas Thrainer
                     " is down")
1008 31b836b8 Thomas Thrainer
1009 31b836b8 Thomas Thrainer
1010 5eacbcae Thomas Thrainer
def CheckIAllocatorOrNode(lu, iallocator_slot, node_slot):
1011 31b836b8 Thomas Thrainer
  """Check the sanity of iallocator and node arguments and use the
1012 31b836b8 Thomas Thrainer
  cluster-wide iallocator if appropriate.
1013 31b836b8 Thomas Thrainer

1014 31b836b8 Thomas Thrainer
  Check that at most one of (iallocator, node) is specified. If none is
1015 31b836b8 Thomas Thrainer
  specified, or the iallocator is L{constants.DEFAULT_IALLOCATOR_SHORTCUT},
1016 31b836b8 Thomas Thrainer
  then the LU's opcode's iallocator slot is filled with the cluster-wide
1017 31b836b8 Thomas Thrainer
  default iallocator.
1018 31b836b8 Thomas Thrainer

1019 31b836b8 Thomas Thrainer
  @type iallocator_slot: string
1020 31b836b8 Thomas Thrainer
  @param iallocator_slot: the name of the opcode iallocator slot
1021 31b836b8 Thomas Thrainer
  @type node_slot: string
1022 31b836b8 Thomas Thrainer
  @param node_slot: the name of the opcode target node slot
1023 31b836b8 Thomas Thrainer

1024 31b836b8 Thomas Thrainer
  """
1025 31b836b8 Thomas Thrainer
  node = getattr(lu.op, node_slot, None)
1026 31b836b8 Thomas Thrainer
  ialloc = getattr(lu.op, iallocator_slot, None)
1027 31b836b8 Thomas Thrainer
  if node == []:
1028 31b836b8 Thomas Thrainer
    node = None
1029 31b836b8 Thomas Thrainer
1030 31b836b8 Thomas Thrainer
  if node is not None and ialloc is not None:
1031 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError("Do not specify both, iallocator and node",
1032 31b836b8 Thomas Thrainer
                               errors.ECODE_INVAL)
1033 31b836b8 Thomas Thrainer
  elif ((node is None and ialloc is None) or
1034 31b836b8 Thomas Thrainer
        ialloc == constants.DEFAULT_IALLOCATOR_SHORTCUT):
1035 31b836b8 Thomas Thrainer
    default_iallocator = lu.cfg.GetDefaultIAllocator()
1036 31b836b8 Thomas Thrainer
    if default_iallocator:
1037 31b836b8 Thomas Thrainer
      setattr(lu.op, iallocator_slot, default_iallocator)
1038 31b836b8 Thomas Thrainer
    else:
1039 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("No iallocator or node given and no"
1040 31b836b8 Thomas Thrainer
                                 " cluster-wide default iallocator found;"
1041 31b836b8 Thomas Thrainer
                                 " please specify either an iallocator or a"
1042 31b836b8 Thomas Thrainer
                                 " node, or set a cluster-wide default"
1043 31b836b8 Thomas Thrainer
                                 " iallocator", errors.ECODE_INVAL)
1044 31b836b8 Thomas Thrainer
1045 31b836b8 Thomas Thrainer
1046 1c3231aa Thomas Thrainer
def FindFaultyInstanceDisks(cfg, rpc_runner, instance, node_uuid, prereq):
1047 31b836b8 Thomas Thrainer
  faulty = []
1048 31b836b8 Thomas Thrainer
1049 1c3231aa Thomas Thrainer
  result = rpc_runner.call_blockdev_getmirrorstatus(
1050 1c3231aa Thomas Thrainer
             node_uuid, (instance.disks, instance))
1051 1c3231aa Thomas Thrainer
  result.Raise("Failed to get disk status from node %s" %
1052 1c3231aa Thomas Thrainer
               cfg.GetNodeName(node_uuid),
1053 31b836b8 Thomas Thrainer
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
1054 31b836b8 Thomas Thrainer
1055 31b836b8 Thomas Thrainer
  for idx, bdev_status in enumerate(result.payload):
1056 31b836b8 Thomas Thrainer
    if bdev_status and bdev_status.ldisk_status == constants.LDS_FAULTY:
1057 31b836b8 Thomas Thrainer
      faulty.append(idx)
1058 31b836b8 Thomas Thrainer
1059 31b836b8 Thomas Thrainer
  return faulty
1060 22b7f6f8 Thomas Thrainer
1061 22b7f6f8 Thomas Thrainer
1062 1c3231aa Thomas Thrainer
def CheckNodeOnline(lu, node_uuid, msg=None):
1063 22b7f6f8 Thomas Thrainer
  """Ensure that a given node is online.
1064 22b7f6f8 Thomas Thrainer

1065 22b7f6f8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
1066 1c3231aa Thomas Thrainer
  @param node_uuid: the node to check
1067 22b7f6f8 Thomas Thrainer
  @param msg: if passed, should be a message to replace the default one
1068 22b7f6f8 Thomas Thrainer
  @raise errors.OpPrereqError: if the node is offline
1069 22b7f6f8 Thomas Thrainer

1070 22b7f6f8 Thomas Thrainer
  """
1071 22b7f6f8 Thomas Thrainer
  if msg is None:
1072 22b7f6f8 Thomas Thrainer
    msg = "Can't use offline node"
1073 1c3231aa Thomas Thrainer
  if lu.cfg.GetNodeInfo(node_uuid).offline:
1074 1c3231aa Thomas Thrainer
    raise errors.OpPrereqError("%s: %s" % (msg, lu.cfg.GetNodeName(node_uuid)),
1075 1c3231aa Thomas Thrainer
                               errors.ECODE_STATE)
1076 1f7c8208 Helga Velroyen
1077 1f7c8208 Helga Velroyen
1078 1f7c8208 Helga Velroyen
def CheckDiskTemplateEnabled(cluster, disk_template):
1079 1f7c8208 Helga Velroyen
  """Helper function to check if a disk template is enabled.
1080 1f7c8208 Helga Velroyen

1081 1f7c8208 Helga Velroyen
  @type cluster: C{objects.Cluster}
1082 1f7c8208 Helga Velroyen
  @param cluster: the cluster's configuration
1083 1f7c8208 Helga Velroyen
  @type disk_template: str
1084 1f7c8208 Helga Velroyen
  @param disk_template: the disk template to be checked
1085 1f7c8208 Helga Velroyen

1086 1f7c8208 Helga Velroyen
  """
1087 1f7c8208 Helga Velroyen
  assert disk_template is not None
1088 bfbffd55 Helga Velroyen
  if disk_template not in constants.DISK_TEMPLATES:
1089 bfbffd55 Helga Velroyen
    raise errors.OpPrereqError("'%s' is not a valid disk template."
1090 bfbffd55 Helga Velroyen
                               " Valid disk templates are: %s" %
1091 bfbffd55 Helga Velroyen
                               (disk_template,
1092 bfbffd55 Helga Velroyen
                                ",".join(constants.DISK_TEMPLATES)))
1093 1f7c8208 Helga Velroyen
  if not disk_template in cluster.enabled_disk_templates:
1094 1f7c8208 Helga Velroyen
    raise errors.OpPrereqError("Disk template '%s' is not enabled in cluster."
1095 1f7c8208 Helga Velroyen
                               " Enabled disk templates are: %s" %
1096 1f7c8208 Helga Velroyen
                               (disk_template,
1097 1f7c8208 Helga Velroyen
                                ",".join(cluster.enabled_disk_templates)))
1098 1f7c8208 Helga Velroyen
1099 9d276e93 Helga Velroyen
1100 9d276e93 Helga Velroyen
def CheckStorageTypeEnabled(cluster, storage_type):
1101 9d276e93 Helga Velroyen
  """Helper function to check if a storage type is enabled.
1102 9d276e93 Helga Velroyen

1103 9d276e93 Helga Velroyen
  @type cluster: C{objects.Cluster}
1104 9d276e93 Helga Velroyen
  @param cluster: the cluster's configuration
1105 9d276e93 Helga Velroyen
  @type storage_type: str
1106 9d276e93 Helga Velroyen
  @param storage_type: the storage type to be checked
1107 9d276e93 Helga Velroyen

1108 9d276e93 Helga Velroyen
  """
1109 9d276e93 Helga Velroyen
  assert storage_type is not None
1110 d8e55568 Helga Velroyen
  assert storage_type in constants.STORAGE_TYPES
1111 9d276e93 Helga Velroyen
  # special case for lvm-pv, because it cannot be enabled
1112 9d276e93 Helga Velroyen
  # via disk templates
1113 9d276e93 Helga Velroyen
  if storage_type == constants.ST_LVM_PV:
1114 9d276e93 Helga Velroyen
    CheckStorageTypeEnabled(cluster, constants.ST_LVM_VG)
1115 9d276e93 Helga Velroyen
  else:
1116 9d276e93 Helga Velroyen
    possible_disk_templates = \
1117 5a904197 Santi Raffa
        utils.storage.GetDiskTemplatesOfStorageTypes(storage_type)
1118 9d276e93 Helga Velroyen
    for disk_template in possible_disk_templates:
1119 9d276e93 Helga Velroyen
      if disk_template in cluster.enabled_disk_templates:
1120 9d276e93 Helga Velroyen
        return
1121 9d276e93 Helga Velroyen
    raise errors.OpPrereqError("No disk template of storage type '%s' is"
1122 9d276e93 Helga Velroyen
                               " enabled in this cluster. Enabled disk"
1123 9d276e93 Helga Velroyen
                               " templates are: %s" % (storage_type,
1124 9d276e93 Helga Velroyen
                               ",".join(cluster.enabled_disk_templates)))
1125 4e771a95 Helga Velroyen
1126 4e771a95 Helga Velroyen
1127 4e771a95 Helga Velroyen
def CheckIpolicyVsDiskTemplates(ipolicy, enabled_disk_templates):
1128 4e771a95 Helga Velroyen
  """Checks ipolicy disk templates against enabled disk tempaltes.
1129 4e771a95 Helga Velroyen

1130 4e771a95 Helga Velroyen
  @type ipolicy: dict
1131 4e771a95 Helga Velroyen
  @param ipolicy: the new ipolicy
1132 4e771a95 Helga Velroyen
  @type enabled_disk_templates: list of string
1133 4e771a95 Helga Velroyen
  @param enabled_disk_templates: list of enabled disk templates on the
1134 4e771a95 Helga Velroyen
    cluster
1135 4e771a95 Helga Velroyen
  @raises errors.OpPrereqError: if there is at least one allowed disk
1136 4e771a95 Helga Velroyen
    template that is not also enabled.
1137 4e771a95 Helga Velroyen

1138 4e771a95 Helga Velroyen
  """
1139 4e771a95 Helga Velroyen
  assert constants.IPOLICY_DTS in ipolicy
1140 4e771a95 Helga Velroyen
  allowed_disk_templates = ipolicy[constants.IPOLICY_DTS]
1141 4e771a95 Helga Velroyen
  not_enabled = set(allowed_disk_templates) - set(enabled_disk_templates)
1142 4e771a95 Helga Velroyen
  if not_enabled:
1143 4e771a95 Helga Velroyen
    raise errors.OpPrereqError("The following disk template are allowed"
1144 4e771a95 Helga Velroyen
                               " by the ipolicy, but not enabled on the"
1145 4e771a95 Helga Velroyen
                               " cluster: %s" % utils.CommaJoin(not_enabled))
1146 294254b1 Raffa Santi
1147 294254b1 Raffa Santi
1148 294254b1 Raffa Santi
def CheckDiskAccessModeValidity(parameters):
1149 294254b1 Raffa Santi
  """Checks if the access parameter is legal.
1150 294254b1 Raffa Santi

1151 294254b1 Raffa Santi
  @see: L{CheckDiskAccessModeConsistency} for cluster consistency checks.
1152 294254b1 Raffa Santi
  @raise errors.OpPrereqError: if the check fails.
1153 294254b1 Raffa Santi

1154 294254b1 Raffa Santi
  """
1155 6488e5bc Santi Raffa
  for disk_template in parameters:
1156 6488e5bc Santi Raffa
    access = parameters[disk_template].get(constants.LDP_ACCESS,
1157 6488e5bc Santi Raffa
                                           constants.DISK_KERNELSPACE)
1158 294254b1 Raffa Santi
    if access not in constants.DISK_VALID_ACCESS_MODES:
1159 294254b1 Raffa Santi
      valid_vals_str = utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
1160 294254b1 Raffa Santi
      raise errors.OpPrereqError("Invalid value of '{d}:{a}': '{v}' (expected"
1161 6488e5bc Santi Raffa
                                 " one of {o})".format(d=disk_template,
1162 6488e5bc Santi Raffa
                                                       a=constants.LDP_ACCESS,
1163 294254b1 Raffa Santi
                                                       v=access,
1164 294254b1 Raffa Santi
                                                       o=valid_vals_str))
1165 294254b1 Raffa Santi
1166 294254b1 Raffa Santi
1167 294254b1 Raffa Santi
def CheckDiskAccessModeConsistency(parameters, cfg, group=None):
1168 294254b1 Raffa Santi
  """Checks if the access param is consistent with the cluster configuration.
1169 294254b1 Raffa Santi

1170 294254b1 Raffa Santi
  @note: requires a configuration lock to run.
1171 294254b1 Raffa Santi
  @param parameters: the parameters to validate
1172 294254b1 Raffa Santi
  @param cfg: the cfg object of the cluster
1173 294254b1 Raffa Santi
  @param group: if set, only check for consistency within this group.
1174 294254b1 Raffa Santi
  @raise errors.OpPrereqError: if the LU attempts to change the access parameter
1175 294254b1 Raffa Santi
                               to an invalid value, such as "pink bunny".
1176 294254b1 Raffa Santi
  @raise errors.OpPrereqError: if the LU attempts to change the access parameter
1177 294254b1 Raffa Santi
                               to an inconsistent value, such as asking for RBD
1178 294254b1 Raffa Santi
                               userspace access to the chroot hypervisor.
1179 294254b1 Raffa Santi

1180 294254b1 Raffa Santi
  """
1181 294254b1 Raffa Santi
  CheckDiskAccessModeValidity(parameters)
1182 294254b1 Raffa Santi
1183 6488e5bc Santi Raffa
  for disk_template in parameters:
1184 6488e5bc Santi Raffa
    access = parameters[disk_template].get(constants.LDP_ACCESS,
1185 6488e5bc Santi Raffa
                                           constants.DISK_KERNELSPACE)
1186 6488e5bc Santi Raffa
1187 5a904197 Santi Raffa
    if disk_template not in constants.DTS_HAVE_ACCESS:
1188 6488e5bc Santi Raffa
      continue
1189 294254b1 Raffa Santi
1190 294254b1 Raffa Santi
    #Check the combination of instance hypervisor, disk template and access
1191 294254b1 Raffa Santi
    #protocol is sane.
1192 294254b1 Raffa Santi
    inst_uuids = cfg.GetNodeGroupInstances(group) if group else \
1193 294254b1 Raffa Santi
                 cfg.GetInstanceList()
1194 294254b1 Raffa Santi
1195 294254b1 Raffa Santi
    for entry in inst_uuids:
1196 294254b1 Raffa Santi
      inst = cfg.GetInstanceInfo(entry)
1197 294254b1 Raffa Santi
      hv = inst.hypervisor
1198 294254b1 Raffa Santi
      dt = inst.disk_template
1199 294254b1 Raffa Santi
1200 294254b1 Raffa Santi
      if not IsValidDiskAccessModeCombination(hv, dt, access):
1201 294254b1 Raffa Santi
        raise errors.OpPrereqError("Instance {i}: cannot use '{a}' access"
1202 294254b1 Raffa Santi
                                   " setting with {h} hypervisor and {d} disk"
1203 294254b1 Raffa Santi
                                   " type.".format(i=inst.name,
1204 294254b1 Raffa Santi
                                                   a=access,
1205 294254b1 Raffa Santi
                                                   h=hv,
1206 294254b1 Raffa Santi
                                                   d=dt))
1207 294254b1 Raffa Santi
1208 294254b1 Raffa Santi
1209 294254b1 Raffa Santi
def IsValidDiskAccessModeCombination(hv, disk_template, mode):
1210 294254b1 Raffa Santi
  """Checks if an hypervisor can read a disk template with given mode.
1211 294254b1 Raffa Santi

1212 294254b1 Raffa Santi
  @param hv: the hypervisor that will access the data
1213 294254b1 Raffa Santi
  @param disk_template: the disk template the data is stored as
1214 294254b1 Raffa Santi
  @param mode: how the hypervisor should access the data
1215 294254b1 Raffa Santi
  @return: True if the hypervisor can read a given read disk_template
1216 294254b1 Raffa Santi
           in the specified mode.
1217 294254b1 Raffa Santi

1218 294254b1 Raffa Santi
  """
1219 294254b1 Raffa Santi
  if mode == constants.DISK_KERNELSPACE:
1220 294254b1 Raffa Santi
    return True
1221 294254b1 Raffa Santi
1222 294254b1 Raffa Santi
  if (hv == constants.HT_KVM and
1223 6488e5bc Santi Raffa
      disk_template in (constants.DT_RBD, constants.DT_GLUSTER) and
1224 294254b1 Raffa Santi
      mode == constants.DISK_USERSPACE):
1225 294254b1 Raffa Santi
    return True
1226 294254b1 Raffa Santi
1227 294254b1 Raffa Santi
  # Everything else:
1228 294254b1 Raffa Santi
  return False
1229 5b6f9e35 Helga Velroyen
1230 5b6f9e35 Helga Velroyen
1231 5b6f9e35 Helga Velroyen
def AddNodeCertToCandidateCerts(lu, node_uuid, cluster):
1232 5b6f9e35 Helga Velroyen
  """Add the node's client SSL certificate digest to the candidate certs.
1233 5b6f9e35 Helga Velroyen

1234 5b6f9e35 Helga Velroyen
  @type node_uuid: string
1235 5b6f9e35 Helga Velroyen
  @param node_uuid: the node's UUID
1236 5b6f9e35 Helga Velroyen
  @type cluster: C{object.Cluster}
1237 5b6f9e35 Helga Velroyen
  @param cluster: the cluster's configuration
1238 5b6f9e35 Helga Velroyen

1239 5b6f9e35 Helga Velroyen
  """
1240 5b6f9e35 Helga Velroyen
  result = lu.rpc.call_node_crypto_tokens(
1241 d722af8b Helga Velroyen
             node_uuid,
1242 d722af8b Helga Velroyen
             [(constants.CRYPTO_TYPE_SSL_DIGEST, constants.CRYPTO_ACTION_GET,
1243 d722af8b Helga Velroyen
               None)])
1244 5b6f9e35 Helga Velroyen
  result.Raise("Could not retrieve the node's (uuid %s) SSL digest."
1245 5b6f9e35 Helga Velroyen
               % node_uuid)
1246 5b6f9e35 Helga Velroyen
  ((crypto_type, digest), ) = result.payload
1247 5b6f9e35 Helga Velroyen
  assert crypto_type == constants.CRYPTO_TYPE_SSL_DIGEST
1248 5b6f9e35 Helga Velroyen
1249 5b6f9e35 Helga Velroyen
  utils.AddNodeToCandidateCerts(node_uuid, digest, cluster.candidate_certs)
1250 28756f80 Helga Velroyen
1251 28756f80 Helga Velroyen
1252 28756f80 Helga Velroyen
def RemoveNodeCertFromCandidateCerts(node_uuid, cluster):
1253 28756f80 Helga Velroyen
  """Removes the node's certificate from the candidate certificates list.
1254 28756f80 Helga Velroyen

1255 28756f80 Helga Velroyen
  @type node_uuid: string
1256 28756f80 Helga Velroyen
  @param node_uuid: the node's UUID
1257 28756f80 Helga Velroyen
  @type cluster: C{objects.Cluster}
1258 28756f80 Helga Velroyen
  @param cluster: the cluster's configuration
1259 28756f80 Helga Velroyen

1260 28756f80 Helga Velroyen
  """
1261 28756f80 Helga Velroyen
  utils.RemoveNodeFromCandidateCerts(node_uuid, cluster.candidate_certs)
1262 28756f80 Helga Velroyen
1263 28756f80 Helga Velroyen
1264 b3cc1646 Helga Velroyen
def CreateNewClientCert(lu, node_uuid, filename=None):
1265 28756f80 Helga Velroyen
  """Creates a new client SSL certificate for the node.
1266 28756f80 Helga Velroyen

1267 28756f80 Helga Velroyen
  @type node_uuid: string
1268 28756f80 Helga Velroyen
  @param node_uuid: the node's UUID
1269 28756f80 Helga Velroyen
  @type filename: string
1270 28756f80 Helga Velroyen
  @param filename: the certificate's filename
1271 28756f80 Helga Velroyen
  @rtype: string
1272 28756f80 Helga Velroyen
  @return: the digest of the newly created certificate
1273 28756f80 Helga Velroyen

1274 28756f80 Helga Velroyen
  """
1275 28756f80 Helga Velroyen
  options = {}
1276 28756f80 Helga Velroyen
  if filename:
1277 28756f80 Helga Velroyen
    options[constants.CRYPTO_OPTION_CERT_FILE] = filename
1278 b3cc1646 Helga Velroyen
  result = lu.rpc.call_node_crypto_tokens(
1279 28756f80 Helga Velroyen
             node_uuid,
1280 28756f80 Helga Velroyen
             [(constants.CRYPTO_TYPE_SSL_DIGEST,
1281 28756f80 Helga Velroyen
               constants.CRYPTO_ACTION_CREATE,
1282 28756f80 Helga Velroyen
               options)])
1283 28756f80 Helga Velroyen
  result.Raise("Could not create the node's (uuid %s) SSL client"
1284 28756f80 Helga Velroyen
               " certificate." % node_uuid)
1285 28756f80 Helga Velroyen
  ((crypto_type, new_digest), ) = result.payload
1286 28756f80 Helga Velroyen
  assert crypto_type == constants.CRYPTO_TYPE_SSL_DIGEST
1287 28756f80 Helga Velroyen
  return new_digest
1288 2ff6426b Jose A. Lopes
1289 2ff6426b Jose A. Lopes
1290 2ff6426b Jose A. Lopes
def OpAddInstanceCommunicationNetwork(network):
1291 2ff6426b Jose A. Lopes
  """Create OpCode that adds the instance communication network.
1292 2ff6426b Jose A. Lopes

1293 2ff6426b Jose A. Lopes
  This OpCode contains the configuration necessary for the instance
1294 2ff6426b Jose A. Lopes
  communication network.
1295 2ff6426b Jose A. Lopes

1296 2ff6426b Jose A. Lopes
  @type network: string
1297 2ff6426b Jose A. Lopes
  @param network: name or UUID of the instance communication network
1298 2ff6426b Jose A. Lopes

1299 2ff6426b Jose A. Lopes
  @rtype: L{ganeti.opcodes.OpCode}
1300 2ff6426b Jose A. Lopes
  @return: OpCode that creates the instance communication network
1301 2ff6426b Jose A. Lopes

1302 2ff6426b Jose A. Lopes
  """
1303 2ff6426b Jose A. Lopes
  return opcodes.OpNetworkAdd(
1304 2ff6426b Jose A. Lopes
    network_name=network,
1305 2ff6426b Jose A. Lopes
    gateway=None,
1306 2ff6426b Jose A. Lopes
    network=constants.INSTANCE_COMMUNICATION_NETWORK4,
1307 2ff6426b Jose A. Lopes
    gateway6=None,
1308 2ff6426b Jose A. Lopes
    network6=constants.INSTANCE_COMMUNICATION_NETWORK6,
1309 2ff6426b Jose A. Lopes
    mac_prefix=constants.INSTANCE_COMMUNICATION_MAC_PREFIX,
1310 2ff6426b Jose A. Lopes
    add_reserved_ips=None,
1311 2ff6426b Jose A. Lopes
    conflicts_check=True,
1312 2ff6426b Jose A. Lopes
    tags=[])
1313 2ff6426b Jose A. Lopes
1314 2ff6426b Jose A. Lopes
1315 2ff6426b Jose A. Lopes
def OpConnectInstanceCommunicationNetwork(group_uuid, network):
1316 2ff6426b Jose A. Lopes
  """Create OpCode that connects a group to the instance communication
1317 2ff6426b Jose A. Lopes
  network.
1318 2ff6426b Jose A. Lopes

1319 2ff6426b Jose A. Lopes
  This OpCode contains the configuration necessary for the instance
1320 2ff6426b Jose A. Lopes
  communication network.
1321 2ff6426b Jose A. Lopes

1322 2ff6426b Jose A. Lopes
  @type group_uuid: string
1323 2ff6426b Jose A. Lopes
  @param group_uuid: UUID of the group to connect
1324 2ff6426b Jose A. Lopes

1325 2ff6426b Jose A. Lopes
  @type network: string
1326 2ff6426b Jose A. Lopes
  @param network: name or UUID of the network to connect to, i.e., the
1327 2ff6426b Jose A. Lopes
                  instance communication network
1328 2ff6426b Jose A. Lopes

1329 2ff6426b Jose A. Lopes
  @rtype: L{ganeti.opcodes.OpCode}
1330 2ff6426b Jose A. Lopes
  @return: OpCode that connects the group to the instance
1331 2ff6426b Jose A. Lopes
           communication network
1332 2ff6426b Jose A. Lopes

1333 2ff6426b Jose A. Lopes
  """
1334 2ff6426b Jose A. Lopes
  return opcodes.OpNetworkConnect(
1335 2ff6426b Jose A. Lopes
    group_name=group_uuid,
1336 2ff6426b Jose A. Lopes
    network_name=network,
1337 2ff6426b Jose A. Lopes
    network_mode=constants.NIC_MODE_ROUTED,
1338 2ff6426b Jose A. Lopes
    network_link=constants.INSTANCE_COMMUNICATION_NETWORK_LINK,
1339 2ff6426b Jose A. Lopes
    conflicts_check=True)