Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ d2d7d5c3

History | View | Annotate | Download (24.7 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 d2d7d5c3 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 e8d563f3 Iustin Pop
  def Copy(self):
158 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
159 e8d563f3 Iustin Pop

160 e8d563f3 Iustin Pop
    """
161 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
162 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
163 e8d563f3 Iustin Pop
    return clone_obj
164 e8d563f3 Iustin Pop
165 ff9c047c Iustin Pop
  def __repr__(self):
166 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
167 ff9c047c Iustin Pop
    return repr(self.ToDict())
168 ff9c047c Iustin Pop
169 d2d7d5c3 Guido Trotter
  def UpgradeConfig(self):
170 d2d7d5c3 Guido Trotter
    """Fill defaults for missing configuration values.
171 d2d7d5c3 Guido Trotter

172 d2d7d5c3 Guido Trotter
    This method will be called at object init time, and its implementation will
173 d2d7d5c3 Guido Trotter
    be object dependent.
174 d2d7d5c3 Guido Trotter

175 d2d7d5c3 Guido Trotter
    """
176 d2d7d5c3 Guido Trotter
    pass
177 d2d7d5c3 Guido Trotter
178 a8083063 Iustin Pop
179 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
180 5c947f38 Iustin Pop
  """An generic class supporting tags.
181 5c947f38 Iustin Pop

182 5c947f38 Iustin Pop
  """
183 ec29fe40 Iustin Pop
  __slots__ = ConfigObject.__slots__ + ["tags"]
184 2057f6c7 Iustin Pop
185 5c947f38 Iustin Pop
  @staticmethod
186 5c947f38 Iustin Pop
  def ValidateTag(tag):
187 5c947f38 Iustin Pop
    """Check if a tag is valid.
188 5c947f38 Iustin Pop

189 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
190 5c947f38 Iustin Pop
    function has no return value.
191 5c947f38 Iustin Pop

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

206 5c947f38 Iustin Pop
    """
207 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
208 5c947f38 Iustin Pop
    if tags is None:
209 5c947f38 Iustin Pop
      tags = self.tags = set()
210 5c947f38 Iustin Pop
    return tags
211 5c947f38 Iustin Pop
212 5c947f38 Iustin Pop
  def AddTag(self, tag):
213 5c947f38 Iustin Pop
    """Add a new tag.
214 5c947f38 Iustin Pop

215 5c947f38 Iustin Pop
    """
216 5c947f38 Iustin Pop
    self.ValidateTag(tag)
217 5c947f38 Iustin Pop
    tags = self.GetTags()
218 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
219 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
220 5c947f38 Iustin Pop
    self.GetTags().add(tag)
221 5c947f38 Iustin Pop
222 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
223 5c947f38 Iustin Pop
    """Remove a tag.
224 5c947f38 Iustin Pop

225 5c947f38 Iustin Pop
    """
226 5c947f38 Iustin Pop
    self.ValidateTag(tag)
227 5c947f38 Iustin Pop
    tags = self.GetTags()
228 5c947f38 Iustin Pop
    try:
229 5c947f38 Iustin Pop
      tags.remove(tag)
230 5c947f38 Iustin Pop
    except KeyError:
231 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
232 5c947f38 Iustin Pop
233 ff9c047c Iustin Pop
  def ToDict(self):
234 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
235 ff9c047c Iustin Pop

236 ff9c047c Iustin Pop
    This replaces the tags set with a list.
237 ff9c047c Iustin Pop

238 ff9c047c Iustin Pop
    """
239 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
240 ff9c047c Iustin Pop
241 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
242 ff9c047c Iustin Pop
    if isinstance(tags, set):
243 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
244 ff9c047c Iustin Pop
    return bo
245 ff9c047c Iustin Pop
246 ff9c047c Iustin Pop
  @classmethod
247 ff9c047c Iustin Pop
  def FromDict(cls, val):
248 ff9c047c Iustin Pop
    """Custom function for instances.
249 ff9c047c Iustin Pop

250 ff9c047c Iustin Pop
    """
251 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
252 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
253 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
254 ff9c047c Iustin Pop
    return obj
255 ff9c047c Iustin Pop
256 5c947f38 Iustin Pop
257 a8083063 Iustin Pop
class ConfigData(ConfigObject):
258 a8083063 Iustin Pop
  """Top-level config object."""
259 f6bd6e98 Michael Hanselmann
  __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"]
260 a8083063 Iustin Pop
261 ff9c047c Iustin Pop
  def ToDict(self):
262 ff9c047c Iustin Pop
    """Custom function for top-level config data.
263 ff9c047c Iustin Pop

264 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
265 ff9c047c Iustin Pop
    with standard python types.
266 ff9c047c Iustin Pop

267 ff9c047c Iustin Pop
    """
268 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
269 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
270 ff9c047c Iustin Pop
    for key in "nodes", "instances":
271 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
272 ff9c047c Iustin Pop
273 ff9c047c Iustin Pop
    return mydict
274 ff9c047c Iustin Pop
275 ff9c047c Iustin Pop
  @classmethod
276 ff9c047c Iustin Pop
  def FromDict(cls, val):
277 ff9c047c Iustin Pop
    """Custom function for top-level config data
278 ff9c047c Iustin Pop

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

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

316 222f2dd5 Iustin Pop
    """
317 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
318 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
319 222f2dd5 Iustin Pop
    return None
320 222f2dd5 Iustin Pop
321 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
322 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
323 fc1dc9d7 Iustin Pop

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

328 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
329 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
330 fc1dc9d7 Iustin Pop
    -1.
331 fc1dc9d7 Iustin Pop

332 fc1dc9d7 Iustin Pop
    """
333 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
334 fc1dc9d7 Iustin Pop
      return 0
335 fc1dc9d7 Iustin Pop
    return -1
336 fc1dc9d7 Iustin Pop
337 a8083063 Iustin Pop
  def GetNodes(self, node):
338 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
339 a8083063 Iustin Pop

340 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
341 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
342 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
343 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
344 a8083063 Iustin Pop

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

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

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

394 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
395 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
396 acec9d51 Iustin Pop
    actual algorithms from bdev.
397 acec9d51 Iustin Pop

398 acec9d51 Iustin Pop
    """
399 acec9d51 Iustin Pop
    if self.dev_type == constants.LD_LV:
400 acec9d51 Iustin Pop
      self.size += amount
401 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
402 acec9d51 Iustin Pop
      if self.children:
403 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
404 acec9d51 Iustin Pop
      self.size += amount
405 acec9d51 Iustin Pop
    else:
406 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
407 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
408 acec9d51 Iustin Pop
409 a805ec18 Iustin Pop
  def UnsetSize(self):
410 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
411 a805ec18 Iustin Pop

412 a805ec18 Iustin Pop
    """
413 a805ec18 Iustin Pop
    if self.children:
414 a805ec18 Iustin Pop
      for child in self.children:
415 a805ec18 Iustin Pop
        child.UnsetSize()
416 a805ec18 Iustin Pop
    self.size = 0
417 a805ec18 Iustin Pop
418 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
419 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
420 0402302c Iustin Pop

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

423 0402302c Iustin Pop
    The routine descends down and updates its children also, because
424 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
425 0402302c Iustin Pop
    node.
426 0402302c Iustin Pop

427 0402302c Iustin Pop
    Arguments:
428 0402302c Iustin Pop
      - target_node: the node we wish to configure for
429 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
430 0402302c Iustin Pop

431 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
432 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
433 0402302c Iustin Pop
    in the disk tree.
434 0402302c Iustin Pop

435 0402302c Iustin Pop
    """
436 0402302c Iustin Pop
    if self.children:
437 0402302c Iustin Pop
      for child in self.children:
438 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
439 0402302c Iustin Pop
440 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
441 0402302c Iustin Pop
      return
442 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
443 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
444 0402302c Iustin Pop
      if target_node not in (pnode, snode):
445 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
446 0402302c Iustin Pop
                                        target_node)
