Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ aa29e95f

History | View | Annotate | Download (41.5 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 870dc44c Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Transportable objects for Ganeti.
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
This module provides small, mostly data-only objects which are safe to
25 a8083063 Iustin Pop
pass to and from external parties.
26 a8083063 Iustin Pop

27 a8083063 Iustin Pop
"""
28 a8083063 Iustin Pop
29 7260cfbe Iustin Pop
# pylint: disable-msg=E0203,W0201
30 6c881c52 Iustin Pop
31 6c881c52 Iustin Pop
# E0203: Access to member %r before its definition, since we use
32 6c881c52 Iustin Pop
# objects.py which doesn't explicitely initialise its members
33 6c881c52 Iustin Pop
34 7260cfbe Iustin Pop
# W0201: Attribute '%s' defined outside __init__
35 a8083063 Iustin Pop
36 a8083063 Iustin Pop
import ConfigParser
37 5c947f38 Iustin Pop
import re
38 5bf7b5cf Iustin Pop
import copy
39 e11a1b77 Adeodato Simo
import time
40 d5835922 Michael Hanselmann
from cStringIO import StringIO
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
from ganeti import errors
43 5c947f38 Iustin Pop
from ganeti import constants
44 a8083063 Iustin Pop
45 f4c9af7a Guido Trotter
from socket import AF_INET
46 f4c9af7a Guido Trotter
47 a8083063 Iustin Pop
48 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
49 24a3707f Guido Trotter
           "OS", "Node", "NodeGroup", "Cluster", "FillDict"]
50 a8083063 Iustin Pop
51 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
52 e1dcc53a Iustin Pop
_UUID = ["uuid"]
53 96acbc09 Michael Hanselmann
54 8d8d650c Michael Hanselmann
55 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
56 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
57 abe609b2 Guido Trotter

58 29921401 Iustin Pop
  @type defaults_dict: dict
59 29921401 Iustin Pop
  @param defaults_dict: dictionary holding the default values
60 29921401 Iustin Pop
  @type custom_dict: dict
61 29921401 Iustin Pop
  @param custom_dict: dictionary holding customized value
62 7736a5f2 Iustin Pop
  @type skip_keys: list
63 7736a5f2 Iustin Pop
  @param skip_keys: which keys not to fill
64 29921401 Iustin Pop
  @rtype: dict
65 29921401 Iustin Pop
  @return: dict with the 'full' values
66 abe609b2 Guido Trotter

67 29921401 Iustin Pop
  """
68 29921401 Iustin Pop
  ret_dict = copy.deepcopy(defaults_dict)
69 29921401 Iustin Pop
  ret_dict.update(custom_dict)
70 e11ddf13 Iustin Pop
  if skip_keys:
71 e11ddf13 Iustin Pop
    for k in skip_keys:
72 e11ddf13 Iustin Pop
      try:
73 e11ddf13 Iustin Pop
        del ret_dict[k]
74 e11ddf13 Iustin Pop
      except KeyError:
75 e11ddf13 Iustin Pop
        pass
76 29921401 Iustin Pop
  return ret_dict
77 a8083063 Iustin Pop
78 6e34b628 Guido Trotter
79 6e34b628 Guido Trotter
def UpgradeGroupedParams(target, defaults):
80 6e34b628 Guido Trotter
  """Update all groups for the target parameter.
81 6e34b628 Guido Trotter

82 6e34b628 Guido Trotter
  @type target: dict of dicts
83 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
84 6e34b628 Guido Trotter
  @type defaults: dict
85 6e34b628 Guido Trotter
  @param defaults: default parameter values
86 6e34b628 Guido Trotter

87 6e34b628 Guido Trotter
  """
88 6e34b628 Guido Trotter
  if target is None:
89 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
90 6e34b628 Guido Trotter
  else:
91 6e34b628 Guido Trotter
    for group in target:
92 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
93 6e34b628 Guido Trotter
  return target
94 6e34b628 Guido Trotter
95 6e34b628 Guido Trotter
96 a8083063 Iustin Pop
class ConfigObject(object):
97 a8083063 Iustin Pop
  """A generic config object.
98 a8083063 Iustin Pop

99 a8083063 Iustin Pop
  It has the following properties:
100 a8083063 Iustin Pop

101 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
102 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
103 a8083063 Iustin Pop
      as None instead of raising an error
104 a8083063 Iustin Pop

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

108 a8083063 Iustin Pop
  """
109 a8083063 Iustin Pop
  __slots__ = []
110 a8083063 Iustin Pop
111 a8083063 Iustin Pop
  def __init__(self, **kwargs):
112 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
113 319856a9 Michael Hanselmann
      setattr(self, k, v)
114 a8083063 Iustin Pop
115 a8083063 Iustin Pop
  def __getattr__(self, name):
116 adf385c7 Iustin Pop
    if name not in self._all_slots():
117 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
118 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
119 a8083063 Iustin Pop
    return None
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  def __setstate__(self, state):
122 adf385c7 Iustin Pop
    slots = self._all_slots()
123 a8083063 Iustin Pop
    for name in state:
124 adf385c7 Iustin Pop
      if name in slots:
125 a8083063 Iustin Pop
        setattr(self, name, state[name])
126 a8083063 Iustin Pop
127 adf385c7 Iustin Pop
  @classmethod
128 adf385c7 Iustin Pop
  def _all_slots(cls):
129 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
130 adf385c7 Iustin Pop

131 adf385c7 Iustin Pop
    """
132 adf385c7 Iustin Pop
    slots = []
133 adf385c7 Iustin Pop
    for parent in cls.__mro__:
134 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
135 adf385c7 Iustin Pop
    return slots
136 adf385c7 Iustin Pop
137 ff9c047c Iustin Pop
  def ToDict(self):
138 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
139 ff9c047c Iustin Pop

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

146 ff9c047c Iustin Pop
    """
147 4c14965f Guido Trotter
    result = {}
148 adf385c7 Iustin Pop
    for name in self._all_slots():
149 4c14965f Guido Trotter
      value = getattr(self, name, None)
150 4c14965f Guido Trotter
      if value is not None:
151 4c14965f Guido Trotter
        result[name] = value
152 4c14965f Guido Trotter
    return result
153 4c14965f Guido Trotter
154 4c14965f Guido Trotter
  __getstate__ = ToDict
155 ff9c047c Iustin Pop
156 ff9c047c Iustin Pop
  @classmethod
157 ff9c047c Iustin Pop
  def FromDict(cls, val):
158 ff9c047c Iustin Pop
    """Create an object from a dictionary.
159 ff9c047c Iustin Pop

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

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

168 ff9c047c Iustin Pop
    """
169 ff9c047c Iustin Pop
    if not isinstance(val, dict):
170 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
171 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
172 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
173 7260cfbe Iustin Pop
    obj = cls(**val_str) # pylint: disable-msg=W0142
174 ff9c047c Iustin Pop
    return obj
175 ff9c047c Iustin Pop
176 ff9c047c Iustin Pop
  @staticmethod
177 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
178 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
179 ff9c047c Iustin Pop

180 ff9c047c Iustin Pop
    This method converts a container with elements derived from
181 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
182 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
183 ff9c047c Iustin Pop

184 ff9c047c Iustin Pop
    """
185 ff9c047c Iustin Pop
    if isinstance(container, dict):
186 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
187 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
188 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
189 ff9c047c Iustin Pop
    else:
190 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
191 ff9c047c Iustin Pop
                      type(container))
192 ff9c047c Iustin Pop
    return ret
193 ff9c047c Iustin Pop
194 ff9c047c Iustin Pop
  @staticmethod
195 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
196 ff9c047c Iustin Pop
    """Convert a container from standard python types.
197 ff9c047c Iustin Pop

198 ff9c047c Iustin Pop
    This method converts a container with standard python types to
199 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
200 ff9c047c Iustin Pop
    keys, only the values.
201 ff9c047c Iustin Pop

202 ff9c047c Iustin Pop
    """
203 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
204 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
205 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
206 fe25a79a Guido Trotter
    if source is None:
207 fe25a79a Guido Trotter
      source = c_type()
208 ff9c047c Iustin Pop
    if c_type is dict:
209 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
210 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
211 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
212 ff9c047c Iustin Pop
    else:
213 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
214 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
215 ff9c047c Iustin Pop
    return ret
216 ff9c047c Iustin Pop
217 e8d563f3 Iustin Pop
  def Copy(self):
218 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
219 e8d563f3 Iustin Pop

220 e8d563f3 Iustin Pop
    """
221 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
222 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
223 e8d563f3 Iustin Pop
    return clone_obj
224 e8d563f3 Iustin Pop
225 ff9c047c Iustin Pop
  def __repr__(self):
226 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
227 ff9c047c Iustin Pop
    return repr(self.ToDict())
228 ff9c047c Iustin Pop
229 560428be Guido Trotter
  def UpgradeConfig(self):
230 560428be Guido Trotter
    """Fill defaults for missing configuration values.
231 560428be Guido Trotter

232 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
233 90d726a8 Iustin Pop
    implementation will be object dependent.
234 560428be Guido Trotter

235 560428be Guido Trotter
    """
236 560428be Guido Trotter
    pass
237 560428be Guido Trotter
238 a8083063 Iustin Pop
239 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
240 5c947f38 Iustin Pop
  """An generic class supporting tags.
241 5c947f38 Iustin Pop

242 5c947f38 Iustin Pop
  """
243 154b9580 Balazs Lecz
  __slots__ = ["tags"]
244 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
245 2057f6c7 Iustin Pop
246 b5e5632e Iustin Pop
  @classmethod
247 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
248 5c947f38 Iustin Pop
    """Check if a tag is valid.
249 5c947f38 Iustin Pop

250 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
251 5c947f38 Iustin Pop
    function has no return value.
252 5c947f38 Iustin Pop

253 5c947f38 Iustin Pop
    """
254 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
255 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
256 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
257 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
258 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
259 5c947f38 Iustin Pop
    if not tag:
260 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
261 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
262 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
263 5c947f38 Iustin Pop
264 5c947f38 Iustin Pop
  def GetTags(self):
265 5c947f38 Iustin Pop
    """Return the tags list.
266 5c947f38 Iustin Pop

267 5c947f38 Iustin Pop
    """
268 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
269 5c947f38 Iustin Pop
    if tags is None:
270 5c947f38 Iustin Pop
      tags = self.tags = set()
271 5c947f38 Iustin Pop
    return tags
272 5c947f38 Iustin Pop
273 5c947f38 Iustin Pop
  def AddTag(self, tag):
274 5c947f38 Iustin Pop
    """Add a new tag.
275 5c947f38 Iustin Pop

276 5c947f38 Iustin Pop
    """
277 5c947f38 Iustin Pop
    self.ValidateTag(tag)
278 5c947f38 Iustin Pop
    tags = self.GetTags()
279 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
280 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
281 5c947f38 Iustin Pop
    self.GetTags().add(tag)
282 5c947f38 Iustin Pop
283 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
284 5c947f38 Iustin Pop
    """Remove a tag.
285 5c947f38 Iustin Pop

286 5c947f38 Iustin Pop
    """
287 5c947f38 Iustin Pop
    self.ValidateTag(tag)
288 5c947f38 Iustin Pop
    tags = self.GetTags()
289 5c947f38 Iustin Pop
    try:
290 5c947f38 Iustin Pop
      tags.remove(tag)
291 5c947f38 Iustin Pop
    except KeyError:
292 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
293 5c947f38 Iustin Pop
294 ff9c047c Iustin Pop
  def ToDict(self):
295 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
296 ff9c047c Iustin Pop

297 ff9c047c Iustin Pop
    This replaces the tags set with a list.
298 ff9c047c Iustin Pop

299 ff9c047c Iustin Pop
    """
300 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
301 ff9c047c Iustin Pop
302 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
303 ff9c047c Iustin Pop
    if isinstance(tags, set):
304 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
305 ff9c047c Iustin Pop
    return bo
306 ff9c047c Iustin Pop
307 ff9c047c Iustin Pop
  @classmethod
308 ff9c047c Iustin Pop
  def FromDict(cls, val):
309 ff9c047c Iustin Pop
    """Custom function for instances.
310 ff9c047c Iustin Pop

311 ff9c047c Iustin Pop
    """
312 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
313 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
314 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
315 ff9c047c Iustin Pop
    return obj
316 ff9c047c Iustin Pop
317 5c947f38 Iustin Pop
318 a8083063 Iustin Pop
class ConfigData(ConfigObject):
319 a8083063 Iustin Pop
  """Top-level config object."""
320 3df43542 Guido Trotter
  __slots__ = [
321 3df43542 Guido Trotter
    "version",
322 3df43542 Guido Trotter
    "cluster",
323 3df43542 Guido Trotter
    "nodes",
324 3df43542 Guido Trotter
    "nodegroups",
325 3df43542 Guido Trotter
    "instances",
326 3df43542 Guido Trotter
    "serial_no",
327 3df43542 Guido Trotter
    ] + _TIMESTAMPS
328 a8083063 Iustin Pop
329 ff9c047c Iustin Pop
  def ToDict(self):
330 ff9c047c Iustin Pop
    """Custom function for top-level config data.
331 ff9c047c Iustin Pop

332 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
333 ff9c047c Iustin Pop
    with standard python types.
334 ff9c047c Iustin Pop

335 ff9c047c Iustin Pop
    """
336 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
337 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
338 3df43542 Guido Trotter
    for key in "nodes", "instances", "nodegroups":
339 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
340 ff9c047c Iustin Pop
341 ff9c047c Iustin Pop
    return mydict
342 ff9c047c Iustin Pop
343 ff9c047c Iustin Pop
  @classmethod
344 ff9c047c Iustin Pop
  def FromDict(cls, val):
345 ff9c047c Iustin Pop
    """Custom function for top-level config data
346 ff9c047c Iustin Pop

347 ff9c047c Iustin Pop
    """
348 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
349 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
350 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
351 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
352 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
353 ff9c047c Iustin Pop
    return obj
354 ff9c047c Iustin Pop
355 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
356 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
357 51cb1581 Luca Bigliardi

358 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
359 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
360 51cb1581 Luca Bigliardi
    @rtype: boolean
361 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
362 51cb1581 Luca Bigliardi

363 51cb1581 Luca Bigliardi
    """
364 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
365 51cb1581 Luca Bigliardi
      for disk in instance.disks:
366 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
367 51cb1581 Luca Bigliardi
          return True
368 51cb1581 Luca Bigliardi
    return False
369 51cb1581 Luca Bigliardi
370 90d726a8 Iustin Pop
  def UpgradeConfig(self):
371 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
372 90d726a8 Iustin Pop

373 90d726a8 Iustin Pop
    """
374 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
375 90d726a8 Iustin Pop
    for node in self.nodes.values():
376 90d726a8 Iustin Pop
      node.UpgradeConfig()
377 90d726a8 Iustin Pop
    for instance in self.instances.values():
378 90d726a8 Iustin Pop
      instance.UpgradeConfig()
379 3df43542 Guido Trotter
    if self.nodegroups is None:
380 3df43542 Guido Trotter
      self.nodegroups = {}
381 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
382 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
383 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
384 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
385 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
386 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
387 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
388 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
389 90d726a8 Iustin Pop
390 a8083063 Iustin Pop
391 a8083063 Iustin Pop
class NIC(ConfigObject):
392 a8083063 Iustin Pop
  """Config object representing a network card."""
393 1177d70e Guido Trotter
  __slots__ = ["mac", "ip", "nicparams"]
394 a8083063 Iustin Pop
395 255e19d4 Guido Trotter
  @classmethod
396 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
397 255e19d4 Guido Trotter
    """Check the given parameters for validity.
398 255e19d4 Guido Trotter

399 255e19d4 Guido Trotter
    @type nicparams:  dict
400 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
401 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
402 255e19d4 Guido Trotter

403 255e19d4 Guido Trotter
    """
404 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
405 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
406 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
407 255e19d4 Guido Trotter
408 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
409 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
410 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
411 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
412 255e19d4 Guido Trotter
413 a8083063 Iustin Pop
414 a8083063 Iustin Pop
class Disk(ConfigObject):
415 a8083063 Iustin Pop
  """Config object representing a block device."""
416 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
417 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
418 a8083063 Iustin Pop
419 a8083063 Iustin Pop
  def CreateOnSecondary(self):
420 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
421 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
422 a8083063 Iustin Pop
423 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
424 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
425 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
  def OpenOnSecondary(self):
428 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
429 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
430 a8083063 Iustin Pop
431 222f2dd5 Iustin Pop
  def StaticDevPath(self):
432 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
433 222f2dd5 Iustin Pop

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

438 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
439 e51db2a6 Iustin Pop
        should check that it is a valid path.
440 e51db2a6 Iustin Pop

441 222f2dd5 Iustin Pop
    """
442 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
443 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
444 222f2dd5 Iustin Pop
    return None
445 222f2dd5 Iustin Pop
446 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
447 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
448 fc1dc9d7 Iustin Pop

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

453 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
454 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
455 fc1dc9d7 Iustin Pop
    -1.
456 fc1dc9d7 Iustin Pop

457 fc1dc9d7 Iustin Pop
    """
458 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
459 fc1dc9d7 Iustin Pop
      return 0
460 fc1dc9d7 Iustin Pop
    return -1
461 fc1dc9d7 Iustin Pop
462 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
463 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
464 51cb1581 Luca Bigliardi

465 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
466 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
467 51cb1581 Luca Bigliardi
    @rtype: boolean
468 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
469 51cb1581 Luca Bigliardi

470 51cb1581 Luca Bigliardi
    """
471 51cb1581 Luca Bigliardi
    if self.children:
472 51cb1581 Luca Bigliardi
      for child in self.children:
473 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
474 51cb1581 Luca Bigliardi
          return True
475 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
476 51cb1581 Luca Bigliardi
477 a8083063 Iustin Pop
  def GetNodes(self, node):
478 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
479 a8083063 Iustin Pop

480 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
481 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
482 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
483 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
484 a8083063 Iustin Pop

485 a8083063 Iustin Pop
    """
486 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
487 a8083063 Iustin Pop
      result = [node]
488 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
489 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
490 a8083063 Iustin Pop
      if node not in result:
491 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
492 a8083063 Iustin Pop
    else:
493 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
494 a8083063 Iustin Pop
    return result
495 a8083063 Iustin Pop
496 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
497 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
498 a8083063 Iustin Pop

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

505 a8083063 Iustin Pop
    """
506 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
507 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
508 a8083063 Iustin Pop
    if not self.children:
509 a8083063 Iustin Pop
      # leaf device
510 a8083063 Iustin Pop
      return result
511 a8083063 Iustin Pop
    for node in my_nodes:
512 a8083063 Iustin Pop
      for child in self.children:
513 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
514 a8083063 Iustin Pop
        if len(child_result) == 1:
515 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
516 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
517 a8083063 Iustin Pop
          # own entry for this node describes it completely
518 a8083063 Iustin Pop
          continue
519 a8083063 Iustin Pop
        else:
520 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
521 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
522 a8083063 Iustin Pop
          # one of its descendants
523 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
524 a8083063 Iustin Pop
            if subnode not in my_nodes:
525 a8083063 Iustin Pop
              result.append((subnode, subdisk))
526 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
527 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
528 a8083063 Iustin Pop
            # be different)
529 a8083063 Iustin Pop
    return result
530 a8083063 Iustin Pop
531 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
532 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
533 acec9d51 Iustin Pop

534 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
535 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
536 acec9d51 Iustin Pop
    actual algorithms from bdev.
537 acec9d51 Iustin Pop

538 acec9d51 Iustin Pop
    """
539 2c42c5df Guido Trotter
    if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE:
540 acec9d51 Iustin Pop
      self.size += amount
541 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
542 acec9d51 Iustin Pop
      if self.children:
543 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
544 acec9d51 Iustin Pop
      self.size += amount
545 acec9d51 Iustin Pop
    else:
546 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
547 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
548 acec9d51 Iustin Pop
549 a805ec18 Iustin Pop
  def UnsetSize(self):
550 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
551 a805ec18 Iustin Pop

552 a805ec18 Iustin Pop
    """
553 a805ec18 Iustin Pop
    if self.children:
554 a805ec18 Iustin Pop
      for child in self.children:
555 a805ec18 Iustin Pop
        child.UnsetSize()
556 a805ec18 Iustin Pop
    self.size = 0
557 a805ec18 Iustin Pop
558 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
559 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
560 0402302c Iustin Pop

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

563 0402302c Iustin Pop
    The routine descends down and updates its children also, because
564 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
565 0402302c Iustin Pop
    node.
566 0402302c Iustin Pop

567 0402302c Iustin Pop
    Arguments:
568 0402302c Iustin Pop
      - target_node: the node we wish to configure for
569 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
570 0402302c Iustin Pop

571 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
572 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
573 0402302c Iustin Pop
    in the disk tree.
574 0402302c Iustin Pop

575 0402302c Iustin Pop
    """
576 0402302c Iustin Pop
    if self.children:
577 0402302c Iustin Pop
      for child in self.children:
578 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
579 0402302c Iustin Pop
580 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
581 0402302c Iustin Pop
      return
582 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
583 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
584 0402302c Iustin Pop
      if target_node not in (pnode, snode):
585 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
586 0402302c Iustin Pop
                                        target_node)
587 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
588 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
589 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
590 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
591 0402302c Iustin Pop
                                        " for %s" % str(self))
592 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
593 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
594 0402302c Iustin Pop
      if pnode == target_node:
595 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
596 0402302c Iustin Pop
      else: # it must be secondary, we tested above
597 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
598 0402302c Iustin Pop
    else:
599 0402302c Iustin Pop
      self.physical_id = self.logical_id
600 0402302c Iustin Pop
    return
601 0402302c Iustin Pop
602 ff9c047c Iustin Pop
  def ToDict(self):
603 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
604 ff9c047c Iustin Pop

605 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
606 ff9c047c Iustin Pop
    standard python types.
607 ff9c047c Iustin Pop

608 ff9c047c Iustin Pop
    """
609 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
610 ff9c047c Iustin Pop
611 ff9c047c Iustin Pop
    for attr in ("children",):
612 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
613 ff9c047c Iustin Pop
      if alist:
614 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
615 ff9c047c Iustin Pop
    return bo
616 ff9c047c Iustin Pop
617 ff9c047c Iustin Pop
  @classmethod
618 ff9c047c Iustin Pop
  def FromDict(cls, val):
619 ff9c047c Iustin Pop
    """Custom function for Disks
620 ff9c047c Iustin Pop

621 ff9c047c Iustin Pop
    """
622 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
623 ff9c047c Iustin Pop
    if obj.children:
624 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
625 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
626 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
627 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
628 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
629 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
630 f9518d38 Iustin Pop
      # we need a tuple of length six here
631 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
632 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
633 ff9c047c Iustin Pop
    return obj
634 ff9c047c Iustin Pop
635 65a15336 Iustin Pop
  def __str__(self):
636 65a15336 Iustin Pop
    """Custom str() formatter for disks.
637 65a15336 Iustin Pop

638 65a15336 Iustin Pop
    """
639 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
640 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
641 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
642 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
643 00fb8246 Michael Hanselmann
      val = "<DRBD8("
644 073ca59e Iustin Pop
      if self.physical_id is None:
645 073ca59e Iustin Pop
        phy = "unconfigured"
646 073ca59e Iustin Pop
      else:
647 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
648 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
649 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
650 073ca59e Iustin Pop
651 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
652 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
653 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
654 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
655 65a15336 Iustin Pop
      else:
656 65a15336 Iustin Pop
        val += "no local storage"
657 65a15336 Iustin Pop
    else:
658 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
659 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
660 65a15336 Iustin Pop
    if self.iv_name is None:
661 65a15336 Iustin Pop
      val += ", not visible"
662 65a15336 Iustin Pop
    else:
663 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
664 fd965830 Iustin Pop
    if isinstance(self.size, int):
665 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
666 fd965830 Iustin Pop
    else:
667 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
668 65a15336 Iustin Pop
    return val
669 65a15336 Iustin Pop
670 332d0e37 Iustin Pop
  def Verify(self):
671 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
672 332d0e37 Iustin Pop

673 332d0e37 Iustin Pop
    """
674 7c4d6c7b Michael Hanselmann
    all_errors = []
675 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
676 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
677 7c4d6c7b Michael Hanselmann
    return all_errors
678 332d0e37 Iustin Pop
679 90d726a8 Iustin Pop
  def UpgradeConfig(self):
680 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
681 90d726a8 Iustin Pop

682 90d726a8 Iustin Pop
    """
683 90d726a8 Iustin Pop
    if self.children:
684 90d726a8 Iustin Pop
      for child in self.children:
685 90d726a8 Iustin Pop
        child.UpgradeConfig()
686 90d726a8 Iustin Pop
    # add here config upgrade for this disk
687 90d726a8 Iustin Pop
688 a8083063 Iustin Pop
689 ec29fe40 Iustin Pop
class Instance(TaggableObject):
690 a8083063 Iustin Pop
  """Config object representing an instance."""
691 154b9580 Balazs Lecz
  __slots__ = [
692 a8083063 Iustin Pop
    "name",
693 a8083063 Iustin Pop
    "primary_node",
694 a8083063 Iustin Pop
    "os",
695 e69d05fd Iustin Pop
    "hypervisor",
696 5bf7b5cf Iustin Pop
    "hvparams",
697 5bf7b5cf Iustin Pop
    "beparams",
698 1bdcbbab Iustin Pop
    "osparams",
699 0d68c45d Iustin Pop
    "admin_up",
700 a8083063 Iustin Pop
    "nics",
701 a8083063 Iustin Pop
    "disks",
702 a8083063 Iustin Pop
    "disk_template",
703 58acb49d Alexander Schreiber
    "network_port",
704 be1fa613 Iustin Pop
    "serial_no",
705 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
706 a8083063 Iustin Pop
707 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
708 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
709 a8083063 Iustin Pop

710 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
711 cfcc5c6d Iustin Pop

712 cfcc5c6d Iustin Pop
    """
713 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
714 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
715 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
716 cfcc5c6d Iustin Pop
717 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
718 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
719 cfcc5c6d Iustin Pop
720 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
721 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
722 cfcc5c6d Iustin Pop

723 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
724 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
725 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
726 a8083063 Iustin Pop
    dynamically.
727 a8083063 Iustin Pop

728 a8083063 Iustin Pop
    """
729 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
730 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
731 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
732 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
733 cfcc5c6d Iustin Pop
        nodes.add(nodea)
734 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
735 a8083063 Iustin Pop
      if device.children:
736 a8083063 Iustin Pop
        for child in device.children:
737 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
738 a8083063 Iustin Pop
739 cfcc5c6d Iustin Pop
    all_nodes = set()
740 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
741 a8083063 Iustin Pop
    for device in self.disks:
742 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
743 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
744 a8083063 Iustin Pop
745 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
746 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
747 a8083063 Iustin Pop
748 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
749 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
750 a8083063 Iustin Pop

751 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
752 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
753 a8083063 Iustin Pop

754 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
755 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
756 a8083063 Iustin Pop

757 84d7e26b Dmitry Chernyak
    @return: None if lvmap arg is given, otherwise, a dictionary of
758 84d7e26b Dmitry Chernyak
        the form { 'nodename' : ['volume1', 'volume2', ...], ... };
759 84d7e26b Dmitry Chernyak
        volumeN is of the form "vg_name/lv_name", compatible with
760 84d7e26b Dmitry Chernyak
        GetVolumeList()
761 a8083063 Iustin Pop

762 a8083063 Iustin Pop
    """
763 a8083063 Iustin Pop
    if node == None:
764 a8083063 Iustin Pop
      node = self.primary_node
765 a8083063 Iustin Pop
766 a8083063 Iustin Pop
    if lvmap is None:
767 a8083063 Iustin Pop
      lvmap = { node : [] }
768 a8083063 Iustin Pop
      ret = lvmap
769 a8083063 Iustin Pop
    else:
770 a8083063 Iustin Pop
      if not node in lvmap:
771 a8083063 Iustin Pop
        lvmap[node] = []
772 a8083063 Iustin Pop
      ret = None
773 a8083063 Iustin Pop
774 a8083063 Iustin Pop
    if not devs:
775 a8083063 Iustin Pop
      devs = self.disks
776 a8083063 Iustin Pop
777 a8083063 Iustin Pop
    for dev in devs:
778 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
779 84d7e26b Dmitry Chernyak
        lvmap[node].append(dev.logical_id[0]+"/"+dev.logical_id[1])
780 a8083063 Iustin Pop
781 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
782 a8083063 Iustin Pop
        if dev.children:
783 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
784 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
785 a8083063 Iustin Pop
786 a8083063 Iustin Pop
      elif dev.children:
787 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
788 a8083063 Iustin Pop
789 a8083063 Iustin Pop
    return ret
790 a8083063 Iustin Pop
791 ad24e046 Iustin Pop
  def FindDisk(self, idx):
792 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
793 644eeef9 Iustin Pop

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

796 ad24e046 Iustin Pop
    @type idx: int
797 ad24e046 Iustin Pop
    @param idx: the disk index
798 ad24e046 Iustin Pop
    @rtype: L{Disk}
799 ad24e046 Iustin Pop
    @return: the corresponding disk
800 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
801 644eeef9 Iustin Pop

802 ad24e046 Iustin Pop
    """
803 ad24e046 Iustin Pop
    try:
804 ad24e046 Iustin Pop
      idx = int(idx)
805 ad24e046 Iustin Pop
      return self.disks[idx]
806 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
807 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
808 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
809 ad24e046 Iustin Pop
    except IndexError:
810 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
811 debac808 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)),
812 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
813 644eeef9 Iustin Pop
814 ff9c047c Iustin Pop
  def ToDict(self):
