Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ adb6d685

History | View | Annotate | Download (34 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 9b31ca85 Guido Trotter
    # upgrading, but will be removed in 2.2
387 9b31ca85 Guido Trotter
    if self.bridge is not None:
388 9b31ca85 Guido Trotter
      self.bridge = None
389 13f1af63 Guido Trotter
390 a8083063 Iustin Pop
391 a8083063 Iustin Pop
class Disk(ConfigObject):
392 a8083063 Iustin Pop
  """Config object representing a block device."""
393 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
394 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
395 a8083063 Iustin Pop
396 a8083063 Iustin Pop
  def CreateOnSecondary(self):
397 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
398 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
399 a8083063 Iustin Pop
400 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
401 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
402 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
403 a8083063 Iustin Pop
404 a8083063 Iustin Pop
  def OpenOnSecondary(self):
405 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
406 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
407 a8083063 Iustin Pop
408 222f2dd5 Iustin Pop
  def StaticDevPath(self):
409 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
410 222f2dd5 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1123 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1124 18d750b9 Guido Trotter
  @ivar type: confd query type
1125 18d750b9 Guido Trotter
  @ivar query: query request
1126 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1127 18d750b9 Guido Trotter

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

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

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

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

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