Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 9afb67fe

History | View | Annotate | Download (24 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 a8083063 Iustin Pop
30 a8083063 Iustin Pop
import ConfigParser
31 5c947f38 Iustin Pop
import re
32 5bf7b5cf Iustin Pop
import copy
33 d5835922 Michael Hanselmann
from cStringIO import StringIO
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti import errors
36 5c947f38 Iustin Pop
from ganeti import constants
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
40 a8083063 Iustin Pop
           "OS", "Node", "Cluster"]
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
43 a8083063 Iustin Pop
class ConfigObject(object):
44 a8083063 Iustin Pop
  """A generic config object.
45 a8083063 Iustin Pop

46 a8083063 Iustin Pop
  It has the following properties:
47 a8083063 Iustin Pop

48 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
49 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
50 a8083063 Iustin Pop
      as None instead of raising an error
51 a8083063 Iustin Pop

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

55 a8083063 Iustin Pop
  """
56 a8083063 Iustin Pop
  __slots__ = []
57 a8083063 Iustin Pop
58 a8083063 Iustin Pop
  def __init__(self, **kwargs):
59 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
60 319856a9 Michael Hanselmann
      setattr(self, k, v)
61 a8083063 Iustin Pop
62 a8083063 Iustin Pop
  def __getattr__(self, name):
63 a8083063 Iustin Pop
    if name not in self.__slots__:
64 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
65 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
66 a8083063 Iustin Pop
    return None
67 a8083063 Iustin Pop
68 47c28c5b Michael Hanselmann
  def __setitem__(self, key, value):
69 47c28c5b Michael Hanselmann
    if key not in self.__slots__:
70 3ecf6786 Iustin Pop
      raise KeyError(key)
71 47c28c5b Michael Hanselmann
    setattr(self, key, value)
72 47c28c5b Michael Hanselmann
73 a8083063 Iustin Pop
  def __getstate__(self):
74 a8083063 Iustin Pop
    state = {}
75 a8083063 Iustin Pop
    for name in self.__slots__:
76 a8083063 Iustin Pop
      if hasattr(self, name):
77 a8083063 Iustin Pop
        state[name] = getattr(self, name)
78 a8083063 Iustin Pop
    return state
79 a8083063 Iustin Pop
80 a8083063 Iustin Pop
  def __setstate__(self, state):
81 a8083063 Iustin Pop
    for name in state:
82 a8083063 Iustin Pop
      if name in self.__slots__:
83 a8083063 Iustin Pop
        setattr(self, name, state[name])
84 a8083063 Iustin Pop
85 ff9c047c Iustin Pop
  def ToDict(self):
86 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
87 ff9c047c Iustin Pop

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

94 ff9c047c Iustin Pop
    """
95 ff9c047c Iustin Pop
    return dict([(k, getattr(self, k, None)) for k in self.__slots__])
96 ff9c047c Iustin Pop
97 ff9c047c Iustin Pop
  @classmethod
98 ff9c047c Iustin Pop
  def FromDict(cls, val):
99 ff9c047c Iustin Pop
    """Create an object from a dictionary.
100 ff9c047c Iustin Pop

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

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

109 ff9c047c Iustin Pop
    """
110 ff9c047c Iustin Pop
    if not isinstance(val, dict):
111 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
112 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
113 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
114 319856a9 Michael Hanselmann
    obj = cls(**val_str)
115 ff9c047c Iustin Pop
    return obj
116 ff9c047c Iustin Pop
117 ff9c047c Iustin Pop
  @staticmethod
118 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
119 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
120 ff9c047c Iustin Pop

121 ff9c047c Iustin Pop
    This method converts a container with elements derived from
122 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
123 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
124 ff9c047c Iustin Pop

125 ff9c047c Iustin Pop
    """
126 ff9c047c Iustin Pop
    if isinstance(container, dict):
127 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
128 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
129 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
130 ff9c047c Iustin Pop
    else:
131 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
132 ff9c047c Iustin Pop
                      type(container))
