Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ cd46491f

History | View | Annotate | Download (60.1 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 2cc673a3 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Transportable objects for Ganeti.
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
This module provides small, mostly data-only objects which are safe to
25 a8083063 Iustin Pop
pass to and from external parties.
26 a8083063 Iustin Pop

27 a8083063 Iustin Pop
"""
28 a8083063 Iustin Pop
29 0007f3ab Andrea Spadaccini
# pylint: disable=E0203,W0201,R0902
30 6c881c52 Iustin Pop
31 6c881c52 Iustin Pop
# E0203: Access to member %r before its definition, since we use
32 6c881c52 Iustin Pop
# objects.py which doesn't explicitely initialise its members
33 6c881c52 Iustin Pop
34 7260cfbe Iustin Pop
# W0201: Attribute '%s' defined outside __init__
35 a8083063 Iustin Pop
36 0007f3ab Andrea Spadaccini
# R0902: Allow instances of these objects to have more than 20 attributes
37 0007f3ab Andrea Spadaccini
38 a8083063 Iustin Pop
import ConfigParser
39 5c947f38 Iustin Pop
import re
40 5bf7b5cf Iustin Pop
import copy
41 e11a1b77 Adeodato Simo
import time
42 d5835922 Michael Hanselmann
from cStringIO import StringIO
43 a8083063 Iustin Pop
44 a8083063 Iustin Pop
from ganeti import errors
45 5c947f38 Iustin Pop
from ganeti import constants
46 0007f3ab Andrea Spadaccini
from ganeti import netutils
47 32017174 Agata Murawska
from ganeti import utils
48 a8083063 Iustin Pop
49 f4c9af7a Guido Trotter
from socket import AF_INET
50 f4c9af7a Guido Trotter
51 a8083063 Iustin Pop
52 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
53 24a3707f Guido Trotter
           "OS", "Node", "NodeGroup", "Cluster", "FillDict"]
54 a8083063 Iustin Pop
55 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
56 e1dcc53a Iustin Pop
_UUID = ["uuid"]
57 96acbc09 Michael Hanselmann
58 32017174 Agata Murawska
# constants used to create InstancePolicy dictionary
59 32017174 Agata Murawska
TISPECS_GROUP_TYPES = {
60 4f725341 Agata Murawska
  constants.ISPECS_MIN: constants.VTYPE_INT,
61 4f725341 Agata Murawska
  constants.ISPECS_MAX: constants.VTYPE_INT,
62 2cc673a3 Iustin Pop
  }
63 32017174 Agata Murawska
64 32017174 Agata Murawska
TISPECS_CLUSTER_TYPES = {
65 4f725341 Agata Murawska
  constants.ISPECS_MIN: constants.VTYPE_INT,
66 4f725341 Agata Murawska
  constants.ISPECS_MAX: constants.VTYPE_INT,
67 4f725341 Agata Murawska
  constants.ISPECS_STD: constants.VTYPE_INT,
68 32017174 Agata Murawska
  }
69 32017174 Agata Murawska
70 8d8d650c Michael Hanselmann
71 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
72 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
73 abe609b2 Guido Trotter

74 29921401 Iustin Pop
  @type defaults_dict: dict
75 29921401 Iustin Pop
  @param defaults_dict: dictionary holding the default values
76 29921401 Iustin Pop
  @type custom_dict: dict
77 29921401 Iustin Pop
  @param custom_dict: dictionary holding customized value
78 7736a5f2 Iustin Pop
  @type skip_keys: list
79 7736a5f2 Iustin Pop
  @param skip_keys: which keys not to fill
80 29921401 Iustin Pop
  @rtype: dict
81 29921401 Iustin Pop
  @return: dict with the 'full' values
82 abe609b2 Guido Trotter

83 29921401 Iustin Pop
  """
84 29921401 Iustin Pop
  ret_dict = copy.deepcopy(defaults_dict)
85 29921401 Iustin Pop
  ret_dict.update(custom_dict)
86 e11ddf13 Iustin Pop
  if skip_keys:
87 e11ddf13 Iustin Pop
    for k in skip_keys:
88 e11ddf13 Iustin Pop
      try:
89 e11ddf13 Iustin Pop
        del ret_dict[k]
90 e11ddf13 Iustin Pop
      except KeyError:
91 e11ddf13 Iustin Pop
        pass
92 29921401 Iustin Pop
  return ret_dict
93 a8083063 Iustin Pop
94 6e34b628 Guido Trotter
95 2cc673a3 Iustin Pop
def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
96 2cc673a3 Iustin Pop
  """Fills an instance policy with defaults.
97 918eb80b Agata Murawska

98 918eb80b Agata Murawska
  """
99 2cc673a3 Iustin Pop
  assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS
100 918eb80b Agata Murawska
  ret_dict = {}
101 12378fe3 Iustin Pop
  for key in constants.IPOLICY_ISPECS:
102 2cc673a3 Iustin Pop
    ret_dict[key] = FillDict(default_ipolicy[key],
103 2cc673a3 Iustin Pop
                             custom_ipolicy.get(key, {}),
104 918eb80b Agata Murawska
                             skip_keys=skip_keys)
105 2cc673a3 Iustin Pop
  # list items
106 d04c9d45 Iustin Pop
  for key in [constants.IPOLICY_DTS]:
107 2cc673a3 Iustin Pop
    ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
108 ff6c5e55 Iustin Pop
  # other items which we know we can directly copy (immutables)
109 ff6c5e55 Iustin Pop
  for key in constants.IPOLICY_PARAMETERS:
110 ff6c5e55 Iustin Pop
    ret_dict[key] = custom_ipolicy.get(key, default_ipolicy[key])
111 2cc673a3 Iustin Pop
112 918eb80b Agata Murawska
  return ret_dict
113 918eb80b Agata Murawska
114 918eb80b Agata Murawska
115 57987785 René Nussbaumer
def FillDiskParams(default_dparams, custom_dparams, skip_keys=None):
116 57987785 René Nussbaumer
  """Fills the disk parameter defaults.
117 57987785 René Nussbaumer

118 57987785 René Nussbaumer
  @see FillDict: For parameters and return value
119 57987785 René Nussbaumer

120 57987785 René Nussbaumer
  """
121 57987785 René Nussbaumer
  assert frozenset(default_dparams.keys()) == constants.DISK_TEMPLATES
122 57987785 René Nussbaumer
123 57987785 René Nussbaumer
  return dict((dt, FillDict(default_dparams[dt], custom_dparams.get(dt, {}),
124 57987785 René Nussbaumer
                             skip_keys=skip_keys))
125 57987785 René Nussbaumer
              for dt in constants.DISK_TEMPLATES)
126 57987785 René Nussbaumer
127 57987785 René Nussbaumer
128 6e34b628 Guido Trotter
def UpgradeGroupedParams(target, defaults):
129 6e34b628 Guido Trotter
  """Update all groups for the target parameter.
130 6e34b628 Guido Trotter

131 6e34b628 Guido Trotter
  @type target: dict of dicts
132 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
133 6e34b628 Guido Trotter
  @type defaults: dict
134 6e34b628 Guido Trotter
  @param defaults: default parameter values
135 6e34b628 Guido Trotter

136 6e34b628 Guido Trotter
  """
137 6e34b628 Guido Trotter
  if target is None:
138 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
139 6e34b628 Guido Trotter
  else:
140 6e34b628 Guido Trotter
    for group in target:
141 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
142 6e34b628 Guido Trotter
  return target
143 6e34b628 Guido Trotter
144 6e34b628 Guido Trotter
145 8c72ab2b Guido Trotter
def UpgradeBeParams(target):
146 8c72ab2b Guido Trotter
  """Update the be parameters dict to the new format.
147 8c72ab2b Guido Trotter

148 8c72ab2b Guido Trotter
  @type target: dict
149 8c72ab2b Guido Trotter
  @param target: "be" parameters dict
150 8c72ab2b Guido Trotter

151 8c72ab2b Guido Trotter
  """
152 8c72ab2b Guido Trotter
  if constants.BE_MEMORY in target:
153 8c72ab2b Guido Trotter
    memory = target[constants.BE_MEMORY]
154 8c72ab2b Guido Trotter
    target[constants.BE_MAXMEM] = memory
155 8c72ab2b Guido Trotter
    target[constants.BE_MINMEM] = memory
156 b2e233a5 Guido Trotter
    del target[constants.BE_MEMORY]
157 8c72ab2b Guido Trotter
158 8c72ab2b Guido Trotter
159 bc5d0215 Andrea Spadaccini
def UpgradeDiskParams(diskparams):
160 bc5d0215 Andrea Spadaccini
  """Upgrade the disk parameters.
161 bc5d0215 Andrea Spadaccini

162 bc5d0215 Andrea Spadaccini
  @type diskparams: dict
163 bc5d0215 Andrea Spadaccini
  @param diskparams: disk parameters to upgrade
164 bc5d0215 Andrea Spadaccini
  @rtype: dict
165 765ada2b Iustin Pop
  @return: the upgraded disk parameters dict
166 bc5d0215 Andrea Spadaccini

167 bc5d0215 Andrea Spadaccini
  """
168 bc5d0215 Andrea Spadaccini
  if diskparams is None:
169 bc5d0215 Andrea Spadaccini
    result = constants.DISK_DT_DEFAULTS.copy()
170 bc5d0215 Andrea Spadaccini
  else:
171 57987785 René Nussbaumer
    result = FillDiskParams(constants.DISK_DT_DEFAULTS, diskparams)
172 bc5d0215 Andrea Spadaccini
173 bc5d0215 Andrea Spadaccini
  return result
174 bc5d0215 Andrea Spadaccini
175 bc5d0215 Andrea Spadaccini
176 2a27dac3 Iustin Pop
def UpgradeNDParams(ndparams):
177 2a27dac3 Iustin Pop
  """Upgrade ndparams structure.
178 2a27dac3 Iustin Pop

179 2a27dac3 Iustin Pop
  @type ndparams: dict
180 2a27dac3 Iustin Pop
  @param ndparams: disk parameters to upgrade
181 2a27dac3 Iustin Pop
  @rtype: dict
182 2a27dac3 Iustin Pop
  @return: the upgraded node parameters dict
183 2a27dac3 Iustin Pop

184 2a27dac3 Iustin Pop
  """
185 2a27dac3 Iustin Pop
  if ndparams is None:
186 2a27dac3 Iustin Pop
    ndparams = {}
187 2a27dac3 Iustin Pop
188 2a27dac3 Iustin Pop
  return FillDict(constants.NDC_DEFAULTS, ndparams)
189 2a27dac3 Iustin Pop
190 2a27dac3 Iustin Pop
191 918eb80b Agata Murawska
def MakeEmptyIPolicy():
192 918eb80b Agata Murawska
  """Create empty IPolicy dictionary.
193 918eb80b Agata Murawska

194 918eb80b Agata Murawska
  """
195 918eb80b Agata Murawska
  return dict([
196 2cc673a3 Iustin Pop
    (constants.ISPECS_MIN, {}),
197 2cc673a3 Iustin Pop
    (constants.ISPECS_MAX, {}),
198 2cc673a3 Iustin Pop
    (constants.ISPECS_STD, {}),
199 918eb80b Agata Murawska
    ])
200 918eb80b Agata Murawska
201 918eb80b Agata Murawska
202 32017174 Agata Murawska
def CreateIPolicyFromOpts(ispecs_mem_size=None,
203 32017174 Agata Murawska
                          ispecs_cpu_count=None,
204 32017174 Agata Murawska
                          ispecs_disk_count=None,
205 32017174 Agata Murawska
                          ispecs_disk_size=None,
206 32017174 Agata Murawska
                          ispecs_nic_count=None,
207 d04c9d45 Iustin Pop
                          ipolicy_disk_templates=None,
208 976b78ba Iustin Pop
                          ipolicy_vcpu_ratio=None,
209 32017174 Agata Murawska
                          group_ipolicy=False,
210 2cc673a3 Iustin Pop
                          allowed_values=None,
211 2cc673a3 Iustin Pop
                          fill_all=False):
212 2cc673a3 Iustin Pop
  """Creation of instance policy based on command line options.
213 2cc673a3 Iustin Pop

214 2cc673a3 Iustin Pop
  @param fill_all: whether for cluster policies we should ensure that
215 2cc673a3 Iustin Pop
    all values are filled
216 32017174 Agata Murawska

217 32017174 Agata Murawska

218 32017174 Agata Murawska
  """
219 32017174 Agata Murawska
  # prepare ipolicy dict
220 32017174 Agata Murawska
  ipolicy_transposed = {
221 4f725341 Agata Murawska
    constants.ISPEC_MEM_SIZE: ispecs_mem_size,
222 4f725341 Agata Murawska
    constants.ISPEC_CPU_COUNT: ispecs_cpu_count,
223 4f725341 Agata Murawska
    constants.ISPEC_DISK_COUNT: ispecs_disk_count,
224 4f725341 Agata Murawska
    constants.ISPEC_DISK_SIZE: ispecs_disk_size,
225 4f725341 Agata Murawska
    constants.ISPEC_NIC_COUNT: ispecs_nic_count,
226 32017174 Agata Murawska
    }
227 32017174 Agata Murawska
228 32017174 Agata Murawska
  # first, check that the values given are correct
229 32017174 Agata Murawska
  if group_ipolicy:
230 32017174 Agata Murawska
    forced_type = TISPECS_GROUP_TYPES
231 32017174 Agata Murawska
  else:
232 32017174 Agata Murawska
    forced_type = TISPECS_CLUSTER_TYPES
233 32017174 Agata Murawska
234 32017174 Agata Murawska
  for specs in ipolicy_transposed.values():
235 32017174 Agata Murawska
    utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
236 32017174 Agata Murawska
237 32017174 Agata Murawska
  # then transpose
238 32017174 Agata Murawska
  ipolicy_out = MakeEmptyIPolicy()
239 32017174 Agata Murawska
  for name, specs in ipolicy_transposed.iteritems():
240 32017174 Agata Murawska
    assert name in constants.ISPECS_PARAMETERS
241 32017174 Agata Murawska
    for key, val in specs.items(): # {min: .. ,max: .., std: ..}
242 32017174 Agata Murawska
      ipolicy_out[key][name] = val
243 32017174 Agata Murawska
244 976b78ba Iustin Pop
  # no filldict for non-dicts
245 976b78ba Iustin Pop
  if not group_ipolicy and fill_all:
246 976b78ba Iustin Pop
    if ipolicy_disk_templates is None:
247 976b78ba Iustin Pop
      ipolicy_disk_templates = constants.DISK_TEMPLATES
248 976b78ba Iustin Pop
    if ipolicy_vcpu_ratio is None:
249 976b78ba Iustin Pop
      ipolicy_vcpu_ratio = \
250 976b78ba Iustin Pop
        constants.IPOLICY_DEFAULTS[constants.IPOLICY_VCPU_RATIO]
251 d04c9d45 Iustin Pop
  if ipolicy_disk_templates is not None:
252 d04c9d45 Iustin Pop
    ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates)
