Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ e0f9ed64

History | View | Annotate | Download (40.4 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 84d7e26b Dmitry Chernyak
    @return: None if lvmap arg is given, otherwise, a dictionary of
772 84d7e26b Dmitry Chernyak
        the form { 'nodename' : ['volume1', 'volume2', ...], ... };
773 84d7e26b Dmitry Chernyak
        volumeN is of the form "vg_name/lv_name", compatible with
774 84d7e26b Dmitry Chernyak
        GetVolumeList()
775 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

881 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
882 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
883 870dc44c Iustin Pop

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

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

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

919 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
920 870dc44c Iustin Pop

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

928 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
929 870dc44c Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1354 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1355 18d750b9 Guido Trotter
  @ivar type: confd query type
1356 18d750b9 Guido Trotter
  @ivar query: query request
1357 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1358 18d750b9 Guido Trotter

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

1371 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1372 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1373 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1374 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1375 18d750b9 Guido Trotter

1376 18d750b9 Guido Trotter
  """
1377 18d750b9 Guido Trotter
  __slots__ = [
1378 18d750b9 Guido Trotter
    "protocol",
1379 18d750b9 Guido Trotter
    "status",
1380 18d750b9 Guido Trotter
    "answer",
1381 18d750b9 Guido Trotter
    "serial",
1382 18d750b9 Guido Trotter
    ]
1383 18d750b9 Guido Trotter
1384 18d750b9 Guido Trotter
1385 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1386 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1387 707f23b5 Michael Hanselmann

1388 707f23b5 Michael Hanselmann
  @ivar name: Field name as a regular expression
1389 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1390 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1391 707f23b5 Michael Hanselmann

1392 707f23b5 Michael Hanselmann
  """
1393 707f23b5 Michael Hanselmann
  __slots__ = [
1394 707f23b5 Michael Hanselmann
    "name",
1395 707f23b5 Michael Hanselmann
    "title",
1396 707f23b5 Michael Hanselmann
    "kind",
1397 707f23b5 Michael Hanselmann
    ]
1398 707f23b5 Michael Hanselmann
1399 707f23b5 Michael Hanselmann
1400 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1401 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1402 a8083063 Iustin Pop

1403 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1404 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1405 a8083063 Iustin Pop
  buffer.
1406 a8083063 Iustin Pop

1407 a8083063 Iustin Pop
  """
1408 a8083063 Iustin Pop
  def Dumps(self):
1409 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1410 a8083063 Iustin Pop
    buf = StringIO()
1411 a8083063 Iustin Pop
    self.write(buf)
1412 a8083063 Iustin Pop
    return buf.getvalue()
1413 a8083063 Iustin Pop
1414 b39bf4bb Guido Trotter
  @classmethod
1415 b39bf4bb Guido Trotter
  def Loads(cls, data):
1416 a8083063 Iustin Pop
    """Load data from a string."""
1417 a8083063 Iustin Pop
    buf = StringIO(data)
1418 b39bf4bb Guido Trotter
    cfp = cls()
1419 a8083063 Iustin Pop
    cfp.readfp(buf)
1420 a8083063 Iustin Pop
    return cfp