133 ff9c047c Iustin Pop
    return ret
134 ff9c047c Iustin Pop
135 ff9c047c Iustin Pop
  @staticmethod
136 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
137 ff9c047c Iustin Pop
    """Convert a container from standard python types.
138 ff9c047c Iustin Pop

139 ff9c047c Iustin Pop
    This method converts a container with standard python types to
140 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
141 ff9c047c Iustin Pop
    keys, only the values.
142 ff9c047c Iustin Pop

143 ff9c047c Iustin Pop
    """
144 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
145 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
146 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
147 ff9c047c Iustin Pop
    if c_type is dict:
148 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
149 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
150 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
151 ff9c047c Iustin Pop
    else:
152 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
153 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
154 ff9c047c Iustin Pop
    return ret
155 ff9c047c Iustin Pop
156 ff9c047c Iustin Pop
  def __repr__(self):
157 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
158 ff9c047c Iustin Pop
    return repr(self.ToDict())
159 ff9c047c Iustin Pop
160 a8083063 Iustin Pop
161 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
162 5c947f38 Iustin Pop
  """An generic class supporting tags.
163 5c947f38 Iustin Pop

164 5c947f38 Iustin Pop
  """
165 ec29fe40 Iustin Pop
  __slots__ = ConfigObject.__slots__ + ["tags"]
166 2057f6c7 Iustin Pop
167 5c947f38 Iustin Pop
  @staticmethod
168 5c947f38 Iustin Pop
  def ValidateTag(tag):
169 5c947f38 Iustin Pop
    """Check if a tag is valid.
170 5c947f38 Iustin Pop

171 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
172 5c947f38 Iustin Pop
    function has no return value.
173 5c947f38 Iustin Pop

174 5c947f38 Iustin Pop
    """
175 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
176 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
177 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
178 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
179 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
180 5c947f38 Iustin Pop
    if not tag:
181 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
182 5c947f38 Iustin Pop
    if not re.match("^[ \w.+*/:-]+$", tag):
183 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
184 5c947f38 Iustin Pop
185 5c947f38 Iustin Pop
  def GetTags(self):
186 5c947f38 Iustin Pop
    """Return the tags list.
187 5c947f38 Iustin Pop

188 5c947f38 Iustin Pop
    """
189 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
190 5c947f38 Iustin Pop
    if tags is None:
191 5c947f38 Iustin Pop
      tags = self.tags = set()
192 5c947f38 Iustin Pop
    return tags
193 5c947f38 Iustin Pop
194 5c947f38 Iustin Pop
  def AddTag(self, tag):
195 5c947f38 Iustin Pop
    """Add a new tag.
196 5c947f38 Iustin Pop

197 5c947f38 Iustin Pop
    """
198 5c947f38 Iustin Pop
    self.ValidateTag(tag)
199 5c947f38 Iustin Pop
    tags = self.GetTags()
200 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
201 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
202 5c947f38 Iustin Pop
    self.GetTags().add(tag)
203 5c947f38 Iustin Pop
204 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
205 5c947f38 Iustin Pop
    """Remove a tag.
206 5c947f38 Iustin Pop

207 5c947f38 Iustin Pop
    """
208 5c947f38 Iustin Pop
    self.ValidateTag(tag)
209 5c947f38 Iustin Pop
    tags = self.GetTags()
210 5c947f38 Iustin Pop
    try:
211 5c947f38 Iustin Pop
      tags.remove(tag)
212 5c947f38 Iustin Pop
    except KeyError:
213 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
214 5c947f38 Iustin Pop
215 ff9c047c Iustin Pop
  def ToDict(self):
216 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
217 ff9c047c Iustin Pop

218 ff9c047c Iustin Pop
    This replaces the tags set with a list.
219 ff9c047c Iustin Pop

