Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ d3ce528b

History | View | Annotate | Download (34.2 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 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 d5835922 Michael Hanselmann
from cStringIO import StringIO
40 a8083063 Iustin Pop
41 a8083063 Iustin Pop
from ganeti import errors
42 5c947f38 Iustin Pop
from ganeti import constants
43 a8083063 Iustin Pop
44 a8083063 Iustin Pop
45 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
46 abe609b2 Guido Trotter
           "OS", "Node", "Cluster", "FillDict"]
47 a8083063 Iustin Pop
48 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
49 e1dcc53a Iustin Pop
_UUID = ["uuid"]
50 96acbc09 Michael Hanselmann
51 8d8d650c Michael Hanselmann
52 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
53 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
54 abe609b2 Guido Trotter

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

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

79 6e34b628 Guido Trotter
  @type target: dict of dicts
80 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
81 6e34b628 Guido Trotter
  @type defaults: dict
82 6e34b628 Guido Trotter
  @param defaults: default parameter values
83 6e34b628 Guido Trotter

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

96 a8083063 Iustin Pop
  It has the following properties:
97 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

227 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
228 90d726a8 Iustin Pop
    implementation will be object dependent.
229 560428be Guido Trotter

230 560428be Guido Trotter
    """
231 560428be Guido Trotter
    pass
232 560428be Guido Trotter
233 a8083063 Iustin Pop
234 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
235 5c947f38 Iustin Pop
  """An generic class supporting tags.
236 5c947f38 Iustin Pop

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

245 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
246 5c947f38 Iustin Pop
    function has no return value.
247 5c947f38 Iustin Pop

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

262 5c947f38 Iustin Pop
    """
263 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
264 5c947f38 Iustin Pop
    if tags is None:
265 5c947f38 Iustin Pop
      tags = self.tags = set()
266 5c947f38 Iustin Pop
    return tags
267 5c947f38 Iustin Pop
268 5c947f38 Iustin Pop
  def AddTag(self, tag):
269 5c947f38 Iustin Pop
    """Add a new tag.
270 5c947f38 Iustin Pop

271 5c947f38 Iustin Pop
    """
272 5c947f38 Iustin Pop
    self.ValidateTag(tag)
273 5c947f38 Iustin Pop
    tags = self.GetTags()
274 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
275 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
276 5c947f38 Iustin Pop
    self.GetTags().add(tag)
277 5c947f38 Iustin Pop
278 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
279 5c947f38 Iustin Pop
    """Remove a tag.
280 5c947f38 Iustin Pop

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

292 ff9c047c Iustin Pop
    This replaces the tags set with a list.
293 ff9c047c Iustin Pop

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

306 ff9c047c Iustin Pop
    """
307 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
308 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
309 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
310 ff9c047c Iustin Pop
    return obj
311 ff9c047c Iustin Pop
312 5c947f38 Iustin Pop
313 a8083063 Iustin Pop
class ConfigData(ConfigObject):
314 a8083063 Iustin Pop
  """Top-level config object."""
315 016d04b3 Michael Hanselmann
  __slots__ = (["version", "cluster", "nodes", "instances", "serial_no"] +
316 016d04b3 Michael Hanselmann
               _TIMESTAMPS)
317 a8083063 Iustin Pop
318 ff9c047c Iustin Pop
  def ToDict(self):
319 ff9c047c Iustin Pop
    """Custom function for top-level config data.
320 ff9c047c Iustin Pop

321 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
322 ff9c047c Iustin Pop
    with standard python types.
323 ff9c047c Iustin Pop

324 ff9c047c Iustin Pop
    """
325 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
326 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
327 ff9c047c Iustin Pop
    for key in "nodes", "instances":
328 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
329 ff9c047c Iustin Pop
330 ff9c047c Iustin Pop
    return mydict
331 ff9c047c Iustin Pop
332 ff9c047c Iustin Pop
  @classmethod
333 ff9c047c Iustin Pop
  def FromDict(cls, val):
334 ff9c047c Iustin Pop
    """Custom function for top-level config data
335 ff9c047c Iustin Pop

336 ff9c047c Iustin Pop
    """
337 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
338 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
339 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
340 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
341 ff9c047c Iustin Pop
    return obj
342 ff9c047c Iustin Pop
343 90d726a8 Iustin Pop
  def UpgradeConfig(self):
344 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
345 90d726a8 Iustin Pop

346 90d726a8 Iustin Pop
    """
347 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
348 90d726a8 Iustin Pop
    for node in self.nodes.values():
349 90d726a8 Iustin Pop
      node.UpgradeConfig()
350 90d726a8 Iustin Pop
    for instance in self.instances.values():
351 90d726a8 Iustin Pop
      instance.UpgradeConfig()