253 976b78ba Iustin Pop
  if ipolicy_vcpu_ratio is not None:
254 976b78ba Iustin Pop
    ipolicy_out[constants.IPOLICY_VCPU_RATIO] = ipolicy_vcpu_ratio
255 2cc673a3 Iustin Pop
256 57dc299a Iustin Pop
  assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
257 57dc299a Iustin Pop
258 32017174 Agata Murawska
  return ipolicy_out
259 32017174 Agata Murawska
260 32017174 Agata Murawska
261 a8083063 Iustin Pop
class ConfigObject(object):
262 a8083063 Iustin Pop
  """A generic config object.
263 a8083063 Iustin Pop

264 a8083063 Iustin Pop
  It has the following properties:
265 a8083063 Iustin Pop

266 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
267 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
268 a8083063 Iustin Pop
      as None instead of raising an error
269 a8083063 Iustin Pop

270 a8083063 Iustin Pop
  Classes derived from this must always declare __slots__ (we use many
271 55224070 Guido Trotter
  config objects and the memory reduction is useful)
272 a8083063 Iustin Pop

273 a8083063 Iustin Pop
  """
274 a8083063 Iustin Pop
  __slots__ = []
275 a8083063 Iustin Pop
276 a8083063 Iustin Pop
  def __init__(self, **kwargs):
277 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
278 319856a9 Michael Hanselmann
      setattr(self, k, v)
279 a8083063 Iustin Pop
280 a8083063 Iustin Pop
  def __getattr__(self, name):
281 adf385c7 Iustin Pop
    if name not in self._all_slots():
282 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
283 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
284 a8083063 Iustin Pop
    return None
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
  def __setstate__(self, state):
287 adf385c7 Iustin Pop
    slots = self._all_slots()
288 a8083063 Iustin Pop
    for name in state:
289 adf385c7 Iustin Pop
      if name in slots:
290 a8083063 Iustin Pop
        setattr(self, name, state[name])
291 a8083063 Iustin Pop
292 adf385c7 Iustin Pop
  @classmethod
293 adf385c7 Iustin Pop
  def _all_slots(cls):
294 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
295 adf385c7 Iustin Pop

296 adf385c7 Iustin Pop
    """
297 adf385c7 Iustin Pop
    slots = []
298 adf385c7 Iustin Pop
    for parent in cls.__mro__:
299 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
300 adf385c7 Iustin Pop
    return slots
301 adf385c7 Iustin Pop
302 415feb2e René Nussbaumer
  #: Public getter for the defined slots
303 415feb2e René Nussbaumer
  GetAllSlots = _all_slots
304 415feb2e René Nussbaumer
305 ff9c047c Iustin Pop
  def ToDict(self):
306 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
307 ff9c047c Iustin Pop

308 ff9c047c Iustin Pop
    The generic routine just dumps all of this object's attributes in
309 ff9c047c Iustin Pop
    a dict. It does not work if the class has children who are
310 ff9c047c Iustin Pop
    ConfigObjects themselves (e.g. the nics list in an Instance), in
311 ff9c047c Iustin Pop
    which case the object should subclass the function in order to
312 ff9c047c Iustin Pop
    make sure all objects returned are only standard python types.
313 ff9c047c Iustin Pop

314 ff9c047c Iustin Pop
    """
315 4c14965f Guido Trotter
    result = {}
316 adf385c7 Iustin Pop
    for name in self._all_slots():
317 4c14965f Guido Trotter
      value = getattr(self, name, None)
318 4c14965f Guido Trotter
      if value is not None:
319 4c14965f Guido Trotter
        result[name] = value
320 4c14965f Guido Trotter
    return result
321 4c14965f Guido Trotter
322 4c14965f Guido Trotter
  __getstate__ = ToDict
323 ff9c047c Iustin Pop
324 ff9c047c Iustin Pop
  @classmethod
325 ff9c047c Iustin Pop
  def FromDict(cls, val):
326 ff9c047c Iustin Pop
    """Create an object from a dictionary.
327 ff9c047c Iustin Pop

328 ff9c047c Iustin Pop
    This generic routine takes a dict, instantiates a new instance of
329 ff9c047c Iustin Pop
    the given class, and sets attributes based on the dict content.
330 ff9c047c Iustin Pop

331 ff9c047c Iustin Pop
    As for `ToDict`, this does not work if the class has children
332 ff9c047c Iustin Pop
    who are ConfigObjects themselves (e.g. the nics list in an
333 ff9c047c Iustin Pop
    Instance), in which case the object should subclass the function
334 ff9c047c Iustin Pop
    and alter the objects.
335 ff9c047c Iustin Pop

336 ff9c047c Iustin Pop
    """
337 ff9c047c Iustin Pop
    if not isinstance(val, dict):
338 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
339 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
340 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
341 b459a848 Andrea Spadaccini
    obj = cls(**val_str) # pylint: disable=W0142
342 ff9c047c Iustin Pop
    return obj
343 ff9c047c Iustin Pop
344 ff9c047c Iustin Pop
  @staticmethod
345 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
346 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
347 ff9c047c Iustin Pop

348 ff9c047c Iustin Pop
    This method converts a container with elements derived from
349 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
350 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
351 ff9c047c Iustin Pop

352 ff9c047c Iustin Pop
    """
353 ff9c047c Iustin Pop
    if isinstance(container, dict):
354 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
355 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
356 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
357 ff9c047c Iustin Pop
    else:
358 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
359 ff9c047c Iustin Pop
                      type(container))
360 ff9c047c Iustin Pop
    return ret
361 ff9c047c Iustin Pop
362 ff9c047c Iustin Pop
  @staticmethod
363 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
364 ff9c047c Iustin Pop
    """Convert a container from standard python types.
365 ff9c047c Iustin Pop

366 ff9c047c Iustin Pop
    This method converts a container with standard python types to
367 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
368 ff9c047c Iustin Pop
    keys, only the values.
369 ff9c047c Iustin Pop

370 ff9c047c Iustin Pop
    """
371 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
372 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
373 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
374 fe25a79a Guido Trotter
    if source is None:
375 fe25a79a Guido Trotter
      source = c_type()
376 ff9c047c Iustin Pop
    if c_type is dict:
377 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
378 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
379 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
380 ff9c047c Iustin Pop
    else:
381 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
382 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
383 ff9c047c Iustin Pop
    return ret
384 ff9c047c Iustin Pop
385 e8d563f3 Iustin Pop
  def Copy(self):
386 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
387 e8d563f3 Iustin Pop

388 e8d563f3 Iustin Pop
    """
389 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
390 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
391 e8d563f3 Iustin Pop
    return clone_obj
392 e8d563f3 Iustin Pop
393 ff9c047c Iustin Pop
  def __repr__(self):
394 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
395 ff9c047c Iustin Pop
    return repr(self.ToDict())
396 ff9c047c Iustin Pop
397 560428be Guido Trotter
  def UpgradeConfig(self):
398 560428be Guido Trotter
    """Fill defaults for missing configuration values.
399 560428be Guido Trotter

400 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
401 90d726a8 Iustin Pop
    implementation will be object dependent.
402 560428be Guido Trotter

403 560428be Guido Trotter
    """
404 560428be Guido Trotter
    pass
405 560428be Guido Trotter
406 a8083063 Iustin Pop
407 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
408 5c947f38 Iustin Pop
  """An generic class supporting tags.
409 5c947f38 Iustin Pop

410 5c947f38 Iustin Pop
  """
411 154b9580 Balazs Lecz
  __slots__ = ["tags"]
412 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
413 2057f6c7 Iustin Pop
414 b5e5632e Iustin Pop
  @classmethod
415 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
416 5c947f38 Iustin Pop
    """Check if a tag is valid.
417 5c947f38 Iustin Pop

418 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
419 5c947f38 Iustin Pop
    function has no return value.
420 5c947f38 Iustin Pop

421 5c947f38 Iustin Pop
    """
422 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
423 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
424 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
425 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
426 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
427 5c947f38 Iustin Pop
    if not tag:
428 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
429 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
430 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
431 5c947f38 Iustin Pop
432 5c947f38 Iustin Pop
  def GetTags(self):
433 5c947f38 Iustin Pop
    """Return the tags list.
434 5c947f38 Iustin Pop

435 5c947f38 Iustin Pop
    """
436 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
437 5c947f38 Iustin Pop
    if tags is None:
438 5c947f38 Iustin Pop
      tags = self.tags = set()
439 5c947f38 Iustin Pop
    return tags
440 5c947f38 Iustin Pop
441 5c947f38 Iustin Pop
  def AddTag(self, tag):
442 5c947f38 Iustin Pop
    """Add a new tag.
443 5c947f38 Iustin Pop

444 5c947f38 Iustin Pop
    """
445 5c947f38 Iustin Pop
    self.ValidateTag(tag)
446 5c947f38 Iustin Pop
    tags = self.GetTags()
447 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
448 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
449 5c947f38 Iustin Pop
    self.GetTags().add(tag)
450 5c947f38 Iustin Pop
451 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
452 5c947f38 Iustin Pop
    """Remove a tag.
453 5c947f38 Iustin Pop

454 5c947f38 Iustin Pop
    """
455 5c947f38 Iustin Pop
    self.ValidateTag(tag)
456 5c947f38 Iustin Pop
    tags = self.GetTags()
457 5c947f38 Iustin Pop
    try:
458 5c947f38 Iustin Pop
      tags.remove(tag)
459 5c947f38 Iustin Pop
    except KeyError:
460 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
461 5c947f38 Iustin Pop
462 ff9c047c Iustin Pop
  def ToDict(self):
463 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
464 ff9c047c Iustin Pop

465 ff9c047c Iustin Pop
    This replaces the tags set with a list.
466 ff9c047c Iustin Pop

467 ff9c047c Iustin Pop
    """
468 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
469 ff9c047c Iustin Pop
470 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
471 ff9c047c Iustin Pop
    if isinstance(tags, set):
472 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
473 ff9c047c Iustin Pop
    return bo
474 ff9c047c Iustin Pop
475 ff9c047c Iustin Pop
  @classmethod
476 ff9c047c Iustin Pop
  def FromDict(cls, val):
477 ff9c047c Iustin Pop
    """Custom function for instances.
478 ff9c047c Iustin Pop

479 ff9c047c Iustin Pop
    """
480 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
481 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
482 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
483 ff9c047c Iustin Pop
    return obj
484 ff9c047c Iustin Pop
485 5c947f38 Iustin Pop
486 061af273 Andrea Spadaccini
class MasterNetworkParameters(ConfigObject):
487 061af273 Andrea Spadaccini
  """Network configuration parameters for the master
488 061af273 Andrea Spadaccini

489 061af273 Andrea Spadaccini
  @ivar name: master name
490 061af273 Andrea Spadaccini
  @ivar ip: master IP
491 061af273 Andrea Spadaccini
  @ivar netmask: master netmask
492 061af273 Andrea Spadaccini
  @ivar netdev: master network device
493 061af273 Andrea Spadaccini
  @ivar ip_family: master IP family
494 061af273 Andrea Spadaccini