815 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
816 ff9c047c Iustin Pop

817 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
818 ff9c047c Iustin Pop
    python types.
819 ff9c047c Iustin Pop

820 ff9c047c Iustin Pop
    """
821 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
822 ff9c047c Iustin Pop
823 ff9c047c Iustin Pop
    for attr in "nics", "disks":
824 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
825 ff9c047c Iustin Pop
      if alist:
826 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
827 ff9c047c Iustin Pop
      else:
828 ff9c047c Iustin Pop
        nlist = []
829 ff9c047c Iustin Pop
      bo[attr] = nlist
830 ff9c047c Iustin Pop
    return bo
831 ff9c047c Iustin Pop
832 ff9c047c Iustin Pop
  @classmethod
833 ff9c047c Iustin Pop
  def FromDict(cls, val):
834 ff9c047c Iustin Pop
    """Custom function for instances.
835 ff9c047c Iustin Pop

836 ff9c047c Iustin Pop
    """
837 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
838 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
839 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
840 ff9c047c Iustin Pop
    return obj
841 ff9c047c Iustin Pop
842 90d726a8 Iustin Pop
  def UpgradeConfig(self):
843 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
844 90d726a8 Iustin Pop

845 90d726a8 Iustin Pop
    """
846 90d726a8 Iustin Pop
    for nic in self.nics:
