Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 095e71aa

History | View | Annotate | Download (40 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 870dc44c Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 7260cfbe Iustin Pop
# pylint: disable-msg=E0203,W0201
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 a8083063 Iustin Pop
import ConfigParser
37 5c947f38 Iustin Pop
import re
38 5bf7b5cf Iustin Pop
import copy
39 d5835922 Michael Hanselmann
from cStringIO import StringIO
40 a8083063 Iustin Pop
41 a8083063 Iustin Pop
from ganeti import errors
42 5c947f38 Iustin Pop
from ganeti import constants
43 a8083063 Iustin Pop
44 f4c9af7a Guido Trotter
from socket import AF_INET
45 f4c9af7a Guido Trotter
46 a8083063 Iustin Pop
47 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
48 24a3707f Guido Trotter
           "OS", "Node", "NodeGroup", "Cluster", "FillDict"]
49 a8083063 Iustin Pop
50 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
51 e1dcc53a Iustin Pop
_UUID = ["uuid"]
52 96acbc09 Michael Hanselmann
53 8d8d650c Michael Hanselmann
54 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
55 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
56 abe609b2 Guido Trotter

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

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

81 6e34b628 Guido Trotter
  @type target: dict of dicts
82 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
83 6e34b628 Guido Trotter
  @type defaults: dict
84 6e34b628 Guido Trotter
  @param defaults: default parameter values
85 6e34b628 Guido Trotter

86 6e34b628 Guido Trotter
  """
87 6e34b628 Guido Trotter
  if target is None:
88 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
89 6e34b628 Guido Trotter
  else:
90 6e34b628 Guido Trotter
    for group in target:
91 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
92 6e34b628 Guido Trotter
  return target
93 6e34b628 Guido Trotter
94 6e34b628 Guido Trotter
95 a8083063 Iustin Pop
class ConfigObject(object):
96 a8083063 Iustin Pop
  """A generic config object.
97 a8083063 Iustin Pop

98 a8083063 Iustin Pop
  It has the following properties:
99 a8083063 Iustin Pop

100 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
101 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
102 a8083063 Iustin Pop
      as None instead of raising an error
103 a8083063 Iustin Pop

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

107 a8083063 Iustin Pop
  """
108 a8083063 Iustin Pop
  __slots__ = []
109 a8083063 Iustin Pop
110 a8083063 Iustin Pop
  def __init__(self, **kwargs):
111 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
112 319856a9 Michael Hanselmann
      setattr(self, k, v)
113 a8083063 Iustin Pop
114 a8083063 Iustin Pop
  def __getattr__(self, name):
115 adf385c7 Iustin Pop
    if name not in self._all_slots():
116 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
117 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
118 a8083063 Iustin Pop
    return None
119 a8083063 Iustin Pop
120 a8083063 Iustin Pop
  def __setstate__(self, state):
121 adf385c7 Iustin Pop
    slots = self._all_slots()
122 a8083063 Iustin Pop
    for name in state:
123 adf385c7 Iustin Pop
      if name in slots:
124 a8083063 Iustin Pop
        setattr(self, name, state[name])
125 a8083063 Iustin Pop
126 adf385c7 Iustin Pop
  @classmethod
127 adf385c7 Iustin Pop
  def _all_slots(cls):
128 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
129 adf385c7 Iustin Pop

130 adf385c7 Iustin Pop
    """
131 adf385c7 Iustin Pop
    slots = []
132 adf385c7 Iustin Pop
    for parent in cls.__mro__:
133 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
134 adf385c7 Iustin Pop
    return slots
135 adf385c7 Iustin Pop
136 ff9c047c Iustin Pop
  def ToDict(self):
137 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
138 ff9c047c Iustin Pop

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

145 ff9c047c Iustin Pop
    """
146 4c14965f Guido Trotter
    result = {}
147 adf385c7 Iustin Pop
    for name in self._all_slots():
148 4c14965f Guido Trotter
      value = getattr(self, name, None)
149 4c14965f Guido Trotter
      if value is not None:
150 4c14965f Guido Trotter
        result[name] = value
151 4c14965f Guido Trotter
    return result
152 4c14965f Guido Trotter
153 4c14965f Guido Trotter
  __getstate__ = ToDict
154 ff9c047c Iustin Pop
155 ff9c047c Iustin Pop
  @classmethod
156 ff9c047c Iustin Pop
  def FromDict(cls, val):
157 ff9c047c Iustin Pop
    """Create an object from a dictionary.
158 ff9c047c Iustin Pop

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

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

167 ff9c047c Iustin Pop
    """
168 ff9c047c Iustin Pop
    if not isinstance(val, dict):
169 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
170 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
171 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
172 7260cfbe Iustin Pop
    obj = cls(**val_str) # pylint: disable-msg=W0142
173 ff9c047c Iustin Pop
    return obj
174 ff9c047c Iustin Pop
175 ff9c047c Iustin Pop
  @staticmethod
176 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
177 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
178 ff9c047c Iustin Pop

179 ff9c047c Iustin Pop
    This method converts a container with elements derived from
180 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
181 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
182 ff9c047c Iustin Pop

183 ff9c047c Iustin Pop
    """
184 ff9c047c Iustin Pop
    if isinstance(container, dict):
185 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
186 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
187 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
188 ff9c047c Iustin Pop
    else:
189 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
190 ff9c047c Iustin Pop
                      type(container))
191 ff9c047c Iustin Pop
    return ret
192 ff9c047c Iustin Pop
193 ff9c047c Iustin Pop
  @staticmethod
194 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
195 ff9c047c Iustin Pop
    """Convert a container from standard python types.
196 ff9c047c Iustin Pop

197 ff9c047c Iustin Pop
    This method converts a container with standard python types to
198 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
199 ff9c047c Iustin Pop
    keys, only the values.
200 ff9c047c Iustin Pop

201 ff9c047c Iustin Pop
    """
202 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
203 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
204 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
205 fe25a79a Guido Trotter
    if source is None:
206 fe25a79a Guido Trotter
      source = c_type()
207 ff9c047c Iustin Pop
    if c_type is dict:
208 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
209 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
210 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
211 ff9c047c Iustin Pop
    else:
212 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
213 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
214 ff9c047c Iustin Pop
    return ret
215 ff9c047c Iustin Pop
216 e8d563f3 Iustin Pop
  def Copy(self):
217 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
218 e8d563f3 Iustin Pop

219 e8d563f3 Iustin Pop
    """
220 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
221 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
222 e8d563f3 Iustin Pop
    return clone_obj
223 e8d563f3 Iustin Pop
224 ff9c047c Iustin Pop
  def __repr__(self):
225 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
226 ff9c047c Iustin Pop
    return repr(self.ToDict())
227 ff9c047c Iustin Pop
228 560428be Guido Trotter
  def UpgradeConfig(self):
229 560428be Guido Trotter
    """Fill defaults for missing configuration values.
