Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ e8d563f3

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

159 e8d563f3 Iustin Pop
    """
160 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
161 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
162 e8d563f3 Iustin Pop
    return clone_obj
163 e8d563f3 Iustin Pop
164 ff9c047c Iustin Pop
  def __repr__(self):
165 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
166 ff9c047c Iustin Pop
    return repr(self.ToDict())
167 ff9c047c Iustin Pop
168 a8083063 Iustin Pop
169 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
170 5c947f38 Iustin Pop
  """An generic class supporting tags.
171 5c947f38 Iustin Pop

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

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

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

196 5c947f38 Iustin Pop
    """
197 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
198 5c947f38 Iustin Pop
    if tags is None:
199 5c947f38 Iustin Pop
      tags = self.tags = set()
200 5c947f38 Iustin Pop
    return tags
201 5c947f38 Iustin Pop
202 5c947f38 Iustin Pop
  def AddTag(self, tag):
203 5c947f38 Iustin Pop
    """Add a new tag.
204 5c947f38 Iustin Pop

205 5c947f38 Iustin Pop
    """
206 5c947f38 Iustin Pop
    self.ValidateTag(tag)
207 5c947f38 Iustin Pop
    tags = self.GetTags()
208 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
209 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
210 5c947f38 Iustin Pop
    self.GetTags().add(tag)
211 5c947f38 Iustin Pop
212 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
213 5c947f38 Iustin Pop
    """Remove a 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
    try:
219 5c947f38 Iustin Pop
      tags.remove(tag)
220 5c947f38 Iustin Pop
    except KeyError:
221 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
222 5c947f38 Iustin Pop
223 ff9c047c Iustin Pop
  def ToDict(self):
224 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
225 ff9c047c Iustin Pop

226 ff9c047c Iustin Pop
    This replaces the tags set with a list.
227 ff9c047c Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

541 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
542 cfcc5c6d Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

741 319856a9 Michael Hanselmann
    """
742 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
743 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
744 319856a9 Michael Hanselmann
    return mydict
745 319856a9 Michael Hanselmann
746 319856a9 Michael Hanselmann
  @classmethod
747 319856a9 Michael Hanselmann
  def FromDict(cls, val):
748 319856a9 Michael Hanselmann
    """Custom function for cluster.
749 319856a9 Michael Hanselmann

750 319856a9 Michael Hanselmann
    """
751 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
752 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
753 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
754 319856a9 Michael Hanselmann
    return obj
755 319856a9 Michael Hanselmann
756 5bf7b5cf Iustin Pop
  @staticmethod
757 5bf7b5cf Iustin Pop
  def FillDict(defaults_dict, custom_dict):
758 5bf7b5cf Iustin Pop
    """Basic function to apply settings on top a default dict.
759 5bf7b5cf Iustin Pop

760 5bf7b5cf Iustin Pop
    @type defaults_dict: dict
761 5bf7b5cf Iustin Pop
    @param defaults_dict: dictionary holding the default values
762 5bf7b5cf Iustin Pop
    @type custom_dict: dict
763 5bf7b5cf Iustin Pop
    @param custom_dict: dictionary holding customized value
764 5bf7b5cf Iustin Pop
    @rtype: dict
765 5bf7b5cf Iustin Pop
    @return: dict with the 'full' values
766 5bf7b5cf Iustin Pop

767 5bf7b5cf Iustin Pop
    """
768 5bf7b5cf Iustin Pop
    ret_dict = copy.deepcopy(defaults_dict)
769 5bf7b5cf Iustin Pop
    ret_dict.update(custom_dict)
770 5bf7b5cf Iustin Pop
    return ret_dict
771 5bf7b5cf Iustin Pop
772 5bf7b5cf Iustin Pop
  def FillHV(self, instance):
773 5bf7b5cf Iustin Pop
    """Fill an instance's hvparams dict.
774 5bf7b5cf Iustin Pop

775 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
776 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
777 5bf7b5cf Iustin Pop
    @rtype: dict
778 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
779 5bf7b5cf Iustin Pop
        the cluster defaults
780 5bf7b5cf Iustin Pop

781 5bf7b5cf Iustin Pop
    """
782 5bf7b5cf Iustin Pop
    return self.FillDict(self.hvparams.get(instance.hypervisor, {}),
783 5bf7b5cf Iustin Pop
                         instance.hvparams)
784 5bf7b5cf Iustin Pop
785 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
786 5bf7b5cf Iustin Pop
    """Fill an instance's beparams dict.
787 5bf7b5cf Iustin Pop

788 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
789 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
790 5bf7b5cf Iustin Pop
    @rtype: dict
791 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
792 5bf7b5cf Iustin Pop
        the cluster defaults
793 5bf7b5cf Iustin Pop

794 5bf7b5cf Iustin Pop
    """
795 5bf7b5cf Iustin Pop
    return self.FillDict(self.beparams.get(constants.BEGR_DEFAULT, {}),
796 5bf7b5cf Iustin Pop
                         instance.beparams)
797 5bf7b5cf Iustin Pop
798 5c947f38 Iustin Pop
799 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
800 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
801 a8083063 Iustin Pop

802 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
803 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
804 a8083063 Iustin Pop
  buffer.
805 a8083063 Iustin Pop

806 a8083063 Iustin Pop
  """
807 a8083063 Iustin Pop
  def Dumps(self):
808 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
809 a8083063 Iustin Pop
    buf = StringIO()
810 a8083063 Iustin Pop
    self.write(buf)
811 a8083063 Iustin Pop
    return buf.getvalue()
812 a8083063 Iustin Pop
813 a8083063 Iustin Pop
  @staticmethod
814 a8083063 Iustin Pop
  def Loads(data):
815 a8083063 Iustin Pop
    """Load data from a string."""
816 a8083063 Iustin Pop
    buf = StringIO(data)
817 a8083063 Iustin Pop
    cfp = SerializableConfigParser()
818 a8083063 Iustin Pop
    cfp.readfp(buf)
819 a8083063 Iustin Pop
    return cfp