Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 0ec2ce46

History | View | Annotate | Download (48.8 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 6d33a6eb Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 a8083063 Iustin Pop
48 f4c9af7a Guido Trotter
from socket import AF_INET
49 f4c9af7a Guido Trotter
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
52 24a3707f Guido Trotter
           "OS", "Node", "NodeGroup", "Cluster", "FillDict"]
53 a8083063 Iustin Pop
54 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
55 e1dcc53a Iustin Pop
_UUID = ["uuid"]
56 96acbc09 Michael Hanselmann
57 8d8d650c Michael Hanselmann
58 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
59 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
60 abe609b2 Guido Trotter

61 29921401 Iustin Pop
  @type defaults_dict: dict
62 29921401 Iustin Pop
  @param defaults_dict: dictionary holding the default values
63 29921401 Iustin Pop
  @type custom_dict: dict
64 29921401 Iustin Pop
  @param custom_dict: dictionary holding customized value
65 7736a5f2 Iustin Pop
  @type skip_keys: list
66 7736a5f2 Iustin Pop
  @param skip_keys: which keys not to fill
67 29921401 Iustin Pop
  @rtype: dict
68 29921401 Iustin Pop
  @return: dict with the 'full' values
69 abe609b2 Guido Trotter

70 29921401 Iustin Pop
  """
71 29921401 Iustin Pop
  ret_dict = copy.deepcopy(defaults_dict)
72 29921401 Iustin Pop
  ret_dict.update(custom_dict)
73 e11ddf13 Iustin Pop
  if skip_keys:
74 e11ddf13 Iustin Pop
    for k in skip_keys:
75 e11ddf13 Iustin Pop
      try:
76 e11ddf13 Iustin Pop
        del ret_dict[k]
77 e11ddf13 Iustin Pop
      except KeyError:
78 e11ddf13 Iustin Pop
        pass
79 29921401 Iustin Pop
  return ret_dict
80 a8083063 Iustin Pop
81 6e34b628 Guido Trotter
82 6e34b628 Guido Trotter
def UpgradeGroupedParams(target, defaults):
83 6e34b628 Guido Trotter
  """Update all groups for the target parameter.
84 6e34b628 Guido Trotter

85 6e34b628 Guido Trotter
  @type target: dict of dicts
86 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
87 6e34b628 Guido Trotter
  @type defaults: dict
88 6e34b628 Guido Trotter
  @param defaults: default parameter values
89 6e34b628 Guido Trotter

90 6e34b628 Guido Trotter
  """
91 6e34b628 Guido Trotter
  if target is None:
92 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
93 6e34b628 Guido Trotter
  else:
94 6e34b628 Guido Trotter
    for group in target:
95 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
96 6e34b628 Guido Trotter
  return target
97 6e34b628 Guido Trotter
98 6e34b628 Guido Trotter
99 8c72ab2b Guido Trotter
def UpgradeBeParams(target):
100 8c72ab2b Guido Trotter
  """Update the be parameters dict to the new format.
101 8c72ab2b Guido Trotter

102 8c72ab2b Guido Trotter
  @type target: dict
103 8c72ab2b Guido Trotter
  @param target: "be" parameters dict
104 8c72ab2b Guido Trotter

105 8c72ab2b Guido Trotter
  """
106 8c72ab2b Guido Trotter
  if constants.BE_MEMORY in target:
107 8c72ab2b Guido Trotter
    memory = target[constants.BE_MEMORY]
108 8c72ab2b Guido Trotter
    target[constants.BE_MAXMEM] = memory
109 8c72ab2b Guido Trotter
    target[constants.BE_MINMEM] = memory
110 b2e233a5 Guido Trotter
    del target[constants.BE_MEMORY]
111 8c72ab2b Guido Trotter
112 8c72ab2b Guido Trotter
113 bc5d0215 Andrea Spadaccini
def UpgradeDiskParams(diskparams):
114 bc5d0215 Andrea Spadaccini
  """Upgrade the disk parameters.
115 bc5d0215 Andrea Spadaccini

116 bc5d0215 Andrea Spadaccini
  @type diskparams: dict
117 bc5d0215 Andrea Spadaccini
  @param diskparams: disk parameters to upgrade
118 bc5d0215 Andrea Spadaccini
  @rtype: dict
119 bc5d0215 Andrea Spadaccini
  @return: the upgraded disk parameters dit
120 bc5d0215 Andrea Spadaccini

121 bc5d0215 Andrea Spadaccini
  """
122 bc5d0215 Andrea Spadaccini
  result = dict()
123 bc5d0215 Andrea Spadaccini
  if diskparams is None:
124 bc5d0215 Andrea Spadaccini
    result = constants.DISK_DT_DEFAULTS.copy()
125 bc5d0215 Andrea Spadaccini
  else:
126 bc5d0215 Andrea Spadaccini
    # Update the disk parameter values for each disk template.
127 bc5d0215 Andrea Spadaccini
    # The code iterates over constants.DISK_TEMPLATES because new templates
128 bc5d0215 Andrea Spadaccini
    # might have been added.
129 bc5d0215 Andrea Spadaccini
    for template in constants.DISK_TEMPLATES:
130 bc5d0215 Andrea Spadaccini
      if template not in diskparams:
131 bc5d0215 Andrea Spadaccini
        result[template] = constants.DISK_DT_DEFAULTS[template].copy()
132 bc5d0215 Andrea Spadaccini
      else:
133 bc5d0215 Andrea Spadaccini
        result[template] = FillDict(constants.DISK_DT_DEFAULTS[template],
134 bc5d0215 Andrea Spadaccini
                                    diskparams[template])
135 bc5d0215 Andrea Spadaccini
136 bc5d0215 Andrea Spadaccini
  return result
137 bc5d0215 Andrea Spadaccini
138 bc5d0215 Andrea Spadaccini
139 a8083063 Iustin Pop
class ConfigObject(object):
140 a8083063 Iustin Pop
  """A generic config object.
141 a8083063 Iustin Pop

142 a8083063 Iustin Pop
  It has the following properties:
143 a8083063 Iustin Pop

144 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
145 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
146 a8083063 Iustin Pop
      as None instead of raising an error
147 a8083063 Iustin Pop

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

151 a8083063 Iustin Pop
  """
152 a8083063 Iustin Pop
  __slots__ = []
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
  def __init__(self, **kwargs):
155 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
156 319856a9 Michael Hanselmann
      setattr(self, k, v)
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
  def __getattr__(self, name):
159 adf385c7 Iustin Pop
    if name not in self._all_slots():
160 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
161 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
162 a8083063 Iustin Pop
    return None
163 a8083063 Iustin Pop
164 a8083063 Iustin Pop
  def __setstate__(self, state):
165 adf385c7 Iustin Pop
    slots = self._all_slots()
166 a8083063 Iustin Pop
    for name in state:
167 adf385c7 Iustin Pop
      if name in slots:
168 a8083063 Iustin Pop
        setattr(self, name, state[name])
169 a8083063 Iustin Pop
170 adf385c7 Iustin Pop
  @classmethod
171 adf385c7 Iustin Pop
  def _all_slots(cls):
172 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
173 adf385c7 Iustin Pop

174 adf385c7 Iustin Pop
    """
175 adf385c7 Iustin Pop
    slots = []
176 adf385c7 Iustin Pop
    for parent in cls.__mro__:
177 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
178 adf385c7 Iustin Pop
    return slots
179 adf385c7 Iustin Pop
180 ff9c047c Iustin Pop
  def ToDict(self):
181 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
182 ff9c047c Iustin Pop

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

189 ff9c047c Iustin Pop
    """
190 4c14965f Guido Trotter
    result = {}
191 adf385c7 Iustin Pop
    for name in self._all_slots():
192 4c14965f Guido Trotter
      value = getattr(self, name, None)
193 4c14965f Guido Trotter
      if value is not None:
194 4c14965f Guido Trotter
        result[name] = value
195 4c14965f Guido Trotter
    return result
196 4c14965f Guido Trotter
197 4c14965f Guido Trotter
  __getstate__ = ToDict
198 ff9c047c Iustin Pop
199 ff9c047c Iustin Pop
  @classmethod
200 ff9c047c Iustin Pop
  def FromDict(cls, val):
201 ff9c047c Iustin Pop
    """Create an object from a dictionary.
202 ff9c047c Iustin Pop

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

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

211 ff9c047c Iustin Pop
    """
212 ff9c047c Iustin Pop
    if not isinstance(val, dict):
213 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
214 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
215 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
216 b459a848 Andrea Spadaccini
    obj = cls(**val_str) # pylint: disable=W0142
217 ff9c047c Iustin Pop
    return obj
218 ff9c047c Iustin Pop
219 ff9c047c Iustin Pop
  @staticmethod
220 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
221 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
222 ff9c047c Iustin Pop

223 ff9c047c Iustin Pop
    This method converts a container with elements derived from
224 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
225 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
226 ff9c047c Iustin Pop

227 ff9c047c Iustin Pop
    """
228 ff9c047c Iustin Pop
    if isinstance(container, dict):
229 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
230 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
231 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
232 ff9c047c Iustin Pop
    else:
233 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
234 ff9c047c Iustin Pop
                      type(container))
235 ff9c047c Iustin Pop
    return ret
236 ff9c047c Iustin Pop
237 ff9c047c Iustin Pop
  @staticmethod
238 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
239 ff9c047c Iustin Pop
    """Convert a container from standard python types.
240 ff9c047c Iustin Pop

241 ff9c047c Iustin Pop
    This method converts a container with standard python types to
242 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
243 ff9c047c Iustin Pop
    keys, only the values.
244 ff9c047c Iustin Pop

245 ff9c047c Iustin Pop
    """