847 90d726a8 Iustin Pop
      nic.UpgradeConfig()
848 90d726a8 Iustin Pop
    for disk in self.disks:
849 90d726a8 Iustin Pop
      disk.UpgradeConfig()
850 7736a5f2 Iustin Pop
    if self.hvparams:
851 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
852 7736a5f2 Iustin Pop
        try:
853 7736a5f2 Iustin Pop
          del self.hvparams[key]
854 7736a5f2 Iustin Pop
        except KeyError:
855 7736a5f2 Iustin Pop
          pass
856 1bdcbbab Iustin Pop
    if self.osparams is None:
857 1bdcbbab Iustin Pop
      self.osparams = {}
858 90d726a8 Iustin Pop
859 a8083063 Iustin Pop
860 a8083063 Iustin Pop
class OS(ConfigObject):
861 b41b3516 Iustin Pop
  """Config object representing an operating system.
862 b41b3516 Iustin Pop

863 b41b3516 Iustin Pop
  @type supported_parameters: list
864 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
865 b41b3516 Iustin Pop
      containing the supported parameters by this OS
866 b41b3516 Iustin Pop

867 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
868 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
869 870dc44c Iustin Pop

870 b41b3516 Iustin Pop
  """
871 a8083063 Iustin Pop
  __slots__ = [
872 a8083063 Iustin Pop
    "name",
873 a8083063 Iustin Pop
    "path",
874 082a7f91 Guido Trotter
    "api_versions",
875 a8083063 Iustin Pop
    "create_script",
876 a8083063 Iustin Pop
    "export_script",
877 386b57af Iustin Pop
    "import_script",
878 386b57af Iustin Pop
    "rename_script",
879 b41b3516 Iustin Pop
    "verify_script",
880 6d79896b Guido Trotter
    "supported_variants",
881 b41b3516 Iustin Pop
    "supported_parameters",
882 a8083063 Iustin Pop
    ]