352 90d726a8 Iustin Pop
353 a8083063 Iustin Pop
354 a8083063 Iustin Pop
class NIC(ConfigObject):
355 a8083063 Iustin Pop
  """Config object representing a network card."""
356 13f1af63 Guido Trotter
  __slots__ = ["mac", "ip", "bridge", "nicparams"]
357 a8083063 Iustin Pop
358 255e19d4 Guido Trotter
  @classmethod
359 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
360 255e19d4 Guido Trotter
    """Check the given parameters for validity.
361 255e19d4 Guido Trotter

362 255e19d4 Guido Trotter
    @type nicparams:  dict
363 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
364 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
365 255e19d4 Guido Trotter

366 255e19d4 Guido Trotter
    """
367 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
368 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
369 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
370 255e19d4 Guido Trotter
371 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
372 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
373 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
374 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
375 255e19d4 Guido Trotter
376 13f1af63 Guido Trotter
  def UpgradeConfig(self):
377 13f1af63 Guido Trotter
    """Fill defaults for missing configuration values.
378 13f1af63 Guido Trotter

379 13f1af63 Guido Trotter
    """
380 13f1af63 Guido Trotter
    if self.nicparams is None:
381 13f1af63 Guido Trotter
      self.nicparams = {}
382 13f1af63 Guido Trotter
      if self.bridge is not None:
383 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_MODE] = constants.NIC_MODE_BRIDGED
384 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_LINK] = self.bridge
385 9b31ca85 Guido Trotter
    # bridge is no longer used it 2.1. The slot is left there to support
386 90d118fd Guido Trotter
    # upgrading, but can be removed once upgrades to the current version
387 90d118fd Guido Trotter
    # straight from 2.0 are deprecated.
388 9b31ca85 Guido Trotter
    if self.bridge is not None:
389 9b31ca85 Guido Trotter
      self.bridge = None
390 13f1af63 Guido Trotter
391 a8083063 Iustin Pop
392 a8083063 Iustin Pop
class Disk(ConfigObject):
393 a8083063 Iustin Pop
  """Config object representing a block device."""
394 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
395 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
396 a8083063 Iustin Pop
397 a8083063 Iustin Pop
  def CreateOnSecondary(self):
398 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
399 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
400 a8083063 Iustin Pop
401 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
402 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
403 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
404 a8083063 Iustin Pop
405 a8083063 Iustin Pop
  def OpenOnSecondary(self):
406 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
407 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
408 a8083063 Iustin Pop
409 222f2dd5 Iustin Pop
  def StaticDevPath(self):
410 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
411 222f2dd5 Iustin Pop

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

416 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
417 e51db2a6 Iustin Pop
        should check that it is a valid path.
418 e51db2a6 Iustin Pop

419 222f2dd5 Iustin Pop
    """
420 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
421 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
422 222f2dd5 Iustin Pop
    return None
423 222f2dd5 Iustin Pop
424 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
425 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
426 fc1dc9d7 Iustin Pop

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

431 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
432 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
433 fc1dc9d7 Iustin Pop
    -1.
434 fc1dc9d7 Iustin Pop

435 fc1dc9d7 Iustin Pop
    """
436 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
437 fc1dc9d7 Iustin Pop
      return 0
438 fc1dc9d7 Iustin Pop
    return -1
439 fc1dc9d7 Iustin Pop
440 a8083063 Iustin Pop
  def GetNodes(self, node):
441 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
442 a8083063 Iustin Pop

443 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
444 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
445 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
446 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
447 a8083063 Iustin Pop

448 a8083063 Iustin Pop
    """
449 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
450 a8083063 Iustin Pop
      result = [node]
451 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
452 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
453 a8083063 Iustin Pop
      if node not in result:
454 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
455 a8083063 Iustin Pop
    else:
456 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
457 a8083063 Iustin Pop
    return result
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
460 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
461 a8083063 Iustin Pop

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

468 a8083063 Iustin Pop
    """
469 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
470 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
471 a8083063 Iustin Pop
    if not self.children:
472 a8083063 Iustin Pop
      # leaf device
473 a8083063 Iustin Pop
      return result
474 a8083063 Iustin Pop
    for node in my_nodes:
475 a8083063 Iustin Pop
      for child in self.children:
476 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
477 a8083063 Iustin Pop
        if len(child_result) == 1:
478 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
479 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
480 a8083063 Iustin Pop
          # own entry for this node describes it completely
481 a8083063 Iustin Pop
          continue
482 a8083063 Iustin Pop
        else:
483 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
484 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
485 a8083063 Iustin Pop
          # one of its descendants
486 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
487 a8083063 Iustin Pop
            if subnode not in my_nodes:
488 a8083063 Iustin Pop
              result.append((subnode, subdisk))