246 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
247 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
248 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
249 fe25a79a Guido Trotter
    if source is None:
250 fe25a79a Guido Trotter
      source = c_type()
251 ff9c047c Iustin Pop
    if c_type is dict:
252 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
253 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
254 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
255 ff9c047c Iustin Pop
    else:
256 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
257 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
258 ff9c047c Iustin Pop
    return ret
259 ff9c047c Iustin Pop
260 e8d563f3 Iustin Pop
  def Copy(self):
261 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
262 e8d563f3 Iustin Pop

263 e8d563f3 Iustin Pop
    """
264 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
265 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
266 e8d563f3 Iustin Pop
    return clone_obj
267 e8d563f3 Iustin Pop
268 ff9c047c Iustin Pop
  def __repr__(self):
269 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
270 ff9c047c Iustin Pop
    return repr(self.ToDict())
271 ff9c047c Iustin Pop
272 560428be Guido Trotter
  def UpgradeConfig(self):
273 560428be Guido Trotter
    """Fill defaults for missing configuration values.
274 560428be Guido Trotter

275 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
276 90d726a8 Iustin Pop
    implementation will be object dependent.
277 560428be Guido Trotter

278 560428be Guido Trotter
    """
279 560428be Guido Trotter
    pass
280 560428be Guido Trotter
281 a8083063 Iustin Pop
282 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
283 5c947f38 Iustin Pop
  """An generic class supporting tags.
284 5c947f38 Iustin Pop

285 5c947f38 Iustin Pop
  """
286 154b9580 Balazs Lecz
  __slots__ = ["tags"]
287 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
288 2057f6c7 Iustin Pop
289 b5e5632e Iustin Pop
  @classmethod
290 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
291 5c947f38 Iustin Pop
    """Check if a tag is valid.
292 5c947f38 Iustin Pop

293 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
294 5c947f38 Iustin Pop
    function has no return value.
295 5c947f38 Iustin Pop

296 5c947f38 Iustin Pop
    """
297 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
298 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
299 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
300 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
301 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
302 5c947f38 Iustin Pop
    if not tag:
303 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
304 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
305 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
306 5c947f38 Iustin Pop
307 5c947f38 Iustin Pop
  def GetTags(self):
308 5c947f38 Iustin Pop
    """Return the tags list.
309 5c947f38 Iustin Pop

310 5c947f38 Iustin Pop
    """
311 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
312 5c947f38 Iustin Pop
    if tags is None:
313 5c947f38 Iustin Pop
      tags = self.tags = set()
314 5c947f38 Iustin Pop
    return tags
315 5c947f38 Iustin Pop
316 5c947f38 Iustin Pop
  def AddTag(self, tag):
317 5c947f38 Iustin Pop
    """Add a new tag.
318 5c947f38 Iustin Pop

319 5c947f38 Iustin Pop
    """
320 5c947f38 Iustin Pop
    self.ValidateTag(tag)
321 5c947f38 Iustin Pop
    tags = self.GetTags()
322 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
323 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
324 5c947f38 Iustin Pop
    self.GetTags().add(tag)
325 5c947f38 Iustin Pop
326 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
327 5c947f38 Iustin Pop
    """Remove a tag.
328 5c947f38 Iustin Pop

329 5c947f38 Iustin Pop
    """
330 5c947f38 Iustin Pop
    self.ValidateTag(tag)
331 5c947f38 Iustin Pop
    tags = self.GetTags()
332 5c947f38 Iustin Pop
    try:
333 5c947f38 Iustin Pop
      tags.remove(tag)
334 5c947f38 Iustin Pop
    except KeyError:
335 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
336 5c947f38 Iustin Pop
337 ff9c047c Iustin Pop
  def ToDict(self):
338 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
339 ff9c047c Iustin Pop

340 ff9c047c Iustin Pop
    This replaces the tags set with a list.
341 ff9c047c Iustin Pop

342 ff9c047c Iustin Pop
    """
343 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
344 ff9c047c Iustin Pop
345 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
346 ff9c047c Iustin Pop
    if isinstance(tags, set):
347 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
348 ff9c047c Iustin Pop
    return bo
349 ff9c047c Iustin Pop
350 ff9c047c Iustin Pop
  @classmethod
351 ff9c047c Iustin Pop
  def FromDict(cls, val):
352 ff9c047c Iustin Pop
    """Custom function for instances.
353 ff9c047c Iustin Pop

354 ff9c047c Iustin Pop
    """
355 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
356 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
357 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
358 ff9c047c Iustin Pop
    return obj
359 ff9c047c Iustin Pop
360 5c947f38 Iustin Pop
361 061af273 Andrea Spadaccini
class MasterNetworkParameters(ConfigObject):
362 061af273 Andrea Spadaccini
  """Network configuration parameters for the master
363 061af273 Andrea Spadaccini

364 061af273 Andrea Spadaccini
  @ivar name: master name
365 061af273 Andrea Spadaccini
  @ivar ip: master IP
366 061af273 Andrea Spadaccini
  @ivar netmask: master netmask
367 061af273 Andrea Spadaccini
  @ivar netdev: master network device
368 061af273 Andrea Spadaccini
  @ivar ip_family: master IP family
369 061af273 Andrea Spadaccini

370 061af273 Andrea Spadaccini
  """
371 061af273 Andrea Spadaccini
  __slots__ = [
372 061af273 Andrea Spadaccini
    "name",
373 061af273 Andrea Spadaccini
    "ip",
374 061af273 Andrea Spadaccini
    "netmask",
375 061af273 Andrea Spadaccini
    "netdev",
376 061af273 Andrea Spadaccini
    "ip_family"
377 061af273 Andrea Spadaccini
    ]
378 061af273 Andrea Spadaccini
379 061af273 Andrea Spadaccini
380 a8083063 Iustin Pop
class ConfigData(ConfigObject):
381 a8083063 Iustin Pop
  """Top-level config object."""
382 3df43542 Guido Trotter
  __slots__ = [
383 3df43542 Guido Trotter
    "version",
384 3df43542 Guido Trotter
    "cluster",
385 3df43542 Guido Trotter
    "nodes",
386 3df43542 Guido Trotter
    "nodegroups",
387 3df43542 Guido Trotter
    "instances",
388 3df43542 Guido Trotter
    "serial_no",
389 3df43542 Guido Trotter
    ] + _TIMESTAMPS
390 a8083063 Iustin Pop
391 ff9c047c Iustin Pop
  def ToDict(self):
392 ff9c047c Iustin Pop
    """Custom function for top-level config data.
393 ff9c047c Iustin Pop

394 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
395 ff9c047c Iustin Pop
    with standard python types.
396 ff9c047c Iustin Pop

397 ff9c047c Iustin Pop
    """
398 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
399 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
400 3df43542 Guido Trotter
    for key in "nodes", "instances", "nodegroups":
401 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
402 ff9c047c Iustin Pop
403 ff9c047c Iustin Pop
    return mydict
404 ff9c047c Iustin Pop
405 ff9c047c Iustin Pop
  @classmethod
406 ff9c047c Iustin Pop
  def FromDict(cls, val):
407 ff9c047c Iustin Pop
    """Custom function for top-level config data
408 ff9c047c Iustin Pop

409 ff9c047c Iustin Pop
    """
410 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
411 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
412 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
413 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
414 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
415 ff9c047c Iustin Pop
    return obj
416 ff9c047c Iustin Pop
417 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
418 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
419 51cb1581 Luca Bigliardi

420 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
421 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
422 51cb1581 Luca Bigliardi
    @rtype: boolean
423 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
424 51cb1581 Luca Bigliardi

425 51cb1581 Luca Bigliardi
    """
426 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
427 51cb1581 Luca Bigliardi
      for disk in instance.disks:
428 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
429 51cb1581 Luca Bigliardi
          return True
430 51cb1581 Luca Bigliardi
    return False
431 51cb1581 Luca Bigliardi
432 90d726a8 Iustin Pop
  def UpgradeConfig(self):
433 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
434 90d726a8 Iustin Pop

435 90d726a8 Iustin Pop
    """
436 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
437 90d726a8 Iustin Pop
    for node in self.nodes.values():
438 90d726a8 Iustin Pop
      node.UpgradeConfig()
439 90d726a8 Iustin Pop
    for instance in self.instances.values():
440 90d726a8 Iustin Pop
      instance.UpgradeConfig()
441 3df43542 Guido Trotter
    if self.nodegroups is None:
442 3df43542 Guido Trotter
      self.nodegroups = {}
443 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
444 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
445 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
446 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
447 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
448 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
449 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
450 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
451 90d726a8 Iustin Pop
452 a8083063 Iustin Pop
453 a8083063 Iustin Pop
class NIC(ConfigObject):
454 a8083063 Iustin Pop
  """Config object representing a network card."""
455 1177d70e Guido Trotter
  __slots__ = ["mac", "ip", "nicparams"]
456 a8083063 Iustin Pop
457 255e19d4 Guido Trotter
  @classmethod
458 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
459 255e19d4 Guido Trotter
    """Check the given parameters for validity.
460 255e19d4 Guido Trotter

461 255e19d4 Guido Trotter
    @type nicparams:  dict
462 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
463 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
464 255e19d4 Guido Trotter

465 255e19d4 Guido Trotter
    """
466 e8448672 Agata Murawska
    if (nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES and
467 e8448672 Agata Murawska
        nicparams[constants.NIC_MODE] != constants.VALUE_AUTO):
468 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
469 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
470 255e19d4 Guido Trotter
471 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
472 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
473 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
474 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
475 255e19d4 Guido Trotter
476 a8083063 Iustin Pop
477 a8083063 Iustin Pop
class Disk(ConfigObject):
478 a8083063 Iustin Pop
  """Config object representing a block device."""