230 560428be Guido Trotter

231 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
232 90d726a8 Iustin Pop
    implementation will be object dependent.
233 560428be Guido Trotter

234 560428be Guido Trotter
    """
235 560428be Guido Trotter
    pass
236 560428be Guido Trotter
237 a8083063 Iustin Pop
238 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
239 5c947f38 Iustin Pop
  """An generic class supporting tags.
240 5c947f38 Iustin Pop

241 5c947f38 Iustin Pop
  """
242 154b9580 Balazs Lecz
  __slots__ = ["tags"]
243 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
244 2057f6c7 Iustin Pop
245 b5e5632e Iustin Pop
  @classmethod
246 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
247 5c947f38 Iustin Pop
    """Check if a tag is valid.
248 5c947f38 Iustin Pop

249 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
250 5c947f38 Iustin Pop
    function has no return value.
251 5c947f38 Iustin Pop

252 5c947f38 Iustin Pop
    """
253 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
254 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
255 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
256 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
257 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
258 5c947f38 Iustin Pop
    if not tag:
259 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
260 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
261 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
262 5c947f38 Iustin Pop
263 5c947f38 Iustin Pop
  def GetTags(self):
264 5c947f38 Iustin Pop
    """Return the tags list.
265 5c947f38 Iustin Pop

266 5c947f38 Iustin Pop
    """
267 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
268 5c947f38 Iustin Pop
    if tags is None:
269 5c947f38 Iustin Pop
      tags = self.tags = set()
270 5c947f38 Iustin Pop
    return tags
271 5c947f38 Iustin Pop
272 5c947f38 Iustin Pop
  def AddTag(self, tag):
273 5c947f38 Iustin Pop
    """Add a new tag.
274 5c947f38 Iustin Pop

275 5c947f38 Iustin Pop
    """
276 5c947f38 Iustin Pop
    self.ValidateTag(tag)
277 5c947f38 Iustin Pop
    tags = self.GetTags()
278 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
279 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
280 5c947f38 Iustin Pop
    self.GetTags().add(tag)
281 5c947f38 Iustin Pop
282 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
283 5c947f38 Iustin Pop
    """Remove a tag.
284 5c947f38 Iustin Pop

285 5c947f38 Iustin Pop
    """
286 5c947f38 Iustin Pop
    self.ValidateTag(tag)
287 5c947f38 Iustin Pop
    tags = self.GetTags()
288 5c947f38 Iustin Pop
    try:
289 5c947f38 Iustin Pop
      tags.remove(tag)
290 5c947f38 Iustin Pop
    except KeyError:
291 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
292 5c947f38 Iustin Pop
293 ff9c047c Iustin Pop
  def ToDict(self):
294 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
295 ff9c047c Iustin Pop

296 ff9c047c Iustin Pop
    This replaces the tags set with a list.
297 ff9c047c Iustin Pop

298 ff9c047c Iustin Pop
    """
299 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
300 ff9c047c Iustin Pop
301 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
302 ff9c047c Iustin Pop
    if isinstance(tags, set):
303 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
304 ff9c047c Iustin Pop
    return bo
305 ff9c047c Iustin Pop
306 ff9c047c Iustin Pop
  @classmethod
307 ff9c047c Iustin Pop
  def FromDict(cls, val):
308 ff9c047c Iustin Pop
    """Custom function for instances.
309 ff9c047c Iustin Pop

310 ff9c047c Iustin Pop
    """
311 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
312 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
313 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
314 ff9c047c Iustin Pop
    return obj
315 ff9c047c Iustin Pop
316 5c947f38 Iustin Pop
317 a8083063 Iustin Pop
class ConfigData(ConfigObject):
318 a8083063 Iustin Pop
  """Top-level config object."""
319 3df43542 Guido Trotter
  __slots__ = [
320 3df43542 Guido Trotter
    "version",
321 3df43542 Guido Trotter
    "cluster",
322 3df43542 Guido Trotter
    "nodes",
323 3df43542 Guido Trotter
    "nodegroups",
324 3df43542 Guido Trotter
    "instances",
325 3df43542 Guido Trotter
    "serial_no",
326 3df43542 Guido Trotter
    ] + _TIMESTAMPS
327 a8083063 Iustin Pop
328 ff9c047c Iustin Pop
  def ToDict(self):
329 ff9c047c Iustin Pop
    """Custom function for top-level config data.
330 ff9c047c Iustin Pop

331 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
332 ff9c047c Iustin Pop
    with standard python types.
333 ff9c047c Iustin Pop

334 ff9c047c Iustin Pop
    """
335 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
336 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
337 3df43542 Guido Trotter
    for key in "nodes", "instances", "nodegroups":
338 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
339 ff9c047c Iustin Pop
340 ff9c047c Iustin Pop
    return mydict
341 ff9c047c Iustin Pop
342 ff9c047c Iustin Pop
  @classmethod
343 ff9c047c Iustin Pop
  def FromDict(cls, val):
344 ff9c047c Iustin Pop
    """Custom function for top-level config data
345 ff9c047c Iustin Pop

346 ff9c047c Iustin Pop
    """
347 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
348 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
349 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
350 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
351 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
352 ff9c047c Iustin Pop
    return obj
353 ff9c047c Iustin Pop
354 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
355 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
356 51cb1581 Luca Bigliardi

357 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
358 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
359 51cb1581 Luca Bigliardi
    @rtype: boolean
360 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
361 51cb1581 Luca Bigliardi

362 51cb1581 Luca Bigliardi
    """
363 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
364 51cb1581 Luca Bigliardi
      for disk in instance.disks:
365 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
366 51cb1581 Luca Bigliardi
          return True
367 51cb1581 Luca Bigliardi
    return False
368 51cb1581 Luca Bigliardi
369 90d726a8 Iustin Pop
  def UpgradeConfig(self):
370 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
371 90d726a8 Iustin Pop

372 90d726a8 Iustin Pop
    """
373 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
374 90d726a8 Iustin Pop
    for node in self.nodes.values():
375 90d726a8 Iustin Pop
      node.UpgradeConfig()
376 90d726a8 Iustin Pop
    for instance in self.instances.values():
377 90d726a8 Iustin Pop
      instance.UpgradeConfig()
378 3df43542 Guido Trotter
    if self.nodegroups is None:
379 3df43542 Guido Trotter
      self.nodegroups = {}
380 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
381 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
382 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
383 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
384 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
385 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
386 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
387 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
388 90d726a8 Iustin Pop
389 a8083063 Iustin Pop
390 a8083063 Iustin Pop
class NIC(ConfigObject):
391 a8083063 Iustin Pop
  """Config object representing a network card."""
392 13f1af63 Guido Trotter
  __slots__ = ["mac", "ip", "bridge", "nicparams"]