495 061af273 Andrea Spadaccini
  """
496 061af273 Andrea Spadaccini
  __slots__ = [
497 061af273 Andrea Spadaccini
    "name",
498 061af273 Andrea Spadaccini
    "ip",
499 061af273 Andrea Spadaccini
    "netmask",
500 061af273 Andrea Spadaccini
    "netdev",
501 061af273 Andrea Spadaccini
    "ip_family"
502 061af273 Andrea Spadaccini
    ]
503 061af273 Andrea Spadaccini
504 061af273 Andrea Spadaccini
505 a8083063 Iustin Pop
class ConfigData(ConfigObject):
506 a8083063 Iustin Pop
  """Top-level config object."""
507 3df43542 Guido Trotter
  __slots__ = [
508 3df43542 Guido Trotter
    "version",
509 3df43542 Guido Trotter
    "cluster",
510 3df43542 Guido Trotter
    "nodes",
511 3df43542 Guido Trotter
    "nodegroups",
512 3df43542 Guido Trotter
    "instances",
513 3df43542 Guido Trotter
    "serial_no",
514 3df43542 Guido Trotter
    ] + _TIMESTAMPS
515 a8083063 Iustin Pop
516 ff9c047c Iustin Pop
  def ToDict(self):
517 ff9c047c Iustin Pop
    """Custom function for top-level config data.
518 ff9c047c Iustin Pop

519 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
520 ff9c047c Iustin Pop
    with standard python types.
521 ff9c047c Iustin Pop

522 ff9c047c Iustin Pop
    """
523 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
524 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
525 3df43542 Guido Trotter
    for key in "nodes", "instances", "nodegroups":
526 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
527 ff9c047c Iustin Pop
528 ff9c047c Iustin Pop
    return mydict
529 ff9c047c Iustin Pop
530 ff9c047c Iustin Pop
  @classmethod
531 ff9c047c Iustin Pop
  def FromDict(cls, val):
532 ff9c047c Iustin Pop
    """Custom function for top-level config data
533 ff9c047c Iustin Pop

534 ff9c047c Iustin Pop
    """
535 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
536 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
537 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
538 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
539 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
540 ff9c047c Iustin Pop
    return obj
541 ff9c047c Iustin Pop
542 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
543 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
544 51cb1581 Luca Bigliardi

545 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
546 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
547 51cb1581 Luca Bigliardi
    @rtype: boolean
548 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
549 51cb1581 Luca Bigliardi

550 51cb1581 Luca Bigliardi
    """
551 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
552 51cb1581 Luca Bigliardi
      for disk in instance.disks:
553 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
554 51cb1581 Luca Bigliardi
          return True
555 51cb1581 Luca Bigliardi
    return False
556 51cb1581 Luca Bigliardi
557 90d726a8 Iustin Pop
  def UpgradeConfig(self):
558 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
559 90d726a8 Iustin Pop

560 90d726a8 Iustin Pop
    """
561 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
562 90d726a8 Iustin Pop
    for node in self.nodes.values():
563 90d726a8 Iustin Pop
      node.UpgradeConfig()
564 90d726a8 Iustin Pop
    for instance in self.instances.values():
565 90d726a8 Iustin Pop
      instance.UpgradeConfig()
566 3df43542 Guido Trotter
    if self.nodegroups is None:
567 3df43542 Guido Trotter
      self.nodegroups = {}
568 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
569 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
570 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
571 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
572 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
573 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
574 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
575 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
576 90d726a8 Iustin Pop
577 a8083063 Iustin Pop
578 a8083063 Iustin Pop
class NIC(ConfigObject):
579 a8083063 Iustin Pop
  """Config object representing a network card."""
580 1177d70e Guido Trotter
  __slots__ = ["mac", "ip", "nicparams"]
581 a8083063 Iustin Pop
582 255e19d4 Guido Trotter
  @classmethod
583 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
584 255e19d4 Guido Trotter
    """Check the given parameters for validity.
585 255e19d4 Guido Trotter

586 255e19d4 Guido Trotter
    @type nicparams:  dict
587 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
588 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
589 255e19d4 Guido Trotter

590 255e19d4 Guido Trotter
    """
591 e8448672 Agata Murawska
    if (nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES and
592 e8448672 Agata Murawska
        nicparams[constants.NIC_MODE] != constants.VALUE_AUTO):
593 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
594 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
595 255e19d4 Guido Trotter
596 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
597 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
598 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
599 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
600 255e19d4 Guido Trotter
601 a8083063 Iustin Pop
602 a8083063 Iustin Pop
class Disk(ConfigObject):
603 a8083063 Iustin Pop
  """Config object representing a block device."""
604 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
605 bc5d0215 Andrea Spadaccini
               "children", "iv_name", "size", "mode", "params"]
606 a8083063 Iustin Pop
607 a8083063 Iustin Pop
  def CreateOnSecondary(self):
608 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
609 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
610 a8083063 Iustin Pop
611 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
612 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
613 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
614 a8083063 Iustin Pop
615 a8083063 Iustin Pop
  def OpenOnSecondary(self):
616 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
617 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
618 a8083063 Iustin Pop
619 222f2dd5 Iustin Pop
  def StaticDevPath(self):
620 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
621 222f2dd5 Iustin Pop

622 222f2dd5 Iustin Pop
    Some devices (LVM for example) live always at the same /dev/ path,
623 222f2dd5 Iustin Pop
    irrespective of their status. For such devices, we return this
624 222f2dd5 Iustin Pop
    path, for others we return None.
625 222f2dd5 Iustin Pop

626 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
627 e51db2a6 Iustin Pop
        should check that it is a valid path.
628 e51db2a6 Iustin Pop

629 222f2dd5 Iustin Pop
    """
630 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
631 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
632 b6135bbc Apollon Oikonomopoulos
    elif self.dev_type == constants.LD_BLOCKDEV:
633 b6135bbc Apollon Oikonomopoulos
      return self.logical_id[1]
634 7181fba0 Constantinos Venetsanopoulos
    elif self.dev_type == constants.LD_RBD:
635 7181fba0 Constantinos Venetsanopoulos
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
636 222f2dd5 Iustin Pop
    return None
637 222f2dd5 Iustin Pop
638 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
639 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
640 fc1dc9d7 Iustin Pop

641 fc1dc9d7 Iustin Pop
    This method will return either -1 (all children) or a positive
642 fc1dc9d7 Iustin Pop
    number denoting the minimum number of children needed for
643 fc1dc9d7 Iustin Pop
    activation (only mirrored devices will usually return >=0).
644 fc1dc9d7 Iustin Pop

645 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
646 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
647 fc1dc9d7 Iustin Pop
    -1.
648 fc1dc9d7 Iustin Pop

649 fc1dc9d7 Iustin Pop
    """
650 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
651 fc1dc9d7 Iustin Pop
      return 0
652 fc1dc9d7 Iustin Pop
    return -1
653 fc1dc9d7 Iustin Pop
654 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
655 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
656 51cb1581 Luca Bigliardi

657 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
658 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
659 51cb1581 Luca Bigliardi
    @rtype: boolean
660 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
661 51cb1581 Luca Bigliardi

662 51cb1581 Luca Bigliardi
    """
663 51cb1581 Luca Bigliardi
    if self.children:
664 51cb1581 Luca Bigliardi
      for child in self.children:
665 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
666 51cb1581 Luca Bigliardi
          return True
667 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
668 51cb1581 Luca Bigliardi
669 a8083063 Iustin Pop
  def GetNodes(self, node):
670 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
671 a8083063 Iustin Pop

672 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
673 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
674 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
675 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
676 a8083063 Iustin Pop

677 a8083063 Iustin Pop
    """
678 b6135bbc Apollon Oikonomopoulos
    if self.dev_type in [constants.LD_LV, constants.LD_FILE,
679 7181fba0 Constantinos Venetsanopoulos
                         constants.LD_BLOCKDEV, constants.LD_RBD]:
680 a8083063 Iustin Pop
      result = [node]
681 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
682 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
683 a8083063 Iustin Pop
      if node not in result:
684 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
685 a8083063 Iustin Pop
    else:
686 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
687 a8083063 Iustin Pop
    return result
688 a8083063 Iustin Pop
689 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
690 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
691 a8083063 Iustin Pop

692 a8083063 Iustin Pop
    This method, given the node on which the parent disk lives, will
693 a8083063 Iustin Pop
    return the list of all (node, disk) pairs which describe the disk
694 abdf0113 Iustin Pop
    tree in the most compact way. For example, a drbd/lvm stack
695 abdf0113 Iustin Pop
    will be returned as (primary_node, drbd) and (secondary_node, drbd)
696 abdf0113 Iustin Pop
    which represents all the top-level devices on the nodes.
697 a8083063 Iustin Pop

698 a8083063 Iustin Pop
    """
699 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
700 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
701 a8083063 Iustin Pop
    if not self.children:
702 a8083063 Iustin Pop
      # leaf device
703 a8083063 Iustin Pop
      return result
704 a8083063 Iustin Pop
    for node in my_nodes:
705 a8083063 Iustin Pop
      for child in self.children:
706 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
707 a8083063 Iustin Pop
        if len(child_result) == 1:
708 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
709 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
710 a8083063 Iustin Pop
          # own entry for this node describes it completely
711 a8083063 Iustin Pop
          continue
712 a8083063 Iustin Pop
        else:
713 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
714 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
715 a8083063 Iustin Pop
          # one of its descendants
716 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
717 a8083063 Iustin Pop
            if subnode not in my_nodes:
718 a8083063 Iustin Pop
              result.append((subnode, subdisk))
719 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
720 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
721 a8083063 Iustin Pop
            # be different)
722 a8083063 Iustin Pop
    return result
723 a8083063 Iustin Pop
724 6d33a6eb Iustin Pop
  def ComputeGrowth(self, amount):
725 6d33a6eb Iustin Pop
    """Compute the per-VG growth requirements.
726 6d33a6eb Iustin Pop

727 6d33a6eb Iustin Pop
    This only works for VG-based disks.
728 6d33a6eb Iustin Pop

729 6d33a6eb Iustin Pop
    @type amount: integer
730 6d33a6eb Iustin Pop
    @param amount: the desired increase in (user-visible) disk space
731 6d33a6eb Iustin Pop
    @rtype: dict
732 6d33a6eb Iustin Pop
    @return: a dictionary of volume-groups and the required size
733 6d33a6eb Iustin Pop

734 6d33a6eb Iustin Pop
    """
735 6d33a6eb Iustin Pop
    if self.dev_type == constants.LD_LV:
736 6d33a6eb Iustin Pop
      return {self.logical_id[0]: amount}
737 6d33a6eb Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
738 6d33a6eb Iustin Pop
      if self.children:
739 6d33a6eb Iustin Pop
        return self.children[0].ComputeGrowth(amount)
740 6d33a6eb Iustin Pop
      else:
741 6d33a6eb Iustin Pop
        return {}
742 6d33a6eb Iustin Pop
    else:
743 6d33a6eb Iustin Pop
      # Other disk types do not require VG space
744 6d33a6eb Iustin Pop
      return {}
745 6d33a6eb Iustin Pop
746 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
747 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
748 acec9d51 Iustin Pop

749 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
750 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
751 acec9d51 Iustin Pop
    actual algorithms from bdev.
752 acec9d51 Iustin Pop

753 acec9d51 Iustin Pop
    """
754 7181fba0 Constantinos Venetsanopoulos
    if self.dev_type in (constants.LD_LV, constants.LD_FILE,
755 7181fba0 Constantinos Venetsanopoulos
                         constants.LD_RBD):
756 acec9d51 Iustin Pop
      self.size += amount
757 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
758 acec9d51 Iustin Pop
      if self.children:
759 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
760 acec9d51 Iustin Pop
      self.size += amount
761 acec9d51 Iustin Pop
    else:
762 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
763 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
764 acec9d51 Iustin Pop
765 735e1318 Michael Hanselmann
  def Update(self, size=None, mode=None):
766 735e1318 Michael Hanselmann
    """Apply changes to size and mode.
767 735e1318 Michael Hanselmann

768 735e1318 Michael Hanselmann
    """
769 735e1318 Michael Hanselmann
    if self.dev_type == constants.LD_DRBD8:
770 735e1318 Michael Hanselmann
      if self.children:
771 735e1318 Michael Hanselmann
        self.children[0].Update(size=size, mode=mode)
772 735e1318 Michael Hanselmann
    else:
773 735e1318 Michael Hanselmann
      assert not self.children
774 735e1318 Michael Hanselmann
775 735e1318 Michael Hanselmann
    if size is not None:
776 735e1318 Michael Hanselmann
      self.size = size
777 735e1318 Michael Hanselmann
    if mode is not None:
778 735e1318 Michael Hanselmann
      self.mode = mode
779 735e1318 Michael Hanselmann
780 a805ec18 Iustin Pop
  def UnsetSize(self):
781 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
782 a805ec18 Iustin Pop

783 a805ec18 Iustin Pop
    """
784 a805ec18 Iustin Pop
    if self.children:
785 a805ec18 Iustin Pop
      for child in self.children:
786 a805ec18 Iustin Pop
        child.UnsetSize()
787 a805ec18 Iustin Pop
    self.size = 0
788 a805ec18 Iustin Pop
789 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
790 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
791 0402302c Iustin Pop

792 0402302c Iustin Pop
    This is used only for drbd, which needs ip/port configuration.
793 0402302c Iustin Pop

794 0402302c Iustin Pop
    The routine descends down and updates its children also, because
795 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
796 0402302c Iustin Pop
    node.
797 0402302c Iustin Pop

798 0402302c Iustin Pop
    Arguments:
799 0402302c Iustin Pop
      - target_node: the node we wish to configure for
800 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
801 0402302c Iustin Pop

802 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
803 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
804 0402302c Iustin Pop
    in the disk tree.
805 0402302c Iustin Pop

806 0402302c Iustin Pop
    """
807 0402302c Iustin Pop
    if self.children:
808 0402302c Iustin Pop
      for child in self.children:
809 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
810 0402302c Iustin Pop
811 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
812 0402302c Iustin Pop
      return
813 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
814 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
815 0402302c Iustin Pop
      if target_node not in (pnode, snode):
816 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
817 0402302c Iustin Pop
                                        target_node)
818 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
819 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
820 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
821 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
822 0402302c Iustin Pop
                                        " for %s" % str(self))
823 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
824 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
825 0402302c Iustin Pop
      if pnode == target_node:
826 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
827 0402302c Iustin Pop
      else: # it must be secondary, we tested above
828 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
829 0402302c Iustin Pop
    else:
830 0402302c Iustin Pop
      self.physical_id = self.logical_id
831 0402302c Iustin Pop
    return
832 0402302c Iustin Pop
833 ff9c047c Iustin Pop
  def ToDict(self):
834 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
835 ff9c047c Iustin Pop

836 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
837 ff9c047c Iustin Pop
    standard python types.
838 ff9c047c Iustin Pop

839 ff9c047c Iustin Pop
    """
840 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
841 ff9c047c Iustin Pop
842 ff9c047c Iustin Pop
    for attr in ("children",):
843 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
844 ff9c047c Iustin Pop
      if alist:
845 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
846 ff9c047c Iustin Pop
    return bo
847 ff9c047c Iustin Pop
848 ff9c047c Iustin Pop
  @classmethod
849 ff9c047c Iustin Pop
  def FromDict(cls, val):
850 ff9c047c Iustin Pop
    """Custom function for Disks
851 ff9c047c Iustin Pop

852 ff9c047c Iustin Pop
    """
853 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
854 ff9c047c Iustin Pop
    if obj.children:
855 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
856 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
857 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
858 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
859 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
860 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
861 f9518d38 Iustin Pop
      # we need a tuple of length six here
862 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
863 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
864 ff9c047c Iustin Pop
    return obj
865 ff9c047c Iustin Pop
866 65a15336 Iustin Pop
  def __str__(self):
867 65a15336 Iustin Pop
    """Custom str() formatter for disks.
868 65a15336 Iustin Pop

869 65a15336 Iustin Pop
    """
870 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
871 e687ec01 Michael Hanselmann
      val = "<LogicalVolume(/dev/%s/%s" % self.logical_id
872 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
873 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
874 00fb8246 Michael Hanselmann
      val = "<DRBD8("
875 073ca59e Iustin Pop
      if self.physical_id is None:
876 073ca59e Iustin Pop
        phy = "unconfigured"
877 073ca59e Iustin Pop
      else:
878 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
879 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
880 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
881 073ca59e Iustin Pop
882 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
883 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
884 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
885 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
886 65a15336 Iustin Pop
      else:
887 65a15336 Iustin Pop
        val += "no local storage"
888 65a15336 Iustin Pop
    else:
889 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
890 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
891 65a15336 Iustin Pop
    if self.iv_name is None:
892 65a15336 Iustin Pop
      val += ", not visible"
893 65a15336 Iustin Pop
    else:
894 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
895 fd965830 Iustin Pop
    if isinstance(self.size, int):
896 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
897 fd965830 Iustin Pop
    else:
898 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
899 65a15336 Iustin Pop
    return val
900 65a15336 Iustin Pop
901 332d0e37 Iustin Pop
  def Verify(self):
902 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
903 332d0e37 Iustin Pop

904 332d0e37 Iustin Pop
    """
905 7c4d6c7b Michael Hanselmann
    all_errors = []
906 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
907 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
908 7c4d6c7b Michael Hanselmann
    return all_errors
909 332d0e37 Iustin Pop
910 90d726a8 Iustin Pop
  def UpgradeConfig(self):
911 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
912 90d726a8 Iustin Pop

913 90d726a8 Iustin Pop
    """
914 90d726a8 Iustin Pop
    if self.children:
915 90d726a8 Iustin Pop
      for child in self.children:
916 90d726a8 Iustin Pop
        child.UpgradeConfig()
917 bc5d0215 Andrea Spadaccini
918 bc5d0215 Andrea Spadaccini
    if not self.params:
919 bc5d0215 Andrea Spadaccini
      self.params = constants.DISK_LD_DEFAULTS[self.dev_type].copy()
920 bc5d0215 Andrea Spadaccini
    else:
921 bc5d0215 Andrea Spadaccini
      self.params = FillDict(constants.DISK_LD_DEFAULTS[self.dev_type],
922 bc5d0215 Andrea Spadaccini
                             self.params)
923 90d726a8 Iustin Pop
    # add here config upgrade for this disk
924 90d726a8 Iustin Pop
925 cd46491f René Nussbaumer
  @staticmethod
926 cd46491f René Nussbaumer
  def ComputeLDParams(disk_template, disk_params):
927 cd46491f René Nussbaumer
    """Computes Logical Disk parameters from Disk Template parameters.
928 cd46491f René Nussbaumer

929 cd46491f René Nussbaumer
    @type disk_template: string
930 cd46491f René Nussbaumer
    @param disk_template: disk template, one of L{constants.DISK_TEMPLATES}
931 cd46491f René Nussbaumer
    @type disk_params: dict
932 cd46491f René Nussbaumer
    @param disk_params: disk template parameters;
933 cd46491f René Nussbaumer
                        dict(template_name -> parameters
934 cd46491f René Nussbaumer
    @rtype: list(dict)
935 cd46491f René Nussbaumer
    @return: a list of dicts, one for each node of the disk hierarchy. Each dict
936 cd46491f René Nussbaumer
      contains the LD parameters of the node. The tree is flattened in-order.
937 cd46491f René Nussbaumer

938 cd46491f René Nussbaumer
    """
939 cd46491f René Nussbaumer
    if disk_template not in constants.DISK_TEMPLATES:
940 cd46491f René Nussbaumer
      raise errors.ProgrammerError("Unknown disk template %s" % disk_template)
941 cd46491f René Nussbaumer
942 cd46491f René Nussbaumer
    assert disk_template in disk_params
943 cd46491f René Nussbaumer
944 cd46491f René Nussbaumer
    result = list()
945 cd46491f René Nussbaumer
    dt_params = disk_params[disk_template]
946 cd46491f René Nussbaumer
    if disk_template == constants.DT_DRBD8:
947 cd46491f René Nussbaumer
      drbd_params = {
948 cd46491f René Nussbaumer
        constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE],
949 cd46491f René Nussbaumer
        constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS],
950 cd46491f René Nussbaumer
        constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS],
951 cd46491f René Nussbaumer
        constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG],
952 cd46491f René Nussbaumer
        constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM],
953 cd46491f René Nussbaumer
        constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM],
954 cd46491f René Nussbaumer
        constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC],
955 cd46491f René Nussbaumer
        constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD],
956 cd46491f René Nussbaumer
        constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET],
957 cd46491f René Nussbaumer
        constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET],
958 cd46491f René Nussbaumer
        constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE],
959 cd46491f René Nussbaumer
        constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE],
960 cd46491f René Nussbaumer
        }
961 cd46491f René Nussbaumer
962 cd46491f René Nussbaumer
      drbd_params = \
963 cd46491f René Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8],
964 cd46491f René Nussbaumer
                 drbd_params)
965 cd46491f René Nussbaumer
966 cd46491f René Nussbaumer
      result.append(drbd_params)
967 cd46491f René Nussbaumer
968 cd46491f René Nussbaumer
      # data LV
969 cd46491f René Nussbaumer
      data_params = {
970 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
971 cd46491f René Nussbaumer
        }
972 cd46491f René Nussbaumer
      data_params = \
973 cd46491f René Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
974 cd46491f René Nussbaumer
                 data_params)
975 cd46491f René Nussbaumer
      result.append(data_params)
976 cd46491f René Nussbaumer
977 cd46491f René Nussbaumer
      # metadata LV
978 cd46491f René Nussbaumer
      meta_params = {
979 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
980 cd46491f René Nussbaumer
        }
981 cd46491f René Nussbaumer
      meta_params = \
982 cd46491f René Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
983 cd46491f René Nussbaumer
                 meta_params)
984 cd46491f René Nussbaumer
      result.append(meta_params)
985 cd46491f René Nussbaumer
986 cd46491f René Nussbaumer
    elif (disk_template == constants.DT_FILE or
987 cd46491f René Nussbaumer
          disk_template == constants.DT_SHARED_FILE):
988 cd46491f René Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
989 cd46491f René Nussbaumer
990 cd46491f René Nussbaumer
    elif disk_template == constants.DT_PLAIN:
991 cd46491f René Nussbaumer
      params = {
992 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
993 cd46491f René Nussbaumer
        }
994 cd46491f René Nussbaumer
      params = \
995 cd46491f René Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
996 cd46491f René Nussbaumer
                 params)
997 cd46491f René Nussbaumer
      result.append(params)
998 cd46491f René Nussbaumer
999 cd46491f René Nussbaumer
    elif disk_template == constants.DT_BLOCK:
1000 cd46491f René Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
1001 cd46491f René Nussbaumer
1002 cd46491f René Nussbaumer
    elif disk_template == constants.DT_RBD:
1003 cd46491f René Nussbaumer
      params = {
1004 cd46491f René Nussbaumer
        constants.LDP_POOL: dt_params[constants.RBD_POOL]
1005 cd46491f René Nussbaumer
        }
1006 cd46491f René Nussbaumer
      params = \
1007 cd46491f René Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD],
1008 cd46491f René Nussbaumer
                 params)
1009 cd46491f René Nussbaumer
      result.append(params)
1010 cd46491f René Nussbaumer
1011 cd46491f René Nussbaumer
    return result
1012 cd46491f René Nussbaumer
1013 a8083063 Iustin Pop
1014 918eb80b Agata Murawska
class InstancePolicy(ConfigObject):
1015 ffa339ca Iustin Pop
  """Config object representing instance policy limits dictionary.
1016 918eb80b Agata Murawska

1017 ffa339ca Iustin Pop

1018 ffa339ca Iustin Pop
  Note that this object is not actually used in the config, it's just
1019 ffa339ca Iustin Pop
  used as a placeholder for a few functions.
1020 ffa339ca Iustin Pop

1021 ffa339ca Iustin Pop
  """
1022 918eb80b Agata Murawska
  @classmethod
1023 918eb80b Agata Murawska
  def CheckParameterSyntax(cls, ipolicy):
1024 918eb80b Agata Murawska
    """ Check the instance policy for validity.
1025 918eb80b Agata Murawska

1026 918eb80b Agata Murawska
    """
1027 918eb80b Agata Murawska
    for param in constants.ISPECS_PARAMETERS:
1028 918eb80b Agata Murawska
      InstancePolicy.CheckISpecSyntax(ipolicy, param)
1029 d04c9d45 Iustin Pop
    if constants.IPOLICY_DTS in ipolicy:
1030 d04c9d45 Iustin Pop
      InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
1031 ff6c5e55 Iustin Pop
    for key in constants.IPOLICY_PARAMETERS:
1032 ff6c5e55 Iustin Pop
      if key in ipolicy:
1033 ff6c5e55 Iustin Pop
        InstancePolicy.CheckParameter(key, ipolicy[key])
1034 57dc299a Iustin Pop
    wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
1035 57dc299a Iustin Pop
    if wrong_keys:
1036 57dc299a Iustin Pop
      raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
1037 57dc299a Iustin Pop
                                      utils.CommaJoin(wrong_keys))
1038 918eb80b Agata Murawska
1039 918eb80b Agata Murawska
  @classmethod
1040 918eb80b Agata Murawska
  def CheckISpecSyntax(cls, ipolicy, name):
1041 918eb80b Agata Murawska
    """Check the instance policy for validity on a given key.
1042 918eb80b Agata Murawska

1043 918eb80b Agata Murawska
    We check if the instance policy makes sense for a given key, that is
1044 918eb80b Agata Murawska
    if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name].
1045 918eb80b Agata Murawska

1046 918eb80b Agata Murawska
    @type ipolicy: dict
1047 918eb80b Agata Murawska
    @param ipolicy: dictionary with min, max, std specs
1048 918eb80b Agata Murawska
    @type name: string
1049 918eb80b Agata Murawska
    @param name: what are the limits for
1050 918eb80b Agata Murawska
    @raise errors.ConfigureError: when specs for given name are not valid
1051 918eb80b Agata Murawska

1052 918eb80b Agata Murawska
    """
1053 4f725341 Agata Murawska
    min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
1054 4f725341 Agata Murawska
    std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
1055 4f725341 Agata Murawska
    max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
1056 918eb80b Agata Murawska
    err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
1057 918eb80b Agata Murawska
           (name,
1058 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MIN].get(name, "-"),
1059 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MAX].get(name, "-"),
1060 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_STD].get(name, "-")))
1061 918eb80b Agata Murawska
    if min_v > std_v or std_v > max_v:
1062 918eb80b Agata Murawska
      raise errors.ConfigurationError(err)