447 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
448 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
449 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
450 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
451 0402302c Iustin Pop
                                        " for %s" % str(self))
452 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
453 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
454 0402302c Iustin Pop
      if pnode == target_node:
455 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
456 0402302c Iustin Pop
      else: # it must be secondary, we tested above
457 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
458 0402302c Iustin Pop
    else:
459 0402302c Iustin Pop
      self.physical_id = self.logical_id
460 0402302c Iustin Pop
    return
461 0402302c Iustin Pop
462 ff9c047c Iustin Pop
  def ToDict(self):
463 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
464 ff9c047c Iustin Pop

465 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
466 ff9c047c Iustin Pop
    standard python types.
467 ff9c047c Iustin Pop

468 ff9c047c Iustin Pop
    """
469 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
470 ff9c047c Iustin Pop
471 ff9c047c Iustin Pop
    for attr in ("children",):
472 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
473 ff9c047c Iustin Pop
      if alist:
474 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
475 ff9c047c Iustin Pop
    return bo
476 ff9c047c Iustin Pop
477 ff9c047c Iustin Pop
  @classmethod
478 ff9c047c Iustin Pop
  def FromDict(cls, val):
479 ff9c047c Iustin Pop
    """Custom function for Disks
480 ff9c047c Iustin Pop

481 ff9c047c Iustin Pop
    """
482 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
483 ff9c047c Iustin Pop
    if obj.children:
484 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
485 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
486 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
487 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
488 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
489 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
490 f9518d38 Iustin Pop
      # we need a tuple of length six here
491 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
492 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
493 ff9c047c Iustin Pop
    return obj
494 ff9c047c Iustin Pop
495 65a15336 Iustin Pop
  def __str__(self):
496 65a15336 Iustin Pop
    """Custom str() formatter for disks.