393 a8083063 Iustin Pop
394 255e19d4 Guido Trotter
  @classmethod
395 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
396 255e19d4 Guido Trotter
    """Check the given parameters for validity.
397 255e19d4 Guido Trotter

398 255e19d4 Guido Trotter
    @type nicparams:  dict
399 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
400 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
401 255e19d4 Guido Trotter

402 255e19d4 Guido Trotter
    """
403 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
404 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
405 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
406 255e19d4 Guido Trotter
407 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
408 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
409 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
410 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
411 255e19d4 Guido Trotter
412 13f1af63 Guido Trotter
  def UpgradeConfig(self):
413 13f1af63 Guido Trotter
    """Fill defaults for missing configuration values.
414 13f1af63 Guido Trotter

415 13f1af63 Guido Trotter
    """
416 13f1af63 Guido Trotter
    if self.nicparams is None:
417 13f1af63 Guido Trotter
      self.nicparams = {}
418 13f1af63 Guido Trotter
      if self.bridge is not None:
419 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_MODE] = constants.NIC_MODE_BRIDGED
420 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_LINK] = self.bridge
421 9b31ca85 Guido Trotter
    # bridge is no longer used it 2.1. The slot is left there to support
422 90d118fd Guido Trotter
    # upgrading, but can be removed once upgrades to the current version
423 90d118fd Guido Trotter
    # straight from 2.0 are deprecated.
424 9b31ca85 Guido Trotter
    if self.bridge is not None:
425 9b31ca85 Guido Trotter
      self.bridge = None
426 13f1af63 Guido Trotter
427 a8083063 Iustin Pop
428 a8083063 Iustin Pop
class Disk(ConfigObject):
429 a8083063 Iustin Pop
  """Config object representing a block device."""
430 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
431 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
432 a8083063 Iustin Pop
433 a8083063 Iustin Pop
  def CreateOnSecondary(self):
434 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
435 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
436 a8083063 Iustin Pop
437 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
438 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
439 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
440 a8083063 Iustin Pop
441 a8083063 Iustin Pop
  def OpenOnSecondary(self):
442 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
443 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
444 a8083063 Iustin Pop
445 222f2dd5 Iustin Pop
  def StaticDevPath(self):
446 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
447 222f2dd5 Iustin Pop

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

452 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
453 e51db2a6 Iustin Pop
        should check that it is a valid path.
454 e51db2a6 Iustin Pop

455 222f2dd5 Iustin Pop
    """
456 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
457 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
458 222f2dd5 Iustin Pop
    return None
459 222f2dd5 Iustin Pop
460 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
461 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
462 fc1dc9d7 Iustin Pop

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

467 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
468 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
469 fc1dc9d7 Iustin Pop
    -1.
470 fc1dc9d7 Iustin Pop

471 fc1dc9d7 Iustin Pop
    """
472 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
473 fc1dc9d7 Iustin Pop
      return 0
474 fc1dc9d7 Iustin Pop
    return -1
475 fc1dc9d7 Iustin Pop
476 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
477 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
478 51cb1581 Luca Bigliardi

479 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
480 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
481 51cb1581 Luca Bigliardi
    @rtype: boolean
482 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
483 51cb1581 Luca Bigliardi

484 51cb1581 Luca Bigliardi
    """
485 51cb1581 Luca Bigliardi
    if self.children:
486 51cb1581 Luca Bigliardi
      for child in self.children:
487 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
488 51cb1581 Luca Bigliardi
          return True
489 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
490 51cb1581 Luca Bigliardi
491 a8083063 Iustin Pop
  def GetNodes(self, node):
492 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
493 a8083063 Iustin Pop

494 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
495 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
496 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
497 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
498 a8083063 Iustin Pop

499 a8083063 Iustin Pop
    """
500 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
501 a8083063 Iustin Pop
      result = [node]
502 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
503 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
504 a8083063 Iustin Pop
      if node not in result:
505 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
506 a8083063 Iustin Pop
    else:
507 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
508 a8083063 Iustin Pop
    return result
509 a8083063 Iustin Pop
510 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
511 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
512 a8083063 Iustin Pop

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

519 a8083063 Iustin Pop
    """
520 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
521 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
522 a8083063 Iustin Pop
    if not self.children:
523 a8083063 Iustin Pop
      # leaf device
524 a8083063 Iustin Pop
      return result
525 a8083063 Iustin Pop
    for node in my_nodes:
526 a8083063 Iustin Pop
      for child in self.children:
527 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
528 a8083063 Iustin Pop
        if len(child_result) == 1:
529 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
530 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
531 a8083063 Iustin Pop
          # own entry for this node describes it completely
532 a8083063 Iustin Pop
          continue
533 a8083063 Iustin Pop
        else:
534 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
535 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
536 a8083063 Iustin Pop
          # one of its descendants
537 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
538 a8083063 Iustin Pop
            if subnode not in my_nodes:
539 a8083063 Iustin Pop
              result.append((subnode, subdisk))
540 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
541 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
542 a8083063 Iustin Pop
            # be different)
543 a8083063 Iustin Pop
    return result
544 a8083063 Iustin Pop
545 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
546 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
547 acec9d51 Iustin Pop

548 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
549 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
550 acec9d51 Iustin Pop
    actual algorithms from bdev.
551 acec9d51 Iustin Pop

552 acec9d51 Iustin Pop
    """
553 2c42c5df Guido Trotter
    if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE:
554 acec9d51 Iustin Pop
      self.size += amount
555 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
556 acec9d51 Iustin Pop
      if self.children:
557 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
558 acec9d51 Iustin Pop
      self.size += amount
559 acec9d51 Iustin Pop
    else:
560 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
561 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
562 acec9d51 Iustin Pop
563 a805ec18 Iustin Pop
  def UnsetSize(self):
564 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
565 a805ec18 Iustin Pop

566 a805ec18 Iustin Pop
    """
567 a805ec18 Iustin Pop
    if self.children:
568 a805ec18 Iustin Pop
      for child in self.children:
569 a805ec18 Iustin Pop
        child.UnsetSize()
570 a805ec18 Iustin Pop
    self.size = 0
571 a805ec18 Iustin Pop
572 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
573 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
574 0402302c Iustin Pop

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

577 0402302c Iustin Pop
    The routine descends down and updates its children also, because
578 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
579 0402302c Iustin Pop
    node.
580 0402302c Iustin Pop

581 0402302c Iustin Pop
    Arguments:
582 0402302c Iustin Pop
      - target_node: the node we wish to configure for
583 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
584 0402302c Iustin Pop

585 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
586 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
587 0402302c Iustin Pop
    in the disk tree.
588 0402302c Iustin Pop

589 0402302c Iustin Pop
    """
590 0402302c Iustin Pop
    if self.children:
591 0402302c Iustin Pop
      for child in self.children:
592 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
593 0402302c Iustin Pop
594 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
595 0402302c Iustin Pop
      return
596 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
597 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
598 0402302c Iustin Pop
      if target_node not in (pnode, snode):
599 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
600 0402302c Iustin Pop
                                        target_node)
601 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
602 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
603 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
604 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
605 0402302c Iustin Pop
                                        " for %s" % str(self))
606 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
607 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
608 0402302c Iustin Pop
      if pnode == target_node:
609 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
610 0402302c Iustin Pop
      else: # it must be secondary, we tested above
611 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
612 0402302c Iustin Pop
    else:
613 0402302c Iustin Pop
      self.physical_id = self.logical_id
614 0402302c Iustin Pop
    return
615 0402302c Iustin Pop
616 ff9c047c Iustin Pop
  def ToDict(self):
617 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
618 ff9c047c Iustin Pop

619 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
620 ff9c047c Iustin Pop
    standard python types.
621 ff9c047c Iustin Pop

622 ff9c047c Iustin Pop
    """
623 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
624 ff9c047c Iustin Pop
625 ff9c047c Iustin Pop
    for attr in ("children",):
626 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
627 ff9c047c Iustin Pop
      if alist:
628 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
629 ff9c047c Iustin Pop
    return bo
630 ff9c047c Iustin Pop
631 ff9c047c Iustin Pop
  @classmethod
632 ff9c047c Iustin Pop
  def FromDict(cls, val):
633 ff9c047c Iustin Pop
    """Custom function for Disks
634 ff9c047c Iustin Pop

635 ff9c047c Iustin Pop
    """
636 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
637 ff9c047c Iustin Pop
    if obj.children:
638 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
639 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
640 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
641 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
642 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
643 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
644 f9518d38 Iustin Pop
      # we need a tuple of length six here
645 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
646 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
647 ff9c047c Iustin Pop
    return obj
648 ff9c047c Iustin Pop
649 65a15336 Iustin Pop
  def __str__(self):
650 65a15336 Iustin Pop
    """Custom str() formatter for disks.
651 65a15336 Iustin Pop

652 65a15336 Iustin Pop
    """
653 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
654 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
655 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
656 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
657 00fb8246 Michael Hanselmann
      val = "<DRBD8("
658 073ca59e Iustin Pop
      if self.physical_id is None:
659 073ca59e Iustin Pop
        phy = "unconfigured"
660 073ca59e Iustin Pop
      else:
661 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
662 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
663 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
664 073ca59e Iustin Pop
665 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
666 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
667 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
668 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
669 65a15336 Iustin Pop
      else:
670 65a15336 Iustin Pop
        val += "no local storage"
671 65a15336 Iustin Pop
    else:
672 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
673 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
674 65a15336 Iustin Pop
    if self.iv_name is None:
675 65a15336 Iustin Pop
      val += ", not visible"
676 65a15336 Iustin Pop
    else:
677 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
678 fd965830 Iustin Pop
    if isinstance(self.size, int):
679 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
680 fd965830 Iustin Pop
    else:
681 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
682 65a15336 Iustin Pop
    return val
683 65a15336 Iustin Pop
684 332d0e37 Iustin Pop
  def Verify(self):
685 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
686 332d0e37 Iustin Pop

687 332d0e37 Iustin Pop
    """
688 7c4d6c7b Michael Hanselmann
    all_errors = []
689 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
690 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
691 7c4d6c7b Michael Hanselmann
    return all_errors
692 332d0e37 Iustin Pop
693 90d726a8 Iustin Pop
  def UpgradeConfig(self):
694 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
695 90d726a8 Iustin Pop

696 90d726a8 Iustin Pop
    """
697 90d726a8 Iustin Pop
    if self.children:
698 90d726a8 Iustin Pop
      for child in self.children:
699 90d726a8 Iustin Pop
        child.UpgradeConfig()
700 90d726a8 Iustin Pop
    # add here config upgrade for this disk
701 90d726a8 Iustin Pop
702 a8083063 Iustin Pop
703 ec29fe40 Iustin Pop
class Instance(TaggableObject):
704 a8083063 Iustin Pop
  """Config object representing an instance."""
705 154b9580 Balazs Lecz
  __slots__ = [
706 a8083063 Iustin Pop
    "name",
707 a8083063 Iustin Pop
    "primary_node",
708 a8083063 Iustin Pop
    "os",
709 e69d05fd Iustin Pop
    "hypervisor",
710 5bf7b5cf Iustin Pop
    "hvparams",
711 5bf7b5cf Iustin Pop
    "beparams",
712 1bdcbbab Iustin Pop
    "osparams",
713 0d68c45d Iustin Pop
    "admin_up",
714 a8083063 Iustin Pop
    "nics",
715 a8083063 Iustin Pop
    "disks",
716 a8083063 Iustin Pop
    "disk_template",
717 58acb49d Alexander Schreiber
    "network_port",
718 be1fa613 Iustin Pop
    "serial_no",
719 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
720 a8083063 Iustin Pop
721 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
722 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
723 a8083063 Iustin Pop

724 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
725 cfcc5c6d Iustin Pop

726 cfcc5c6d Iustin Pop
    """
727 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
728 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
729 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
730 cfcc5c6d Iustin Pop
731 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
732 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
733 cfcc5c6d Iustin Pop
734 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
735 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
736 cfcc5c6d Iustin Pop

737 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
738 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
739 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
740 a8083063 Iustin Pop
    dynamically.
741 a8083063 Iustin Pop

742 a8083063 Iustin Pop
    """
743 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
744 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
745 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
746 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
747 cfcc5c6d Iustin Pop
        nodes.add(nodea)
748 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
749 a8083063 Iustin Pop
      if device.children:
750 a8083063 Iustin Pop
        for child in device.children:
751 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
752 a8083063 Iustin Pop
753 cfcc5c6d Iustin Pop
    all_nodes = set()
754 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
755 a8083063 Iustin Pop
    for device in self.disks:
756 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
757 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
758 a8083063 Iustin Pop
759 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
760 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
761 a8083063 Iustin Pop
762 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
763 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
764 a8083063 Iustin Pop

765 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
766 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
767 a8083063 Iustin Pop

768 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
769 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
770 a8083063 Iustin Pop

771 c41eea6e Iustin Pop
    @return: None if lvmap arg is given, otherwise, a dictionary
772 c41eea6e Iustin Pop
        of the form { 'nodename' : ['volume1', 'volume2', ...], ... }
773 a8083063 Iustin Pop

774 a8083063 Iustin Pop
    """
775 a8083063 Iustin Pop
    if node == None:
776 a8083063 Iustin Pop
      node = self.primary_node
777 a8083063 Iustin Pop
778 a8083063 Iustin Pop
    if lvmap is None:
779 a8083063 Iustin Pop
      lvmap = { node : [] }
780 a8083063 Iustin Pop
      ret = lvmap