1063 918eb80b Agata Murawska
1064 2cc673a3 Iustin Pop
  @classmethod
1065 2cc673a3 Iustin Pop
  def CheckDiskTemplates(cls, disk_templates):
1066 2cc673a3 Iustin Pop
    """Checks the disk templates for validity.
1067 2cc673a3 Iustin Pop

1068 2cc673a3 Iustin Pop
    """
1069 2cc673a3 Iustin Pop
    wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
1070 2cc673a3 Iustin Pop
    if wrong:
1071 2cc673a3 Iustin Pop
      raise errors.ConfigurationError("Invalid disk template(s) %s" %
1072 2cc673a3 Iustin Pop
                                      utils.CommaJoin(wrong))
1073 2cc673a3 Iustin Pop
1074 ff6c5e55 Iustin Pop
  @classmethod
1075 ff6c5e55 Iustin Pop
  def CheckParameter(cls, key, value):
1076 ff6c5e55 Iustin Pop
    """Checks a parameter.
1077 ff6c5e55 Iustin Pop

1078 ff6c5e55 Iustin Pop
    Currently we expect all parameters to be float values.
1079 ff6c5e55 Iustin Pop

1080 ff6c5e55 Iustin Pop
    """
1081 ff6c5e55 Iustin Pop
    try:
1082 ff6c5e55 Iustin Pop
      float(value)
1083 ff6c5e55 Iustin Pop
    except (TypeError, ValueError), err:
1084 ff6c5e55 Iustin Pop
      raise errors.ConfigurationError("Invalid value for key" " '%s':"
1085 ff6c5e55 Iustin Pop
                                      " '%s', error: %s" % (key, value, err))
1086 ff6c5e55 Iustin Pop
1087 918eb80b Agata Murawska
1088 ec29fe40 Iustin Pop
class Instance(TaggableObject):
1089 a8083063 Iustin Pop
  """Config object representing an instance."""
1090 154b9580 Balazs Lecz
  __slots__ = [
1091 a8083063 Iustin Pop
    "name",
1092 a8083063 Iustin Pop
    "primary_node",
1093 a8083063 Iustin Pop
    "os",
1094 e69d05fd Iustin Pop
    "hypervisor",
1095 5bf7b5cf Iustin Pop
    "hvparams",
1096 5bf7b5cf Iustin Pop
    "beparams",
1097 1bdcbbab Iustin Pop
    "osparams",
1098 9ca8a7c5 Agata Murawska
    "admin_state",
1099 a8083063 Iustin Pop
    "nics",
1100 a8083063 Iustin Pop
    "disks",
1101 a8083063 Iustin Pop
    "disk_template",
1102 58acb49d Alexander Schreiber
    "network_port",
1103 be1fa613 Iustin Pop
    "serial_no",
1104 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1105 a8083063 Iustin Pop
1106 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
1107 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
1108 a8083063 Iustin Pop

1109 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
1110 cfcc5c6d Iustin Pop

1111 cfcc5c6d Iustin Pop
    """
1112 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
1113 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
1114 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1115 cfcc5c6d Iustin Pop
1116 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
1117 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
1118 cfcc5c6d Iustin Pop
1119 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
1120 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
1121 cfcc5c6d Iustin Pop

1122 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
1123 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
1124 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
1125 a8083063 Iustin Pop
    dynamically.
1126 a8083063 Iustin Pop

1127 a8083063 Iustin Pop
    """
1128 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
1129 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
1130 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
1131 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
1132 cfcc5c6d Iustin Pop
        nodes.add(nodea)
1133 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
1134 a8083063 Iustin Pop
      if device.children:
1135 a8083063 Iustin Pop
        for child in device.children:
1136 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
1137 a8083063 Iustin Pop
1138 cfcc5c6d Iustin Pop
    all_nodes = set()
1139 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
1140 a8083063 Iustin Pop
    for device in self.disks:
1141 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
1142 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1143 a8083063 Iustin Pop
1144 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
1145 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
1146 a8083063 Iustin Pop
1147 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
1148 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
1149 a8083063 Iustin Pop

1150 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
1151 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
1152 a8083063 Iustin Pop

1153 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
1154 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
1155 a8083063 Iustin Pop

1156 84d7e26b Dmitry Chernyak
    @return: None if lvmap arg is given, otherwise, a dictionary of
1157 84d7e26b Dmitry Chernyak
        the form { 'nodename' : ['volume1', 'volume2', ...], ... };
1158 84d7e26b Dmitry Chernyak
        volumeN is of the form "vg_name/lv_name", compatible with
1159 84d7e26b Dmitry Chernyak
        GetVolumeList()
1160 a8083063 Iustin Pop

1161 a8083063 Iustin Pop
    """
1162 a8083063 Iustin Pop
    if node == None:
1163 a8083063 Iustin Pop
      node = self.primary_node
1164 a8083063 Iustin Pop
1165 a8083063 Iustin Pop
    if lvmap is None:
1166 e687ec01 Michael Hanselmann
      lvmap = {
1167 e687ec01 Michael Hanselmann
        node: [],
1168 e687ec01 Michael Hanselmann
        }
1169 a8083063 Iustin Pop
      ret = lvmap
1170 a8083063 Iustin Pop
    else:
1171 a8083063 Iustin Pop
      if not node in lvmap:
1172 a8083063 Iustin Pop
        lvmap[node] = []
1173 a8083063 Iustin Pop
      ret = None
1174 a8083063 Iustin Pop
1175 a8083063 Iustin Pop
    if not devs:
1176 a8083063 Iustin Pop
      devs = self.disks
1177 a8083063 Iustin Pop
1178 a8083063 Iustin Pop
    for dev in devs:
1179 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
1180 e687ec01 Michael Hanselmann
        lvmap[node].append(dev.logical_id[0] + "/" + dev.logical_id[1])
1181 a8083063 Iustin Pop
1182 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
1183 a8083063 Iustin Pop
        if dev.children:
1184 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
1185 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
1186 a8083063 Iustin Pop
1187 a8083063 Iustin Pop
      elif dev.children:
1188 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
1189 a8083063 Iustin Pop
1190 a8083063 Iustin Pop
    return ret
1191 a8083063 Iustin Pop
1192 ad24e046 Iustin Pop
  def FindDisk(self, idx):
1193 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
1194 644eeef9 Iustin Pop

1195 ad24e046 Iustin Pop
    This is just a wrapper that does validation of the index.
1196 644eeef9 Iustin Pop

1197 ad24e046 Iustin Pop
    @type idx: int
1198 ad24e046 Iustin Pop
    @param idx: the disk index
1199 ad24e046 Iustin Pop
    @rtype: L{Disk}
1200 ad24e046 Iustin Pop
    @return: the corresponding disk
1201 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
1202 644eeef9 Iustin Pop

1203 ad24e046 Iustin Pop
    """
1204 ad24e046 Iustin Pop
    try:
1205 ad24e046 Iustin Pop
      idx = int(idx)
1206 ad24e046 Iustin Pop
      return self.disks[idx]
1207 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
1208 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
1209 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1210 ad24e046 Iustin Pop
    except IndexError:
1211 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
1212 daa55b04 Michael Hanselmann
                                 " 0 to %d" % (idx, len(self.disks) - 1),
1213 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1214 644eeef9 Iustin Pop
1215 ff9c047c Iustin Pop
  def ToDict(self):
1216 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
1217 ff9c047c Iustin Pop

1218 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
1219 ff9c047c Iustin Pop
    python types.
1220 ff9c047c Iustin Pop

1221 ff9c047c Iustin Pop
    """
1222 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
1223 ff9c047c Iustin Pop
1224 ff9c047c Iustin Pop
    for attr in "nics", "disks":
1225 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
1226 ff9c047c Iustin Pop
      if alist:
1227 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
1228 ff9c047c Iustin Pop
      else:
1229 ff9c047c Iustin Pop
        nlist = []
1230 ff9c047c Iustin Pop
      bo[attr] = nlist
1231 ff9c047c Iustin Pop
    return bo
1232 ff9c047c Iustin Pop
1233 ff9c047c Iustin Pop
  @classmethod
1234 ff9c047c Iustin Pop
  def FromDict(cls, val):
1235 ff9c047c Iustin Pop
    """Custom function for instances.
1236 ff9c047c Iustin Pop

1237 ff9c047c Iustin Pop
    """
1238 9ca8a7c5 Agata Murawska
    if "admin_state" not in val:
1239 9ca8a7c5 Agata Murawska
      if val.get("admin_up", False):
1240 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_UP
1241 9ca8a7c5 Agata Murawska
      else:
1242 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_DOWN
1243 9ca8a7c5 Agata Murawska
    if "admin_up" in val:
1244 9ca8a7c5 Agata Murawska
      del val["admin_up"]
1245 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
1246 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
1247 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
1248 ff9c047c Iustin Pop
    return obj
1249 ff9c047c Iustin Pop
1250 90d726a8 Iustin Pop
  def UpgradeConfig(self):
1251 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
1252 90d726a8 Iustin Pop

1253 90d726a8 Iustin Pop
    """
1254 90d726a8 Iustin Pop
    for nic in self.nics:
1255 90d726a8 Iustin Pop
      nic.UpgradeConfig()
1256 90d726a8 Iustin Pop
    for disk in self.disks:
1257 90d726a8 Iustin Pop
      disk.UpgradeConfig()
1258 7736a5f2 Iustin Pop
    if self.hvparams:
1259 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
1260 7736a5f2 Iustin Pop
        try:
1261 7736a5f2 Iustin Pop
          del self.hvparams[key]
1262 7736a5f2 Iustin Pop
        except KeyError:
1263 7736a5f2 Iustin Pop
          pass
1264 1bdcbbab Iustin Pop
    if self.osparams is None:
1265 1bdcbbab Iustin Pop
      self.osparams = {}
1266 8c72ab2b Guido Trotter
    UpgradeBeParams(self.beparams)
1267 90d726a8 Iustin Pop
1268 a8083063 Iustin Pop
1269 a8083063 Iustin Pop
class OS(ConfigObject):
1270 b41b3516 Iustin Pop
  """Config object representing an operating system.
1271 b41b3516 Iustin Pop

1272 b41b3516 Iustin Pop
  @type supported_parameters: list
1273 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
1274 b41b3516 Iustin Pop
      containing the supported parameters by this OS
1275 b41b3516 Iustin Pop

1276 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
1277 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
1278 870dc44c Iustin Pop

1279 b41b3516 Iustin Pop
  """
1280 a8083063 Iustin Pop
  __slots__ = [
1281 a8083063 Iustin Pop
    "name",
1282 a8083063 Iustin Pop
    "path",
1283 082a7f91 Guido Trotter
    "api_versions",
1284 a8083063 Iustin Pop
    "create_script",
1285 a8083063 Iustin Pop
    "export_script",
1286 386b57af Iustin Pop
    "import_script",
1287 386b57af Iustin Pop
    "rename_script",
1288 b41b3516 Iustin Pop
    "verify_script",
1289 6d79896b Guido Trotter
    "supported_variants",
1290 b41b3516 Iustin Pop
    "supported_parameters",
1291 a8083063 Iustin Pop
    ]
1292 a8083063 Iustin Pop
1293 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
1294 870dc44c Iustin Pop
1295 870dc44c Iustin Pop
  @classmethod
1296 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
1297 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
1298 870dc44c Iustin Pop

1299 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1300 870dc44c Iustin Pop
    @rtype: list
1301 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
1302 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
1303 870dc44c Iustin Pop

1304 870dc44c Iustin Pop
    """
1305 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
1306 870dc44c Iustin Pop
    if len(nv) == 1:
1307 870dc44c Iustin Pop
      nv.append("")
1308 870dc44c Iustin Pop
    return nv
1309 870dc44c Iustin Pop
1310 870dc44c Iustin Pop
  @classmethod
1311 870dc44c Iustin Pop
  def GetName(cls, name):
1312 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
1313 870dc44c Iustin Pop

1314 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1315 870dc44c Iustin Pop

1316 870dc44c Iustin Pop
    """
1317 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
1318 870dc44c Iustin Pop
1319 870dc44c Iustin Pop
  @classmethod
1320 870dc44c Iustin Pop
  def GetVariant(cls, name):
1321 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
1322 870dc44c Iustin Pop

1323 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1324 870dc44c Iustin Pop

1325 870dc44c Iustin Pop
    """
1326 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
1327 870dc44c Iustin Pop
1328 7c0d6283 Michael Hanselmann
1329 5f06ce5e Michael Hanselmann
class NodeHvState(ConfigObject):
1330 5f06ce5e Michael Hanselmann
  """Hypvervisor state on a node.
1331 5f06ce5e Michael Hanselmann

1332 5f06ce5e Michael Hanselmann
  @ivar mem_total: Total amount of memory
1333 5f06ce5e Michael Hanselmann
  @ivar mem_node: Memory used by, or reserved for, the node itself (not always
1334 5f06ce5e Michael Hanselmann
    available)
1335 5f06ce5e Michael Hanselmann
  @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation
1336 5f06ce5e Michael Hanselmann
    rounding
1337 5f06ce5e Michael Hanselmann
  @ivar mem_inst: Memory used by instances living on node
1338 5f06ce5e Michael Hanselmann
  @ivar cpu_total: Total node CPU core count
1339 5f06ce5e Michael Hanselmann
  @ivar cpu_node: Number of CPU cores reserved for the node itself
1340 5f06ce5e Michael Hanselmann

1341 5f06ce5e Michael Hanselmann
  """
1342 5f06ce5e Michael Hanselmann
  __slots__ = [
1343 5f06ce5e Michael Hanselmann
    "mem_total",
1344 5f06ce5e Michael Hanselmann
    "mem_node",
1345 5f06ce5e Michael Hanselmann
    "mem_hv",
1346 5f06ce5e Michael Hanselmann
    "mem_inst",
1347 5f06ce5e Michael Hanselmann
    "cpu_total",
1348 5f06ce5e Michael Hanselmann
    "cpu_node",
1349 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1350 5f06ce5e Michael Hanselmann
1351 5f06ce5e Michael Hanselmann
1352 5f06ce5e Michael Hanselmann
class NodeDiskState(ConfigObject):
1353 5f06ce5e Michael Hanselmann
  """Disk state on a node.
1354 5f06ce5e Michael Hanselmann

1355 5f06ce5e Michael Hanselmann
  """
1356 5f06ce5e Michael Hanselmann
  __slots__ = [
1357 5f06ce5e Michael Hanselmann
    "total",
1358 5f06ce5e Michael Hanselmann
    "reserved",
1359 5f06ce5e Michael Hanselmann
    "overhead",
1360 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1361 5f06ce5e Michael Hanselmann
1362 5f06ce5e Michael Hanselmann
1363 ec29fe40 Iustin Pop
class Node(TaggableObject):
1364 634d30f4 Michael Hanselmann
  """Config object representing a node.
1365 634d30f4 Michael Hanselmann

1366 634d30f4 Michael Hanselmann
  @ivar hv_state: Hypervisor state (e.g. number of CPUs)
1367 634d30f4 Michael Hanselmann
  @ivar hv_state_static: Hypervisor state overriden by user
1368 634d30f4 Michael Hanselmann
  @ivar disk_state: Disk state (e.g. free space)
1369 634d30f4 Michael Hanselmann
  @ivar disk_state_static: Disk state overriden by user
1370 634d30f4 Michael Hanselmann

1371 634d30f4 Michael Hanselmann
  """
1372 154b9580 Balazs Lecz
  __slots__ = [
1373 ec29fe40 Iustin Pop
    "name",
1374 ec29fe40 Iustin Pop
    "primary_ip",
1375 ec29fe40 Iustin Pop
    "secondary_ip",
1376 be1fa613 Iustin Pop
    "serial_no",
1377 8b8b8b81 Iustin Pop
    "master_candidate",
1378 fc0fe88c Iustin Pop
    "offline",
1379 af64c0ea Iustin Pop
    "drained",
1380 f936c153 Iustin Pop
    "group",
1381 490acd18 Iustin Pop
    "master_capable",
1382 490acd18 Iustin Pop
    "vm_capable",
1383 095e71aa René Nussbaumer
    "ndparams",
1384 25124d4a René Nussbaumer
    "powered",
1385 5b49ed09 René Nussbaumer
    "hv_state",
1386 634d30f4 Michael Hanselmann
    "hv_state_static",
1387 5b49ed09 René Nussbaumer
    "disk_state",
1388 634d30f4 Michael Hanselmann
    "disk_state_static",
1389 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1390 a8083063 Iustin Pop
1391 490acd18 Iustin Pop
  def UpgradeConfig(self):
1392 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
1393 490acd18 Iustin Pop

1394 490acd18 Iustin Pop
    """
1395 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1396 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
1397 490acd18 Iustin Pop
    if self.master_capable is None:
1398 490acd18 Iustin Pop
      self.master_capable = True
1399 490acd18 Iustin Pop
1400 490acd18 Iustin Pop
    if self.vm_capable is None:
1401 490acd18 Iustin Pop
      self.vm_capable = True
1402 490acd18 Iustin Pop
1403 095e71aa René Nussbaumer
    if self.ndparams is None:
1404 095e71aa René Nussbaumer
      self.ndparams = {}
1405 095e71aa René Nussbaumer
1406 25124d4a René Nussbaumer
    if self.powered is None:
1407 25124d4a René Nussbaumer
      self.powered = True
1408 25124d4a René Nussbaumer
1409 5f06ce5e Michael Hanselmann
  def ToDict(self):
1410 5f06ce5e Michael Hanselmann
    """Custom function for serializing.
1411 5f06ce5e Michael Hanselmann

1412 5f06ce5e Michael Hanselmann
    """
1413 5f06ce5e Michael Hanselmann
    data = super(Node, self).ToDict()
1414 5f06ce5e Michael Hanselmann
1415 5f06ce5e Michael Hanselmann
    hv_state = data.get("hv_state", None)
1416 5f06ce5e Michael Hanselmann
    if hv_state is not None:
1417 5f06ce5e Michael Hanselmann
      data["hv_state"] = self._ContainerToDicts(hv_state)
1418 5f06ce5e Michael Hanselmann
1419 5f06ce5e Michael Hanselmann
    disk_state = data.get("disk_state", None)
1420 5f06ce5e Michael Hanselmann
    if disk_state is not None:
1421 5f06ce5e Michael Hanselmann
      data["disk_state"] = \
1422 5f06ce5e Michael Hanselmann
        dict((key, self._ContainerToDicts(value))
1423 5f06ce5e Michael Hanselmann
             for (key, value) in disk_state.items())
1424 5f06ce5e Michael Hanselmann
1425 5f06ce5e Michael Hanselmann
    return data
1426 5f06ce5e Michael Hanselmann
1427 5f06ce5e Michael Hanselmann
  @classmethod
1428 5f06ce5e Michael Hanselmann
  def FromDict(cls, val):
1429 5f06ce5e Michael Hanselmann
    """Custom function for deserializing.
1430 5f06ce5e Michael Hanselmann

1431 5f06ce5e Michael Hanselmann
    """
1432 5f06ce5e Michael Hanselmann
    obj = super(Node, cls).FromDict(val)
1433 5f06ce5e Michael Hanselmann
1434 5f06ce5e Michael Hanselmann
    if obj.hv_state is not None:
1435 5f06ce5e Michael Hanselmann
      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1436 5f06ce5e Michael Hanselmann
1437 5f06ce5e Michael Hanselmann
    if obj.disk_state is not None:
1438 5f06ce5e Michael Hanselmann
      obj.disk_state = \
1439 5f06ce5e Michael Hanselmann
        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
1440 5f06ce5e Michael Hanselmann
             for (key, value) in obj.disk_state.items())