497 65a15336 Iustin Pop

498 65a15336 Iustin Pop
    """
499 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
500 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
501 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
502 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
503 00fb8246 Michael Hanselmann
      val = "<DRBD8("
504 073ca59e Iustin Pop
      if self.physical_id is None:
505 073ca59e Iustin Pop
        phy = "unconfigured"
506 073ca59e Iustin Pop
      else:
507 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
508 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
509 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
510 073ca59e Iustin Pop
511 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
512 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
513 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
514 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
515 65a15336 Iustin Pop
      else:
516 65a15336 Iustin Pop
        val += "no local storage"
517 65a15336 Iustin Pop
    else:
518 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
519 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
520 65a15336 Iustin Pop
    if self.iv_name is None:
521 65a15336 Iustin Pop
      val += ", not visible"
522 65a15336 Iustin Pop
    else:
523 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
524 fd965830 Iustin Pop
    if isinstance(self.size, int):
525 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
526 fd965830 Iustin Pop
    else:
527 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
528 65a15336 Iustin Pop
    return val
529 65a15336 Iustin Pop
530 332d0e37 Iustin Pop
  def Verify(self):
531 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
532 332d0e37 Iustin Pop

533 332d0e37 Iustin Pop
    """
534 7c4d6c7b Michael Hanselmann
    all_errors = []
535 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
536 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
537 7c4d6c7b Michael Hanselmann
    return all_errors
538 332d0e37 Iustin Pop
539 a8083063 Iustin Pop
540 ec29fe40 Iustin Pop
class Instance(TaggableObject):
541 a8083063 Iustin Pop
  """Config object representing an instance."""
542 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
543 a8083063 Iustin Pop
    "name",
544 a8083063 Iustin Pop
    "primary_node",
545 a8083063 Iustin Pop
    "os",
546 e69d05fd Iustin Pop
    "hypervisor",
547 5bf7b5cf Iustin Pop
    "hvparams",
548 5bf7b5cf Iustin Pop
    "beparams",
549 0d68c45d Iustin Pop
    "admin_up",
550 a8083063 Iustin Pop
    "nics",
551 a8083063 Iustin Pop
    "disks",