781 a8083063 Iustin Pop
    else:
782 a8083063 Iustin Pop
      if not node in lvmap:
783 a8083063 Iustin Pop
        lvmap[node] = []
784 a8083063 Iustin Pop
      ret = None
785 a8083063 Iustin Pop
786 a8083063 Iustin Pop
    if not devs:
787 a8083063 Iustin Pop
      devs = self.disks
788 a8083063 Iustin Pop
789 a8083063 Iustin Pop
    for dev in devs:
790 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
791 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
792 a8083063 Iustin Pop
793 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
794 a8083063 Iustin Pop
        if dev.children:
795 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
796 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
797 a8083063 Iustin Pop
798 a8083063 Iustin Pop
      elif dev.children:
799 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
800 a8083063 Iustin Pop
801 a8083063 Iustin Pop
    return ret
802 a8083063 Iustin Pop
803 ad24e046 Iustin Pop
  def FindDisk(self, idx):
804 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
805 644eeef9 Iustin Pop

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

808 ad24e046 Iustin Pop
    @type idx: int
809 ad24e046 Iustin Pop
    @param idx: the disk index
810 ad24e046 Iustin Pop
    @rtype: L{Disk}
811 ad24e046 Iustin Pop
    @return: the corresponding disk
812 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
813 644eeef9 Iustin Pop

814 ad24e046 Iustin Pop
    """
815 ad24e046 Iustin Pop
    try:
816 ad24e046 Iustin Pop
      idx = int(idx)
817 ad24e046 Iustin Pop
      return self.disks[idx]
818 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
819 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
820 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
821 ad24e046 Iustin Pop
    except IndexError:
822 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
823 debac808 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)),
824 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
825 644eeef9 Iustin Pop
826 ff9c047c Iustin Pop
  def ToDict(self):
827 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
828 ff9c047c Iustin Pop

829 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
830 ff9c047c Iustin Pop
    python types.
831 ff9c047c Iustin Pop

832 ff9c047c Iustin Pop
    """
833 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
834 ff9c047c Iustin Pop
835 ff9c047c Iustin Pop
    for attr in "nics", "disks":
836 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
837 ff9c047c Iustin Pop
      if alist:
838 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
839 ff9c047c Iustin Pop
      else:
840 ff9c047c Iustin Pop
        nlist = []
841 ff9c047c Iustin Pop
      bo[attr] = nlist
842 ff9c047c Iustin Pop
    return bo
843 ff9c047c Iustin Pop
844 ff9c047c Iustin Pop
  @classmethod
845 ff9c047c Iustin Pop
  def FromDict(cls, val):
846 ff9c047c Iustin Pop
    """Custom function for instances.
847 ff9c047c Iustin Pop

848 ff9c047c Iustin Pop
    """
849 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
850 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
851 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
852 ff9c047c Iustin Pop
    return obj
853 ff9c047c Iustin Pop
854 90d726a8 Iustin Pop
  def UpgradeConfig(self):
855 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
856 90d726a8 Iustin Pop

857 90d726a8 Iustin Pop
    """
858 90d726a8 Iustin Pop
    for nic in self.nics:
859 90d726a8 Iustin Pop
      nic.UpgradeConfig()
860 90d726a8 Iustin Pop
    for disk in self.disks:
861 90d726a8 Iustin Pop
      disk.UpgradeConfig()
862 7736a5f2 Iustin Pop
    if self.hvparams:
863 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
864 7736a5f2 Iustin Pop
        try:
865 7736a5f2 Iustin Pop
          del self.hvparams[key]
866 7736a5f2 Iustin Pop
        except KeyError:
867 7736a5f2 Iustin Pop
          pass
868 1bdcbbab Iustin Pop
    if self.osparams is None:
869 1bdcbbab Iustin Pop
      self.osparams = {}
870 90d726a8 Iustin Pop
871 a8083063 Iustin Pop
872 a8083063 Iustin Pop
class OS(ConfigObject):
873 b41b3516 Iustin Pop
  """Config object representing an operating system.
874 b41b3516 Iustin Pop

875 b41b3516 Iustin Pop
  @type supported_parameters: list
876 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
877 b41b3516 Iustin Pop
      containing the supported parameters by this OS
878 b41b3516 Iustin Pop

879 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
880 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
881 870dc44c Iustin Pop

882 b41b3516 Iustin Pop
  """
883 a8083063 Iustin Pop
  __slots__ = [
884 a8083063 Iustin Pop
    "name",
885 a8083063 Iustin Pop
    "path",
886 082a7f91 Guido Trotter
    "api_versions",
887 a8083063 Iustin Pop
    "create_script",
888 a8083063 Iustin Pop
    "export_script",
889 386b57af Iustin Pop
    "import_script",
890 386b57af Iustin Pop
    "rename_script",
891 b41b3516 Iustin Pop
    "verify_script",
892 6d79896b Guido Trotter
    "supported_variants",
893 b41b3516 Iustin Pop
    "supported_parameters",
894 a8083063 Iustin Pop
    ]
895 a8083063 Iustin Pop
896 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
897 870dc44c Iustin Pop
898 870dc44c Iustin Pop
  @classmethod
899 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
900 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
901 870dc44c Iustin Pop

902 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
903 870dc44c Iustin Pop
    @rtype: list
904 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
905 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
906 870dc44c Iustin Pop

907 870dc44c Iustin Pop
    """
908 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
909 870dc44c Iustin Pop
    if len(nv) == 1:
910 870dc44c Iustin Pop
      nv.append("")
911 870dc44c Iustin Pop
    return nv
912 870dc44c Iustin Pop
913 870dc44c Iustin Pop
  @classmethod
914 870dc44c Iustin Pop
  def GetName(cls, name):
915 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
916 870dc44c Iustin Pop

917 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
918 870dc44c Iustin Pop

919 870dc44c Iustin Pop
    """
920 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
921 870dc44c Iustin Pop
922 870dc44c Iustin Pop
  @classmethod
923 870dc44c Iustin Pop
  def GetVariant(cls, name):
924 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
925 870dc44c Iustin Pop

926 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
927 870dc44c Iustin Pop

928 870dc44c Iustin Pop
    """
929 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
930 870dc44c Iustin Pop
931 7c0d6283 Michael Hanselmann
932 ec29fe40 Iustin Pop
class Node(TaggableObject):
933 a8083063 Iustin Pop
  """Config object representing a node."""