1441 5f06ce5e Michael Hanselmann
1442 5f06ce5e Michael Hanselmann
    return obj
1443 5f06ce5e Michael Hanselmann
1444 a8083063 Iustin Pop
1445 1ffd2673 Michael Hanselmann
class NodeGroup(TaggableObject):
1446 24a3707f Guido Trotter
  """Config object representing a node group."""
1447 24a3707f Guido Trotter
  __slots__ = [
1448 24a3707f Guido Trotter
    "name",
1449 24a3707f Guido Trotter
    "members",
1450 095e71aa René Nussbaumer
    "ndparams",
1451 bc5d0215 Andrea Spadaccini
    "diskparams",
1452 81e3ab4f Agata Murawska
    "ipolicy",
1453 e11a1b77 Adeodato Simo
    "serial_no",
1454 a8282327 René Nussbaumer
    "hv_state_static",
1455 a8282327 René Nussbaumer
    "disk_state_static",
1456 90e99856 Adeodato Simo
    "alloc_policy",
1457 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
1458 24a3707f Guido Trotter
1459 24a3707f Guido Trotter
  def ToDict(self):
1460 24a3707f Guido Trotter
    """Custom function for nodegroup.
1461 24a3707f Guido Trotter

1462 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1463 c60abd62 Guido Trotter
    in memory.
1464 24a3707f Guido Trotter

1465 24a3707f Guido Trotter
    """
1466 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
1467 24a3707f Guido Trotter
    del mydict["members"]
1468 24a3707f Guido Trotter
    return mydict
1469 24a3707f Guido Trotter
1470 24a3707f Guido Trotter
  @classmethod
1471 24a3707f Guido Trotter
  def FromDict(cls, val):
1472 24a3707f Guido Trotter
    """Custom function for nodegroup.
1473 24a3707f Guido Trotter

1474 24a3707f Guido Trotter
    The members slot is initialized to an empty list, upon deserialization.
1475 24a3707f Guido Trotter

1476 24a3707f Guido Trotter
    """
1477 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
1478 24a3707f Guido Trotter
    obj.members = []
1479 24a3707f Guido Trotter
    return obj
1480 24a3707f Guido Trotter
1481 095e71aa René Nussbaumer
  def UpgradeConfig(self):
1482 095e71aa René Nussbaumer
    """Fill defaults for missing configuration values.
1483 095e71aa René Nussbaumer

1484 095e71aa René Nussbaumer
    """
1485 095e71aa René Nussbaumer
    if self.ndparams is None:
1486 095e71aa René Nussbaumer
      self.ndparams = {}
1487 095e71aa René Nussbaumer
1488 e11a1b77 Adeodato Simo
    if self.serial_no is None:
1489 e11a1b77 Adeodato Simo
      self.serial_no = 1
1490 e11a1b77 Adeodato Simo
1491 90e99856 Adeodato Simo
    if self.alloc_policy is None:
1492 90e99856 Adeodato Simo
      self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
1493 90e99856 Adeodato Simo
1494 4b97458c Iustin Pop
    # We only update mtime, and not ctime, since we would not be able
1495 4b97458c Iustin Pop
    # to provide a correct value for creation time.
1496 e11a1b77 Adeodato Simo
    if self.mtime is None:
1497 e11a1b77 Adeodato Simo
      self.mtime = time.time()
1498 e11a1b77 Adeodato Simo
1499 bc5d0215 Andrea Spadaccini
    self.diskparams = UpgradeDiskParams(self.diskparams)
1500 81e3ab4f Agata Murawska
    if self.ipolicy is None:
1501 81e3ab4f Agata Murawska
      self.ipolicy = MakeEmptyIPolicy()
1502 bc5d0215 Andrea Spadaccini
1503 095e71aa René Nussbaumer
  def FillND(self, node):
1504 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.Node}
1505 095e71aa René Nussbaumer

1506 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1507 095e71aa René Nussbaumer
    @param node: A Node object to fill
1508 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1509 095e71aa René Nussbaumer

1510 095e71aa René Nussbaumer
    """
1511 095e71aa René Nussbaumer
    return self.SimpleFillND(node.ndparams)
1512 095e71aa René Nussbaumer
1513 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1514 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1515 095e71aa René Nussbaumer

1516 095e71aa René Nussbaumer
    @type ndparams: dict
1517 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1518 095e71aa René Nussbaumer
    @rtype: dict
1519 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1520 e6e88de6 Adeodato Simo
        from the node group defaults
1521 095e71aa René Nussbaumer

1522 095e71aa René Nussbaumer
    """
1523 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1524 095e71aa René Nussbaumer
1525 24a3707f Guido Trotter
1526 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
1527 a8083063 Iustin Pop
  """Config object representing the cluster."""