883 a8083063 Iustin Pop
884 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
885 870dc44c Iustin Pop
886 870dc44c Iustin Pop
  @classmethod
887 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
888 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
889 870dc44c Iustin Pop

890 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
891 870dc44c Iustin Pop
    @rtype: list
892 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
893 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
894 870dc44c Iustin Pop

895 870dc44c Iustin Pop
    """
896 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
897 870dc44c Iustin Pop
    if len(nv) == 1:
898 870dc44c Iustin Pop
      nv.append("")
899 870dc44c Iustin Pop
    return nv
900 870dc44c Iustin Pop
901 870dc44c Iustin Pop
  @classmethod
902 870dc44c Iustin Pop
  def GetName(cls, name):
903 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
904 870dc44c Iustin Pop

905 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
906 870dc44c Iustin Pop

907 870dc44c Iustin Pop
    """
908 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
909 870dc44c Iustin Pop
910 870dc44c Iustin Pop
  @classmethod
911 870dc44c Iustin Pop
  def GetVariant(cls, name):
912 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
913 870dc44c Iustin Pop

914 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
915 870dc44c Iustin Pop

916 870dc44c Iustin Pop
    """
917 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
918 870dc44c Iustin Pop
919 7c0d6283 Michael Hanselmann
920 ec29fe40 Iustin Pop
class Node(TaggableObject):
921 a8083063 Iustin Pop
  """Config object representing a node."""
922 154b9580 Balazs Lecz
  __slots__ = [
923 ec29fe40 Iustin Pop
    "name",
924 ec29fe40 Iustin Pop
    "primary_ip",
925 ec29fe40 Iustin Pop
    "secondary_ip",
926 be1fa613 Iustin Pop
    "serial_no",
927 8b8b8b81 Iustin Pop
    "master_candidate",
928 fc0fe88c Iustin Pop
    "offline",
929 af64c0ea Iustin Pop
    "drained",
930 f936c153 Iustin Pop
    "group",
931 490acd18 Iustin Pop
    "master_capable",
932 490acd18 Iustin Pop
    "vm_capable",
933 095e71aa Renรฉ Nussbaumer
    "ndparams",
934 25124d4a Renรฉ Nussbaumer
    "powered",
935 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
936 a8083063 Iustin Pop
937 490acd18 Iustin Pop
  def UpgradeConfig(self):
938 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
939 490acd18 Iustin Pop

940 490acd18 Iustin Pop
    """