934 154b9580 Balazs Lecz
  __slots__ = [
935 ec29fe40 Iustin Pop
    "name",
936 ec29fe40 Iustin Pop
    "primary_ip",
937 ec29fe40 Iustin Pop
    "secondary_ip",
938 be1fa613 Iustin Pop
    "serial_no",
939 8b8b8b81 Iustin Pop
    "master_candidate",
940 fc0fe88c Iustin Pop
    "offline",
941 af64c0ea Iustin Pop
    "drained",
942 f936c153 Iustin Pop
    "group",
943 490acd18 Iustin Pop
    "master_capable",
944 490acd18 Iustin Pop
    "vm_capable",
945 095e71aa René Nussbaumer
    "ndparams",
946 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
947 a8083063 Iustin Pop
948 490acd18 Iustin Pop
  def UpgradeConfig(self):
949 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
950 490acd18 Iustin Pop

951 490acd18 Iustin Pop
    """
952 490acd18 Iustin Pop
    # pylint: disable-msg=E0203
953 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
954 490acd18 Iustin Pop
    if self.master_capable is None:
955 490acd18 Iustin Pop
      self.master_capable = True
956 490acd18 Iustin Pop
957 490acd18 Iustin Pop
    if self.vm_capable is None:
958 490acd18 Iustin Pop
      self.vm_capable = True
959 490acd18 Iustin Pop
960 095e71aa René Nussbaumer
    if self.ndparams is None:
961 095e71aa René Nussbaumer
      self.ndparams = {}
962 095e71aa René Nussbaumer
963 a8083063 Iustin Pop
964 24a3707f Guido Trotter
class NodeGroup(ConfigObject):
965 24a3707f Guido Trotter
  """Config object representing a node group."""
966 24a3707f Guido Trotter
  __slots__ = [
967 24a3707f Guido Trotter
    "name",
968 24a3707f Guido Trotter
    "members",
969 095e71aa René Nussbaumer
    "ndparams",
970 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
971 24a3707f Guido Trotter
972 24a3707f Guido Trotter
  def ToDict(self):
973 24a3707f Guido Trotter
    """Custom function for nodegroup.
974 24a3707f Guido Trotter

975 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
976 c60abd62 Guido Trotter
    in memory.
977 24a3707f Guido Trotter

978 24a3707f Guido Trotter
    """
979 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
980 24a3707f Guido Trotter
    del mydict["members"]
981 24a3707f Guido Trotter
    return mydict
982 24a3707f Guido Trotter
983 24a3707f Guido Trotter
  @classmethod
984 24a3707f Guido Trotter
  def FromDict(cls, val):
985 24a3707f Guido Trotter
    """Custom function for nodegroup.
986 24a3707f Guido Trotter

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

989 24a3707f Guido Trotter
    """
990 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
991 24a3707f Guido Trotter
    obj.members = []
992 24a3707f Guido Trotter
    return obj
993 24a3707f Guido Trotter
994 095e71aa René Nussbaumer
  def UpgradeConfig(self):
995 095e71aa René Nussbaumer
    """Fill defaults for missing configuration values.
996 095e71aa René Nussbaumer

997 095e71aa René Nussbaumer
    """
998 095e71aa René Nussbaumer
    if self.ndparams is None:
999 095e71aa René Nussbaumer
      self.ndparams = {}
1000 095e71aa René Nussbaumer
1001 095e71aa René Nussbaumer
  def FillND(self, node):
1002 095e71aa René Nussbaumer
    """Return filled out ndparams for L{object.Node}
1003 095e71aa René Nussbaumer

1004 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1005 095e71aa René Nussbaumer
    @param node: A Node object to fill
1006 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1007 095e71aa René Nussbaumer

1008 095e71aa René Nussbaumer
    """
1009 095e71aa René Nussbaumer
    return self.SimpleFillND(node.ndparams)
1010 095e71aa René Nussbaumer
1011 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1012 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1013 095e71aa René Nussbaumer

1014 095e71aa René Nussbaumer
    @type ndparams: dict
1015 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1016 095e71aa René Nussbaumer
    @rtype: dict
1017 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1018 095e71aa René Nussbaumer
        from the cluster defaults
1019 095e71aa René Nussbaumer

1020 095e71aa René Nussbaumer
    """
1021 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1022 095e71aa René Nussbaumer
1023 24a3707f Guido Trotter
1024 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
1025 a8083063 Iustin Pop
  """Config object representing the cluster."""
1026 154b9580 Balazs Lecz
  __slots__ = [
1027 a8083063 Iustin Pop
    "serial_no",
1028 a8083063 Iustin Pop
    "rsahostkeypub",
1029 a8083063 Iustin Pop
    "highest_used_port",
1030 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
1031 a8083063 Iustin Pop
    "mac_prefix",
1032 a8083063 Iustin Pop
    "volume_group_name",
1033 999b183c Iustin Pop
    "reserved_lvs",
1034 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
1035 a8083063 Iustin Pop
    "default_bridge",
1036 02691904 Alexander Schreiber
    "default_hypervisor",
1037 f6bd6e98 Michael Hanselmann
    "master_node",
1038 f6bd6e98 Michael Hanselmann
    "master_ip",
1039 f6bd6e98 Michael Hanselmann
    "master_netdev",
1040 f6bd6e98 Michael Hanselmann
    "cluster_name",
1041 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
1042 e69d05fd Iustin Pop
    "enabled_hypervisors",
1043 5bf7b5cf Iustin Pop
    "hvparams",
1044 17463d22 René Nussbaumer
    "os_hvp",
1045 5bf7b5cf Iustin Pop
    "beparams",
1046 1bdcbbab Iustin Pop
    "osparams",
1047 c8fcde47 Guido Trotter
    "nicparams",
1048 095e71aa René Nussbaumer
    "ndparams",
1049 4b7735f9 Iustin Pop
    "candidate_pool_size",
1050 b86a6bcd Guido Trotter
    "modify_etc_hosts",
1051 b989b9d9 Ken Wehr
    "modify_ssh_setup",
1052 3953242f Iustin Pop
    "maintain_node_health",
1053 4437d889 Balazs Lecz
    "uid_pool",
1054 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
1055 87b2cd45 Iustin Pop
    "hidden_os",
1056 87b2cd45 Iustin Pop
    "blacklisted_os",
1057 2f20d07b Manuel Franceschini
    "primary_ip_family",
1058 3d914585 René Nussbaumer
    "prealloc_wipe_disks",
1059 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1060 a8083063 Iustin Pop
1061 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
1062 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
1063 b86a6bcd Guido Trotter

1064 b86a6bcd Guido Trotter
    """
1065 fe267188 Iustin Pop
    # pylint: disable-msg=E0203
1066 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
1067 c1b42c18 Guido Trotter
    if self.hvparams is None:
1068 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
1069 c1b42c18 Guido Trotter
    else:
1070 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
1071 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
1072 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
1073 c1b42c18 Guido Trotter
1074 17463d22 René Nussbaumer
    if self.os_hvp is None:
1075 17463d22 René Nussbaumer
      self.os_hvp = {}
1076 17463d22 René Nussbaumer
1077 1bdcbbab Iustin Pop
    # osparams added before 2.2
1078 1bdcbbab Iustin Pop
    if self.osparams is None:
1079 1bdcbbab Iustin Pop
      self.osparams = {}
1080 1bdcbbab Iustin Pop
1081 095e71aa René Nussbaumer
    if self.ndparams is None:
1082 095e71aa René Nussbaumer
      self.ndparams = constants.NDC_DEFAULTS
1083 095e71aa René Nussbaumer
1084 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
1085 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
1086 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
1087 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
1088 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
1089 c8fcde47 Guido Trotter
    if migrate_default_bridge:
1090 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
1091 c8fcde47 Guido Trotter
        self.default_bridge
1092 c1b42c18 Guido Trotter
1093 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1094 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1095 b86a6bcd Guido Trotter
1096 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1097 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1098 b989b9d9 Ken Wehr
1099 9b31ca85 Guido Trotter
    # default_bridge is no longer used it 2.1. The slot is left there to
1100 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1101 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1102 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1103 9b31ca85 Guido Trotter
      self.default_bridge = None
1104 9b31ca85 Guido Trotter
1105 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1106 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1107 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1108 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1109 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1110 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1111 066f465d Guido Trotter
      self.default_hypervisor = None
1112 066f465d Guido Trotter
1113 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1114 3953242f Iustin Pop
    if self.maintain_node_health is None:
1115 3953242f Iustin Pop
      self.maintain_node_health = False
1116 3953242f Iustin Pop
1117 4437d889 Balazs Lecz
    if self.uid_pool is None:
1118 4437d889 Balazs Lecz
      self.uid_pool = []
1119 4437d889 Balazs Lecz
1120 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1121 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1122 bf4af505 Apollon Oikonomopoulos
1123 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1124 999b183c Iustin Pop
    if self.reserved_lvs is None:
1125 999b183c Iustin Pop
      self.reserved_lvs = []
1126 999b183c Iustin Pop
1127 546b1111 Iustin Pop
    # hidden and blacklisted operating systems added before 2.2.1
1128 87b2cd45 Iustin Pop
    if self.hidden_os is None:
1129 87b2cd45 Iustin Pop
      self.hidden_os = []
1130 546b1111 Iustin Pop
1131 87b2cd45 Iustin Pop
    if self.blacklisted_os is None:
1132 87b2cd45 Iustin Pop
      self.blacklisted_os = []
1133 546b1111 Iustin Pop
1134 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1135 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1136 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1137 f4c9af7a Guido Trotter
1138 3d914585 René Nussbaumer
    if self.prealloc_wipe_disks is None:
1139 3d914585 René Nussbaumer
      self.prealloc_wipe_disks = False
1140 3d914585 René Nussbaumer
1141 319856a9 Michael Hanselmann
  def ToDict(self):
1142 319856a9 Michael Hanselmann
    """Custom function for cluster.
1143 319856a9 Michael Hanselmann

1144 319856a9 Michael Hanselmann
    """
1145 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1146 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1147 319856a9 Michael Hanselmann
    return mydict
1148 319856a9 Michael Hanselmann
1149 319856a9 Michael Hanselmann
  @classmethod
1150 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1151 319856a9 Michael Hanselmann
    """Custom function for cluster.
1152 319856a9 Michael Hanselmann

1153 319856a9 Michael Hanselmann
    """
1154 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1155 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1156 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1157 319856a9 Michael Hanselmann
    return obj
1158 319856a9 Michael Hanselmann
1159 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1160 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1161 d63479b5 Iustin Pop

1162 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1163 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1164 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1165 d63479b5 Iustin Pop
    @return: the defaults dict
1166 d63479b5 Iustin Pop

1167 d63479b5 Iustin Pop
    """
1168 d63479b5 Iustin Pop
    if skip_keys is None:
1169 d63479b5 Iustin Pop
      skip_keys = []
1170 d63479b5 Iustin Pop
1171 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1172 d63479b5 Iustin Pop
    if os_name is not None:
1173 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1174 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1175 d63479b5 Iustin Pop
1176 d63479b5 Iustin Pop
    ret_dict = {}
1177 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1178 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1179 d63479b5 Iustin Pop
1180 d63479b5 Iustin Pop
    return ret_dict
1181 d63479b5 Iustin Pop
1182 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1183 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1184 73e0328b Iustin Pop

1185 73e0328b Iustin Pop
    @type hv_name: string
1186 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1187 73e0328b Iustin Pop
    @type os_name: string
1188 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1189 73e0328b Iustin Pop
    @type skip_globals: boolean
1190 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1191 73e0328b Iustin Pop
        not be filled
1192 73e0328b Iustin Pop
    @rtype: dict
1193 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1194 73e0328b Iustin Pop
        the cluster defaults
1195 73e0328b Iustin Pop

1196 73e0328b Iustin Pop
    """
1197 73e0328b Iustin Pop
    if skip_globals:
1198 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1199 73e0328b Iustin Pop
    else:
1200 73e0328b Iustin Pop
      skip_keys = []
1201 73e0328b Iustin Pop
1202 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1203 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1204 d63479b5 Iustin Pop
1205 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1206 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1207 5bf7b5cf Iustin Pop

1208 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1209 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1210 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1211 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1212 7736a5f2 Iustin Pop
        not be filled
1213 5bf7b5cf Iustin Pop
    @rtype: dict
1214 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1215 5bf7b5cf Iustin Pop
        the cluster defaults
1216 5bf7b5cf Iustin Pop

1217 5bf7b5cf Iustin Pop
    """
1218 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1219 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1220 17463d22 René Nussbaumer
1221 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1222 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1223 73e0328b Iustin Pop

1224 06596a60 Guido Trotter
    @type beparams: dict
1225 06596a60 Guido Trotter
    @param beparams: the dict to fill
1226 73e0328b Iustin Pop
    @rtype: dict
1227 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1228 73e0328b Iustin Pop
        from the cluster defaults
1229 73e0328b Iustin Pop

1230 73e0328b Iustin Pop
    """
1231 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1232 5bf7b5cf Iustin Pop
1233 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1234 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1235 5bf7b5cf Iustin Pop

1236 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1237 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1238 5bf7b5cf Iustin Pop
    @rtype: dict
1239 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1240 5bf7b5cf Iustin Pop
        the cluster defaults
1241 5bf7b5cf Iustin Pop

1242 5bf7b5cf Iustin Pop
    """
1243 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1244 73e0328b Iustin Pop
1245 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1246 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1247 73e0328b Iustin Pop

1248 06596a60 Guido Trotter
    @type nicparams: dict
1249 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1250 73e0328b Iustin Pop
    @rtype: dict
1251 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1252 73e0328b Iustin Pop
        from the cluster defaults
1253 73e0328b Iustin Pop

1254 73e0328b Iustin Pop
    """
1255 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1256 5bf7b5cf Iustin Pop
1257 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1258 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1259 1bdcbbab Iustin Pop

1260 1bdcbbab Iustin Pop
    @type os_name: string
1261 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1262 1bdcbbab Iustin Pop
    @type os_params: dict
1263 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1264 1bdcbbab Iustin Pop
    @rtype: dict
1265 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1266 1bdcbbab Iustin Pop
        the cluster defaults
1267 1bdcbbab Iustin Pop

1268 1bdcbbab Iustin Pop
    """
1269 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1270 1bdcbbab Iustin Pop
    # base OS
1271 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1272 1bdcbbab Iustin Pop
    # OS with variant
1273 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1274 1bdcbbab Iustin Pop
    # specified params
1275 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1276 1bdcbbab Iustin Pop
1277 095e71aa René Nussbaumer
  def FillND(self, node, nodegroup):
1278 095e71aa René Nussbaumer
    """Return filled out ndparams for L{objects.NodeGroup} and L{object.Node}
1279 095e71aa René Nussbaumer

1280 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1281 095e71aa René Nussbaumer
    @param node: A Node object to fill
1282 095e71aa René Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1283 095e71aa René Nussbaumer
    @param nodegroup: A Node object to fill
1284 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1285 095e71aa René Nussbaumer

1286 095e71aa René Nussbaumer
    """
1287 095e71aa René Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1288 095e71aa René Nussbaumer
1289 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1290 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1291 095e71aa René Nussbaumer

1292 095e71aa René Nussbaumer
    @type ndparams: dict
1293 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1294 095e71aa René Nussbaumer
    @rtype: dict
1295 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1296 095e71aa René Nussbaumer
        from the cluster defaults
1297 095e71aa René Nussbaumer

1298 095e71aa René Nussbaumer
    """
1299 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1300 095e71aa René Nussbaumer
1301 5c947f38 Iustin Pop
1302 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1303 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1304 96acbc09 Michael Hanselmann
  __slots__ = [
1305 96acbc09 Michael Hanselmann
    "dev_path",
1306 96acbc09 Michael Hanselmann
    "major",
1307 96acbc09 Michael Hanselmann
    "minor",
1308 96acbc09 Michael Hanselmann
    "sync_percent",
1309 96acbc09 Michael Hanselmann
    "estimated_time",
1310 96acbc09 Michael Hanselmann
    "is_degraded",
1311 f208978a Michael Hanselmann
    "ldisk_status",
1312 96acbc09 Michael Hanselmann
    ]
1313 96acbc09 Michael Hanselmann
1314 96acbc09 Michael Hanselmann
1315 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1316 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1317 2d76b580 Michael Hanselmann
  __slots__ = [
1318 2d76b580 Michael Hanselmann
    "recent_output",
1319 2d76b580 Michael Hanselmann
    "listen_port",
1320 2d76b580 Michael Hanselmann
    "connected",
1321 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1322 c08d76f5 Michael Hanselmann
    "progress_throughput",
1323 c08d76f5 Michael Hanselmann
    "progress_eta",
1324 c08d76f5 Michael Hanselmann
    "progress_percent",
1325 2d76b580 Michael Hanselmann
    "exit_status",
1326 2d76b580 Michael Hanselmann
    "error_message",
1327 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1328 2d76b580 Michael Hanselmann
1329 2d76b580 Michael Hanselmann
1330 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1331 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1332 eb630f50 Michael Hanselmann

1333 eb630f50 Michael Hanselmann
  @ivar key_name: X509 key name (None for cluster certificate)
1334 eb630f50 Michael Hanselmann
  @ivar ca_pem: Remote peer CA in PEM format (None for cluster certificate)
1335 a5310c2a Michael Hanselmann
  @ivar compress: Compression method (one of L{constants.IEC_ALL})
1336 af1d39b1 Michael Hanselmann
  @ivar magic: Used to ensure the connection goes to the right disk
1337 eb630f50 Michael Hanselmann

1338 eb630f50 Michael Hanselmann
  """
1339 eb630f50 Michael Hanselmann
  __slots__ = [
1340 eb630f50 Michael Hanselmann
    "key_name",
1341 eb630f50 Michael Hanselmann
    "ca_pem",
1342 a5310c2a Michael Hanselmann
    "compress",
1343 af1d39b1 Michael Hanselmann
    "magic",
1344 eb630f50 Michael Hanselmann
    ]
1345 eb630f50 Michael Hanselmann
1346 eb630f50 Michael Hanselmann
1347 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1348 18d750b9 Guido Trotter
  """Object holding a confd request.
1349 18d750b9 Guido Trotter

1350 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1351 18d750b9 Guido Trotter
  @ivar type: confd query type
1352 18d750b9 Guido Trotter
  @ivar query: query request
1353 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1354 18d750b9 Guido Trotter

1355 18d750b9 Guido Trotter
  """
1356 18d750b9 Guido Trotter
  __slots__ = [
1357 18d750b9 Guido Trotter
    "protocol",
1358 18d750b9 Guido Trotter
    "type",
1359 18d750b9 Guido Trotter
    "query",
1360 18d750b9 Guido Trotter
    "rsalt",
1361 18d750b9 Guido Trotter
    ]
1362 18d750b9 Guido Trotter
1363 18d750b9 Guido Trotter
1364 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1365 18d750b9 Guido Trotter
  """Object holding a confd reply.
1366 18d750b9 Guido Trotter

1367 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1368 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1369 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1370 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1371 18d750b9 Guido Trotter

1372 18d750b9 Guido Trotter
  """
1373 18d750b9 Guido Trotter
  __slots__ = [
1374 18d750b9 Guido Trotter
    "protocol",
1375 18d750b9 Guido Trotter
    "status",
1376 18d750b9 Guido Trotter
    "answer",
1377 18d750b9 Guido Trotter
    "serial",
1378 18d750b9 Guido Trotter
    ]
1379 18d750b9 Guido Trotter
1380 18d750b9 Guido Trotter
1381 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1382 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1383 a8083063 Iustin Pop

1384 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1385 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1386 a8083063 Iustin Pop
  buffer.
1387 a8083063 Iustin Pop

1388 a8083063 Iustin Pop
  """
1389 a8083063 Iustin Pop
  def Dumps(self):
1390 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1391 a8083063 Iustin Pop
    buf = StringIO()
1392 a8083063 Iustin Pop
    self.write(buf)
1393 a8083063 Iustin Pop
    return buf.getvalue()
1394 a8083063 Iustin Pop
1395 b39bf4bb Guido Trotter
  @classmethod
1396 b39bf4bb Guido Trotter
  def Loads(cls, data):
1397 a8083063 Iustin Pop
    """Load data from a string."""
1398 a8083063 Iustin Pop
    buf = StringIO(data)
1399 b39bf4bb Guido Trotter
    cfp = cls()
1400 a8083063 Iustin Pop
    cfp.readfp(buf)
1401 a8083063 Iustin Pop
    return cfp