552 a8083063 Iustin Pop
    "disk_template",
553 58acb49d Alexander Schreiber
    "network_port",
554 be1fa613 Iustin Pop
    "serial_no",
555 a8083063 Iustin Pop
    ]
556 a8083063 Iustin Pop
557 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
558 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
559 a8083063 Iustin Pop

560 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
561 cfcc5c6d Iustin Pop

562 cfcc5c6d Iustin Pop
    """
563 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
564 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
565 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
566 cfcc5c6d Iustin Pop
567 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
568 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
569 cfcc5c6d Iustin Pop
570 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
571 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
572 cfcc5c6d Iustin Pop

573 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
574 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
575 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
576 a8083063 Iustin Pop
    dynamically.
577 a8083063 Iustin Pop

578 a8083063 Iustin Pop
    """
579 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
580 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
581 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
582 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
583 cfcc5c6d Iustin Pop
        nodes.add(nodea)
584 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
585 a8083063 Iustin Pop
      if device.children:
586 a8083063 Iustin Pop
        for child in device.children:
587 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
588 a8083063 Iustin Pop
589 cfcc5c6d Iustin Pop
    all_nodes = set()
590 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
591 a8083063 Iustin Pop
    for device in self.disks:
592 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
593 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
594 a8083063 Iustin Pop
595 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
596 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
599 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
600 a8083063 Iustin Pop

601 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
602 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
603 a8083063 Iustin Pop

604 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
605 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
606 a8083063 Iustin Pop

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

610 a8083063 Iustin Pop
    """
611 a8083063 Iustin Pop
    if node == None:
612 a8083063 Iustin Pop
      node = self.primary_node
613 a8083063 Iustin Pop
614 a8083063 Iustin Pop
    if lvmap is None:
615 a8083063 Iustin Pop
      lvmap = { node : [] }
616 a8083063 Iustin Pop
      ret = lvmap
617 a8083063 Iustin Pop
    else:
618 a8083063 Iustin Pop
      if not node in lvmap:
619 a8083063 Iustin Pop
        lvmap[node] = []
620 a8083063 Iustin Pop
      ret = None
621 a8083063 Iustin Pop
622 a8083063 Iustin Pop
    if not devs:
623 a8083063 Iustin Pop
      devs = self.disks
624 a8083063 Iustin Pop
625 a8083063 Iustin Pop
    for dev in devs:
626 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
627 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
628 a8083063 Iustin Pop
629 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
630 a8083063 Iustin Pop
        if dev.children:
631 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
632 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
633 a8083063 Iustin Pop
634 a8083063 Iustin Pop
      elif dev.children:
635 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
636 a8083063 Iustin Pop
637 a8083063 Iustin Pop
    return ret
638 a8083063 Iustin Pop
639 ad24e046 Iustin Pop
  def FindDisk(self, idx):
640 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
641 644eeef9 Iustin Pop

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

644 ad24e046 Iustin Pop
    @type idx: int
645 ad24e046 Iustin Pop
    @param idx: the disk index
646 ad24e046 Iustin Pop
    @rtype: L{Disk}
647 ad24e046 Iustin Pop
    @return: the corresponding disk
648 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
649 644eeef9 Iustin Pop

650 ad24e046 Iustin Pop
    """
651 ad24e046 Iustin Pop
    try:
652 ad24e046 Iustin Pop
      idx = int(idx)
653 ad24e046 Iustin Pop
      return self.disks[idx]
654 ad24e046 Iustin Pop
    except ValueError, err:
655 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err))
656 ad24e046 Iustin Pop
    except IndexError:
657 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
658 ad24e046 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)))
659 644eeef9 Iustin Pop
660 ff9c047c Iustin Pop
  def ToDict(self):
661 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
662 ff9c047c Iustin Pop

663 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
664 ff9c047c Iustin Pop
    python types.
665 ff9c047c Iustin Pop