489 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
490 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
491 a8083063 Iustin Pop
            # be different)
492 a8083063 Iustin Pop
    return result
493 a8083063 Iustin Pop
494 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
495 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
496 acec9d51 Iustin Pop

497 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
498 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
499 acec9d51 Iustin Pop
    actual algorithms from bdev.
500 acec9d51 Iustin Pop

501 acec9d51 Iustin Pop
    """
502 2c42c5df Guido Trotter
    if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE:
503 acec9d51 Iustin Pop
      self.size += amount
504 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
505 acec9d51 Iustin Pop
      if self.children:
506 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
507 acec9d51 Iustin Pop
      self.size += amount
508 acec9d51 Iustin Pop
    else:
509 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
510 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
511 acec9d51 Iustin Pop
512 a805ec18 Iustin Pop
  def UnsetSize(self):
513 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
514 a805ec18 Iustin Pop

515 a805ec18 Iustin Pop
    """
516 a805ec18 Iustin Pop
    if self.children:
517 a805ec18 Iustin Pop
      for child in self.children:
518 a805ec18 Iustin Pop
        child.UnsetSize()
519 a805ec18 Iustin Pop
    self.size = 0
520 a805ec18 Iustin Pop
521 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
522 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
523 0402302c Iustin Pop

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

526 0402302c Iustin Pop
    The routine descends down and updates its children also, because
527 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
528 0402302c Iustin Pop
    node.
529 0402302c Iustin Pop

530 0402302c Iustin Pop
    Arguments:
531 0402302c Iustin Pop
      - target_node: the node we wish to configure for
532 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
533 0402302c Iustin Pop

534 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
535 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
536 0402302c Iustin Pop
    in the disk tree.
537 0402302c Iustin Pop

538 0402302c Iustin Pop
    """
539 0402302c Iustin Pop
    if self.children:
540 0402302c Iustin Pop
      for child in self.children:
541 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
542 0402302c Iustin Pop
543 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
544 0402302c Iustin Pop
      return
545 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
546 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
547 0402302c Iustin Pop
      if target_node not in (pnode, snode):
548 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
549 0402302c Iustin Pop
                                        target_node)
550 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
551 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
552 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
553 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
554 0402302c Iustin Pop
                                        " for %s" % str(self))
555 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
556 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
557 0402302c Iustin Pop
      if pnode == target_node:
558 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
559 0402302c Iustin Pop
      else: # it must be secondary, we tested above
560 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
561 0402302c Iustin Pop
    else:
562 0402302c Iustin Pop
      self.physical_id = self.logical_id
563 0402302c Iustin Pop
    return
564 0402302c Iustin Pop
565 ff9c047c Iustin Pop
  def ToDict(self):
566 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
567 ff9c047c Iustin Pop

568 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
569 ff9c047c Iustin Pop
    standard python types.
570 ff9c047c Iustin Pop

571 ff9c047c Iustin Pop
    """
572 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
573 ff9c047c Iustin Pop
574 ff9c047c Iustin Pop
    for attr in ("children",):
575 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
576 ff9c047c Iustin Pop
      if alist:
577 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
578 ff9c047c Iustin Pop
    return bo
579 ff9c047c Iustin Pop
580 ff9c047c Iustin Pop
  @classmethod
581 ff9c047c Iustin Pop
  def FromDict(cls, val):
582 ff9c047c Iustin Pop
    """Custom function for Disks
583 ff9c047c Iustin Pop

584 ff9c047c Iustin Pop
    """
585 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
586 ff9c047c Iustin Pop
    if obj.children:
587 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
588 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
589 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
590 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
591 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
592 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
593 f9518d38 Iustin Pop
      # we need a tuple of length six here
594 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
595 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
596 ff9c047c Iustin Pop
    return obj
597 ff9c047c Iustin Pop
598 65a15336 Iustin Pop
  def __str__(self):
599 65a15336 Iustin Pop
    """Custom str() formatter for disks.
600 65a15336 Iustin Pop

601 65a15336 Iustin Pop
    """
602 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
603 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
604 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
605 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
606 00fb8246 Michael Hanselmann
      val = "<DRBD8("
607 073ca59e Iustin Pop
      if self.physical_id is None:
608 073ca59e Iustin Pop
        phy = "unconfigured"
609 073ca59e Iustin Pop
      else:
610 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
611 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
612 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
613 073ca59e Iustin Pop
614 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
615 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
616 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
617 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
618 65a15336 Iustin Pop
      else:
619 65a15336 Iustin Pop
        val += "no local storage"
620 65a15336 Iustin Pop
    else:
621 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
622 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
623 65a15336 Iustin Pop
    if self.iv_name is None:
624 65a15336 Iustin Pop
      val += ", not visible"