220 ff9c047c Iustin Pop
    """
221 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
222 ff9c047c Iustin Pop
223 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
224 ff9c047c Iustin Pop
    if isinstance(tags, set):
225 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
226 ff9c047c Iustin Pop
    return bo
227 ff9c047c Iustin Pop
228 ff9c047c Iustin Pop
  @classmethod
229 ff9c047c Iustin Pop
  def FromDict(cls, val):
230 ff9c047c Iustin Pop
    """Custom function for instances.
231 ff9c047c Iustin Pop

232 ff9c047c Iustin Pop
    """
233 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
234 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
235 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
236 ff9c047c Iustin Pop
    return obj
237 ff9c047c Iustin Pop
238 5c947f38 Iustin Pop
239 a8083063 Iustin Pop
class ConfigData(ConfigObject):
240 a8083063 Iustin Pop
  """Top-level config object."""
241 f6bd6e98 Michael Hanselmann
  __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"]
242 a8083063 Iustin Pop
243 ff9c047c Iustin Pop
  def ToDict(self):
244 ff9c047c Iustin Pop
    """Custom function for top-level config data.
245 ff9c047c Iustin Pop

246 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
247 ff9c047c Iustin Pop
    with standard python types.
248 ff9c047c Iustin Pop

249 ff9c047c Iustin Pop
    """
250 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
251 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
252 ff9c047c Iustin Pop
    for key in "nodes", "instances":
253 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
254 ff9c047c Iustin Pop
255 ff9c047c Iustin Pop
    return mydict
256 ff9c047c Iustin Pop
257 ff9c047c Iustin Pop
  @classmethod
258 ff9c047c Iustin Pop
  def FromDict(cls, val):
259 ff9c047c Iustin Pop
    """Custom function for top-level config data
260 ff9c047c Iustin Pop

261 ff9c047c Iustin Pop
    """
262 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
263 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
264 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
265 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
266 ff9c047c Iustin Pop
    return obj
267 ff9c047c Iustin Pop
268 a8083063 Iustin Pop
269 a8083063 Iustin Pop
class NIC(ConfigObject):
270 a8083063 Iustin Pop
  """Config object representing a network card."""
271 a8083063 Iustin Pop
  __slots__ = ["mac", "ip", "bridge"]
272 a8083063 Iustin Pop
273 a8083063 Iustin Pop
274 a8083063 Iustin Pop
class Disk(ConfigObject):
275 a8083063 Iustin Pop
  """Config object representing a block device."""
276 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
277 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
278 a8083063 Iustin Pop
279 a8083063 Iustin Pop
  def CreateOnSecondary(self):
280 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
281 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
284 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
285 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
286 a8083063 Iustin Pop
287 a8083063 Iustin Pop
  def OpenOnSecondary(self):
288 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
289 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
290 a8083063 Iustin Pop
291 222f2dd5 Iustin Pop
  def StaticDevPath(self):
292 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
293 222f2dd5 Iustin Pop

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

298 222f2dd5 Iustin Pop
    """
299 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
300 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
301 222f2dd5 Iustin Pop
    return None
302 222f2dd5 Iustin Pop
303 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
304 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
305 fc1dc9d7 Iustin Pop

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

310 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
311 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
312 fc1dc9d7 Iustin Pop
    -1.
313 fc1dc9d7 Iustin Pop

314 fc1dc9d7 Iustin Pop
    """
315 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
316 fc1dc9d7 Iustin Pop
      return 0
317 fc1dc9d7 Iustin Pop
    return -1
318 fc1dc9d7 Iustin Pop
319 a8083063 Iustin Pop
  def GetNodes(self, node):
320 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
321 a8083063 Iustin Pop

322 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
323 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
324 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
325 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
326 a8083063 Iustin Pop

327 a8083063 Iustin Pop
    """
328 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
329 a8083063 Iustin Pop
      result = [node]
330 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
331 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
332 a8083063 Iustin Pop
      if node not in result:
333 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
334 a8083063 Iustin Pop
    else:
335 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
336 a8083063 Iustin Pop
    return result
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
339 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
340 a8083063 Iustin Pop

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

