Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ c1b42c18

History | View | Annotate | Download (25 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 560428be Guido Trotter
    self.UpgradeConfig()
62 a8083063 Iustin Pop
63 a8083063 Iustin Pop
  def __getattr__(self, name):
64 a8083063 Iustin Pop
    if name not in self.__slots__:
65 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
66 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
67 a8083063 Iustin Pop
    return None
68 a8083063 Iustin Pop
69 47c28c5b Michael Hanselmann
  def __setitem__(self, key, value):
70 47c28c5b Michael Hanselmann
    if key not in self.__slots__:
71 3ecf6786 Iustin Pop
      raise KeyError(key)
72 47c28c5b Michael Hanselmann
    setattr(self, key, value)
73 47c28c5b Michael Hanselmann
74 a8083063 Iustin Pop
  def __getstate__(self):
75 a8083063 Iustin Pop
    state = {}
76 a8083063 Iustin Pop
    for name in self.__slots__:
77 a8083063 Iustin Pop
      if hasattr(self, name):
78 a8083063 Iustin Pop
        state[name] = getattr(self, name)
79 a8083063 Iustin Pop
    return state
80 a8083063 Iustin Pop
81 a8083063 Iustin Pop
  def __setstate__(self, state):
82 a8083063 Iustin Pop
    for name in state:
83 a8083063 Iustin Pop
      if name in self.__slots__:
84 a8083063 Iustin Pop
        setattr(self, name, state[name])
85 a8083063 Iustin Pop
86 ff9c047c Iustin Pop
  def ToDict(self):
87 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
88 ff9c047c Iustin Pop

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

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

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

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

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

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

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

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

144 ff9c047c Iustin Pop
    """
145 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
146 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
147 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
148 ff9c047c Iustin Pop
    if c_type is dict:
149 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
150 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
151 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
152 ff9c047c Iustin Pop
    else:
153 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
154 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
155 ff9c047c Iustin Pop
    return ret
156 ff9c047c Iustin Pop
157 ff9c047c Iustin Pop
  def __repr__(self):
158 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
159 ff9c047c Iustin Pop
    return repr(self.ToDict())
160 ff9c047c Iustin Pop
161 560428be Guido Trotter
  def UpgradeConfig(self):
162 560428be Guido Trotter
    """Fill defaults for missing configuration values.
163 560428be Guido Trotter

164 560428be Guido Trotter
    This method will be called at object init time, and its implementation will
165 560428be Guido Trotter
    be object dependent.
166 560428be Guido Trotter

167 560428be Guido Trotter
    """
168 560428be Guido Trotter
    pass
169 560428be Guido Trotter
170 a8083063 Iustin Pop
171 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
172 5c947f38 Iustin Pop
  """An generic class supporting tags.
173 5c947f38 Iustin Pop

174 5c947f38 Iustin Pop
  """
175 ec29fe40 Iustin Pop
  __slots__ = ConfigObject.__slots__ + ["tags"]
176 2057f6c7 Iustin Pop
177 5c947f38 Iustin Pop
  @staticmethod
178 5c947f38 Iustin Pop
  def ValidateTag(tag):
179 5c947f38 Iustin Pop
    """Check if a tag is valid.
180 5c947f38 Iustin Pop

181 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
182 5c947f38 Iustin Pop
    function has no return value.
183 5c947f38 Iustin Pop

184 5c947f38 Iustin Pop
    """
185 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
186 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
187 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
188 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
189 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
190 5c947f38 Iustin Pop
    if not tag:
191 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
192 28ab6fed Iustin Pop
    if not re.match("^[\w.+*/:-]+$", tag):
193 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
194 5c947f38 Iustin Pop
195 5c947f38 Iustin Pop
  def GetTags(self):
196 5c947f38 Iustin Pop
    """Return the tags list.
197 5c947f38 Iustin Pop

198 5c947f38 Iustin Pop
    """
199 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
200 5c947f38 Iustin Pop
    if tags is None:
201 5c947f38 Iustin Pop
      tags = self.tags = set()
202 5c947f38 Iustin Pop
    return tags
203 5c947f38 Iustin Pop
204 5c947f38 Iustin Pop
  def AddTag(self, tag):
205 5c947f38 Iustin Pop
    """Add a new 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
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
211 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
212 5c947f38 Iustin Pop
    self.GetTags().add(tag)
213 5c947f38 Iustin Pop
214 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
215 5c947f38 Iustin Pop
    """Remove a tag.
216 5c947f38 Iustin Pop

217 5c947f38 Iustin Pop
    """
218 5c947f38 Iustin Pop
    self.ValidateTag(tag)
219 5c947f38 Iustin Pop
    tags = self.GetTags()
220 5c947f38 Iustin Pop
    try:
221 5c947f38 Iustin Pop
      tags.remove(tag)
222 5c947f38 Iustin Pop
    except KeyError:
223 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
224 5c947f38 Iustin Pop
225 ff9c047c Iustin Pop
  def ToDict(self):
226 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
227 ff9c047c Iustin Pop

228 ff9c047c Iustin Pop
    This replaces the tags set with a list.
229 ff9c047c Iustin Pop

230 ff9c047c Iustin Pop
    """
231 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
232 ff9c047c Iustin Pop
233 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
234 ff9c047c Iustin Pop
    if isinstance(tags, set):
235 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
236 ff9c047c Iustin Pop
    return bo
237 ff9c047c Iustin Pop
238 ff9c047c Iustin Pop
  @classmethod
239 ff9c047c Iustin Pop
  def FromDict(cls, val):
240 ff9c047c Iustin Pop
    """Custom function for instances.
241 ff9c047c Iustin Pop

242 ff9c047c Iustin Pop
    """
243 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
244 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
245 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
246 ff9c047c Iustin Pop
    return obj
247 ff9c047c Iustin Pop
248 5c947f38 Iustin Pop
249 a8083063 Iustin Pop
class ConfigData(ConfigObject):
250 a8083063 Iustin Pop
  """Top-level config object."""
251 f6bd6e98 Michael Hanselmann
  __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"]
252 a8083063 Iustin Pop
253 ff9c047c Iustin Pop
  def ToDict(self):
254 ff9c047c Iustin Pop
    """Custom function for top-level config data.
255 ff9c047c Iustin Pop

256 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
257 ff9c047c Iustin Pop
    with standard python types.
258 ff9c047c Iustin Pop

259 ff9c047c Iustin Pop
    """
260 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
261 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
262 ff9c047c Iustin Pop
    for key in "nodes", "instances":
263 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
264 ff9c047c Iustin Pop
265 ff9c047c Iustin Pop
    return mydict
266 ff9c047c Iustin Pop
267 ff9c047c Iustin Pop
  @classmethod
268 ff9c047c Iustin Pop
  def FromDict(cls, val):
269 ff9c047c Iustin Pop
    """Custom function for top-level config data
270 ff9c047c Iustin Pop

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

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

308 222f2dd5 Iustin Pop
    """
309 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
310 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
311 222f2dd5 Iustin Pop
    return None
312 222f2dd5 Iustin Pop
313 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
314 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
315 fc1dc9d7 Iustin Pop

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

320 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
321 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
322 fc1dc9d7 Iustin Pop
    -1.
323 fc1dc9d7 Iustin Pop

324 fc1dc9d7 Iustin Pop
    """
325 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
326 fc1dc9d7 Iustin Pop
      return 0
327 fc1dc9d7 Iustin Pop
    return -1
328 fc1dc9d7 Iustin Pop
329 a8083063 Iustin Pop
  def GetNodes(self, node):
330 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
331 a8083063 Iustin Pop

332 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
333 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
334 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
335 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
336 a8083063 Iustin Pop

337 a8083063 Iustin Pop
    """
338 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
339 a8083063 Iustin Pop
      result = [node]
340 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
341 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
342 a8083063 Iustin Pop
      if node not in result:
343 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
344 a8083063 Iustin Pop
    else:
345 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
346 a8083063 Iustin Pop
    return result
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
349 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
350 a8083063 Iustin Pop

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

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

386 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
387 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
388 acec9d51 Iustin Pop
    actual algorithms from bdev.
389 acec9d51 Iustin Pop

390 acec9d51 Iustin Pop
    """
391 acec9d51 Iustin Pop
    if self.dev_type == constants.LD_LV:
392 acec9d51 Iustin Pop
      self.size += amount
393 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
394 acec9d51 Iustin Pop
      if self.children:
395 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
396 acec9d51 Iustin Pop
      self.size += amount
397 acec9d51 Iustin Pop
    else:
398 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
399 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
400 acec9d51 Iustin Pop
401 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
402 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
403 0402302c Iustin Pop

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

406 0402302c Iustin Pop
    The routine descends down and updates its children also, because
407 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
408 0402302c Iustin Pop
    node.
409 0402302c Iustin Pop

410 0402302c Iustin Pop
    Arguments:
411 0402302c Iustin Pop
      - target_node: the node we wish to configure for
412 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
413 0402302c Iustin Pop

414 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
415 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
416 0402302c Iustin Pop
    in the disk tree.
417 0402302c Iustin Pop

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

448 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
449 ff9c047c Iustin Pop
    standard python types.
450 ff9c047c Iustin Pop

451 ff9c047c Iustin Pop
    """
452 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
453 ff9c047c Iustin Pop
454 ff9c047c Iustin Pop
    for attr in ("children",):
455 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
456 ff9c047c Iustin Pop
      if alist:
457 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
458 ff9c047c Iustin Pop
    return bo
459 ff9c047c Iustin Pop
460 ff9c047c Iustin Pop
  @classmethod
461 ff9c047c Iustin Pop
  def FromDict(cls, val):
462 ff9c047c Iustin Pop
    """Custom function for Disks
463 ff9c047c Iustin Pop

464 ff9c047c Iustin Pop
    """
465 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
466 ff9c047c Iustin Pop
    if obj.children:
467 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
468 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
469 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
470 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
471 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
472 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
473 f9518d38 Iustin Pop
      # we need a tuple of length six here
474 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
475 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
476 ff9c047c Iustin Pop
    return obj
477 ff9c047c Iustin Pop
478 65a15336 Iustin Pop
  def __str__(self):
479 65a15336 Iustin Pop
    """Custom str() formatter for disks.
480 65a15336 Iustin Pop

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

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

543 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
544 cfcc5c6d Iustin Pop

545 cfcc5c6d Iustin Pop
    """
546 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
547 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
548 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
549 cfcc5c6d Iustin Pop
550 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
551 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
552 cfcc5c6d Iustin Pop
553 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
554 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
555 cfcc5c6d Iustin Pop

556 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
557 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
558 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
559 a8083063 Iustin Pop
    dynamically.
560 a8083063 Iustin Pop

561 a8083063 Iustin Pop
    """
562 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
563 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
564 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
565 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
566 cfcc5c6d Iustin Pop
        nodes.add(nodea)
567 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
568 a8083063 Iustin Pop
      if device.children:
569 a8083063 Iustin Pop
        for child in device.children:
570 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
571 a8083063 Iustin Pop
572 cfcc5c6d Iustin Pop
    all_nodes = set()
573 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
574 a8083063 Iustin Pop
    for device in self.disks:
575 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
576 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
577 a8083063 Iustin Pop
578 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
579 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
580 a8083063 Iustin Pop
581 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
582 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
583 a8083063 Iustin Pop

584 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
585 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
586 a8083063 Iustin Pop

587 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
588 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
589 a8083063 Iustin Pop

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

593 a8083063 Iustin Pop
    """
594 a8083063 Iustin Pop
    if node == None:
595 a8083063 Iustin Pop
      node = self.primary_node
596 a8083063 Iustin Pop
597 a8083063 Iustin Pop
    if lvmap is None:
598 a8083063 Iustin Pop
      lvmap = { node : [] }
599 a8083063 Iustin Pop
      ret = lvmap
600 a8083063 Iustin Pop
    else:
601 a8083063 Iustin Pop
      if not node in lvmap:
602 a8083063 Iustin Pop
        lvmap[node] = []
603 a8083063 Iustin Pop
      ret = None
604 a8083063 Iustin Pop
605 a8083063 Iustin Pop
    if not devs:
606 a8083063 Iustin Pop
      devs = self.disks
607 a8083063 Iustin Pop
608 a8083063 Iustin Pop
    for dev in devs:
609 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
610 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
611 a8083063 Iustin Pop
612 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
613 a8083063 Iustin Pop
        if dev.children:
614 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
615 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
616 a8083063 Iustin Pop
617 a8083063 Iustin Pop
      elif dev.children:
618 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
619 a8083063 Iustin Pop
620 a8083063 Iustin Pop
    return ret
621 a8083063 Iustin Pop
622 ad24e046 Iustin Pop
  def FindDisk(self, idx):
623 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
624 644eeef9 Iustin Pop

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

627 ad24e046 Iustin Pop
    @type idx: int
628 ad24e046 Iustin Pop
    @param idx: the disk index
629 ad24e046 Iustin Pop
    @rtype: L{Disk}
630 ad24e046 Iustin Pop
    @return: the corresponding disk
631 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
632 644eeef9 Iustin Pop

633 ad24e046 Iustin Pop
    """
634 ad24e046 Iustin Pop
    try:
635 ad24e046 Iustin Pop
      idx = int(idx)
636 ad24e046 Iustin Pop
      return self.disks[idx]
637 ad24e046 Iustin Pop
    except ValueError, err:
638 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err))
639 ad24e046 Iustin Pop
    except IndexError:
640 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
641 ad24e046 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)))
642 644eeef9 Iustin Pop
643 ff9c047c Iustin Pop
  def ToDict(self):
644 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
645 ff9c047c Iustin Pop

646 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
647 ff9c047c Iustin Pop
    python types.
648 ff9c047c Iustin Pop

649 ff9c047c Iustin Pop
    """
650 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
651 ff9c047c Iustin Pop
652 ff9c047c Iustin Pop
    for attr in "nics", "disks":
653 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
654 ff9c047c Iustin Pop
      if alist:
655 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
656 ff9c047c Iustin Pop
      else:
657 ff9c047c Iustin Pop
        nlist = []
658 ff9c047c Iustin Pop
      bo[attr] = nlist
659 ff9c047c Iustin Pop
    return bo
660 ff9c047c Iustin Pop
661 ff9c047c Iustin Pop
  @classmethod
662 ff9c047c Iustin Pop
  def FromDict(cls, val):
663 ff9c047c Iustin Pop
    """Custom function for instances.
664 ff9c047c Iustin Pop

665 ff9c047c Iustin Pop
    """
666 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
667 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
668 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
669 ff9c047c Iustin Pop
    return obj
670 ff9c047c Iustin Pop
671 a8083063 Iustin Pop
672 a8083063 Iustin Pop
class OS(ConfigObject):
673 a8083063 Iustin Pop
  """Config object representing an operating system."""
674 a8083063 Iustin Pop
  __slots__ = [
675 a8083063 Iustin Pop
    "name",
676 a8083063 Iustin Pop
    "path",
677 37482e7b Guido Trotter
    "status",
678 082a7f91 Guido Trotter
    "api_versions",
679 a8083063 Iustin Pop
    "create_script",
680 a8083063 Iustin Pop
    "export_script",
681 386b57af Iustin Pop
    "import_script",
682 386b57af Iustin Pop
    "rename_script",
683 a8083063 Iustin Pop
    ]
684 a8083063 Iustin Pop
685 d2c807e4 Guido Trotter
  @classmethod
686 d2c807e4 Guido Trotter
  def FromInvalidOS(cls, err):
687 d2c807e4 Guido Trotter
    """Create an OS from an InvalidOS error.