1528 154b9580 Balazs Lecz
  __slots__ = [
1529 a8083063 Iustin Pop
    "serial_no",
1530 a8083063 Iustin Pop
    "rsahostkeypub",
1531 a8083063 Iustin Pop
    "highest_used_port",
1532 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
1533 a8083063 Iustin Pop
    "mac_prefix",
1534 a8083063 Iustin Pop
    "volume_group_name",
1535 999b183c Iustin Pop
    "reserved_lvs",
1536 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
1537 a8083063 Iustin Pop
    "default_bridge",
1538 02691904 Alexander Schreiber
    "default_hypervisor",
1539 f6bd6e98 Michael Hanselmann
    "master_node",
1540 f6bd6e98 Michael Hanselmann
    "master_ip",
1541 f6bd6e98 Michael Hanselmann
    "master_netdev",
1542 5a8648eb Andrea Spadaccini
    "master_netmask",
1543 33be7576 Andrea Spadaccini
    "use_external_mip_script",
1544 f6bd6e98 Michael Hanselmann
    "cluster_name",
1545 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
1546 4b97f902 Apollon Oikonomopoulos
    "shared_file_storage_dir",
1547 e69d05fd Iustin Pop
    "enabled_hypervisors",
1548 5bf7b5cf Iustin Pop
    "hvparams",
1549 918eb80b Agata Murawska
    "ipolicy",
1550 17463d22 René Nussbaumer
    "os_hvp",
1551 5bf7b5cf Iustin Pop
    "beparams",
1552 1bdcbbab Iustin Pop
    "osparams",
1553 c8fcde47 Guido Trotter
    "nicparams",
1554 095e71aa René Nussbaumer
    "ndparams",
1555 bc5d0215 Andrea Spadaccini
    "diskparams",
1556 4b7735f9 Iustin Pop
    "candidate_pool_size",
1557 b86a6bcd Guido Trotter
    "modify_etc_hosts",
1558 b989b9d9 Ken Wehr
    "modify_ssh_setup",
1559 3953242f Iustin Pop
    "maintain_node_health",
1560 4437d889 Balazs Lecz
    "uid_pool",
1561 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
1562 87b2cd45 Iustin Pop
    "hidden_os",
1563 87b2cd45 Iustin Pop
    "blacklisted_os",
1564 2f20d07b Manuel Franceschini
    "primary_ip_family",
1565 3d914585 René Nussbaumer
    "prealloc_wipe_disks",
1566 2da9f556 René Nussbaumer
    "hv_state_static",
1567 2da9f556 René Nussbaumer
    "disk_state_static",
1568 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1569 a8083063 Iustin Pop
1570 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
1571 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
1572 b86a6bcd Guido Trotter

1573 b86a6bcd Guido Trotter
    """
1574 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1575 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
1576 c1b42c18 Guido Trotter
    if self.hvparams is None:
1577 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
1578 c1b42c18 Guido Trotter
    else:
1579 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
1580 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
1581 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
1582 c1b42c18 Guido Trotter
1583 17463d22 René Nussbaumer
    if self.os_hvp is None:
1584 17463d22 René Nussbaumer
      self.os_hvp = {}
1585 17463d22 René Nussbaumer
1586 1bdcbbab Iustin Pop
    # osparams added before 2.2
1587 1bdcbbab Iustin Pop
    if self.osparams is None:
1588 1bdcbbab Iustin Pop
      self.osparams = {}
1589 1bdcbbab Iustin Pop
1590 2a27dac3 Iustin Pop
    self.ndparams = UpgradeNDParams(self.ndparams)
1591 095e71aa René Nussbaumer
1592 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
1593 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
1594 8c72ab2b Guido Trotter
    for beparams_group in self.beparams:
1595 8c72ab2b Guido Trotter
      UpgradeBeParams(self.beparams[beparams_group])
1596 8c72ab2b Guido Trotter
1597 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
1598 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
1599 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
1600 c8fcde47 Guido Trotter
    if migrate_default_bridge:
1601 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
1602 c8fcde47 Guido Trotter
        self.default_bridge
1603 c1b42c18 Guido Trotter
1604 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1605 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1606 b86a6bcd Guido Trotter
1607 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1608 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1609 b989b9d9 Ken Wehr
1610 73f1d185 Stephen Shirley
    # default_bridge is no longer used in 2.1. The slot is left there to
1611 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1612 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1613 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1614 9b31ca85 Guido Trotter
      self.default_bridge = None
1615 9b31ca85 Guido Trotter
1616 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1617 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1618 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1619 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1620 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1621 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1622 066f465d Guido Trotter
      self.default_hypervisor = None
1623 066f465d Guido Trotter
1624 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1625 3953242f Iustin Pop
    if self.maintain_node_health is None:
1626 3953242f Iustin Pop
      self.maintain_node_health = False
1627 3953242f Iustin Pop
1628 4437d889 Balazs Lecz
    if self.uid_pool is None:
1629 4437d889 Balazs Lecz
      self.uid_pool = []
1630 4437d889 Balazs Lecz
1631 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1632 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1633 bf4af505 Apollon Oikonomopoulos
1634 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1635 999b183c Iustin Pop
    if self.reserved_lvs is None:
1636 999b183c Iustin Pop
      self.reserved_lvs = []
1637 999b183c Iustin Pop
1638 546b1111 Iustin Pop
    # hidden and blacklisted operating systems added before 2.2.1
1639 87b2cd45 Iustin Pop
    if self.hidden_os is None:
1640 87b2cd45 Iustin Pop
      self.hidden_os = []
1641 546b1111 Iustin Pop
1642 87b2cd45 Iustin Pop
    if self.blacklisted_os is None:
1643 87b2cd45 Iustin Pop
      self.blacklisted_os = []
1644 546b1111 Iustin Pop
1645 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1646 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1647 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1648 f4c9af7a Guido Trotter
1649 0007f3ab Andrea Spadaccini
    if self.master_netmask is None:
1650 0007f3ab Andrea Spadaccini
      ipcls = netutils.IPAddress.GetClassFromIpFamily(self.primary_ip_family)
1651 0007f3ab Andrea Spadaccini
      self.master_netmask = ipcls.iplen
1652 0007f3ab Andrea Spadaccini
1653 3d914585 René Nussbaumer
    if self.prealloc_wipe_disks is None:
1654 3d914585 René Nussbaumer
      self.prealloc_wipe_disks = False
1655 3d914585 René Nussbaumer
1656 e8f472d1 Iustin Pop
    # shared_file_storage_dir added before 2.5
1657 e8f472d1 Iustin Pop
    if self.shared_file_storage_dir is None:
1658 e8f472d1 Iustin Pop
      self.shared_file_storage_dir = ""
1659 e8f472d1 Iustin Pop
1660 33be7576 Andrea Spadaccini
    if self.use_external_mip_script is None:
1661 33be7576 Andrea Spadaccini
      self.use_external_mip_script = False
1662 33be7576 Andrea Spadaccini
1663 bc5d0215 Andrea Spadaccini
    self.diskparams = UpgradeDiskParams(self.diskparams)
1664 bc5d0215 Andrea Spadaccini
1665 918eb80b Agata Murawska
    # instance policy added before 2.6
1666 918eb80b Agata Murawska
    if self.ipolicy is None:
1667 2cc673a3 Iustin Pop
      self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, {})
1668 38a6e2e1 Iustin Pop
    else:
1669 38a6e2e1 Iustin Pop
      # we can either make sure to upgrade the ipolicy always, or only
1670 38a6e2e1 Iustin Pop
      # do it in some corner cases (e.g. missing keys); note that this
1671 38a6e2e1 Iustin Pop
      # will break any removal of keys from the ipolicy dict
1672 38a6e2e1 Iustin Pop
      self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, self.ipolicy)
1673 918eb80b Agata Murawska
1674 0fbedb7a Michael Hanselmann
  @property
1675 0fbedb7a Michael Hanselmann
  def primary_hypervisor(self):
1676 0fbedb7a Michael Hanselmann
    """The first hypervisor is the primary.
1677 0fbedb7a Michael Hanselmann

1678 0fbedb7a Michael Hanselmann
    Useful, for example, for L{Node}'s hv/disk state.
1679 0fbedb7a Michael Hanselmann

1680 0fbedb7a Michael Hanselmann
    """
1681 0fbedb7a Michael Hanselmann
    return self.enabled_hypervisors[0]
1682 0fbedb7a Michael Hanselmann
1683 319856a9 Michael Hanselmann
  def ToDict(self):
1684 319856a9 Michael Hanselmann
    """Custom function for cluster.
1685 319856a9 Michael Hanselmann

1686 319856a9 Michael Hanselmann
    """
1687 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1688 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1689 319856a9 Michael Hanselmann
    return mydict
1690 319856a9 Michael Hanselmann
1691 319856a9 Michael Hanselmann
  @classmethod
1692 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1693 319856a9 Michael Hanselmann
    """Custom function for cluster.
1694 319856a9 Michael Hanselmann

1695 319856a9 Michael Hanselmann
    """
1696 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1697 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1698 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1699 319856a9 Michael Hanselmann
    return obj
1700 319856a9 Michael Hanselmann
1701 8a147bba René Nussbaumer
  def SimpleFillDP(self, diskparams):
1702 8a147bba René Nussbaumer
    """Fill a given diskparams dict with cluster defaults.
1703 8a147bba René Nussbaumer

1704 8a147bba René Nussbaumer
    @param diskparams: The diskparams
1705 8a147bba René Nussbaumer
    @return: The defaults dict
1706 8a147bba René Nussbaumer

1707 8a147bba René Nussbaumer
    """
1708 8a147bba René Nussbaumer
    return FillDiskParams(self.diskparams, diskparams)
1709 8a147bba René Nussbaumer
1710 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1711 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1712 d63479b5 Iustin Pop

1713 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1714 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1715 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1716 d63479b5 Iustin Pop
    @return: the defaults dict
1717 d63479b5 Iustin Pop

1718 d63479b5 Iustin Pop
    """
1719 d63479b5 Iustin Pop
    if skip_keys is None:
1720 d63479b5 Iustin Pop
      skip_keys = []
1721 d63479b5 Iustin Pop
1722 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1723 d63479b5 Iustin Pop
    if os_name is not None:
1724 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1725 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1726 d63479b5 Iustin Pop
1727 d63479b5 Iustin Pop
    ret_dict = {}
1728 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1729 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1730 d63479b5 Iustin Pop
1731 d63479b5 Iustin Pop
    return ret_dict
1732 d63479b5 Iustin Pop
1733 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1734 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1735 73e0328b Iustin Pop

1736 73e0328b Iustin Pop
    @type hv_name: string
1737 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1738 73e0328b Iustin Pop
    @type os_name: string
1739 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1740 73e0328b Iustin Pop
    @type skip_globals: boolean
1741 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1742 73e0328b Iustin Pop
        not be filled
1743 73e0328b Iustin Pop
    @rtype: dict
1744 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1745 73e0328b Iustin Pop
        the cluster defaults
1746 73e0328b Iustin Pop

1747 73e0328b Iustin Pop
    """
1748 73e0328b Iustin Pop
    if skip_globals:
1749 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1750 73e0328b Iustin Pop
    else:
1751 73e0328b Iustin Pop
      skip_keys = []
1752 73e0328b Iustin Pop
1753 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1754 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1755 d63479b5 Iustin Pop
1756 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1757 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1758 5bf7b5cf Iustin Pop

1759 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1760 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1761 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1762 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1763 7736a5f2 Iustin Pop
        not be filled
1764 5bf7b5cf Iustin Pop
    @rtype: dict
1765 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1766 5bf7b5cf Iustin Pop
        the cluster defaults
1767 5bf7b5cf Iustin Pop

1768 5bf7b5cf Iustin Pop
    """
1769 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1770 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1771 17463d22 René Nussbaumer
1772 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1773 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1774 73e0328b Iustin Pop

1775 06596a60 Guido Trotter
    @type beparams: dict
1776 06596a60 Guido Trotter
    @param beparams: the dict to fill
1777 73e0328b Iustin Pop
    @rtype: dict
1778 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1779 73e0328b Iustin Pop
        from the cluster defaults
1780 73e0328b Iustin Pop

1781 73e0328b Iustin Pop
    """
1782 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1783 5bf7b5cf Iustin Pop
1784 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1785 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1786 5bf7b5cf Iustin Pop

1787 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1788 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1789 5bf7b5cf Iustin Pop
    @rtype: dict
1790 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1791 5bf7b5cf Iustin Pop
        the cluster defaults
1792 5bf7b5cf Iustin Pop

1793 5bf7b5cf Iustin Pop
    """
1794 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1795 73e0328b Iustin Pop
1796 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1797 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1798 73e0328b Iustin Pop

1799 06596a60 Guido Trotter
    @type nicparams: dict
1800 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1801 73e0328b Iustin Pop
    @rtype: dict
1802 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1803 73e0328b Iustin Pop
        from the cluster defaults
1804 73e0328b Iustin Pop

1805 73e0328b Iustin Pop
    """
1806 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1807 5bf7b5cf Iustin Pop
1808 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1809 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1810 1bdcbbab Iustin Pop

1811 1bdcbbab Iustin Pop
    @type os_name: string
1812 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1813 1bdcbbab Iustin Pop
    @type os_params: dict
1814 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1815 1bdcbbab Iustin Pop
    @rtype: dict
1816 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1817 1bdcbbab Iustin Pop
        the cluster defaults
1818 1bdcbbab Iustin Pop

1819 1bdcbbab Iustin Pop
    """
1820 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1821 1bdcbbab Iustin Pop
    # base OS
1822 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1823 1bdcbbab Iustin Pop
    # OS with variant
1824 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1825 1bdcbbab Iustin Pop
    # specified params
1826 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1827 1bdcbbab Iustin Pop
1828 2da9f556 René Nussbaumer
  @staticmethod
1829 2da9f556 René Nussbaumer
  def SimpleFillHvState(hv_state):
1830 2da9f556 René Nussbaumer
    """Fill an hv_state sub dict with cluster defaults.
1831 2da9f556 René Nussbaumer

1832 2da9f556 René Nussbaumer
    """
1833 2da9f556 René Nussbaumer
    return FillDict(constants.HVST_DEFAULTS, hv_state)
1834 2da9f556 René Nussbaumer
1835 2da9f556 René Nussbaumer
  @staticmethod
1836 2da9f556 René Nussbaumer
  def SimpleFillDiskState(disk_state):
1837 2da9f556 René Nussbaumer
    """Fill an disk_state sub dict with cluster defaults.
1838 2da9f556 René Nussbaumer

1839 2da9f556 René Nussbaumer
    """
1840 2da9f556 René Nussbaumer
    return FillDict(constants.DS_DEFAULTS, disk_state)
1841 2da9f556 René Nussbaumer
1842 095e71aa René Nussbaumer
  def FillND(self, node, nodegroup):
1843 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.NodeGroup} and L{objects.Node}
1844 095e71aa René Nussbaumer

1845 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1846 095e71aa René Nussbaumer
    @param node: A Node object to fill
1847 095e71aa René Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1848 095e71aa René Nussbaumer
    @param nodegroup: A Node object to fill
1849 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1850 095e71aa René Nussbaumer