347 a8083063 Iustin Pop
    """
348 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
349 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
350 a8083063 Iustin Pop
    if not self.children:
351 a8083063 Iustin Pop
      # leaf device
352 a8083063 Iustin Pop
      return result
353 a8083063 Iustin Pop
    for node in my_nodes:
354 a8083063 Iustin Pop
      for child in self.children:
355 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
356 a8083063 Iustin Pop
        if len(child_result) == 1:
357 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
358 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
359 a8083063 Iustin Pop
          # own entry for this node describes it completely
360 a8083063 Iustin Pop
          continue
361 a8083063 Iustin Pop
        else:
362 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
363 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
364 a8083063 Iustin Pop
          # one of its descendants
365 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
366 a8083063 Iustin Pop
            if subnode not in my_nodes:
367 a8083063 Iustin Pop
              result.append((subnode, subdisk))
368 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
369 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
370 a8083063 Iustin Pop
            # be different)
371 a8083063 Iustin Pop
    return result
372 a8083063 Iustin Pop
373 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
374 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
375 acec9d51 Iustin Pop

376 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
377 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
378 acec9d51 Iustin Pop
    actual algorithms from bdev.
379 acec9d51 Iustin Pop

380 acec9d51 Iustin Pop
    """
381 acec9d51 Iustin Pop
    if self.dev_type == constants.LD_LV:
382 acec9d51 Iustin Pop
      self.size += amount
383 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
384 acec9d51 Iustin Pop
      if self.children:
385 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
386 acec9d51 Iustin Pop
      self.size += amount
387 acec9d51 Iustin Pop
    else:
388 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
389 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
390 acec9d51 Iustin Pop
391 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
392 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
393 0402302c Iustin Pop

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

396 0402302c Iustin Pop
    The routine descends down and updates its children also, because
397 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
398 0402302c Iustin Pop
    node.
399 0402302c Iustin Pop

400 0402302c Iustin Pop
    Arguments:
401 0402302c Iustin Pop
      - target_node: the node we wish to configure for
402 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
403 0402302c Iustin Pop

404 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
405 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
406 0402302c Iustin Pop
    in the disk tree.
407 0402302c Iustin Pop

408 0402302c Iustin Pop
    """
409 0402302c Iustin Pop
    if self.children:
410 0402302c Iustin Pop
      for child in self.children:
411 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
412 0402302c Iustin Pop
413 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
414 0402302c Iustin Pop
      return
415 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
416 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
417 0402302c Iustin Pop
      if target_node not in (pnode, snode):
418 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
419 0402302c Iustin Pop
                                        target_node)
420 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
421 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
422 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
423 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
424 0402302c Iustin Pop
                                        " for %s" % str(self))
425 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
426 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
427 0402302c Iustin Pop
      if pnode == target_node:
428 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
429 0402302c Iustin Pop
      else: # it must be secondary, we tested above
430 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
431 0402302c Iustin Pop
    else:
432 0402302c Iustin Pop
      self.physical_id = self.logical_id
433 0402302c Iustin Pop
    return
434 0402302c Iustin Pop
435 ff9c047c Iustin Pop
  def ToDict(self):
436 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
437 ff9c047c Iustin Pop

438 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
439 ff9c047c Iustin Pop
    standard python types.
440 ff9c047c Iustin Pop

441 ff9c047c Iustin Pop
    """
442 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
443 ff9c047c Iustin Pop
444 ff9c047c Iustin Pop
    for attr in ("children",):
445 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
446 ff9c047c Iustin Pop
      if alist:
447 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
448 ff9c047c Iustin Pop
    return bo
449 ff9c047c Iustin Pop
450 ff9c047c Iustin Pop
  @classmethod
451 ff9c047c Iustin Pop
  def FromDict(cls, val):
452 ff9c047c Iustin Pop
    """Custom function for Disks
453 ff9c047c Iustin Pop

454 ff9c047c Iustin Pop
    """
455 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
456 ff9c047c Iustin Pop
    if obj.children:
457 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
458 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
459 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
460 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
461 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
462 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
463 f9518d38 Iustin Pop
      # we need a tuple of length six here
464 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
465 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
466 ff9c047c Iustin Pop
    return obj
467 ff9c047c Iustin Pop
468 65a15336 Iustin Pop
  def __str__(self):
469 65a15336 Iustin Pop
    """Custom str() formatter for disks.
470 65a15336 Iustin Pop

471 65a15336 Iustin Pop
    """
472 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
473 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
474 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
475 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
476 00fb8246 Michael Hanselmann
      val = "<DRBD8("
477 073ca59e Iustin Pop
      if self.physical_id is None:
478 073ca59e Iustin Pop
        phy = "unconfigured"
479 073ca59e Iustin Pop
      else:
480 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
481 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
482 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
483 073ca59e Iustin Pop
484 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
485 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
486 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
487 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
488 65a15336 Iustin Pop
      else:
489 65a15336 Iustin Pop
        val += "no local storage"
490 65a15336 Iustin Pop
    else:
491 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
492 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
493 65a15336 Iustin Pop
    if self.iv_name is None:
494 65a15336 Iustin Pop
      val += ", not visible"
495 65a15336 Iustin Pop
    else:
496 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
497 fd965830 Iustin Pop
    if isinstance(self.size, int):
498 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
499 fd965830 Iustin Pop
    else:
500 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
501 65a15336 Iustin Pop
    return val
502 65a15336 Iustin Pop
503 332d0e37 Iustin Pop
  def Verify(self):
504 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
505 332d0e37 Iustin Pop

506 332d0e37 Iustin Pop
    """
507 332d0e37 Iustin Pop
    errors = []
508 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
509 332d0e37 Iustin Pop
      errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
510 332d0e37 Iustin Pop
    return errors
511 332d0e37 Iustin Pop
512 a8083063 Iustin Pop
513 ec29fe40 Iustin Pop
class Instance(TaggableObject):
514 a8083063 Iustin Pop
  """Config object representing an instance."""
515 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
516 a8083063 Iustin Pop
    "name",
517 a8083063 Iustin Pop
    "primary_node",
518 a8083063 Iustin Pop
    "os",
519 e69d05fd Iustin Pop
    "hypervisor",
520 5bf7b5cf Iustin Pop
    "hvparams",
521 5bf7b5cf Iustin Pop
    "beparams",
522 0d68c45d Iustin Pop
    "admin_up",
523 a8083063 Iustin Pop
    "nics",
524 a8083063 Iustin Pop
    "disks",
525 a8083063 Iustin Pop
    "disk_template",
526 58acb49d Alexander Schreiber
    "network_port",
527 be1fa613 Iustin Pop
    "serial_no",
528 a8083063 Iustin Pop
    ]
529 a8083063 Iustin Pop
530 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
531 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
532 a8083063 Iustin Pop

533 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
534 cfcc5c6d Iustin Pop

535 cfcc5c6d Iustin Pop
    """
536 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
537 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
538 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
539 cfcc5c6d Iustin Pop
540 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
541 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
542 cfcc5c6d Iustin Pop
543 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
544 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
545 cfcc5c6d Iustin Pop

546 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
547 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
548 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
549 a8083063 Iustin Pop
    dynamically.
550 a8083063 Iustin Pop

551 a8083063 Iustin Pop
    """
552 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
553 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
554 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
555 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
556 cfcc5c6d Iustin Pop
        nodes.add(nodea)
557 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
558 a8083063 Iustin Pop
      if device.children:
559 a8083063 Iustin Pop
        for child in device.children:
560 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
561 a8083063 Iustin Pop
562 cfcc5c6d Iustin Pop
    all_nodes = set()
563 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
564 a8083063 Iustin Pop
    for device in self.disks:
565 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
566 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
567 a8083063 Iustin Pop
568 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
569 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
570 a8083063 Iustin Pop
571 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
572 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
573 a8083063 Iustin Pop

574 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
575 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
576 a8083063 Iustin Pop

577 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
578 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
579 a8083063 Iustin Pop

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

583 a8083063 Iustin Pop
    """