625 65a15336 Iustin Pop
    else:
626 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
627 fd965830 Iustin Pop
    if isinstance(self.size, int):
628 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
629 fd965830 Iustin Pop
    else:
630 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
631 65a15336 Iustin Pop
    return val
632 65a15336 Iustin Pop
633 332d0e37 Iustin Pop
  def Verify(self):
634 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
635 332d0e37 Iustin Pop

636 332d0e37 Iustin Pop
    """
637 7c4d6c7b Michael Hanselmann
    all_errors = []
638 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
639 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
640 7c4d6c7b Michael Hanselmann
    return all_errors
641 332d0e37 Iustin Pop
642 90d726a8 Iustin Pop
  def UpgradeConfig(self):
643 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
644 90d726a8 Iustin Pop

645 90d726a8 Iustin Pop
    """
646 90d726a8 Iustin Pop
    if self.children:
647 90d726a8 Iustin Pop
      for child in self.children:
648 90d726a8 Iustin Pop
        child.UpgradeConfig()
649 90d726a8 Iustin Pop
    # add here config upgrade for this disk
650 90d726a8 Iustin Pop
651 a8083063 Iustin Pop
652 ec29fe40 Iustin Pop
class Instance(TaggableObject):
653 a8083063 Iustin Pop
  """Config object representing an instance."""
654 154b9580 Balazs Lecz
  __slots__ = [
655 a8083063 Iustin Pop
    "name",
656 a8083063 Iustin Pop
    "primary_node",
657 a8083063 Iustin Pop
    "os",
658 e69d05fd Iustin Pop
    "hypervisor",
659 5bf7b5cf Iustin Pop
    "hvparams",
660 5bf7b5cf Iustin Pop
    "beparams",
661 1bdcbbab Iustin Pop
    "osparams",
662 0d68c45d Iustin Pop
    "admin_up",
663 a8083063 Iustin Pop
    "nics",
664 a8083063 Iustin Pop
    "disks",
665 a8083063 Iustin Pop
    "disk_template",
666 58acb49d Alexander Schreiber
    "network_port",
667 be1fa613 Iustin Pop
    "serial_no",
668 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
669 a8083063 Iustin Pop
670 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
671 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
672 a8083063 Iustin Pop

673 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
674 cfcc5c6d Iustin Pop

675 cfcc5c6d Iustin Pop
    """
676 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
677 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
678 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
679 cfcc5c6d Iustin Pop
680 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
681 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
682 cfcc5c6d Iustin Pop
683 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
684 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
685 cfcc5c6d Iustin Pop

686 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
687 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
688 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
689 a8083063 Iustin Pop
    dynamically.
690 a8083063 Iustin Pop

691 a8083063 Iustin Pop
    """
692 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
693 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
694 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
695 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
696 cfcc5c6d Iustin Pop
        nodes.add(nodea)
697 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
698 a8083063 Iustin Pop
      if device.children:
699 a8083063 Iustin Pop
        for child in device.children:
700 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
701 a8083063 Iustin Pop
702 cfcc5c6d Iustin Pop
    all_nodes = set()
703 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
704 a8083063 Iustin Pop
    for device in self.disks:
705 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
706 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
707 a8083063 Iustin Pop
708 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
709 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
710 a8083063 Iustin Pop
711 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
712 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
713 a8083063 Iustin Pop

714 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
715 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
716 a8083063 Iustin Pop

717 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
718 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
719 a8083063 Iustin Pop

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

723 a8083063 Iustin Pop
    """
724 a8083063 Iustin Pop
    if node == None:
725 a8083063 Iustin Pop
      node = self.primary_node
726 a8083063 Iustin Pop
727 a8083063 Iustin Pop
    if lvmap is None:
728 a8083063 Iustin Pop
      lvmap = { node : [] }
729 a8083063 Iustin Pop
      ret = lvmap
730 a8083063 Iustin Pop
    else:
731 a8083063 Iustin Pop
      if not node in lvmap:
732 a8083063 Iustin Pop
        lvmap[node] = []
733 a8083063 Iustin Pop
      ret = None
734 a8083063 Iustin Pop
735 a8083063 Iustin Pop
    if not devs:
736 a8083063 Iustin Pop
      devs = self.disks
737 a8083063 Iustin Pop
738 a8083063 Iustin Pop
    for dev in devs:
739 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
740 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
741 a8083063 Iustin Pop
742 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
743 a8083063 Iustin Pop
        if dev.children:
744 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
745 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
746 a8083063 Iustin Pop
747 a8083063 Iustin Pop
      elif dev.children:
748 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
749 a8083063 Iustin Pop
750 a8083063 Iustin Pop
    return ret
751 a8083063 Iustin Pop
752 ad24e046 Iustin Pop
  def FindDisk(self, idx):
753 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
754 644eeef9 Iustin Pop

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

757 ad24e046 Iustin Pop
    @type idx: int
758 ad24e046 Iustin Pop
    @param idx: the disk index
759 ad24e046 Iustin Pop
    @rtype: L{Disk}
760 ad24e046 Iustin Pop
    @return: the corresponding disk
761 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
762 644eeef9 Iustin Pop

763 ad24e046 Iustin Pop
    """
764 ad24e046 Iustin Pop
    try:
765 ad24e046 Iustin Pop
      idx = int(idx)
766 ad24e046 Iustin Pop
      return self.disks[idx]
767 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
768 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
769 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
770 ad24e046 Iustin Pop
    except IndexError:
771 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
772 debac808 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)),
773 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
774 644eeef9 Iustin Pop
775 ff9c047c Iustin Pop
  def ToDict(self):