1851 095e71aa René Nussbaumer
    """
1852 095e71aa René Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1853 095e71aa René Nussbaumer
1854 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1855 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1856 095e71aa René Nussbaumer

1857 095e71aa René Nussbaumer
    @type ndparams: dict
1858 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1859 095e71aa René Nussbaumer
    @rtype: dict
1860 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1861 095e71aa René Nussbaumer
        from the cluster defaults
1862 095e71aa René Nussbaumer

1863 095e71aa René Nussbaumer
    """
1864 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1865 095e71aa René Nussbaumer
1866 918eb80b Agata Murawska
  def SimpleFillIPolicy(self, ipolicy):
1867 918eb80b Agata Murawska
    """ Fill instance policy dict with defaults.
1868 918eb80b Agata Murawska

1869 918eb80b Agata Murawska
    @type ipolicy: dict
1870 918eb80b Agata Murawska
    @param ipolicy: the dict to fill
1871 918eb80b Agata Murawska
    @rtype: dict
1872 918eb80b Agata Murawska
    @return: a copy of passed ipolicy with missing keys filled from
1873 918eb80b Agata Murawska
      the cluster defaults
1874 918eb80b Agata Murawska

1875 918eb80b Agata Murawska
    """
1876 2cc673a3 Iustin Pop
    return FillIPolicy(self.ipolicy, ipolicy)
1877 918eb80b Agata Murawska
1878 5c947f38 Iustin Pop
1879 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1880 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1881 96acbc09 Michael Hanselmann
  __slots__ = [
1882 96acbc09 Michael Hanselmann
    "dev_path",
1883 96acbc09 Michael Hanselmann
    "major",
1884 96acbc09 Michael Hanselmann
    "minor",
1885 96acbc09 Michael Hanselmann
    "sync_percent",
1886 96acbc09 Michael Hanselmann
    "estimated_time",
1887 96acbc09 Michael Hanselmann
    "is_degraded",
1888 f208978a Michael Hanselmann
    "ldisk_status",
1889 96acbc09 Michael Hanselmann
    ]
1890 96acbc09 Michael Hanselmann
1891 96acbc09 Michael Hanselmann
1892 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1893 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1894 2d76b580 Michael Hanselmann
  __slots__ = [
1895 2d76b580 Michael Hanselmann
    "recent_output",
1896 2d76b580 Michael Hanselmann
    "listen_port",
1897 2d76b580 Michael Hanselmann
    "connected",
1898 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1899 c08d76f5 Michael Hanselmann
    "progress_throughput",
1900 c08d76f5 Michael Hanselmann
    "progress_eta",
1901 c08d76f5 Michael Hanselmann
    "progress_percent",
1902 2d76b580 Michael Hanselmann
    "exit_status",
1903 2d76b580 Michael Hanselmann
    "error_message",
1904 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1905 2d76b580 Michael Hanselmann
1906 2d76b580 Michael Hanselmann
1907 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1908 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1909 eb630f50 Michael Hanselmann

1910 eb630f50 Michael Hanselmann
  @ivar key_name: X509 key name (None for cluster certificate)
1911 eb630f50 Michael Hanselmann
  @ivar ca_pem: Remote peer CA in PEM format (None for cluster certificate)
1912 a5310c2a Michael Hanselmann
  @ivar compress: Compression method (one of L{constants.IEC_ALL})
1913 af1d39b1 Michael Hanselmann
  @ivar magic: Used to ensure the connection goes to the right disk
1914 855d2fc7 Michael Hanselmann
  @ivar ipv6: Whether to use IPv6
1915 4478301b Michael Hanselmann
  @ivar connect_timeout: Number of seconds for establishing connection
1916 eb630f50 Michael Hanselmann

1917 eb630f50 Michael Hanselmann
  """
1918 eb630f50 Michael Hanselmann
  __slots__ = [
1919 eb630f50 Michael Hanselmann
    "key_name",
1920 eb630f50 Michael Hanselmann
    "ca_pem",
1921 a5310c2a Michael Hanselmann
    "compress",
1922 af1d39b1 Michael Hanselmann
    "magic",
1923 855d2fc7 Michael Hanselmann
    "ipv6",
1924 4478301b Michael Hanselmann
    "connect_timeout",
1925 eb630f50 Michael Hanselmann
    ]
1926 eb630f50 Michael Hanselmann
1927 eb630f50 Michael Hanselmann
1928 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1929 18d750b9 Guido Trotter
  """Object holding a confd request.
1930 18d750b9 Guido Trotter

1931 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1932 18d750b9 Guido Trotter
  @ivar type: confd query type
1933 18d750b9 Guido Trotter
  @ivar query: query request
1934 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1935 18d750b9 Guido Trotter

1936 18d750b9 Guido Trotter
  """
1937 18d750b9 Guido Trotter
  __slots__ = [
1938 18d750b9 Guido Trotter
    "protocol",
1939 18d750b9 Guido Trotter
    "type",
1940 18d750b9 Guido Trotter
    "query",
1941 18d750b9 Guido Trotter
    "rsalt",
1942 18d750b9 Guido Trotter
    ]
1943 18d750b9 Guido Trotter
1944 18d750b9 Guido Trotter
1945 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1946 18d750b9 Guido Trotter
  """Object holding a confd reply.
1947 18d750b9 Guido Trotter

1948 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1949 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1950 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1951 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1952 18d750b9 Guido Trotter

1953 18d750b9 Guido Trotter
  """
1954 18d750b9 Guido Trotter
  __slots__ = [
1955 18d750b9 Guido Trotter
    "protocol",
1956 18d750b9 Guido Trotter
    "status",
1957 18d750b9 Guido Trotter
    "answer",
1958 18d750b9 Guido Trotter
    "serial",
1959 18d750b9 Guido Trotter
    ]
1960 18d750b9 Guido Trotter
1961 18d750b9 Guido Trotter
1962 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1963 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1964 707f23b5 Michael Hanselmann

1965 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1966 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1967 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1968 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1969 707f23b5 Michael Hanselmann

1970 707f23b5 Michael Hanselmann
  """
1971 707f23b5 Michael Hanselmann
  __slots__ = [
1972 707f23b5 Michael Hanselmann
    "name",
1973 707f23b5 Michael Hanselmann
    "title",
1974 707f23b5 Michael Hanselmann
    "kind",
1975 1ae17369 Michael Hanselmann
    "doc",
1976 707f23b5 Michael Hanselmann
    ]
1977 707f23b5 Michael Hanselmann
1978 707f23b5 Michael Hanselmann
1979 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1980 0538c375 Michael Hanselmann
  __slots__ = [
1981 0538c375 Michael Hanselmann
    "fields",
1982 0538c375 Michael Hanselmann
    ]
1983 0538c375 Michael Hanselmann
1984 0538c375 Michael Hanselmann
  def ToDict(self):
1985 0538c375 Michael Hanselmann
    """Custom function for serializing.
1986 0538c375 Michael Hanselmann

1987 0538c375 Michael Hanselmann
    """
1988 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1989 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1990 0538c375 Michael Hanselmann
    return mydict
1991 0538c375 Michael Hanselmann
1992 0538c375 Michael Hanselmann
  @classmethod
1993 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1994 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1995 0538c375 Michael Hanselmann

1996 0538c375 Michael Hanselmann
    """
1997 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1998 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1999 0538c375 Michael Hanselmann
    return obj
2000 0538c375 Michael Hanselmann
2001 0538c375 Michael Hanselmann
2002 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
2003 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
2004 24d6d3e2 Michael Hanselmann

2005 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
2006 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
2007 24d6d3e2 Michael Hanselmann

2008 24d6d3e2 Michael Hanselmann
  """
2009 24d6d3e2 Michael Hanselmann
  __slots__ = [
2010 24d6d3e2 Michael Hanselmann
    "data",
2011 24d6d3e2 Michael Hanselmann
    ]
2012 24d6d3e2 Michael Hanselmann
2013 24d6d3e2 Michael Hanselmann
2014 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
2015 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
2016 24d6d3e2 Michael Hanselmann

2017 24d6d3e2 Michael Hanselmann
  """
2018 24d6d3e2 Michael Hanselmann
  __slots__ = [
2019 24d6d3e2 Michael Hanselmann
    "what",
2020 24d6d3e2 Michael Hanselmann
    "fields",
2021 24d6d3e2 Michael Hanselmann
    ]
2022 24d6d3e2 Michael Hanselmann
2023 24d6d3e2 Michael Hanselmann
2024 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
2025 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
2026 24d6d3e2 Michael Hanselmann

2027 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
2028 24d6d3e2 Michael Hanselmann

2029 24d6d3e2 Michael Hanselmann
  """
2030 24d6d3e2 Michael Hanselmann
  __slots__ = [
2031 24d6d3e2 Michael Hanselmann
    ]
2032 24d6d3e2 Michael Hanselmann
2033 24d6d3e2 Michael Hanselmann
2034 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
2035 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
2036 6a1434d7 Andrea Spadaccini

2037 6a1434d7 Andrea Spadaccini
  """
2038 6a1434d7 Andrea Spadaccini
  __slots__ = [
2039 6a1434d7 Andrea Spadaccini
    "status",
2040 6a1434d7 Andrea Spadaccini
    "transferred_ram",
2041 6a1434d7 Andrea Spadaccini
    "total_ram",
2042 6a1434d7 Andrea Spadaccini
    ]
2043 6a1434d7 Andrea Spadaccini
2044 6a1434d7 Andrea Spadaccini
2045 25ce3ec4 Michael Hanselmann
class InstanceConsole(ConfigObject):
2046 25ce3ec4 Michael Hanselmann
  """Object describing how to access the console of an instance.
2047 25ce3ec4 Michael Hanselmann

2048 25ce3ec4 Michael Hanselmann
  """
2049 25ce3ec4 Michael Hanselmann
  __slots__ = [
2050 25ce3ec4 Michael Hanselmann
    "instance",
2051 25ce3ec4 Michael Hanselmann
    "kind",
2052 25ce3ec4 Michael Hanselmann
    "message",
2053 25ce3ec4 Michael Hanselmann
    "host",
2054 25ce3ec4 Michael Hanselmann
    "port",
2055 25ce3ec4 Michael Hanselmann
    "user",
2056 25ce3ec4 Michael Hanselmann
    "command",
2057 25ce3ec4 Michael Hanselmann
    "display",
2058 25ce3ec4 Michael Hanselmann
    ]
2059 25ce3ec4 Michael Hanselmann
2060 25ce3ec4 Michael Hanselmann
  def Validate(self):
2061 25ce3ec4 Michael Hanselmann
    """Validates contents of this object.
2062 25ce3ec4 Michael Hanselmann

2063 25ce3ec4 Michael Hanselmann
    """
2064 25ce3ec4 Michael Hanselmann
    assert self.kind in constants.CONS_ALL, "Unknown console type"
2065 25ce3ec4 Michael Hanselmann
    assert self.instance, "Missing instance name"
2066 4d2cdb5a Andrea Spadaccini
    assert self.message or self.kind in [constants.CONS_SSH,
2067 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2068 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_VNC]
2069 25ce3ec4 Michael Hanselmann
    assert self.host or self.kind == constants.CONS_MESSAGE
2070 25ce3ec4 Michael Hanselmann
    assert self.port or self.kind in [constants.CONS_MESSAGE,
2071 25ce3ec4 Michael Hanselmann
                                      constants.CONS_SSH]
2072 25ce3ec4 Michael Hanselmann
    assert self.user or self.kind in [constants.CONS_MESSAGE,
2073 4d2cdb5a Andrea Spadaccini
                                      constants.CONS_SPICE,
2074 25ce3ec4 Michael Hanselmann
                                      constants.CONS_VNC]
2075 25ce3ec4 Michael Hanselmann
    assert self.command or self.kind in [constants.CONS_MESSAGE,
2076 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2077 25ce3ec4 Michael Hanselmann
                                         constants.CONS_VNC]
2078 25ce3ec4 Michael Hanselmann
    assert self.display or self.kind in [constants.CONS_MESSAGE,
2079 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2080 25ce3ec4 Michael Hanselmann
                                         constants.CONS_SSH]
2081 25ce3ec4 Michael Hanselmann
    return True
2082 25ce3ec4 Michael Hanselmann
2083 25ce3ec4 Michael Hanselmann
2084 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
2085 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
2086 a8083063 Iustin Pop

2087 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
2088 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
2089 a8083063 Iustin Pop
  buffer.
2090 a8083063 Iustin Pop

2091 a8083063 Iustin Pop
  """
2092 a8083063 Iustin Pop
  def Dumps(self):
2093 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
2094 a8083063 Iustin Pop
    buf = StringIO()
2095 a8083063 Iustin Pop
    self.write(buf)
2096 a8083063 Iustin Pop
    return buf.getvalue()
2097 a8083063 Iustin Pop
2098 b39bf4bb Guido Trotter
  @classmethod
2099 b39bf4bb Guido Trotter
  def Loads(cls, data):
2100 a8083063 Iustin Pop
    """Load data from a string."""
2101 a8083063 Iustin Pop
    buf = StringIO(data)
2102 b39bf4bb Guido Trotter
    cfp = cls()
2103 a8083063 Iustin Pop
    cfp.readfp(buf)
2104 a8083063 Iustin Pop
    return cfp