584 a8083063 Iustin Pop
    if node == None:
585 a8083063 Iustin Pop
      node = self.primary_node
586 a8083063 Iustin Pop
587 a8083063 Iustin Pop
    if lvmap is None:
588 a8083063 Iustin Pop
      lvmap = { node : [] }
589 a8083063 Iustin Pop
      ret = lvmap
590 a8083063 Iustin Pop
    else:
591 a8083063 Iustin Pop
      if not node in lvmap:
592 a8083063 Iustin Pop
        lvmap[node] = []
593 a8083063 Iustin Pop
      ret = None
594 a8083063 Iustin Pop
595 a8083063 Iustin Pop
    if not devs:
596 a8083063 Iustin Pop
      devs = self.disks
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
    for dev in devs:
599 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
600 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
601 a8083063 Iustin Pop
602 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
603 a8083063 Iustin Pop
        if dev.children:
604 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
605 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
606 a8083063 Iustin Pop
607 a8083063 Iustin Pop
      elif dev.children:
608 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
609 a8083063 Iustin Pop
610 a8083063 Iustin Pop
    return ret
611 a8083063 Iustin Pop
612 ad24e046 Iustin Pop
  def FindDisk(self, idx):
613 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
614 644eeef9 Iustin Pop

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

617 ad24e046 Iustin Pop
    @type idx: int
618 ad24e046 Iustin Pop
    @param idx: the disk index
619 ad24e046 Iustin Pop
    @rtype: L{Disk}
620 ad24e046 Iustin Pop
    @return: the corresponding disk
621 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
622 644eeef9 Iustin Pop

623 ad24e046 Iustin Pop
    """
624 ad24e046 Iustin Pop
    try:
625 ad24e046 Iustin Pop
      idx = int(idx)
626 ad24e046 Iustin Pop
      return self.disks[idx]
627 ad24e046 Iustin Pop
    except ValueError, err:
628 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err))
629 ad24e046 Iustin Pop
    except IndexError:
630 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
631 ad24e046 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)))
632 644eeef9 Iustin Pop
633 ff9c047c Iustin Pop
  def ToDict(self):
634 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
635 ff9c047c Iustin Pop

636 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
637 ff9c047c Iustin Pop
    python types.
638 ff9c047c Iustin Pop

639 ff9c047c Iustin Pop
    """
640 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
641 ff9c047c Iustin Pop
642 ff9c047c Iustin Pop
    for attr in "nics", "disks":
643 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
644 ff9c047c Iustin Pop
      if alist:
645 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
646 ff9c047c Iustin Pop
      else:
647 ff9c047c Iustin Pop
        nlist = []
648 ff9c047c Iustin Pop
      bo[attr] = nlist
649 ff9c047c Iustin Pop
    return bo
650 ff9c047c Iustin Pop
651 ff9c047c Iustin Pop
  @classmethod
652 ff9c047c Iustin Pop
  def FromDict(cls, val):
653 ff9c047c Iustin Pop
    """Custom function for instances.
654 ff9c047c Iustin Pop

655 ff9c047c Iustin Pop
    """
656 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
657 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
658 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
659 ff9c047c Iustin Pop
    return obj
660 ff9c047c Iustin Pop
661 a8083063 Iustin Pop
662 a8083063 Iustin Pop
class OS(ConfigObject):
663 a8083063 Iustin Pop
  """Config object representing an operating system."""
664 a8083063 Iustin Pop
  __slots__ = [
665 a8083063 Iustin Pop
    "name",
666 a8083063 Iustin Pop
    "path",
667 37482e7b Guido Trotter
    "status",
668 082a7f91 Guido Trotter
    "api_versions",
669 a8083063 Iustin Pop
    "create_script",
670 a8083063 Iustin Pop
    "export_script",
671 386b57af Iustin Pop
    "import_script",
672 386b57af Iustin Pop
    "rename_script",
673 a8083063 Iustin Pop
    ]