941 490acd18 Iustin Pop
    # pylint: disable-msg=E0203
942 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
943 490acd18 Iustin Pop
    if self.master_capable is None:
944 490acd18 Iustin Pop
      self.master_capable = True
945 490acd18 Iustin Pop
946 490acd18 Iustin Pop
    if self.vm_capable is None:
947 490acd18 Iustin Pop
      self.vm_capable = True
948 490acd18 Iustin Pop
949 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
950 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
951 095e71aa Renรฉ Nussbaumer
952 25124d4a Renรฉ Nussbaumer
    if self.powered is None:
953 25124d4a Renรฉ Nussbaumer
      self.powered = True
954 25124d4a Renรฉ Nussbaumer
955 a8083063 Iustin Pop
956 24a3707f Guido Trotter
class NodeGroup(ConfigObject):
957 24a3707f Guido Trotter
  """Config object representing a node group."""
958 24a3707f Guido Trotter
  __slots__ = [
959 24a3707f Guido Trotter
    "name",
960 24a3707f Guido Trotter
    "members",
961 095e71aa Renรฉ Nussbaumer
    "ndparams",
962 e11a1b77 Adeodato Simo
    "serial_no",
963 90e99856 Adeodato Simo
    "alloc_policy",
964 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
965 24a3707f Guido Trotter
966 24a3707f Guido Trotter
  def ToDict(self):
967 24a3707f Guido Trotter
    """Custom function for nodegroup.
968 24a3707f Guido Trotter

969 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
970 c60abd62 Guido Trotter
    in memory.
971 24a3707f Guido Trotter

972 24a3707f Guido Trotter
    """
973 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
974 24a3707f Guido Trotter
    del mydict["members"]
975 24a3707f Guido Trotter
    return mydict
976 24a3707f Guido Trotter
977 24a3707f Guido Trotter
  @classmethod
978 24a3707f Guido Trotter
  def FromDict(cls, val):
979 24a3707f Guido Trotter
    """Custom function for nodegroup.
980 24a3707f Guido Trotter

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

983 24a3707f Guido Trotter
    """
984 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
985 24a3707f Guido Trotter
    obj.members = []
986 24a3707f Guido Trotter
    return obj
987 24a3707f Guido Trotter
988 095e71aa Renรฉ Nussbaumer
  def UpgradeConfig(self):
989 095e71aa Renรฉ Nussbaumer
    """Fill defaults for missing configuration values.
990 095e71aa Renรฉ Nussbaumer

991 095e71aa Renรฉ Nussbaumer
    """
992 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
993 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
994 095e71aa Renรฉ Nussbaumer
995 e11a1b77 Adeodato Simo
    if self.serial_no is None:
996 e11a1b77 Adeodato Simo
      self.serial_no = 1
997 e11a1b77 Adeodato Simo
998 90e99856 Adeodato Simo
    if self.alloc_policy is None:
999 90e99856 Adeodato Simo
      self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
1000 90e99856 Adeodato Simo
1001 e11a1b77 Adeodato Simo
    # We only update mtime, and not ctime, since we would not be able to provide
1002 e11a1b77 Adeodato Simo
    # a correct value for creation time.
1003 e11a1b77 Adeodato Simo
    if self.mtime is None:
1004 e11a1b77 Adeodato Simo
      self.mtime = time.time()
1005 e11a1b77 Adeodato Simo
1006 095e71aa Renรฉ Nussbaumer
  def FillND(self, node):
1007 095e71aa Renรฉ Nussbaumer
    """Return filled out ndparams for L{object.Node}
1008 095e71aa Renรฉ Nussbaumer

1009 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1010 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1011 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1012 095e71aa Renรฉ Nussbaumer

1013 095e71aa Renรฉ Nussbaumer
    """
1014 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(node.ndparams)
1015 095e71aa Renรฉ Nussbaumer
1016 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1017 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1018 095e71aa Renรฉ Nussbaumer

1019 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1020 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1021 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1022 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1023 e6e88de6 Adeodato Simo
        from the node group defaults
1024 095e71aa Renรฉ Nussbaumer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1285 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1286 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1287 095e71aa Renรฉ Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1288 095e71aa Renรฉ Nussbaumer
    @param nodegroup: A Node object to fill
1289 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1290 095e71aa Renรฉ Nussbaumer

1291 095e71aa Renรฉ Nussbaumer
    """
1292 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1293 095e71aa Renรฉ Nussbaumer
1294 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1295 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1296 095e71aa Renรฉ Nussbaumer

1297 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1298 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1299 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1300 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1301 095e71aa Renรฉ Nussbaumer
        from the cluster defaults
1302 095e71aa Renรฉ Nussbaumer

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

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

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

1357 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1358 18d750b9 Guido Trotter
  @ivar type: confd query type
1359 18d750b9 Guido Trotter
  @ivar query: query request
1360 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1361 18d750b9 Guido Trotter

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

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

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

1391 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1392 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1393 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1394 707f23b5 Michael Hanselmann

1395 707f23b5 Michael Hanselmann
  """
1396 707f23b5 Michael Hanselmann
  __slots__ = [
1397 707f23b5 Michael Hanselmann
    "name",
1398 707f23b5 Michael Hanselmann
    "title",
1399 707f23b5 Michael Hanselmann
    "kind",
1400 707f23b5 Michael Hanselmann
    ]
1401 707f23b5 Michael Hanselmann
1402 707f23b5 Michael Hanselmann
1403 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1404 0538c375 Michael Hanselmann
  __slots__ = [
1405 0538c375 Michael Hanselmann
    "fields",
1406 0538c375 Michael Hanselmann
    ]
1407 0538c375 Michael Hanselmann
1408 0538c375 Michael Hanselmann
  def ToDict(self):
1409 0538c375 Michael Hanselmann
    """Custom function for serializing.
1410 0538c375 Michael Hanselmann

1411 0538c375 Michael Hanselmann
    """
1412 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1413 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1414 0538c375 Michael Hanselmann
    return mydict
1415 0538c375 Michael Hanselmann
1416 0538c375 Michael Hanselmann
  @classmethod
1417 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1418 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1419 0538c375 Michael Hanselmann

1420 0538c375 Michael Hanselmann
    """
1421 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1422 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1423 0538c375 Michael Hanselmann
    return obj
1424 0538c375 Michael Hanselmann
1425 0538c375 Michael Hanselmann
1426 24d6d3e2 Michael Hanselmann
class QueryRequest(ConfigObject):
1427 24d6d3e2 Michael Hanselmann
  """Object holding a query request.
1428 24d6d3e2 Michael Hanselmann

1429 24d6d3e2 Michael Hanselmann
  """
1430 24d6d3e2 Michael Hanselmann
  __slots__ = [
1431 24d6d3e2 Michael Hanselmann
    "what",
1432 24d6d3e2 Michael Hanselmann
    "fields",
1433 24d6d3e2 Michael Hanselmann
    "filter",
1434 24d6d3e2 Michael Hanselmann
    ]
1435 24d6d3e2 Michael Hanselmann
1436 24d6d3e2 Michael Hanselmann
1437 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
1438 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
1439 24d6d3e2 Michael Hanselmann

1440 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1441 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1442 24d6d3e2 Michael Hanselmann

1443 24d6d3e2 Michael Hanselmann
  """
1444 24d6d3e2 Michael Hanselmann
  __slots__ = [
1445 24d6d3e2 Michael Hanselmann
    "data",
1446 24d6d3e2 Michael Hanselmann
    ]
1447 24d6d3e2 Michael Hanselmann
1448 24d6d3e2 Michael Hanselmann
1449 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
1450 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
1451 24d6d3e2 Michael Hanselmann

1452 24d6d3e2 Michael Hanselmann
  """
1453 24d6d3e2 Michael Hanselmann
  __slots__ = [
1454 24d6d3e2 Michael Hanselmann
    "what",
1455 24d6d3e2 Michael Hanselmann
    "fields",
1456 24d6d3e2 Michael Hanselmann
    ]
1457 24d6d3e2 Michael Hanselmann
1458 24d6d3e2 Michael Hanselmann
1459 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
1460 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
1461 24d6d3e2 Michael Hanselmann

1462 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1463 24d6d3e2 Michael Hanselmann

1464 24d6d3e2 Michael Hanselmann
  """
1465 24d6d3e2 Michael Hanselmann
  __slots__ = [
1466 24d6d3e2 Michael Hanselmann
    ]
1467 24d6d3e2 Michael Hanselmann
1468 24d6d3e2 Michael Hanselmann
1469 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1470 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1471 a8083063 Iustin Pop

1472 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1473 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1474 a8083063 Iustin Pop
  buffer.
1475 a8083063 Iustin Pop

1476 a8083063 Iustin Pop
  """
1477 a8083063 Iustin Pop
  def Dumps(self):
1478 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1479 a8083063 Iustin Pop
    buf = StringIO()
1480 a8083063 Iustin Pop
    self.write(buf)
1481 a8083063 Iustin Pop
    return buf.getvalue()
1482 a8083063 Iustin Pop
1483 b39bf4bb Guido Trotter
  @classmethod
1484 b39bf4bb Guido Trotter
  def Loads(cls, data):
1485 a8083063 Iustin Pop
    """Load data from a string."""
1486 a8083063 Iustin Pop
    buf = StringIO(data)
1487 b39bf4bb Guido Trotter
    cfp = cls()
1488 a8083063 Iustin Pop
    cfp.readfp(buf)
1489 a8083063 Iustin Pop
    return cfp