688 d2c807e4 Guido Trotter

689 d2c807e4 Guido Trotter
    This routine knows how to convert an InvalidOS error to an OS
690 d2c807e4 Guido Trotter
    object representing the broken OS with a meaningful error message.
691 d2c807e4 Guido Trotter

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

744 b86a6bcd Guido Trotter
    """
745 c1b42c18 Guido Trotter
    if self.hvparams is None:
746 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
747 c1b42c18 Guido Trotter
    else:
748 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
749 c1b42c18 Guido Trotter
        self.hvparams[hypervisor] = self.FillDict(
750 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
751 c1b42c18 Guido Trotter
752 c1b42c18 Guido Trotter
    if self.beparams is None:
753 c1b42c18 Guido Trotter
      self.beparams = {constants.BEGR_DEFAULT: constants.BEC_DEFAULTS}
754 c1b42c18 Guido Trotter
    else:
755 c1b42c18 Guido Trotter
      for begroup in self.beparams:
756 c1b42c18 Guido Trotter
        self.beparams[begroup] = self.FillDict(constants.BEC_DEFAULTS,
757 c1b42c18 Guido Trotter
                                               self.beparams[begroup])
758 c1b42c18 Guido Trotter
759 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
760 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
761 b86a6bcd Guido Trotter
762 319856a9 Michael Hanselmann
  def ToDict(self):
763 319856a9 Michael Hanselmann
    """Custom function for cluster.