674 a8083063 Iustin Pop
675 d2c807e4 Guido Trotter
  @classmethod
676 d2c807e4 Guido Trotter
  def FromInvalidOS(cls, err):
677 d2c807e4 Guido Trotter
    """Create an OS from an InvalidOS error.
678 d2c807e4 Guido Trotter

679 d2c807e4 Guido Trotter
    This routine knows how to convert an InvalidOS error to an OS
680 d2c807e4 Guido Trotter
    object representing the broken OS with a meaningful error message.
681 d2c807e4 Guido Trotter

682 d2c807e4 Guido Trotter
    """
683 d2c807e4 Guido Trotter
    if not isinstance(err, errors.InvalidOS):
684 d2c807e4 Guido Trotter
      raise errors.ProgrammerError("Trying to initialize an OS from an"
685 d2c807e4 Guido Trotter
                                   " invalid object of type %s" % type(err))
686 d2c807e4 Guido Trotter
687 d2c807e4 Guido Trotter
    return cls(name=err.args[0], path=err.args[1], status=err.args[2])
688 d2c807e4 Guido Trotter
689 37482e7b Guido Trotter
  def __nonzero__(self):
690 37482e7b Guido Trotter
    return self.status == constants.OS_VALID_STATUS
691 37482e7b Guido Trotter
692 37482e7b Guido Trotter
  __bool__ = __nonzero__
693 a8083063 Iustin Pop
694 7c0d6283 Michael Hanselmann
695 ec29fe40 Iustin Pop
class Node(TaggableObject):
696 a8083063 Iustin Pop
  """Config object representing a node."""
697 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
698 ec29fe40 Iustin Pop
    "name",
699 ec29fe40 Iustin Pop
    "primary_ip",
700 ec29fe40 Iustin Pop
    "secondary_ip",
701 be1fa613 Iustin Pop
    "serial_no",
702 8b8b8b81 Iustin Pop
    "master_candidate",
703 fc0fe88c Iustin Pop
    "offline",
704 af64c0ea Iustin Pop
    "drained",
705 ec29fe40 Iustin Pop
    ]
706 a8083063 Iustin Pop
707 a8083063 Iustin Pop
708 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
709 a8083063 Iustin Pop
  """Config object representing the cluster."""
710 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
711 a8083063 Iustin Pop
    "serial_no",
712 a8083063 Iustin Pop
    "rsahostkeypub",
713 a8083063 Iustin Pop
    "highest_used_port",
714 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
715 a8083063 Iustin Pop
    "mac_prefix",
716 a8083063 Iustin Pop
    "volume_group_name",
717 a8083063 Iustin Pop
    "default_bridge",
718 02691904 Alexander Schreiber
    "default_hypervisor",
719 f6bd6e98 Michael Hanselmann
    "master_node",
720 f6bd6e98 Michael Hanselmann
    "master_ip",
721 f6bd6e98 Michael Hanselmann
    "master_netdev",
722 f6bd6e98 Michael Hanselmann
    "cluster_name",
723 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
724 e69d05fd Iustin Pop
    "enabled_hypervisors",
725 5bf7b5cf Iustin Pop
    "hvparams",
726 5bf7b5cf Iustin Pop
    "beparams",
727 4b7735f9 Iustin Pop
    "candidate_pool_size",
728 a8083063 Iustin Pop
    ]
729 a8083063 Iustin Pop
730 319856a9 Michael Hanselmann
  def ToDict(self):
731 319856a9 Michael Hanselmann
    """Custom function for cluster.
732 319856a9 Michael Hanselmann

733 319856a9 Michael Hanselmann
    """
734 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
735 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
736 319856a9 Michael Hanselmann
    return mydict
737 319856a9 Michael Hanselmann
738 319856a9 Michael Hanselmann
  @classmethod
739 319856a9 Michael Hanselmann
  def FromDict(cls, val):