479 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
480 bc5d0215 Andrea Spadaccini
               "children", "iv_name", "size", "mode", "params"]
481 a8083063 Iustin Pop
482 a8083063 Iustin Pop
  def CreateOnSecondary(self):
483 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
484 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
487 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
488 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
489 a8083063 Iustin Pop
490 a8083063 Iustin Pop
  def OpenOnSecondary(self):
491 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
492 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
493 a8083063 Iustin Pop
494 222f2dd5 Iustin Pop
  def StaticDevPath(self):
495 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
496 222f2dd5 Iustin Pop

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

501 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
502 e51db2a6 Iustin Pop
        should check that it is a valid path.
503 e51db2a6 Iustin Pop

504 222f2dd5 Iustin Pop
    """
505 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
506 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
507 b6135bbc Apollon Oikonomopoulos
    elif self.dev_type == constants.LD_BLOCKDEV:
508 b6135bbc Apollon Oikonomopoulos
      return self.logical_id[1]
509 222f2dd5 Iustin Pop
    return None
510 222f2dd5 Iustin Pop
511 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
512 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
513 fc1dc9d7 Iustin Pop

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

518 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
519 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
520 fc1dc9d7 Iustin Pop
    -1.
521 fc1dc9d7 Iustin Pop

522 fc1dc9d7 Iustin Pop
    """
523 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
524 fc1dc9d7 Iustin Pop
      return 0
525 fc1dc9d7 Iustin Pop
    return -1
526 fc1dc9d7 Iustin Pop
527 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
528 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
529 51cb1581 Luca Bigliardi

530 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
531 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
532 51cb1581 Luca Bigliardi
    @rtype: boolean
533 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
534 51cb1581 Luca Bigliardi

535 51cb1581 Luca Bigliardi
    """
536 51cb1581 Luca Bigliardi
    if self.children:
537 51cb1581 Luca Bigliardi
      for child in self.children:
538 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
539 51cb1581 Luca Bigliardi
          return True
540 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
541 51cb1581 Luca Bigliardi
542 a8083063 Iustin Pop
  def GetNodes(self, node):
543 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
544 a8083063 Iustin Pop

545 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
546 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
547 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
548 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
549 a8083063 Iustin Pop

550 a8083063 Iustin Pop
    """
551 b6135bbc Apollon Oikonomopoulos
    if self.dev_type in [constants.LD_LV, constants.LD_FILE,
552 b6135bbc Apollon Oikonomopoulos
                         constants.LD_BLOCKDEV]:
553 a8083063 Iustin Pop
      result = [node]
554 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
555 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
556 a8083063 Iustin Pop
      if node not in result:
557 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
558 a8083063 Iustin Pop
    else:
559 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
560 a8083063 Iustin Pop
    return result
561 a8083063 Iustin Pop
562 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
563 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
564 a8083063 Iustin Pop

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

571 a8083063 Iustin Pop
    """
572 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
573 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
574 a8083063 Iustin Pop
    if not self.children:
575 a8083063 Iustin Pop
      # leaf device
576 a8083063 Iustin Pop
      return result
577 a8083063 Iustin Pop
    for node in my_nodes:
578 a8083063 Iustin Pop
      for child in self.children:
579 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
580 a8083063 Iustin Pop
        if len(child_result) == 1:
581 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
582 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
583 a8083063 Iustin Pop
          # own entry for this node describes it completely
584 a8083063 Iustin Pop
          continue
585 a8083063 Iustin Pop
        else:
586 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
587 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
588 a8083063 Iustin Pop
          # one of its descendants
589 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
590 a8083063 Iustin Pop
            if subnode not in my_nodes:
591 a8083063 Iustin Pop
              result.append((subnode, subdisk))
592 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
593 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
594 a8083063 Iustin Pop
            # be different)
595 a8083063 Iustin Pop
    return result
596 a8083063 Iustin Pop
597 6d33a6eb Iustin Pop
  def ComputeGrowth(self, amount):
598 6d33a6eb Iustin Pop
    """Compute the per-VG growth requirements.
599 6d33a6eb Iustin Pop

600 6d33a6eb Iustin Pop
    This only works for VG-based disks.
601 6d33a6eb Iustin Pop

602 6d33a6eb Iustin Pop
    @type amount: integer
603 6d33a6eb Iustin Pop
    @param amount: the desired increase in (user-visible) disk space
604 6d33a6eb Iustin Pop
    @rtype: dict
605 6d33a6eb Iustin Pop
    @return: a dictionary of volume-groups and the required size
606 6d33a6eb Iustin Pop

607 6d33a6eb Iustin Pop
    """
608 6d33a6eb Iustin Pop
    if self.dev_type == constants.LD_LV:
609 6d33a6eb Iustin Pop
      return {self.logical_id[0]: amount}
610 6d33a6eb Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
611 6d33a6eb Iustin Pop
      if self.children:
612 6d33a6eb Iustin Pop
        return self.children[0].ComputeGrowth(amount)
613 6d33a6eb Iustin Pop
      else:
614 6d33a6eb Iustin Pop
        return {}
615 6d33a6eb Iustin Pop
    else:
616 6d33a6eb Iustin Pop
      # Other disk types do not require VG space
617 6d33a6eb Iustin Pop
      return {}
618 6d33a6eb Iustin Pop
619 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
620 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
621 acec9d51 Iustin Pop

622 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
623 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
624 acec9d51 Iustin Pop
    actual algorithms from bdev.
625 acec9d51 Iustin Pop

626 acec9d51 Iustin Pop
    """
627 4b97f902 Apollon Oikonomopoulos
    if self.dev_type in (constants.LD_LV, constants.LD_FILE):
628 acec9d51 Iustin Pop
      self.size += amount
629 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
630 acec9d51 Iustin Pop
      if self.children:
631 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
632 acec9d51 Iustin Pop
      self.size += amount
633 acec9d51 Iustin Pop
    else:
634 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
635 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
636 acec9d51 Iustin Pop
637 a805ec18 Iustin Pop
  def UnsetSize(self):
638 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
639 a805ec18 Iustin Pop

640 a805ec18 Iustin Pop
    """
641 a805ec18 Iustin Pop
    if self.children:
642 a805ec18 Iustin Pop
      for child in self.children:
643 a805ec18 Iustin Pop
        child.UnsetSize()
644 a805ec18 Iustin Pop
    self.size = 0
645 a805ec18 Iustin Pop
646 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
647 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
648 0402302c Iustin Pop

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

651 0402302c Iustin Pop
    The routine descends down and updates its children also, because
652 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
653 0402302c Iustin Pop
    node.
654 0402302c Iustin Pop

655 0402302c Iustin Pop
    Arguments:
656 0402302c Iustin Pop
      - target_node: the node we wish to configure for
657 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
658 0402302c Iustin Pop

659 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
660 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
661 0402302c Iustin Pop
    in the disk tree.
662 0402302c Iustin Pop

663 0402302c Iustin Pop
    """
664 0402302c Iustin Pop
    if self.children:
665 0402302c Iustin Pop
      for child in self.children:
666 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
667 0402302c Iustin Pop
668 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
669 0402302c Iustin Pop
      return
670 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
671 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
672 0402302c Iustin Pop
      if target_node not in (pnode, snode):
673 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
674 0402302c Iustin Pop
                                        target_node)
675 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
676 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
677 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
678 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
679 0402302c Iustin Pop
                                        " for %s" % str(self))
680 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
681 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
682 0402302c Iustin Pop
      if pnode == target_node:
683 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
684 0402302c Iustin Pop
      else: # it must be secondary, we tested above
685 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
686 0402302c Iustin Pop
    else:
687 0402302c Iustin Pop
      self.physical_id = self.logical_id
688 0402302c Iustin Pop
    return
689 0402302c Iustin Pop
690 ff9c047c Iustin Pop
  def ToDict(self):
691 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
692 ff9c047c Iustin Pop

693 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
694 ff9c047c Iustin Pop
    standard python types.
695 ff9c047c Iustin Pop

696 ff9c047c Iustin Pop
    """
697 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
698 ff9c047c Iustin Pop
699 ff9c047c Iustin Pop
    for attr in ("children",):
700 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
701 ff9c047c Iustin Pop
      if alist:
702 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
703 ff9c047c Iustin Pop
    return bo
704 ff9c047c Iustin Pop
705 ff9c047c Iustin Pop
  @classmethod
706 ff9c047c Iustin Pop
  def FromDict(cls, val):
707 ff9c047c Iustin Pop
    """Custom function for Disks
708 ff9c047c Iustin Pop

709 ff9c047c Iustin Pop
    """
710 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
711 ff9c047c Iustin Pop
    if obj.children:
712 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
713 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
714 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
715 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
716 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
717 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
718 f9518d38 Iustin Pop
      # we need a tuple of length six here
719 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
720 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
721 ff9c047c Iustin Pop
    return obj
722 ff9c047c Iustin Pop
723 65a15336 Iustin Pop
  def __str__(self):
724 65a15336 Iustin Pop
    """Custom str() formatter for disks.
725 65a15336 Iustin Pop