666 ff9c047c Iustin Pop
    """
667 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
668 ff9c047c Iustin Pop
669 ff9c047c Iustin Pop
    for attr in "nics", "disks":
670 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
671 ff9c047c Iustin Pop
      if alist:
672 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
673 ff9c047c Iustin Pop
      else:
674 ff9c047c Iustin Pop
        nlist = []
675 ff9c047c Iustin Pop
      bo[attr] = nlist
676 ff9c047c Iustin Pop
    return bo
677 ff9c047c Iustin Pop
678 ff9c047c Iustin Pop
  @classmethod
679 ff9c047c Iustin Pop
  def FromDict(cls, val):
680 ff9c047c Iustin Pop
    """Custom function for instances.
681 ff9c047c Iustin Pop

682 ff9c047c Iustin Pop
    """
683 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
684 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
685 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
686 ff9c047c Iustin Pop
    return obj
687 ff9c047c Iustin Pop
688 a8083063 Iustin Pop
689 a8083063 Iustin Pop
class OS(ConfigObject):
690 a8083063 Iustin Pop
  """Config object representing an operating system."""
691 a8083063 Iustin Pop
  __slots__ = [
692 a8083063 Iustin Pop
    "name",
693 a8083063 Iustin Pop
    "path",
694 37482e7b Guido Trotter
    "status",
695 082a7f91 Guido Trotter
    "api_versions",
696 a8083063 Iustin Pop
    "create_script",
697 a8083063 Iustin Pop
    "export_script",
698 386b57af Iustin Pop
    "import_script",
699 386b57af Iustin Pop
    "rename_script",
700 a8083063 Iustin Pop
    ]
701 a8083063 Iustin Pop
702 d2c807e4 Guido Trotter
  @classmethod
703 d2c807e4 Guido Trotter
  def FromInvalidOS(cls, err):
704 d2c807e4 Guido Trotter
    """Create an OS from an InvalidOS error.
705 d2c807e4 Guido Trotter

706 d2c807e4 Guido Trotter
    This routine knows how to convert an InvalidOS error to an OS
707 d2c807e4 Guido Trotter
    object representing the broken OS with a meaningful error message.
708 d2c807e4 Guido Trotter

709 d2c807e4 Guido Trotter
    """
710 d2c807e4 Guido Trotter
    if not isinstance(err, errors.InvalidOS):
711 d2c807e4 Guido Trotter
      raise errors.ProgrammerError("Trying to initialize an OS from an"
712 d2c807e4 Guido Trotter
                                   " invalid object of type %s" % type(err))
713 d2c807e4 Guido Trotter
714 d2c807e4 Guido Trotter
    return cls(name=err.args[0], path=err.args[1], status=err.args[2])
715 d2c807e4 Guido Trotter
716 37482e7b Guido Trotter
  def __nonzero__(self):
717 37482e7b Guido Trotter
    return self.status == constants.OS_VALID_STATUS
718 37482e7b Guido Trotter
719 37482e7b Guido Trotter
  __bool__ = __nonzero__
720 a8083063 Iustin Pop
721 7c0d6283 Michael Hanselmann
722 ec29fe40 Iustin Pop
class Node(TaggableObject):
723 a8083063 Iustin Pop
  """Config object representing a node."""
724 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
725 ec29fe40 Iustin Pop
    "name",
726 ec29fe40 Iustin Pop
    "primary_ip",
727 ec29fe40 Iustin Pop
    "secondary_ip",
728 be1fa613 Iustin Pop
    "serial_no",
729 8b8b8b81 Iustin Pop
    "master_candidate",
730 fc0fe88c Iustin Pop
    "offline",
731 af64c0ea Iustin Pop
    "drained",
732 ec29fe40 Iustin Pop
    ]
733 a8083063 Iustin Pop
734 a8083063 Iustin Pop
735 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
736 a8083063 Iustin Pop
  """Config object representing the cluster."""
737 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
738 a8083063 Iustin Pop
    "serial_no",
739 a8083063 Iustin Pop
    "rsahostkeypub",
740 a8083063 Iustin Pop
    "highest_used_port",
741 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
742 a8083063 Iustin Pop
    "mac_prefix",
743 a8083063 Iustin Pop
    "volume_group_name",
744 a8083063 Iustin Pop
    "default_bridge",
745 02691904 Alexander Schreiber
    "default_hypervisor",
746 f6bd6e98 Michael Hanselmann
    "master_node",
747 f6bd6e98 Michael Hanselmann
    "master_ip",
748 f6bd6e98 Michael Hanselmann
    "master_netdev",
749 f6bd6e98 Michael Hanselmann
    "cluster_name",
750 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
751 e69d05fd Iustin Pop
    "enabled_hypervisors",
752 5bf7b5cf Iustin Pop
    "hvparams",
753 5bf7b5cf Iustin Pop
    "beparams",
754 4b7735f9 Iustin Pop
    "candidate_pool_size",
755 a8083063 Iustin Pop
    ]
756 a8083063 Iustin Pop
757 319856a9 Michael Hanselmann
  def ToDict(self):
758 319856a9 Michael Hanselmann
    """Custom function for cluster.