776 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
777 ff9c047c Iustin Pop

778 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
779 ff9c047c Iustin Pop
    python types.
780 ff9c047c Iustin Pop

781 ff9c047c Iustin Pop
    """
782 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
783 ff9c047c Iustin Pop
784 ff9c047c Iustin Pop
    for attr in "nics", "disks":
785 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
786 ff9c047c Iustin Pop
      if alist:
787 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
788 ff9c047c Iustin Pop
      else:
789 ff9c047c Iustin Pop
        nlist = []
790 ff9c047c Iustin Pop
      bo[attr] = nlist
791 ff9c047c Iustin Pop
    return bo
792 ff9c047c Iustin Pop
793 ff9c047c Iustin Pop
  @classmethod
794 ff9c047c Iustin Pop
  def FromDict(cls, val):
795 ff9c047c Iustin Pop
    """Custom function for instances.
796 ff9c047c Iustin Pop

797 ff9c047c Iustin Pop
    """
798 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
799 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
800 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
801 ff9c047c Iustin Pop
    return obj
802 ff9c047c Iustin Pop
803 90d726a8 Iustin Pop
  def UpgradeConfig(self):
804 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
805 90d726a8 Iustin Pop

806 90d726a8 Iustin Pop
    """
807 90d726a8 Iustin Pop
    for nic in self.nics:
808 90d726a8 Iustin Pop
      nic.UpgradeConfig()
809 90d726a8 Iustin Pop
    for disk in self.disks:
810 90d726a8 Iustin Pop
      disk.UpgradeConfig()
811 7736a5f2 Iustin Pop
    if self.hvparams:
812 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
813 7736a5f2 Iustin Pop
        try:
814 7736a5f2 Iustin Pop
          del self.hvparams[key]
815 7736a5f2 Iustin Pop
        except KeyError:
816 7736a5f2 Iustin Pop
          pass
817 1bdcbbab Iustin Pop
    if self.osparams is None:
818 1bdcbbab Iustin Pop
      self.osparams = {}
819 90d726a8 Iustin Pop
820 a8083063 Iustin Pop
821 a8083063 Iustin Pop
class OS(ConfigObject):
822 b41b3516 Iustin Pop
  """Config object representing an operating system.
823 b41b3516 Iustin Pop

824 b41b3516 Iustin Pop
  @type supported_parameters: list
825 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
826 b41b3516 Iustin Pop
      containing the supported parameters by this OS
827 b41b3516 Iustin Pop

828 b41b3516 Iustin Pop
  """
829 a8083063 Iustin Pop
  __slots__ = [
830 a8083063 Iustin Pop
    "name",
831 a8083063 Iustin Pop
    "path",
832 082a7f91 Guido Trotter
    "api_versions",
833 a8083063 Iustin Pop
    "create_script",
834 a8083063 Iustin Pop
    "export_script",
835 386b57af Iustin Pop
    "import_script",
836 386b57af Iustin Pop
    "rename_script",
837 b41b3516 Iustin Pop
    "verify_script",
838 6d79896b Guido Trotter
    "supported_variants",
839 b41b3516 Iustin Pop
    "supported_parameters",
840 a8083063 Iustin Pop
    ]
841 a8083063 Iustin Pop
842 7c0d6283 Michael Hanselmann
843 ec29fe40 Iustin Pop
class Node(TaggableObject):
844 a8083063 Iustin Pop
  """Config object representing a node."""