726 65a15336 Iustin Pop
    """
727 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
728 e687ec01 Michael Hanselmann
      val = "<LogicalVolume(/dev/%s/%s" % self.logical_id
729 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
730 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
731 00fb8246 Michael Hanselmann
      val = "<DRBD8("
732 073ca59e Iustin Pop
      if self.physical_id is None:
733 073ca59e Iustin Pop
        phy = "unconfigured"
734 073ca59e Iustin Pop
      else:
735 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
736 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
737 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
738 073ca59e Iustin Pop
739 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
740 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
741 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
742 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
743 65a15336 Iustin Pop
      else:
744 65a15336 Iustin Pop
        val += "no local storage"
745 65a15336 Iustin Pop
    else:
746 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
747 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
748 65a15336 Iustin Pop
    if self.iv_name is None:
749 65a15336 Iustin Pop
      val += ", not visible"
750 65a15336 Iustin Pop
    else:
751 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
752 fd965830 Iustin Pop
    if isinstance(self.size, int):
753 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
754 fd965830 Iustin Pop
    else:
755 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
756 65a15336 Iustin Pop
    return val
757 65a15336 Iustin Pop
758 332d0e37 Iustin Pop
  def Verify(self):
759 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
760 332d0e37 Iustin Pop

761 332d0e37 Iustin Pop
    """
762 7c4d6c7b Michael Hanselmann
    all_errors = []
763 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
764 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
765 7c4d6c7b Michael Hanselmann
    return all_errors
766 332d0e37 Iustin Pop
767 90d726a8 Iustin Pop
  def UpgradeConfig(self):
768 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
769 90d726a8 Iustin Pop

770 90d726a8 Iustin Pop
    """
771 90d726a8 Iustin Pop
    if self.children:
772 90d726a8 Iustin Pop
      for child in self.children:
773 90d726a8 Iustin Pop
        child.UpgradeConfig()
774 bc5d0215 Andrea Spadaccini
775 bc5d0215 Andrea Spadaccini
    if not self.params:
776 bc5d0215 Andrea Spadaccini
      self.params = constants.DISK_LD_DEFAULTS[self.dev_type].copy()
777 bc5d0215 Andrea Spadaccini
    else:
778 bc5d0215 Andrea Spadaccini
      self.params = FillDict(constants.DISK_LD_DEFAULTS[self.dev_type],
779 bc5d0215 Andrea Spadaccini
                             self.params)
780 90d726a8 Iustin Pop
    # add here config upgrade for this disk
781 90d726a8 Iustin Pop
782 a8083063 Iustin Pop
783 ec29fe40 Iustin Pop
class Instance(TaggableObject):
784 a8083063 Iustin Pop
  """Config object representing an instance."""
785 154b9580 Balazs Lecz
  __slots__ = [
786 a8083063 Iustin Pop
    "name",
787 a8083063 Iustin Pop
    "primary_node",
788 a8083063 Iustin Pop
    "os",
789 e69d05fd Iustin Pop
    "hypervisor",
790 5bf7b5cf Iustin Pop
    "hvparams",
791 5bf7b5cf Iustin Pop
    "beparams",
792 1bdcbbab Iustin Pop
    "osparams",
793 9ca8a7c5 Agata Murawska
    "admin_state",
794 a8083063 Iustin Pop
    "nics",
795 a8083063 Iustin Pop
    "disks",
796 a8083063 Iustin Pop
    "disk_template",
797 58acb49d Alexander Schreiber
    "network_port",
798 be1fa613 Iustin Pop
    "serial_no",
799 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
800 a8083063 Iustin Pop
801 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
802 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
803 a8083063 Iustin Pop

804 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
805 cfcc5c6d Iustin Pop

806 cfcc5c6d Iustin Pop
    """
807 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
808 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
809 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
810 cfcc5c6d Iustin Pop
811 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
812 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
813 cfcc5c6d Iustin Pop
814 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
815 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
816 cfcc5c6d Iustin Pop

817 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
818 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
819 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
820 a8083063 Iustin Pop
    dynamically.
821 a8083063 Iustin Pop

822 a8083063 Iustin Pop
    """
823 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
824 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
825 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
826 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
827 cfcc5c6d Iustin Pop
        nodes.add(nodea)
828 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
829 a8083063 Iustin Pop
      if device.children:
830 a8083063 Iustin Pop
        for child in device.children:
831 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
832 a8083063 Iustin Pop
833 cfcc5c6d Iustin Pop
    all_nodes = set()
834 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
835 a8083063 Iustin Pop
    for device in self.disks:
836 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
837 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
838 a8083063 Iustin Pop
839 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
840 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
841 a8083063 Iustin Pop
842 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
843 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
844 a8083063 Iustin Pop

845 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
846 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
847 a8083063 Iustin Pop

848 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
849 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
850 a8083063 Iustin Pop

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

856 a8083063 Iustin Pop
    """
857 a8083063 Iustin Pop
    if node == None:
858 a8083063 Iustin Pop
      node = self.primary_node
859 a8083063 Iustin Pop
860 a8083063 Iustin Pop
    if lvmap is None:
861 e687ec01 Michael Hanselmann
      lvmap = {
862 e687ec01 Michael Hanselmann
        node: [],
863 e687ec01 Michael Hanselmann
        }
864 a8083063 Iustin Pop
      ret = lvmap
865 a8083063 Iustin Pop
    else:
866 a8083063 Iustin Pop
      if not node in lvmap:
867 a8083063 Iustin Pop
        lvmap[node] = []
868 a8083063 Iustin Pop
      ret = None
869 a8083063 Iustin Pop
870 a8083063 Iustin Pop
    if not devs:
871 a8083063 Iustin Pop
      devs = self.disks
872 a8083063 Iustin Pop
873 a8083063 Iustin Pop
    for dev in devs:
874 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
875 e687ec01 Michael Hanselmann
        lvmap[node].append(dev.logical_id[0] + "/" + dev.logical_id[1])
876 a8083063 Iustin Pop
877 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
878 a8083063 Iustin Pop
        if dev.children:
879 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
880 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
881 a8083063 Iustin Pop
882 a8083063 Iustin Pop
      elif dev.children:
883 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
884 a8083063 Iustin Pop
885 a8083063 Iustin Pop
    return ret
886 a8083063 Iustin Pop
887 ad24e046 Iustin Pop
  def FindDisk(self, idx):
888 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
889 644eeef9 Iustin Pop

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

892 ad24e046 Iustin Pop
    @type idx: int
893 ad24e046 Iustin Pop
    @param idx: the disk index
894 ad24e046 Iustin Pop
    @rtype: L{Disk}
895 ad24e046 Iustin Pop
    @return: the corresponding disk
896 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
897 644eeef9 Iustin Pop

898 ad24e046 Iustin Pop
    """
899 ad24e046 Iustin Pop
    try:
900 ad24e046 Iustin Pop
      idx = int(idx)
901 ad24e046 Iustin Pop
      return self.disks[idx]
902 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
903 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
904 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
905 ad24e046 Iustin Pop
    except IndexError:
906 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
907 daa55b04 Michael Hanselmann
                                 " 0 to %d" % (idx, len(self.disks) - 1),
908 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
909 644eeef9 Iustin Pop
910 ff9c047c Iustin Pop
  def ToDict(self):
911 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
912 ff9c047c Iustin Pop

913 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
914 ff9c047c Iustin Pop
    python types.
915 ff9c047c Iustin Pop

916 ff9c047c Iustin Pop
    """
917 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
918 ff9c047c Iustin Pop
919 ff9c047c Iustin Pop
    for attr in "nics", "disks":
920 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
921 ff9c047c Iustin Pop
      if alist:
922 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
923 ff9c047c Iustin Pop
      else:
924 ff9c047c Iustin Pop
        nlist = []
925 ff9c047c Iustin Pop
      bo[attr] = nlist
926 ff9c047c Iustin Pop
    return bo
927 ff9c047c Iustin Pop
928 ff9c047c Iustin Pop
  @classmethod
929 ff9c047c Iustin Pop
  def FromDict(cls, val):
930 ff9c047c Iustin Pop
    """Custom function for instances.
931 ff9c047c Iustin Pop

932 ff9c047c Iustin Pop
    """
933 9ca8a7c5 Agata Murawska
    if "admin_state" not in val:
934 9ca8a7c5 Agata Murawska
      if val.get("admin_up", False):
935 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_UP
936 9ca8a7c5 Agata Murawska
      else:
937 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_DOWN
938 9ca8a7c5 Agata Murawska
    if "admin_up" in val:
939 9ca8a7c5 Agata Murawska
      del val["admin_up"]
940 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
941 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
942 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
943 ff9c047c Iustin Pop
    return obj
944 ff9c047c Iustin Pop
945 90d726a8 Iustin Pop
  def UpgradeConfig(self):
946 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
947 90d726a8 Iustin Pop

948 90d726a8 Iustin Pop
    """
949 90d726a8 Iustin Pop
    for nic in self.nics:
950 90d726a8 Iustin Pop
      nic.UpgradeConfig()
951 90d726a8 Iustin Pop
    for disk in self.disks:
952 90d726a8 Iustin Pop
      disk.UpgradeConfig()
953 7736a5f2 Iustin Pop
    if self.hvparams:
954 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
955 7736a5f2 Iustin Pop
        try:
956 7736a5f2 Iustin Pop
          del self.hvparams[key]
957 7736a5f2 Iustin Pop
        except KeyError:
958 7736a5f2 Iustin Pop
          pass
959 1bdcbbab Iustin Pop
    if self.osparams is None:
960 1bdcbbab Iustin Pop
      self.osparams = {}
961 8c72ab2b Guido Trotter
    UpgradeBeParams(self.beparams)
962 90d726a8 Iustin Pop
963 a8083063 Iustin Pop
964 a8083063 Iustin Pop
class OS(ConfigObject):
965 b41b3516 Iustin Pop
  """Config object representing an operating system.
966 b41b3516 Iustin Pop

967 b41b3516 Iustin Pop
  @type supported_parameters: list
968 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
969 b41b3516 Iustin Pop
      containing the supported parameters by this OS
970 b41b3516 Iustin Pop

971 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
972 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
973 870dc44c Iustin Pop