759 319856a9 Michael Hanselmann

760 319856a9 Michael Hanselmann
    """
761 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
762 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
763 319856a9 Michael Hanselmann
    return mydict
764 319856a9 Michael Hanselmann
765 319856a9 Michael Hanselmann
  @classmethod
766 319856a9 Michael Hanselmann
  def FromDict(cls, val):
767 319856a9 Michael Hanselmann
    """Custom function for cluster.
768 319856a9 Michael Hanselmann

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

779 5bf7b5cf Iustin Pop
    @type defaults_dict: dict
780 5bf7b5cf Iustin Pop
    @param defaults_dict: dictionary holding the default values
781 5bf7b5cf Iustin Pop
    @type custom_dict: dict
782 5bf7b5cf Iustin Pop
    @param custom_dict: dictionary holding customized value
783 5bf7b5cf Iustin Pop
    @rtype: dict
784 5bf7b5cf Iustin Pop
    @return: dict with the 'full' values
785 5bf7b5cf Iustin Pop

786 5bf7b5cf Iustin Pop
    """
787 5bf7b5cf Iustin Pop
    ret_dict = copy.deepcopy(defaults_dict)
788 5bf7b5cf Iustin Pop
    ret_dict.update(custom_dict)
789 5bf7b5cf Iustin Pop
    return ret_dict
790 5bf7b5cf Iustin Pop
791 5bf7b5cf Iustin Pop
  def FillHV(self, instance):
792 5bf7b5cf Iustin Pop
    """Fill an instance's hvparams dict.
793 5bf7b5cf Iustin Pop

794 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
795 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
796 5bf7b5cf Iustin Pop
    @rtype: dict
797 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
798 5bf7b5cf Iustin Pop
        the cluster defaults
799 5bf7b5cf Iustin Pop

800 5bf7b5cf Iustin Pop
    """
801 5bf7b5cf Iustin Pop
    return self.FillDict(self.hvparams.get(instance.hypervisor, {}),
802 5bf7b5cf Iustin Pop
                         instance.hvparams)
803 5bf7b5cf Iustin Pop
804 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
805 5bf7b5cf Iustin Pop
    """Fill an instance's beparams dict.
806 5bf7b5cf Iustin Pop

807 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
808 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
809 5bf7b5cf Iustin Pop
    @rtype: dict
810 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
811 5bf7b5cf Iustin Pop
        the cluster defaults
812 5bf7b5cf Iustin Pop

813 5bf7b5cf Iustin Pop
    """
814 5bf7b5cf Iustin Pop
    return self.FillDict(self.beparams.get(constants.BEGR_DEFAULT, {}),
815 5bf7b5cf Iustin Pop
                         instance.beparams)
816 5bf7b5cf Iustin Pop
817 5c947f38 Iustin Pop
818 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
819 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
820 a8083063 Iustin Pop

821 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
822 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
823 a8083063 Iustin Pop
  buffer.
824 a8083063 Iustin Pop

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