740 319856a9 Michael Hanselmann
    """Custom function for cluster.
741 319856a9 Michael Hanselmann

742 319856a9 Michael Hanselmann
    """
743 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
744 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
745 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
746 319856a9 Michael Hanselmann
    return obj
747 319856a9 Michael Hanselmann
748 5bf7b5cf Iustin Pop
  @staticmethod
749 5bf7b5cf Iustin Pop
  def FillDict(defaults_dict, custom_dict):
750 5bf7b5cf Iustin Pop
    """Basic function to apply settings on top a default dict.
751 5bf7b5cf Iustin Pop

752 5bf7b5cf Iustin Pop
    @type defaults_dict: dict
753 5bf7b5cf Iustin Pop
    @param defaults_dict: dictionary holding the default values
754 5bf7b5cf Iustin Pop
    @type custom_dict: dict
755 5bf7b5cf Iustin Pop
    @param custom_dict: dictionary holding customized value
756 5bf7b5cf Iustin Pop
    @rtype: dict
757 5bf7b5cf Iustin Pop
    @return: dict with the 'full' values
758 5bf7b5cf Iustin Pop

759 5bf7b5cf Iustin Pop
    """
760 5bf7b5cf Iustin Pop
    ret_dict = copy.deepcopy(defaults_dict)
761 5bf7b5cf Iustin Pop
    ret_dict.update(custom_dict)
762 5bf7b5cf Iustin Pop
    return ret_dict
763 5bf7b5cf Iustin Pop
764 5bf7b5cf Iustin Pop
  def FillHV(self, instance):
765 5bf7b5cf Iustin Pop
    """Fill an instance's hvparams dict.
766 5bf7b5cf Iustin Pop

767 5bf7b5cf Iustin Pop
    @type instance: object
768 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
769 5bf7b5cf Iustin Pop
    @rtype: dict
770 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
771 5bf7b5cf Iustin Pop
        the cluster defaults
772 5bf7b5cf Iustin Pop

773 5bf7b5cf Iustin Pop
    """
774 5bf7b5cf Iustin Pop
    return self.FillDict(self.hvparams.get(instance.hypervisor, {}),
775 5bf7b5cf Iustin Pop
                         instance.hvparams)
776 5bf7b5cf Iustin Pop
777 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
778 5bf7b5cf Iustin Pop
    """Fill an instance's beparams dict.
779 5bf7b5cf Iustin Pop

780 5bf7b5cf Iustin Pop
    @type instance: object
781 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
782 5bf7b5cf Iustin Pop
    @rtype: dict
783 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
784 5bf7b5cf Iustin Pop
        the cluster defaults
785 5bf7b5cf Iustin Pop

786 5bf7b5cf Iustin Pop
    """
787 5bf7b5cf Iustin Pop
    return self.FillDict(self.beparams.get(constants.BEGR_DEFAULT, {}),
788 5bf7b5cf Iustin Pop
                         instance.beparams)
789 5bf7b5cf Iustin Pop
790 5c947f38 Iustin Pop
791 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
792 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
793 a8083063 Iustin Pop

794 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
795 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
796 a8083063 Iustin Pop
  buffer.
797 a8083063 Iustin Pop

798 a8083063 Iustin Pop
  """
799 a8083063 Iustin Pop
  def Dumps(self):
800 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
801 a8083063 Iustin Pop
    buf = StringIO()
802 a8083063 Iustin Pop
    self.write(buf)
803 a8083063 Iustin Pop
    return buf.getvalue()
804 a8083063 Iustin Pop
805 a8083063 Iustin Pop
  @staticmethod
806 a8083063 Iustin Pop
  def Loads(data):
807 a8083063 Iustin Pop
    """Load data from a string."""
808 a8083063 Iustin Pop
    buf = StringIO(data)
809 a8083063 Iustin Pop
    cfp = SerializableConfigParser()
810 a8083063 Iustin Pop
    cfp.readfp(buf)
811 a8083063 Iustin Pop
    return cfp