974 b41b3516 Iustin Pop
  """
975 a8083063 Iustin Pop
  __slots__ = [
976 a8083063 Iustin Pop
    "name",
977 a8083063 Iustin Pop
    "path",
978 082a7f91 Guido Trotter
    "api_versions",
979 a8083063 Iustin Pop
    "create_script",
980 a8083063 Iustin Pop
    "export_script",
981 386b57af Iustin Pop
    "import_script",
982 386b57af Iustin Pop
    "rename_script",
983 b41b3516 Iustin Pop
    "verify_script",
984 6d79896b Guido Trotter
    "supported_variants",
985 b41b3516 Iustin Pop
    "supported_parameters",
986 a8083063 Iustin Pop
    ]
987 a8083063 Iustin Pop
988 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
989 870dc44c Iustin Pop
990 870dc44c Iustin Pop
  @classmethod
991 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
992 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
993 870dc44c Iustin Pop

994 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
995 870dc44c Iustin Pop
    @rtype: list
996 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
997 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
998 870dc44c Iustin Pop

999 870dc44c Iustin Pop
    """
1000 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
1001 870dc44c Iustin Pop
    if len(nv) == 1:
1002 870dc44c Iustin Pop
      nv.append("")
1003 870dc44c Iustin Pop
    return nv
1004 870dc44c Iustin Pop
1005 870dc44c Iustin Pop
  @classmethod
1006 870dc44c Iustin Pop
  def GetName(cls, name):
1007 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
1008 870dc44c Iustin Pop

1009 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1010 870dc44c Iustin Pop

1011 870dc44c Iustin Pop
    """
1012 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
1013 870dc44c Iustin Pop
1014 870dc44c Iustin Pop
  @classmethod
1015 870dc44c Iustin Pop
  def GetVariant(cls, name):
1016 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
1017 870dc44c Iustin Pop

1018 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1019 870dc44c Iustin Pop

1020 870dc44c Iustin Pop
    """
1021 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
1022 870dc44c Iustin Pop
1023 7c0d6283 Michael Hanselmann
1024 5f06ce5e Michael Hanselmann
class NodeHvState(ConfigObject):
1025 5f06ce5e Michael Hanselmann
  """Hypvervisor state on a node.
1026 5f06ce5e Michael Hanselmann

1027 5f06ce5e Michael Hanselmann
  @ivar mem_total: Total amount of memory
1028 5f06ce5e Michael Hanselmann
  @ivar mem_node: Memory used by, or reserved for, the node itself (not always
1029 5f06ce5e Michael Hanselmann
    available)
1030 5f06ce5e Michael Hanselmann
  @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation
1031 5f06ce5e Michael Hanselmann
    rounding
1032 5f06ce5e Michael Hanselmann
  @ivar mem_inst: Memory used by instances living on node
1033 5f06ce5e Michael Hanselmann
  @ivar cpu_total: Total node CPU core count
1034 5f06ce5e Michael Hanselmann
  @ivar cpu_node: Number of CPU cores reserved for the node itself
1035 5f06ce5e Michael Hanselmann

1036 5f06ce5e Michael Hanselmann
  """