764 319856a9 Michael Hanselmann

765 319856a9 Michael Hanselmann
    """
766 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
767 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
768 319856a9 Michael Hanselmann
    return mydict
769 319856a9 Michael Hanselmann
770 319856a9 Michael Hanselmann
  @classmethod
771 319856a9 Michael Hanselmann
  def FromDict(cls, val):
772 319856a9 Michael Hanselmann
    """Custom function for cluster.
773 319856a9 Michael Hanselmann

774 319856a9 Michael Hanselmann
    """
775 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
776 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
777 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
778 319856a9 Michael Hanselmann
    return obj
779 319856a9 Michael Hanselmann
780 5bf7b5cf Iustin Pop
  @staticmethod
781 5bf7b5cf Iustin Pop
  def FillDict(defaults_dict, custom_dict):
782 5bf7b5cf Iustin Pop
    """Basic function to apply settings on top a default dict.
783 5bf7b5cf Iustin Pop

784 5bf7b5cf Iustin Pop
    @type defaults_dict: dict
785 5bf7b5cf Iustin Pop
    @param defaults_dict: dictionary holding the default values
786 5bf7b5cf Iustin Pop
    @type custom_dict: dict
787 5bf7b5cf Iustin Pop
    @param custom_dict: dictionary holding customized value