845 154b9580 Balazs Lecz
  __slots__ = [
846 ec29fe40 Iustin Pop
    "name",
847 ec29fe40 Iustin Pop
    "primary_ip",
848 ec29fe40 Iustin Pop
    "secondary_ip",
849 be1fa613 Iustin Pop
    "serial_no",
850 8b8b8b81 Iustin Pop
    "master_candidate",
851 fc0fe88c Iustin Pop
    "offline",
852 af64c0ea Iustin Pop
    "drained",
853 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
854 a8083063 Iustin Pop
855 a8083063 Iustin Pop
856 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
857 a8083063 Iustin Pop
  """Config object representing the cluster."""
858 154b9580 Balazs Lecz
  __slots__ = [
859 a8083063 Iustin Pop
    "serial_no",
860 a8083063 Iustin Pop
    "rsahostkeypub",
861 a8083063 Iustin Pop
    "highest_used_port",
862 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
863 a8083063 Iustin Pop
    "mac_prefix",
864 a8083063 Iustin Pop
    "volume_group_name",
865 a8083063 Iustin Pop
    "default_bridge",
866 02691904 Alexander Schreiber
    "default_hypervisor",
867 f6bd6e98 Michael Hanselmann
    "master_node",
868 f6bd6e98 Michael Hanselmann
    "master_ip",
869 f6bd6e98 Michael Hanselmann
    "master_netdev",
870 f6bd6e98 Michael Hanselmann
    "cluster_name",
871 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
872 e69d05fd Iustin Pop
    "enabled_hypervisors",
873 5bf7b5cf Iustin Pop
    "hvparams",
874 17463d22 Renรฉ Nussbaumer
    "os_hvp",
875 5bf7b5cf Iustin Pop
    "beparams",
876 1bdcbbab Iustin Pop
    "osparams",
877 c8fcde47 Guido Trotter
    "nicparams",
878 4b7735f9 Iustin Pop
    "candidate_pool_size",
879 b86a6bcd Guido Trotter
    "modify_etc_hosts",
880 b989b9d9 Ken Wehr
    "modify_ssh_setup",
881 3953242f Iustin Pop
    "maintain_node_health",
882 4437d889 Balazs Lecz
    "uid_pool",
883 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
884 a8083063 Iustin Pop
885 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
886 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
887 b86a6bcd Guido Trotter

888 b86a6bcd Guido Trotter
    """
889 fe267188 Iustin Pop
    # pylint: disable-msg=E0203
890 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
891 c1b42c18 Guido Trotter
    if self.hvparams is None:
892 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
893 c1b42c18 Guido Trotter
    else:
894 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
895 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
896 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
897 c1b42c18 Guido Trotter
898 17463d22 Renรฉ Nussbaumer
    if self.os_hvp is None:
899 17463d22 Renรฉ Nussbaumer
      self.os_hvp = {}
900 17463d22 Renรฉ Nussbaumer
901 1bdcbbab Iustin Pop
    # osparams added before 2.2
902 1bdcbbab Iustin Pop
    if self.osparams is None:
903 1bdcbbab Iustin Pop
      self.osparams = {}
904 1bdcbbab Iustin Pop
905 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
906 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
907 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
908 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
909 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
910 c8fcde47 Guido Trotter
    if migrate_default_bridge:
911 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
912 c8fcde47 Guido Trotter
        self.default_bridge
913 c1b42c18 Guido Trotter
914 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
915 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
916 b86a6bcd Guido Trotter
917 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
918 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
919 b989b9d9 Ken Wehr
920 9b31ca85 Guido Trotter
    # default_bridge is no longer used it 2.1. The slot is left there to
921 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
922 90d118fd Guido Trotter
    # upgrading straight from 2.0.
923 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
924 9b31ca85 Guido Trotter
      self.default_bridge = None
925 9b31ca85 Guido Trotter
926 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
927 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
928 066f465d Guido Trotter
    if self.default_hypervisor is not None:
929 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
930 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
931 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
932 066f465d Guido Trotter
      self.default_hypervisor = None
933 066f465d Guido Trotter
934 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
935 3953242f Iustin Pop
    if self.maintain_node_health is None:
936 3953242f Iustin Pop
      self.maintain_node_health = False
937 3953242f Iustin Pop
938 4437d889 Balazs Lecz
    if self.uid_pool is None:
939 4437d889 Balazs Lecz
      self.uid_pool = []
940 4437d889 Balazs Lecz
941 319856a9 Michael Hanselmann
  def ToDict(self):
942 319856a9 Michael Hanselmann
    """Custom function for cluster.
943 319856a9 Michael Hanselmann

944 319856a9 Michael Hanselmann
    """
945 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
946 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
947 319856a9 Michael Hanselmann
    return mydict
948 319856a9 Michael Hanselmann
949 319856a9 Michael Hanselmann
  @classmethod
950 319856a9 Michael Hanselmann
  def FromDict(cls, val):
951 319856a9 Michael Hanselmann
    """Custom function for cluster.
952 319856a9 Michael Hanselmann

953 319856a9 Michael Hanselmann
    """
954 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
955 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
956 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
957 319856a9 Michael Hanselmann
    return obj
958 319856a9 Michael Hanselmann
959 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
960 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
961 d63479b5 Iustin Pop

962 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
963 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
964 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
965 d63479b5 Iustin Pop
    @return: the defaults dict
966 d63479b5 Iustin Pop

967 d63479b5 Iustin Pop
    """
968 d63479b5 Iustin Pop
    if skip_keys is None:
969 d63479b5 Iustin Pop
      skip_keys = []
970 d63479b5 Iustin Pop
971 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
972 d63479b5 Iustin Pop
    if os_name is not None:
973 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
974 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
975 d63479b5 Iustin Pop
976 d63479b5 Iustin Pop
    ret_dict = {}
977 d63479b5 Iustin Pop
    for o_dict in fill_stack:
978 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
979 d63479b5 Iustin Pop
980 d63479b5 Iustin Pop
    return ret_dict
981 d63479b5 Iustin Pop
982 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
983 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
984 73e0328b Iustin Pop

985 73e0328b Iustin Pop
    @type hv_name: string
986 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
987 73e0328b Iustin Pop
    @type os_name: string
988 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
989 73e0328b Iustin Pop
    @type skip_globals: boolean
990 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
991 73e0328b Iustin Pop
        not be filled
992 73e0328b Iustin Pop
    @rtype: dict
993 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
994 73e0328b Iustin Pop
        the cluster defaults
995 73e0328b Iustin Pop

996 73e0328b Iustin Pop
    """
997 73e0328b Iustin Pop
    if skip_globals:
998 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
999 73e0328b Iustin Pop
    else:
1000 73e0328b Iustin Pop
      skip_keys = []
1001 73e0328b Iustin Pop
1002 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1003 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1004 d63479b5 Iustin Pop
1005 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1006 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1007 5bf7b5cf Iustin Pop

1008 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1009 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1010 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1011 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1012 7736a5f2 Iustin Pop
        not be filled
1013 5bf7b5cf Iustin Pop
    @rtype: dict
1014 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1015 5bf7b5cf Iustin Pop
        the cluster defaults
1016 5bf7b5cf Iustin Pop

1017 5bf7b5cf Iustin Pop
    """
1018 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1019 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1020 17463d22 Renรฉ Nussbaumer
1021 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1022 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1023 73e0328b Iustin Pop

1024 06596a60 Guido Trotter
    @type beparams: dict
1025 06596a60 Guido Trotter
    @param beparams: the dict to fill
1026 73e0328b Iustin Pop
    @rtype: dict
1027 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1028 73e0328b Iustin Pop
        from the cluster defaults
1029 73e0328b Iustin Pop

1030 73e0328b Iustin Pop
    """
1031 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1032 5bf7b5cf Iustin Pop
1033 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1034 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1035 5bf7b5cf Iustin Pop

1036 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1037 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1038 5bf7b5cf Iustin Pop
    @rtype: dict
1039 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1040 5bf7b5cf Iustin Pop
        the cluster defaults
1041 5bf7b5cf Iustin Pop

1042 5bf7b5cf Iustin Pop
    """
1043 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1044 73e0328b Iustin Pop
1045 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1046 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1047 73e0328b Iustin Pop

1048 06596a60 Guido Trotter
    @type nicparams: dict
1049 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1050 73e0328b Iustin Pop
    @rtype: dict
1051 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1052 73e0328b Iustin Pop
        from the cluster defaults
1053 73e0328b Iustin Pop

1054 73e0328b Iustin Pop
    """
1055 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1056 5bf7b5cf Iustin Pop
1057 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1058 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1059 1bdcbbab Iustin Pop

1060 1bdcbbab Iustin Pop
    @type os_name: string
1061 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1062 1bdcbbab Iustin Pop
    @type os_params: dict
1063 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1064 1bdcbbab Iustin Pop
    @rtype: dict
1065 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1066 1bdcbbab Iustin Pop
        the cluster defaults
1067 1bdcbbab Iustin Pop

1068 1bdcbbab Iustin Pop
    """
1069 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1070 1bdcbbab Iustin Pop
    # base OS
1071 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1072 1bdcbbab Iustin Pop
    # OS with variant
1073 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1074 1bdcbbab Iustin Pop
    # specified params
1075 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1076 1bdcbbab Iustin Pop
1077 5c947f38 Iustin Pop
1078 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1079 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1080 96acbc09 Michael Hanselmann
  __slots__ = [
1081 96acbc09 Michael Hanselmann
    "dev_path",
1082 96acbc09 Michael Hanselmann
    "major",
1083 96acbc09 Michael Hanselmann
    "minor",
1084 96acbc09 Michael Hanselmann
    "sync_percent",
1085 96acbc09 Michael Hanselmann
    "estimated_time",
1086 96acbc09 Michael Hanselmann
    "is_degraded",
1087 f208978a Michael Hanselmann
    "ldisk_status",
1088 96acbc09 Michael Hanselmann
    ]
1089 96acbc09 Michael Hanselmann
1090 96acbc09 Michael Hanselmann
1091 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1092 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1093 2d76b580 Michael Hanselmann
  __slots__ = [
1094 2d76b580 Michael Hanselmann
    "recent_output",
1095 2d76b580 Michael Hanselmann
    "listen_port",
1096 2d76b580 Michael Hanselmann
    "connected",
1097 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1098 c08d76f5 Michael Hanselmann
    "progress_throughput",
1099 c08d76f5 Michael Hanselmann
    "progress_eta",
1100 c08d76f5 Michael Hanselmann
    "progress_percent",
1101 2d76b580 Michael Hanselmann
    "exit_status",
1102 2d76b580 Michael Hanselmann
    "error_message",
1103 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1104 2d76b580 Michael Hanselmann
1105 2d76b580 Michael Hanselmann
1106 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1107 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1108 eb630f50 Michael Hanselmann

1109 eb630f50 Michael Hanselmann
  @ivar key_name: X509 key name (None for cluster certificate)
1110 eb630f50 Michael Hanselmann
  @ivar ca_pem: Remote peer CA in PEM format (None for cluster certificate)
1111 a5310c2a Michael Hanselmann
  @ivar compress: Compression method (one of L{constants.IEC_ALL})
1112 af1d39b1 Michael Hanselmann
  @ivar magic: Used to ensure the connection goes to the right disk
1113 eb630f50 Michael Hanselmann

1114 eb630f50 Michael Hanselmann
  """
1115 eb630f50 Michael Hanselmann
  __slots__ = [
1116 eb630f50 Michael Hanselmann
    "key_name",
1117 eb630f50 Michael Hanselmann
    "ca_pem",
1118 a5310c2a Michael Hanselmann
    "compress",
1119 af1d39b1 Michael Hanselmann
    "magic",
1120 eb630f50 Michael Hanselmann
    ]
1121 eb630f50 Michael Hanselmann
1122 eb630f50 Michael Hanselmann
1123 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1124 18d750b9 Guido Trotter
  """Object holding a confd request.
1125 18d750b9 Guido Trotter

1126 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1127 18d750b9 Guido Trotter
  @ivar type: confd query type
1128 18d750b9 Guido Trotter
  @ivar query: query request
1129 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1130 18d750b9 Guido Trotter

1131 18d750b9 Guido Trotter
  """
1132 18d750b9 Guido Trotter
  __slots__ = [
1133 18d750b9 Guido Trotter
    "protocol",
1134 18d750b9 Guido Trotter
    "type",
1135 18d750b9 Guido Trotter
    "query",
1136 18d750b9 Guido Trotter
    "rsalt",
1137 18d750b9 Guido Trotter
    ]
1138 18d750b9 Guido Trotter
1139 18d750b9 Guido Trotter
1140 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1141 18d750b9 Guido Trotter
  """Object holding a confd reply.
1142 18d750b9 Guido Trotter

1143 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1144 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1145 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1146 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1147 18d750b9 Guido Trotter

1148 18d750b9 Guido Trotter
  """
1149 18d750b9 Guido Trotter
  __slots__ = [
1150 18d750b9 Guido Trotter
    "protocol",
1151 18d750b9 Guido Trotter
    "status",
1152 18d750b9 Guido Trotter
    "answer",
1153 18d750b9 Guido Trotter
    "serial",
1154 18d750b9 Guido Trotter
    ]
1155 18d750b9 Guido Trotter
1156 18d750b9 Guido Trotter
1157 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1158 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1159 a8083063 Iustin Pop

1160 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1161 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1162 a8083063 Iustin Pop
  buffer.
1163 a8083063 Iustin Pop

1164 a8083063 Iustin Pop
  """
1165 a8083063 Iustin Pop
  def Dumps(self):
1166 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1167 a8083063 Iustin Pop
    buf = StringIO()
1168 a8083063 Iustin Pop
    self.write(buf)
1169 a8083063 Iustin Pop
    return buf.getvalue()
1170 a8083063 Iustin Pop
1171 b39bf4bb Guido Trotter
  @classmethod
1172 b39bf4bb Guido Trotter
  def Loads(cls, data):
1173 a8083063 Iustin Pop
    """Load data from a string."""
1174 a8083063 Iustin Pop
    buf = StringIO(data)
1175 b39bf4bb Guido Trotter
    cfp = cls()
1176 a8083063 Iustin Pop
    cfp.readfp(buf)
1177 a8083063 Iustin Pop
    return cfp