1037 5f06ce5e Michael Hanselmann
  __slots__ = [
1038 5f06ce5e Michael Hanselmann
    "mem_total",
1039 5f06ce5e Michael Hanselmann
    "mem_node",
1040 5f06ce5e Michael Hanselmann
    "mem_hv",
1041 5f06ce5e Michael Hanselmann
    "mem_inst",
1042 5f06ce5e Michael Hanselmann
    "cpu_total",
1043 5f06ce5e Michael Hanselmann
    "cpu_node",
1044 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1045 5f06ce5e Michael Hanselmann
1046 5f06ce5e Michael Hanselmann
1047 5f06ce5e Michael Hanselmann
class NodeDiskState(ConfigObject):
1048 5f06ce5e Michael Hanselmann
  """Disk state on a node.
1049 5f06ce5e Michael Hanselmann

1050 5f06ce5e Michael Hanselmann
  """
1051 5f06ce5e Michael Hanselmann
  __slots__ = [
1052 5f06ce5e Michael Hanselmann
    "total",
1053 5f06ce5e Michael Hanselmann
    "reserved",
1054 5f06ce5e Michael Hanselmann
    "overhead",
1055 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1056 5f06ce5e Michael Hanselmann
1057 5f06ce5e Michael Hanselmann
1058 ec29fe40 Iustin Pop
class Node(TaggableObject):
1059 634d30f4 Michael Hanselmann
  """Config object representing a node.
1060 634d30f4 Michael Hanselmann

1061 634d30f4 Michael Hanselmann
  @ivar hv_state: Hypervisor state (e.g. number of CPUs)
1062 634d30f4 Michael Hanselmann
  @ivar hv_state_static: Hypervisor state overriden by user
1063 634d30f4 Michael Hanselmann
  @ivar disk_state: Disk state (e.g. free space)
1064 634d30f4 Michael Hanselmann
  @ivar disk_state_static: Disk state overriden by user
1065 634d30f4 Michael Hanselmann

1066 634d30f4 Michael Hanselmann
  """
1067 154b9580 Balazs Lecz
  __slots__ = [
1068 ec29fe40 Iustin Pop
    "name",
1069 ec29fe40 Iustin Pop
    "primary_ip",
1070 ec29fe40 Iustin Pop
    "secondary_ip",
1071 be1fa613 Iustin Pop
    "serial_no",
1072 8b8b8b81 Iustin Pop
    "master_candidate",
1073 fc0fe88c Iustin Pop
    "offline",
1074 af64c0ea Iustin Pop
    "drained",
1075 f936c153 Iustin Pop
    "group",
1076 490acd18 Iustin Pop
    "master_capable",
1077 490acd18 Iustin Pop
    "vm_capable",
1078 095e71aa Renรฉ Nussbaumer
    "ndparams",
1079 25124d4a Renรฉ Nussbaumer
    "powered",
1080 5b49ed09 Renรฉ Nussbaumer
    "hv_state",
1081 634d30f4 Michael Hanselmann
    "hv_state_static",
1082 5b49ed09 Renรฉ Nussbaumer
    "disk_state",
1083 634d30f4 Michael Hanselmann
    "disk_state_static",
1084 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1085 a8083063 Iustin Pop
1086 490acd18 Iustin Pop
  def UpgradeConfig(self):
1087 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
1088 490acd18 Iustin Pop

1089 490acd18 Iustin Pop
    """
1090 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1091 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
1092 490acd18 Iustin Pop
    if self.master_capable is None:
1093 490acd18 Iustin Pop
      self.master_capable = True
1094 490acd18 Iustin Pop
1095 490acd18 Iustin Pop
    if self.vm_capable is None:
1096 490acd18 Iustin Pop
      self.vm_capable = True
1097 490acd18 Iustin Pop
1098 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1099 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1100 095e71aa Renรฉ Nussbaumer
1101 25124d4a Renรฉ Nussbaumer
    if self.powered is None:
1102 25124d4a Renรฉ Nussbaumer
      self.powered = True
1103 25124d4a Renรฉ Nussbaumer
1104 5f06ce5e Michael Hanselmann
  def ToDict(self):
1105 5f06ce5e Michael Hanselmann
    """Custom function for serializing.
1106 5f06ce5e Michael Hanselmann

1107 5f06ce5e Michael Hanselmann
    """
1108 5f06ce5e Michael Hanselmann
    data = super(Node, self).ToDict()
1109 5f06ce5e Michael Hanselmann
1110 5f06ce5e Michael Hanselmann
    hv_state = data.get("hv_state", None)
1111 5f06ce5e Michael Hanselmann
    if hv_state is not None:
1112 5f06ce5e Michael Hanselmann
      data["hv_state"] = self._ContainerToDicts(hv_state)
1113 5f06ce5e Michael Hanselmann
1114 5f06ce5e Michael Hanselmann
    disk_state = data.get("disk_state", None)
1115 5f06ce5e Michael Hanselmann
    if disk_state is not None:
1116 5f06ce5e Michael Hanselmann
      data["disk_state"] = \
1117 5f06ce5e Michael Hanselmann
        dict((key, self._ContainerToDicts(value))
1118 5f06ce5e Michael Hanselmann
             for (key, value) in disk_state.items())
1119 5f06ce5e Michael Hanselmann
1120 5f06ce5e Michael Hanselmann
    return data
1121 5f06ce5e Michael Hanselmann
1122 5f06ce5e Michael Hanselmann
  @classmethod
1123 5f06ce5e Michael Hanselmann
  def FromDict(cls, val):
1124 5f06ce5e Michael Hanselmann
    """Custom function for deserializing.
1125 5f06ce5e Michael Hanselmann

1126 5f06ce5e Michael Hanselmann
    """
1127 5f06ce5e Michael Hanselmann
    obj = super(Node, cls).FromDict(val)
1128 5f06ce5e Michael Hanselmann
1129 5f06ce5e Michael Hanselmann
    if obj.hv_state is not None:
1130 5f06ce5e Michael Hanselmann
      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1131 5f06ce5e Michael Hanselmann
1132 5f06ce5e Michael Hanselmann
    if obj.disk_state is not None:
1133 5f06ce5e Michael Hanselmann
      obj.disk_state = \
1134 5f06ce5e Michael Hanselmann
        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
1135 5f06ce5e Michael Hanselmann
             for (key, value) in obj.disk_state.items())
1136 5f06ce5e Michael Hanselmann
1137 5f06ce5e Michael Hanselmann
    return obj
1138 5f06ce5e Michael Hanselmann
1139 a8083063 Iustin Pop
1140 1ffd2673 Michael Hanselmann
class NodeGroup(TaggableObject):
1141 24a3707f Guido Trotter
  """Config object representing a node group."""
1142 24a3707f Guido Trotter
  __slots__ = [
1143 24a3707f Guido Trotter
    "name",
1144 24a3707f Guido Trotter
    "members",
1145 095e71aa Renรฉ Nussbaumer
    "ndparams",
1146 bc5d0215 Andrea Spadaccini
    "diskparams",
1147 e11a1b77 Adeodato Simo
    "serial_no",
1148 90e99856 Adeodato Simo
    "alloc_policy",
1149 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
1150 24a3707f Guido Trotter
1151 24a3707f Guido Trotter
  def ToDict(self):
1152 24a3707f Guido Trotter
    """Custom function for nodegroup.
1153 24a3707f Guido Trotter

1154 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1155 c60abd62 Guido Trotter
    in memory.
1156 24a3707f Guido Trotter

1157 24a3707f Guido Trotter
    """
1158 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
1159 24a3707f Guido Trotter
    del mydict["members"]
1160 24a3707f Guido Trotter
    return mydict
1161 24a3707f Guido Trotter
1162 24a3707f Guido Trotter
  @classmethod
1163 24a3707f Guido Trotter
  def FromDict(cls, val):
1164 24a3707f Guido Trotter
    """Custom function for nodegroup.
1165 24a3707f Guido Trotter

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

1168 24a3707f Guido Trotter
    """
1169 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
1170 24a3707f Guido Trotter
    obj.members = []
1171 24a3707f Guido Trotter
    return obj
1172 24a3707f Guido Trotter
1173 095e71aa Renรฉ Nussbaumer
  def UpgradeConfig(self):
1174 095e71aa Renรฉ Nussbaumer
    """Fill defaults for missing configuration values.
1175 095e71aa Renรฉ Nussbaumer

1176 095e71aa Renรฉ Nussbaumer
    """
1177 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1178 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1179 095e71aa Renรฉ Nussbaumer
1180 e11a1b77 Adeodato Simo
    if self.serial_no is None:
1181 e11a1b77 Adeodato Simo
      self.serial_no = 1
1182 e11a1b77 Adeodato Simo
1183 90e99856 Adeodato Simo
    if self.alloc_policy is None:
1184 90e99856 Adeodato Simo
      self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
1185 90e99856 Adeodato Simo
1186 e11a1b77 Adeodato Simo
    # We only update mtime, and not ctime, since we would not be able to provide
1187 e11a1b77 Adeodato Simo
    # a correct value for creation time.
1188 e11a1b77 Adeodato Simo
    if self.mtime is None:
1189 e11a1b77 Adeodato Simo
      self.mtime = time.time()
1190 e11a1b77 Adeodato Simo
1191 bc5d0215 Andrea Spadaccini
    self.diskparams = UpgradeDiskParams(self.diskparams)
1192 bc5d0215 Andrea Spadaccini
1193 095e71aa Renรฉ Nussbaumer
  def FillND(self, node):
1194 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.Node}
1195 095e71aa Renรฉ Nussbaumer

1196 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1197 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1198 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1199 095e71aa Renรฉ Nussbaumer

1200 095e71aa Renรฉ Nussbaumer
    """
1201 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(node.ndparams)
1202 095e71aa Renรฉ Nussbaumer
1203 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1204 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1205 095e71aa Renรฉ Nussbaumer

1206 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1207 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1208 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1209 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1210 e6e88de6 Adeodato Simo
        from the node group defaults
1211 095e71aa Renรฉ Nussbaumer

1212 095e71aa Renรฉ Nussbaumer
    """
1213 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1214 095e71aa Renรฉ Nussbaumer
1215 24a3707f Guido Trotter
1216 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
1217 a8083063 Iustin Pop
  """Config object representing the cluster."""
1218 154b9580 Balazs Lecz
  __slots__ = [
1219 a8083063 Iustin Pop
    "serial_no",
1220 a8083063 Iustin Pop
    "rsahostkeypub",
1221 a8083063 Iustin Pop
    "highest_used_port",
1222 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
1223 a8083063 Iustin Pop
    "mac_prefix",
1224 a8083063 Iustin Pop
    "volume_group_name",
1225 999b183c Iustin Pop
    "reserved_lvs",
1226 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
1227 a8083063 Iustin Pop
    "default_bridge",
1228 02691904 Alexander Schreiber
    "default_hypervisor",
1229 f6bd6e98 Michael Hanselmann
    "master_node",
1230 f6bd6e98 Michael Hanselmann
    "master_ip",
1231 f6bd6e98 Michael Hanselmann
    "master_netdev",
1232 5a8648eb Andrea Spadaccini
    "master_netmask",
1233 33be7576 Andrea Spadaccini
    "use_external_mip_script",
1234 f6bd6e98 Michael Hanselmann
    "cluster_name",
1235 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
1236 4b97f902 Apollon Oikonomopoulos
    "shared_file_storage_dir",
1237 e69d05fd Iustin Pop
    "enabled_hypervisors",
1238 5bf7b5cf Iustin Pop
    "hvparams",
1239 17463d22 Renรฉ Nussbaumer
    "os_hvp",
1240 5bf7b5cf Iustin Pop
    "beparams",
1241 1bdcbbab Iustin Pop
    "osparams",
1242 c8fcde47 Guido Trotter
    "nicparams",
1243 095e71aa Renรฉ Nussbaumer
    "ndparams",
1244 bc5d0215 Andrea Spadaccini
    "diskparams",
1245 4b7735f9 Iustin Pop
    "candidate_pool_size",
1246 b86a6bcd Guido Trotter
    "modify_etc_hosts",
1247 b989b9d9 Ken Wehr
    "modify_ssh_setup",
1248 3953242f Iustin Pop
    "maintain_node_health",
1249 4437d889 Balazs Lecz
    "uid_pool",
1250 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
1251 87b2cd45 Iustin Pop
    "hidden_os",
1252 87b2cd45 Iustin Pop
    "blacklisted_os",
1253 2f20d07b Manuel Franceschini
    "primary_ip_family",
1254 3d914585 Renรฉ Nussbaumer
    "prealloc_wipe_disks",
1255 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1256 a8083063 Iustin Pop
1257 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
1258 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
1259 b86a6bcd Guido Trotter

1260 b86a6bcd Guido Trotter
    """
1261 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1262 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
1263 c1b42c18 Guido Trotter
    if self.hvparams is None:
1264 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
1265 c1b42c18 Guido Trotter
    else:
1266 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
1267 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
1268 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
1269 c1b42c18 Guido Trotter
1270 17463d22 Renรฉ Nussbaumer
    if self.os_hvp is None:
1271 17463d22 Renรฉ Nussbaumer
      self.os_hvp = {}
1272 17463d22 Renรฉ Nussbaumer
1273 1bdcbbab Iustin Pop
    # osparams added before 2.2
1274 1bdcbbab Iustin Pop
    if self.osparams is None:
1275 1bdcbbab Iustin Pop
      self.osparams = {}
1276 1bdcbbab Iustin Pop
1277 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1278 095e71aa Renรฉ Nussbaumer
      self.ndparams = constants.NDC_DEFAULTS
1279 095e71aa Renรฉ Nussbaumer
1280 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
1281 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
1282 8c72ab2b Guido Trotter
    for beparams_group in self.beparams:
1283 8c72ab2b Guido Trotter
      UpgradeBeParams(self.beparams[beparams_group])
1284 8c72ab2b Guido Trotter
1285 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
1286 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
1287 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
1288 c8fcde47 Guido Trotter
    if migrate_default_bridge:
1289 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
1290 c8fcde47 Guido Trotter
        self.default_bridge
1291 c1b42c18 Guido Trotter
1292 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1293 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1294 b86a6bcd Guido Trotter
1295 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1296 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1297 b989b9d9 Ken Wehr
1298 73f1d185 Stephen Shirley
    # default_bridge is no longer used in 2.1. The slot is left there to
1299 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1300 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1301 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1302 9b31ca85 Guido Trotter
      self.default_bridge = None
1303 9b31ca85 Guido Trotter
1304 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1305 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1306 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1307 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1308 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1309 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1310 066f465d Guido Trotter
      self.default_hypervisor = None
1311 066f465d Guido Trotter
1312 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1313 3953242f Iustin Pop
    if self.maintain_node_health is None:
1314 3953242f Iustin Pop
      self.maintain_node_health = False
1315 3953242f Iustin Pop
1316 4437d889 Balazs Lecz
    if self.uid_pool is None:
1317 4437d889 Balazs Lecz
      self.uid_pool = []
1318 4437d889 Balazs Lecz
1319 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1320 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1321 bf4af505 Apollon Oikonomopoulos
1322 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1323 999b183c Iustin Pop
    if self.reserved_lvs is None:
1324 999b183c Iustin Pop
      self.reserved_lvs = []
1325 999b183c Iustin Pop
1326 546b1111 Iustin Pop
    # hidden and blacklisted operating systems added before 2.2.1
1327 87b2cd45 Iustin Pop
    if self.hidden_os is None:
1328 87b2cd45 Iustin Pop
      self.hidden_os = []
1329 546b1111 Iustin Pop
1330 87b2cd45 Iustin Pop
    if self.blacklisted_os is None:
1331 87b2cd45 Iustin Pop
      self.blacklisted_os = []
1332 546b1111 Iustin Pop
1333 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1334 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1335 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1336 f4c9af7a Guido Trotter
1337 0007f3ab Andrea Spadaccini
    if self.master_netmask is None:
1338 0007f3ab Andrea Spadaccini
      ipcls = netutils.IPAddress.GetClassFromIpFamily(self.primary_ip_family)
1339 0007f3ab Andrea Spadaccini
      self.master_netmask = ipcls.iplen
1340 0007f3ab Andrea Spadaccini
1341 3d914585 Renรฉ Nussbaumer
    if self.prealloc_wipe_disks is None:
1342 3d914585 Renรฉ Nussbaumer
      self.prealloc_wipe_disks = False
1343 3d914585 Renรฉ Nussbaumer
1344 e8f472d1 Iustin Pop
    # shared_file_storage_dir added before 2.5
1345 e8f472d1 Iustin Pop
    if self.shared_file_storage_dir is None:
1346 e8f472d1 Iustin Pop
      self.shared_file_storage_dir = ""
1347 e8f472d1 Iustin Pop
1348 33be7576 Andrea Spadaccini
    if self.use_external_mip_script is None:
1349 33be7576 Andrea Spadaccini
      self.use_external_mip_script = False
1350 33be7576 Andrea Spadaccini
1351 bc5d0215 Andrea Spadaccini
    self.diskparams = UpgradeDiskParams(self.diskparams)
1352 bc5d0215 Andrea Spadaccini
1353 0fbedb7a Michael Hanselmann
  @property
1354 0fbedb7a Michael Hanselmann
  def primary_hypervisor(self):
1355 0fbedb7a Michael Hanselmann
    """The first hypervisor is the primary.
1356 0fbedb7a Michael Hanselmann

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

1359 0fbedb7a Michael Hanselmann
    """
1360 0fbedb7a Michael Hanselmann
    return self.enabled_hypervisors[0]
1361 0fbedb7a Michael Hanselmann
1362 319856a9 Michael Hanselmann
  def ToDict(self):
1363 319856a9 Michael Hanselmann
    """Custom function for cluster.
1364 319856a9 Michael Hanselmann

1365 319856a9 Michael Hanselmann
    """
1366 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1367 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1368 319856a9 Michael Hanselmann
    return mydict
1369 319856a9 Michael Hanselmann
1370 319856a9 Michael Hanselmann
  @classmethod
1371 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1372 319856a9 Michael Hanselmann
    """Custom function for cluster.
1373 319856a9 Michael Hanselmann

1374 319856a9 Michael Hanselmann
    """
1375 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1376 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1377 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1378 319856a9 Michael Hanselmann
    return obj
1379 319856a9 Michael Hanselmann
1380 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1381 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1382 d63479b5 Iustin Pop

1383 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1384 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1385 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1386 d63479b5 Iustin Pop
    @return: the defaults dict
1387 d63479b5 Iustin Pop

1388 d63479b5 Iustin Pop
    """
1389 d63479b5 Iustin Pop
    if skip_keys is None:
1390 d63479b5 Iustin Pop
      skip_keys = []
1391 d63479b5 Iustin Pop
1392 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1393 d63479b5 Iustin Pop
    if os_name is not None:
1394 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1395 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1396 d63479b5 Iustin Pop
1397 d63479b5 Iustin Pop
    ret_dict = {}
1398 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1399 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1400 d63479b5 Iustin Pop
1401 d63479b5 Iustin Pop
    return ret_dict
1402 d63479b5 Iustin Pop
1403 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1404 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1405 73e0328b Iustin Pop

1406 73e0328b Iustin Pop
    @type hv_name: string
1407 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1408 73e0328b Iustin Pop
    @type os_name: string
1409 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1410 73e0328b Iustin Pop
    @type skip_globals: boolean
1411 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1412 73e0328b Iustin Pop
        not be filled
1413 73e0328b Iustin Pop
    @rtype: dict
1414 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1415 73e0328b Iustin Pop
        the cluster defaults
1416 73e0328b Iustin Pop

1417 73e0328b Iustin Pop
    """
1418 73e0328b Iustin Pop
    if skip_globals:
1419 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1420 73e0328b Iustin Pop
    else:
1421 73e0328b Iustin Pop
      skip_keys = []
1422 73e0328b Iustin Pop
1423 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1424 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1425 d63479b5 Iustin Pop
1426 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1427 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1428 5bf7b5cf Iustin Pop

1429 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1430 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1431 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1432 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1433 7736a5f2 Iustin Pop
        not be filled
1434 5bf7b5cf Iustin Pop
    @rtype: dict
1435 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1436 5bf7b5cf Iustin Pop
        the cluster defaults
1437 5bf7b5cf Iustin Pop

1438 5bf7b5cf Iustin Pop
    """
1439 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1440 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1441 17463d22 Renรฉ Nussbaumer
1442 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1443 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1444 73e0328b Iustin Pop

1445 06596a60 Guido Trotter
    @type beparams: dict
1446 06596a60 Guido Trotter
    @param beparams: the dict to fill
1447 73e0328b Iustin Pop
    @rtype: dict
1448 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1449 73e0328b Iustin Pop
        from the cluster defaults
1450 73e0328b Iustin Pop

1451 73e0328b Iustin Pop
    """
1452 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1453 5bf7b5cf Iustin Pop
1454 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1455 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1456 5bf7b5cf Iustin Pop

1457 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1458 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1459 5bf7b5cf Iustin Pop
    @rtype: dict
1460 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1461 5bf7b5cf Iustin Pop
        the cluster defaults
1462 5bf7b5cf Iustin Pop

1463 5bf7b5cf Iustin Pop
    """
1464 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1465 73e0328b Iustin Pop
1466 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1467 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1468 73e0328b Iustin Pop

1469 06596a60 Guido Trotter
    @type nicparams: dict
1470 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1471 73e0328b Iustin Pop
    @rtype: dict
1472 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1473 73e0328b Iustin Pop
        from the cluster defaults
1474 73e0328b Iustin Pop

1475 73e0328b Iustin Pop
    """
1476 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1477 5bf7b5cf Iustin Pop
1478 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1479 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1480 1bdcbbab Iustin Pop

1481 1bdcbbab Iustin Pop
    @type os_name: string
1482 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1483 1bdcbbab Iustin Pop
    @type os_params: dict
1484 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1485 1bdcbbab Iustin Pop
    @rtype: dict
1486 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1487 1bdcbbab Iustin Pop
        the cluster defaults
1488 1bdcbbab Iustin Pop

1489 1bdcbbab Iustin Pop
    """
1490 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1491 1bdcbbab Iustin Pop
    # base OS
1492 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1493 1bdcbbab Iustin Pop
    # OS with variant
1494 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1495 1bdcbbab Iustin Pop
    # specified params
1496 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1497 1bdcbbab Iustin Pop
1498 095e71aa Renรฉ Nussbaumer
  def FillND(self, node, nodegroup):
1499 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.NodeGroup} and L{objects.Node}
1500 095e71aa Renรฉ Nussbaumer

1501 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1502 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1503 095e71aa Renรฉ Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1504 095e71aa Renรฉ Nussbaumer
    @param nodegroup: A Node object to fill
1505 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1506 095e71aa Renรฉ Nussbaumer

1507 095e71aa Renรฉ Nussbaumer
    """
1508 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1509 095e71aa Renรฉ Nussbaumer
1510 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1511 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1512 095e71aa Renรฉ Nussbaumer

1513 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1514 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1515 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1516 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1517 095e71aa Renรฉ Nussbaumer
        from the cluster defaults
1518 095e71aa Renรฉ Nussbaumer

1519 095e71aa Renรฉ Nussbaumer
    """
1520 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1521 095e71aa Renรฉ Nussbaumer
1522 5c947f38 Iustin Pop
1523 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1524 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1525 96acbc09 Michael Hanselmann
  __slots__ = [
1526 96acbc09 Michael Hanselmann
    "dev_path",
1527 96acbc09 Michael Hanselmann
    "major",
1528 96acbc09 Michael Hanselmann
    "minor",
1529 96acbc09 Michael Hanselmann
    "sync_percent",
1530 96acbc09 Michael Hanselmann
    "estimated_time",
1531 96acbc09 Michael Hanselmann
    "is_degraded",
1532 f208978a Michael Hanselmann
    "ldisk_status",
1533 96acbc09 Michael Hanselmann
    ]
1534 96acbc09 Michael Hanselmann
1535 96acbc09 Michael Hanselmann
1536 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1537 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1538 2d76b580 Michael Hanselmann
  __slots__ = [
1539 2d76b580 Michael Hanselmann
    "recent_output",
1540 2d76b580 Michael Hanselmann
    "listen_port",
1541 2d76b580 Michael Hanselmann
    "connected",
1542 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1543 c08d76f5 Michael Hanselmann
    "progress_throughput",
1544 c08d76f5 Michael Hanselmann
    "progress_eta",
1545 c08d76f5 Michael Hanselmann
    "progress_percent",
1546 2d76b580 Michael Hanselmann
    "exit_status",
1547 2d76b580 Michael Hanselmann
    "error_message",
1548 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1549 2d76b580 Michael Hanselmann
1550 2d76b580 Michael Hanselmann
1551 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1552 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1553 eb630f50 Michael Hanselmann

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

1561 eb630f50 Michael Hanselmann
  """
1562 eb630f50 Michael Hanselmann
  __slots__ = [
1563 eb630f50 Michael Hanselmann
    "key_name",
1564 eb630f50 Michael Hanselmann
    "ca_pem",
1565 a5310c2a Michael Hanselmann
    "compress",
1566 af1d39b1 Michael Hanselmann
    "magic",
1567 855d2fc7 Michael Hanselmann
    "ipv6",
1568 4478301b Michael Hanselmann
    "connect_timeout",
1569 eb630f50 Michael Hanselmann
    ]
1570 eb630f50 Michael Hanselmann
1571 eb630f50 Michael Hanselmann
1572 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1573 18d750b9 Guido Trotter
  """Object holding a confd request.
1574 18d750b9 Guido Trotter

1575 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1576 18d750b9 Guido Trotter
  @ivar type: confd query type
1577 18d750b9 Guido Trotter
  @ivar query: query request
1578 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1579 18d750b9 Guido Trotter

1580 18d750b9 Guido Trotter
  """
1581 18d750b9 Guido Trotter
  __slots__ = [
1582 18d750b9 Guido Trotter
    "protocol",
1583 18d750b9 Guido Trotter
    "type",
1584 18d750b9 Guido Trotter
    "query",
1585 18d750b9 Guido Trotter
    "rsalt",
1586 18d750b9 Guido Trotter
    ]
1587 18d750b9 Guido Trotter
1588 18d750b9 Guido Trotter
1589 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1590 18d750b9 Guido Trotter
  """Object holding a confd reply.
1591 18d750b9 Guido Trotter

1592 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1593 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1594 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1595 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1596 18d750b9 Guido Trotter

1597 18d750b9 Guido Trotter
  """
1598 18d750b9 Guido Trotter
  __slots__ = [
1599 18d750b9 Guido Trotter
    "protocol",
1600 18d750b9 Guido Trotter
    "status",
1601 18d750b9 Guido Trotter
    "answer",
1602 18d750b9 Guido Trotter
    "serial",
1603 18d750b9 Guido Trotter
    ]
1604 18d750b9 Guido Trotter
1605 18d750b9 Guido Trotter
1606 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1607 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1608 707f23b5 Michael Hanselmann

1609 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1610 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1611 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1612 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1613 707f23b5 Michael Hanselmann

1614 707f23b5 Michael Hanselmann
  """
1615 707f23b5 Michael Hanselmann
  __slots__ = [
1616 707f23b5 Michael Hanselmann
    "name",
1617 707f23b5 Michael Hanselmann
    "title",
1618 707f23b5 Michael Hanselmann
    "kind",
1619 1ae17369 Michael Hanselmann
    "doc",
1620 707f23b5 Michael Hanselmann
    ]
1621 707f23b5 Michael Hanselmann
1622 707f23b5 Michael Hanselmann
1623 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1624 0538c375 Michael Hanselmann
  __slots__ = [
1625 0538c375 Michael Hanselmann
    "fields",
1626 0538c375 Michael Hanselmann
    ]
1627 0538c375 Michael Hanselmann
1628 0538c375 Michael Hanselmann
  def ToDict(self):
1629 0538c375 Michael Hanselmann
    """Custom function for serializing.
1630 0538c375 Michael Hanselmann

1631 0538c375 Michael Hanselmann
    """
1632 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1633 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1634 0538c375 Michael Hanselmann
    return mydict
1635 0538c375 Michael Hanselmann
1636 0538c375 Michael Hanselmann
  @classmethod
1637 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1638 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1639 0538c375 Michael Hanselmann

1640 0538c375 Michael Hanselmann
    """
1641 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1642 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1643 0538c375 Michael Hanselmann
    return obj
1644 0538c375 Michael Hanselmann
1645 0538c375 Michael Hanselmann
1646 24d6d3e2 Michael Hanselmann
class QueryRequest(ConfigObject):
1647 24d6d3e2 Michael Hanselmann
  """Object holding a query request.
1648 24d6d3e2 Michael Hanselmann

1649 24d6d3e2 Michael Hanselmann
  """
1650 24d6d3e2 Michael Hanselmann
  __slots__ = [
1651 24d6d3e2 Michael Hanselmann
    "what",
1652 24d6d3e2 Michael Hanselmann
    "fields",
1653 2e5c33db Iustin Pop
    "qfilter",
1654 24d6d3e2 Michael Hanselmann
    ]
1655 24d6d3e2 Michael Hanselmann
1656 24d6d3e2 Michael Hanselmann
1657 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
1658 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
1659 24d6d3e2 Michael Hanselmann

1660 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1661 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1662 24d6d3e2 Michael Hanselmann

1663 24d6d3e2 Michael Hanselmann
  """
1664 24d6d3e2 Michael Hanselmann
  __slots__ = [
1665 24d6d3e2 Michael Hanselmann
    "data",
1666 24d6d3e2 Michael Hanselmann
    ]
1667 24d6d3e2 Michael Hanselmann
1668 24d6d3e2 Michael Hanselmann
1669 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
1670 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
1671 24d6d3e2 Michael Hanselmann

1672 24d6d3e2 Michael Hanselmann
  """
1673 24d6d3e2 Michael Hanselmann
  __slots__ = [
1674 24d6d3e2 Michael Hanselmann
    "what",
1675 24d6d3e2 Michael Hanselmann
    "fields",
1676 24d6d3e2 Michael Hanselmann
    ]
1677 24d6d3e2 Michael Hanselmann
1678 24d6d3e2 Michael Hanselmann
1679 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
1680 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
1681 24d6d3e2 Michael Hanselmann

1682 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1683 24d6d3e2 Michael Hanselmann

1684 24d6d3e2 Michael Hanselmann
  """
1685 24d6d3e2 Michael Hanselmann
  __slots__ = [
1686 24d6d3e2 Michael Hanselmann
    ]
1687 24d6d3e2 Michael Hanselmann
1688 24d6d3e2 Michael Hanselmann
1689 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
1690 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
1691 6a1434d7 Andrea Spadaccini

1692 6a1434d7 Andrea Spadaccini
  """
1693 6a1434d7 Andrea Spadaccini
  __slots__ = [
1694 6a1434d7 Andrea Spadaccini
    "status",
1695 6a1434d7 Andrea Spadaccini
    "transferred_ram",
1696 6a1434d7 Andrea Spadaccini
    "total_ram",
1697 6a1434d7 Andrea Spadaccini
    ]
1698 6a1434d7 Andrea Spadaccini
1699 6a1434d7 Andrea Spadaccini
1700 25ce3ec4 Michael Hanselmann
class InstanceConsole(ConfigObject):
1701 25ce3ec4 Michael Hanselmann
  """Object describing how to access the console of an instance.
1702 25ce3ec4 Michael Hanselmann

1703 25ce3ec4 Michael Hanselmann
  """
1704 25ce3ec4 Michael Hanselmann
  __slots__ = [
1705 25ce3ec4 Michael Hanselmann
    "instance",
1706 25ce3ec4 Michael Hanselmann
    "kind",
1707 25ce3ec4 Michael Hanselmann
    "message",
1708 25ce3ec4 Michael Hanselmann
    "host",
1709 25ce3ec4 Michael Hanselmann
    "port",
1710 25ce3ec4 Michael Hanselmann
    "user",
1711 25ce3ec4 Michael Hanselmann
    "command",
1712 25ce3ec4 Michael Hanselmann
    "display",
1713 25ce3ec4 Michael Hanselmann
    ]
1714 25ce3ec4 Michael Hanselmann
1715 25ce3ec4 Michael Hanselmann
  def Validate(self):
1716 25ce3ec4 Michael Hanselmann
    """Validates contents of this object.
1717 25ce3ec4 Michael Hanselmann

1718 25ce3ec4 Michael Hanselmann
    """
1719 25ce3ec4 Michael Hanselmann
    assert self.kind in constants.CONS_ALL, "Unknown console type"
1720 25ce3ec4 Michael Hanselmann
    assert self.instance, "Missing instance name"
1721 4d2cdb5a Andrea Spadaccini
    assert self.message or self.kind in [constants.CONS_SSH,
1722 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1723 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_VNC]
1724 25ce3ec4 Michael Hanselmann
    assert self.host or self.kind == constants.CONS_MESSAGE
1725 25ce3ec4 Michael Hanselmann
    assert self.port or self.kind in [constants.CONS_MESSAGE,
1726 25ce3ec4 Michael Hanselmann
                                      constants.CONS_SSH]
1727 25ce3ec4 Michael Hanselmann
    assert self.user or self.kind in [constants.CONS_MESSAGE,
1728 4d2cdb5a Andrea Spadaccini
                                      constants.CONS_SPICE,
1729 25ce3ec4 Michael Hanselmann
                                      constants.CONS_VNC]
1730 25ce3ec4 Michael Hanselmann
    assert self.command or self.kind in [constants.CONS_MESSAGE,
1731 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1732 25ce3ec4 Michael Hanselmann
                                         constants.CONS_VNC]
1733 25ce3ec4 Michael Hanselmann
    assert self.display or self.kind in [constants.CONS_MESSAGE,
1734 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1735 25ce3ec4 Michael Hanselmann
                                         constants.CONS_SSH]
1736 25ce3ec4 Michael Hanselmann
    return True
1737 25ce3ec4 Michael Hanselmann
1738 25ce3ec4 Michael Hanselmann
1739 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1740 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1741 a8083063 Iustin Pop

1742 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1743 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1744 a8083063 Iustin Pop
  buffer.
1745 a8083063 Iustin Pop

1746 a8083063 Iustin Pop
  """
1747 a8083063 Iustin Pop
  def Dumps(self):
1748 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1749 a8083063 Iustin Pop
    buf = StringIO()
1750 a8083063 Iustin Pop
    self.write(buf)
1751 a8083063 Iustin Pop
    return buf.getvalue()
1752 a8083063 Iustin Pop
1753 b39bf4bb Guido Trotter
  @classmethod
1754 b39bf4bb Guido Trotter
  def Loads(cls, data):
1755 a8083063 Iustin Pop
    """Load data from a string."""
1756 a8083063 Iustin Pop
    buf = StringIO(data)
1757 b39bf4bb Guido Trotter
    cfp = cls()
1758 a8083063 Iustin Pop
    cfp.readfp(buf)
1759 a8083063 Iustin Pop
    return cfp