788 5bf7b5cf Iustin Pop
    @rtype: dict
789 5bf7b5cf Iustin Pop
    @return: dict with the 'full' values
790 5bf7b5cf Iustin Pop

791 5bf7b5cf Iustin Pop
    """
792 5bf7b5cf Iustin Pop
    ret_dict = copy.deepcopy(defaults_dict)
793 5bf7b5cf Iustin Pop
    ret_dict.update(custom_dict)
794 5bf7b5cf Iustin Pop
    return ret_dict
795 5bf7b5cf Iustin Pop
796 5bf7b5cf Iustin Pop
  def FillHV(self, instance):
797 5bf7b5cf Iustin Pop
    """Fill an instance's hvparams dict.
798 5bf7b5cf Iustin Pop

799 5bf7b5cf Iustin Pop
    @type instance: object
800 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
801 5bf7b5cf Iustin Pop
    @rtype: dict
802 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
803 5bf7b5cf Iustin Pop
        the cluster defaults
804 5bf7b5cf Iustin Pop

805 5bf7b5cf Iustin Pop
    """
806 5bf7b5cf Iustin Pop
    return self.FillDict(self.hvparams.get(instance.hypervisor, {}),
807 5bf7b5cf Iustin Pop
                         instance.hvparams)
808 5bf7b5cf Iustin Pop
809 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
810 5bf7b5cf Iustin Pop
    """Fill an instance's beparams dict.
811 5bf7b5cf Iustin Pop

812 5bf7b5cf Iustin Pop
    @type instance: object
813 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
814 5bf7b5cf Iustin Pop
    @rtype: dict
815 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
816 5bf7b5cf Iustin Pop
        the cluster defaults
817 5bf7b5cf Iustin Pop

818 5bf7b5cf Iustin Pop
    """
819 5bf7b5cf Iustin Pop
    return self.FillDict(self.beparams.get(constants.BEGR_DEFAULT, {}),
820 5bf7b5cf Iustin Pop
                         instance.beparams)
821 5bf7b5cf Iustin Pop
822 5c947f38 Iustin Pop
823 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
824 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
825 a8083063 Iustin Pop

826 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
827 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
828 a8083063 Iustin Pop
  buffer.
829 a8083063 Iustin Pop

830 a8083063 Iustin Pop
  """
831 a8083063 Iustin Pop
  def Dumps(self):
832 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
833 a8083063 Iustin Pop
    buf = StringIO()
834 a8083063 Iustin Pop
    self.write(buf)
835 a8083063 Iustin Pop
    return buf.getvalue()
836 a8083063 Iustin Pop
837 a8083063 Iustin Pop
  @staticmethod
838 a8083063 Iustin Pop
  def Loads(data):
839 a8083063 Iustin Pop
    """Load data from a string."""
840 a8083063 Iustin Pop
    buf = StringIO(data)
841 a8083063 Iustin Pop
    cfp = SerializableConfigParser()
842 a8083063 Iustin Pop
    cfp.readfp(buf)
843 a8083063 Iustin Pop
    return cfp