Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ e1ea54e9

History | View | Annotate | Download (36.9 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

402 255e19d4 Guido Trotter
    """
403 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
404 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
405 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
406 255e19d4 Guido Trotter
407 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
408 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
409 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
410 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
411 255e19d4 Guido Trotter
412 13f1af63 Guido Trotter
  def UpgradeConfig(self):
413 13f1af63 Guido Trotter
    """Fill defaults for missing configuration values.
414 13f1af63 Guido Trotter

415 13f1af63 Guido Trotter
    """
416 13f1af63 Guido Trotter
    if self.nicparams is None:
417 13f1af63 Guido Trotter
      self.nicparams = {}
418 13f1af63 Guido Trotter
      if self.bridge is not None:
419 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_MODE] = constants.NIC_MODE_BRIDGED
420 13f1af63 Guido Trotter
        self.nicparams[constants.NIC_LINK] = self.bridge
421 9b31ca85 Guido Trotter
    # bridge is no longer used it 2.1. The slot is left there to support
422 90d118fd Guido Trotter
    # upgrading, but can be removed once upgrades to the current version
423 90d118fd Guido Trotter
    # straight from 2.0 are deprecated.
424 9b31ca85 Guido Trotter
    if self.bridge is not None:
425 9b31ca85 Guido Trotter
      self.bridge = None
426 13f1af63 Guido Trotter
427 a8083063 Iustin Pop
428 a8083063 Iustin Pop
class Disk(ConfigObject):
429 a8083063 Iustin Pop
  """Config object representing a block device."""
430 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
431 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
432 a8083063 Iustin Pop
433 a8083063 Iustin Pop
  def CreateOnSecondary(self):
434 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
435 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
436 a8083063 Iustin Pop
437 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
438 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
439 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
440 a8083063 Iustin Pop
441 a8083063 Iustin Pop
  def OpenOnSecondary(self):
442 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
443 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
444 a8083063 Iustin Pop
445 222f2dd5 Iustin Pop
  def StaticDevPath(self):
446 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
447 222f2dd5 Iustin Pop

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

452 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
453 e51db2a6 Iustin Pop
        should check that it is a valid path.
454 e51db2a6 Iustin Pop

455 222f2dd5 Iustin Pop
    """
456 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
457 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
458 222f2dd5 Iustin Pop
    return None
459 222f2dd5 Iustin Pop
460 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
461 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
462 fc1dc9d7 Iustin Pop

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

467 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
468 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
469 fc1dc9d7 Iustin Pop
    -1.
470 fc1dc9d7 Iustin Pop

471 fc1dc9d7 Iustin Pop
    """
472 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
473 fc1dc9d7 Iustin Pop
      return 0
474 fc1dc9d7 Iustin Pop
    return -1
475 fc1dc9d7 Iustin Pop
476 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
477 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
478 51cb1581 Luca Bigliardi

479 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
480 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
481 51cb1581 Luca Bigliardi
    @rtype: boolean
482 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
483 51cb1581 Luca Bigliardi

484 51cb1581 Luca Bigliardi
    """
485 51cb1581 Luca Bigliardi
    if self.children:
486 51cb1581 Luca Bigliardi
      for child in self.children:
487 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
488 51cb1581 Luca Bigliardi
          return True
489 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
490 51cb1581 Luca Bigliardi
491 a8083063 Iustin Pop
  def GetNodes(self, node):
492 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
493 a8083063 Iustin Pop

494 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
495 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
496 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
497 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
498 a8083063 Iustin Pop

499 a8083063 Iustin Pop
    """
500 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
501 a8083063 Iustin Pop
      result = [node]
502 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
503 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
504 a8083063 Iustin Pop
      if node not in result:
505 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
506 a8083063 Iustin Pop
    else:
507 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
508 a8083063 Iustin Pop
    return result
509 a8083063 Iustin Pop
510 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
511 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
512 a8083063 Iustin Pop

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

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

548 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
549 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
550 acec9d51 Iustin Pop
    actual algorithms from bdev.
551 acec9d51 Iustin Pop

552 acec9d51 Iustin Pop
    """
553 2c42c5df Guido Trotter
    if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE:
554 acec9d51 Iustin Pop
      self.size += amount
555 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
556 acec9d51 Iustin Pop
      if self.children:
557 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
558 acec9d51 Iustin Pop
      self.size += amount
559 acec9d51 Iustin Pop
    else:
560 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
561 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
562 acec9d51 Iustin Pop
563 a805ec18 Iustin Pop
  def UnsetSize(self):
564 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
565 a805ec18 Iustin Pop

566 a805ec18 Iustin Pop
    """
567 a805ec18 Iustin Pop
    if self.children:
568 a805ec18 Iustin Pop
      for child in self.children:
569 a805ec18 Iustin Pop
        child.UnsetSize()
570 a805ec18 Iustin Pop
    self.size = 0
571 a805ec18 Iustin Pop
572 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
573 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
574 0402302c Iustin Pop

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

577 0402302c Iustin Pop
    The routine descends down and updates its children also, because
578 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
579 0402302c Iustin Pop
    node.
580 0402302c Iustin Pop

581 0402302c Iustin Pop
    Arguments:
582 0402302c Iustin Pop
      - target_node: the node we wish to configure for
583 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
584 0402302c Iustin Pop

585 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
586 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
587 0402302c Iustin Pop
    in the disk tree.
588 0402302c Iustin Pop

589 0402302c Iustin Pop
    """
590 0402302c Iustin Pop
    if self.children:
591 0402302c Iustin Pop
      for child in self.children:
592 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
593 0402302c Iustin Pop
594 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
595 0402302c Iustin Pop
      return
596 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
597 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
598 0402302c Iustin Pop
      if target_node not in (pnode, snode):
599 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
600 0402302c Iustin Pop
                                        target_node)
601 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
602 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
603 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
604 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
605 0402302c Iustin Pop
                                        " for %s" % str(self))
606 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
607 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
608 0402302c Iustin Pop
      if pnode == target_node:
609 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
610 0402302c Iustin Pop
      else: # it must be secondary, we tested above
611 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
612 0402302c Iustin Pop
    else:
613 0402302c Iustin Pop
      self.physical_id = self.logical_id
614 0402302c Iustin Pop
    return
615 0402302c Iustin Pop
616 ff9c047c Iustin Pop
  def ToDict(self):
617 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
618 ff9c047c Iustin Pop

619 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
620 ff9c047c Iustin Pop
    standard python types.
621 ff9c047c Iustin Pop

622 ff9c047c Iustin Pop
    """
623 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
624 ff9c047c Iustin Pop
625 ff9c047c Iustin Pop
    for attr in ("children",):
626 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
627 ff9c047c Iustin Pop
      if alist:
628 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
629 ff9c047c Iustin Pop
    return bo
630 ff9c047c Iustin Pop
631 ff9c047c Iustin Pop
  @classmethod
632 ff9c047c Iustin Pop
  def FromDict(cls, val):
633 ff9c047c Iustin Pop
    """Custom function for Disks
634 ff9c047c Iustin Pop

635 ff9c047c Iustin Pop
    """
636 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
637 ff9c047c Iustin Pop
    if obj.children:
638 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
639 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
640 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
641 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
642 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
643 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
644 f9518d38 Iustin Pop
      # we need a tuple of length six here
645 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
646 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
647 ff9c047c Iustin Pop
    return obj
648 ff9c047c Iustin Pop
649 65a15336 Iustin Pop
  def __str__(self):
650 65a15336 Iustin Pop
    """Custom str() formatter for disks.
651 65a15336 Iustin Pop

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

687 332d0e37 Iustin Pop
    """
688 7c4d6c7b Michael Hanselmann
    all_errors = []
689 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
690 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
691 7c4d6c7b Michael Hanselmann
    return all_errors
692 332d0e37 Iustin Pop
693 90d726a8 Iustin Pop
  def UpgradeConfig(self):
694 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
695 90d726a8 Iustin Pop

696 90d726a8 Iustin Pop
    """
697 90d726a8 Iustin Pop
    if self.children:
698 90d726a8 Iustin Pop
      for child in self.children:
699 90d726a8 Iustin Pop
        child.UpgradeConfig()
700 90d726a8 Iustin Pop
    # add here config upgrade for this disk
701 90d726a8 Iustin Pop
702 a8083063 Iustin Pop
703 ec29fe40 Iustin Pop
class Instance(TaggableObject):
704 a8083063 Iustin Pop
  """Config object representing an instance."""
705 154b9580 Balazs Lecz
  __slots__ = [
706 a8083063 Iustin Pop
    "name",
707 a8083063 Iustin Pop
    "primary_node",
708 a8083063 Iustin Pop
    "os",
709 e69d05fd Iustin Pop
    "hypervisor",
710 5bf7b5cf Iustin Pop
    "hvparams",
711 5bf7b5cf Iustin Pop
    "beparams",
712 1bdcbbab Iustin Pop
    "osparams",
713 0d68c45d Iustin Pop
    "admin_up",
714 a8083063 Iustin Pop
    "nics",
715 a8083063 Iustin Pop
    "disks",
716 a8083063 Iustin Pop
    "disk_template",
717 58acb49d Alexander Schreiber
    "network_port",
718 be1fa613 Iustin Pop
    "serial_no",
719 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
720 a8083063 Iustin Pop
721 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
722 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
723 a8083063 Iustin Pop

724 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
725 cfcc5c6d Iustin Pop

726 cfcc5c6d Iustin Pop
    """
727 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
728 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
729 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
730 cfcc5c6d Iustin Pop
731 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
732 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
733 cfcc5c6d Iustin Pop
734 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
735 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
736 cfcc5c6d Iustin Pop

737 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
738 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
739 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
740 a8083063 Iustin Pop
    dynamically.
741 a8083063 Iustin Pop

742 a8083063 Iustin Pop
    """
743 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
744 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
745 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
746 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
747 cfcc5c6d Iustin Pop
        nodes.add(nodea)
748 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
749 a8083063 Iustin Pop
      if device.children:
750 a8083063 Iustin Pop
        for child in device.children:
751 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
752 a8083063 Iustin Pop
753 cfcc5c6d Iustin Pop
    all_nodes = set()
754 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
755 a8083063 Iustin Pop
    for device in self.disks:
756 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
757 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
758 a8083063 Iustin Pop
759 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
760 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
761 a8083063 Iustin Pop
762 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
763 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
764 a8083063 Iustin Pop

765 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
766 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
767 a8083063 Iustin Pop

768 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
769 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
770 a8083063 Iustin Pop

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

774 a8083063 Iustin Pop
    """
775 a8083063 Iustin Pop
    if node == None:
776 a8083063 Iustin Pop
      node = self.primary_node
777 a8083063 Iustin Pop
778 a8083063 Iustin Pop
    if lvmap is None:
779 a8083063 Iustin Pop
      lvmap = { node : [] }
780 a8083063 Iustin Pop
      ret = lvmap
781 a8083063 Iustin Pop
    else:
782 a8083063 Iustin Pop
      if not node in lvmap:
783 a8083063 Iustin Pop
        lvmap[node] = []
784 a8083063 Iustin Pop
      ret = None
785 a8083063 Iustin Pop
786 a8083063 Iustin Pop
    if not devs:
787 a8083063 Iustin Pop
      devs = self.disks
788 a8083063 Iustin Pop
789 a8083063 Iustin Pop
    for dev in devs:
790 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
791 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
792 a8083063 Iustin Pop
793 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
794 a8083063 Iustin Pop
        if dev.children:
795 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
796 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
797 a8083063 Iustin Pop
798 a8083063 Iustin Pop
      elif dev.children:
799 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
800 a8083063 Iustin Pop
801 a8083063 Iustin Pop
    return ret
802 a8083063 Iustin Pop
803 ad24e046 Iustin Pop
  def FindDisk(self, idx):
804 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
805 644eeef9 Iustin Pop

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

808 ad24e046 Iustin Pop
    @type idx: int
809 ad24e046 Iustin Pop
    @param idx: the disk index
810 ad24e046 Iustin Pop
    @rtype: L{Disk}
811 ad24e046 Iustin Pop
    @return: the corresponding disk
812 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
813 644eeef9 Iustin Pop

814 ad24e046 Iustin Pop
    """
815 ad24e046 Iustin Pop
    try:
816 ad24e046 Iustin Pop
      idx = int(idx)
817 ad24e046 Iustin Pop
      return self.disks[idx]
818 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
819 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
820 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
821 ad24e046 Iustin Pop
    except IndexError:
822 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
823 debac808 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)),
824 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
825 644eeef9 Iustin Pop
826 ff9c047c Iustin Pop
  def ToDict(self):
827 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
828 ff9c047c Iustin Pop

829 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
830 ff9c047c Iustin Pop
    python types.
831 ff9c047c Iustin Pop

832 ff9c047c Iustin Pop
    """
833 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
834 ff9c047c Iustin Pop
835 ff9c047c Iustin Pop
    for attr in "nics", "disks":
836 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
837 ff9c047c Iustin Pop
      if alist:
838 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
839 ff9c047c Iustin Pop
      else:
840 ff9c047c Iustin Pop
        nlist = []
841 ff9c047c Iustin Pop
      bo[attr] = nlist
842 ff9c047c Iustin Pop
    return bo
843 ff9c047c Iustin Pop
844 ff9c047c Iustin Pop
  @classmethod
845 ff9c047c Iustin Pop
  def FromDict(cls, val):
846 ff9c047c Iustin Pop
    """Custom function for instances.
847 ff9c047c Iustin Pop

848 ff9c047c Iustin Pop
    """
849 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
850 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
851 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
852 ff9c047c Iustin Pop
    return obj
853 ff9c047c Iustin Pop
854 90d726a8 Iustin Pop
  def UpgradeConfig(self):
855 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
856 90d726a8 Iustin Pop

857 90d726a8 Iustin Pop
    """
858 90d726a8 Iustin Pop
    for nic in self.nics:
859 90d726a8 Iustin Pop
      nic.UpgradeConfig()
860 90d726a8 Iustin Pop
    for disk in self.disks:
861 90d726a8 Iustin Pop
      disk.UpgradeConfig()
862 7736a5f2 Iustin Pop
    if self.hvparams:
863 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
864 7736a5f2 Iustin Pop
        try:
865 7736a5f2 Iustin Pop
          del self.hvparams[key]
866 7736a5f2 Iustin Pop
        except KeyError:
867 7736a5f2 Iustin Pop
          pass
868 1bdcbbab Iustin Pop
    if self.osparams is None:
869 1bdcbbab Iustin Pop
      self.osparams = {}
870 90d726a8 Iustin Pop
871 a8083063 Iustin Pop
872 a8083063 Iustin Pop
class OS(ConfigObject):
873 b41b3516 Iustin Pop
  """Config object representing an operating system.
874 b41b3516 Iustin Pop

875 b41b3516 Iustin Pop
  @type supported_parameters: list
876 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
877 b41b3516 Iustin Pop
      containing the supported parameters by this OS
878 b41b3516 Iustin Pop

879 b41b3516 Iustin Pop
  """
880 a8083063 Iustin Pop
  __slots__ = [
881 a8083063 Iustin Pop
    "name",
882 a8083063 Iustin Pop
    "path",
883 082a7f91 Guido Trotter
    "api_versions",
884 a8083063 Iustin Pop
    "create_script",
885 a8083063 Iustin Pop
    "export_script",
886 386b57af Iustin Pop
    "import_script",
887 386b57af Iustin Pop
    "rename_script",
888 b41b3516 Iustin Pop
    "verify_script",
889 6d79896b Guido Trotter
    "supported_variants",
890 b41b3516 Iustin Pop
    "supported_parameters",
891 a8083063 Iustin Pop
    ]
892 a8083063 Iustin Pop
893 7c0d6283 Michael Hanselmann
894 ec29fe40 Iustin Pop
class Node(TaggableObject):
895 a8083063 Iustin Pop
  """Config object representing a node."""
896 154b9580 Balazs Lecz
  __slots__ = [
897 ec29fe40 Iustin Pop
    "name",
898 ec29fe40 Iustin Pop
    "primary_ip",
899 ec29fe40 Iustin Pop
    "secondary_ip",
900 be1fa613 Iustin Pop
    "serial_no",
901 8b8b8b81 Iustin Pop
    "master_candidate",
902 fc0fe88c Iustin Pop
    "offline",
903 af64c0ea Iustin Pop
    "drained",
904 190e3cb6 Guido Trotter
    "nodegroup",
905 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
906 a8083063 Iustin Pop
907 a8083063 Iustin Pop
908 24a3707f Guido Trotter
class NodeGroup(ConfigObject):
909 24a3707f Guido Trotter
  """Config object representing a node group."""
910 24a3707f Guido Trotter
  __slots__ = [
911 24a3707f Guido Trotter
    "name",
912 24a3707f Guido Trotter
    "members",
913 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
914 24a3707f Guido Trotter
915 24a3707f Guido Trotter
  def ToDict(self):
916 24a3707f Guido Trotter
    """Custom function for nodegroup.
917 24a3707f Guido Trotter

918 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
919 c60abd62 Guido Trotter
    in memory.
920 24a3707f Guido Trotter

921 24a3707f Guido Trotter
    """
922 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
923 24a3707f Guido Trotter
    del mydict["members"]
924 24a3707f Guido Trotter
    return mydict
925 24a3707f Guido Trotter
926 24a3707f Guido Trotter
  @classmethod
927 24a3707f Guido Trotter
  def FromDict(cls, val):
928 24a3707f Guido Trotter
    """Custom function for nodegroup.
929 24a3707f Guido Trotter

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

932 24a3707f Guido Trotter
    """
933 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
934 24a3707f Guido Trotter
    obj.members = []
935 24a3707f Guido Trotter
    return obj
936 24a3707f Guido Trotter
937 24a3707f Guido Trotter
938 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
939 a8083063 Iustin Pop
  """Config object representing the cluster."""
940 154b9580 Balazs Lecz
  __slots__ = [
941 a8083063 Iustin Pop
    "serial_no",
942 a8083063 Iustin Pop
    "rsahostkeypub",
943 a8083063 Iustin Pop
    "highest_used_port",
944 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
945 a8083063 Iustin Pop
    "mac_prefix",
946 a8083063 Iustin Pop
    "volume_group_name",
947 999b183c Iustin Pop
    "reserved_lvs",
948 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
949 a8083063 Iustin Pop
    "default_bridge",
950 02691904 Alexander Schreiber
    "default_hypervisor",
951 f6bd6e98 Michael Hanselmann
    "master_node",
952 f6bd6e98 Michael Hanselmann
    "master_ip",
953 f6bd6e98 Michael Hanselmann
    "master_netdev",
954 f6bd6e98 Michael Hanselmann
    "cluster_name",
955 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
956 e69d05fd Iustin Pop
    "enabled_hypervisors",
957 5bf7b5cf Iustin Pop
    "hvparams",
958 17463d22 Renรฉ Nussbaumer
    "os_hvp",
959 5bf7b5cf Iustin Pop
    "beparams",
960 1bdcbbab Iustin Pop
    "osparams",
961 c8fcde47 Guido Trotter
    "nicparams",
962 4b7735f9 Iustin Pop
    "candidate_pool_size",
963 b86a6bcd Guido Trotter
    "modify_etc_hosts",
964 b989b9d9 Ken Wehr
    "modify_ssh_setup",
965 3953242f Iustin Pop
    "maintain_node_health",
966 4437d889 Balazs Lecz
    "uid_pool",
967 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
968 2f20d07b Manuel Franceschini
    "primary_ip_family",
969 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
970 a8083063 Iustin Pop
971 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
972 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
973 b86a6bcd Guido Trotter

974 b86a6bcd Guido Trotter
    """
975 fe267188 Iustin Pop
    # pylint: disable-msg=E0203
976 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
977 c1b42c18 Guido Trotter
    if self.hvparams is None:
978 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
979 c1b42c18 Guido Trotter
    else:
980 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
981 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
982 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
983 c1b42c18 Guido Trotter
984 17463d22 Renรฉ Nussbaumer
    if self.os_hvp is None:
985 17463d22 Renรฉ Nussbaumer
      self.os_hvp = {}
986 17463d22 Renรฉ Nussbaumer
987 1bdcbbab Iustin Pop
    # osparams added before 2.2
988 1bdcbbab Iustin Pop
    if self.osparams is None:
989 1bdcbbab Iustin Pop
      self.osparams = {}
990 1bdcbbab Iustin Pop
991 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
992 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
993 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
994 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
995 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
996 c8fcde47 Guido Trotter
    if migrate_default_bridge:
997 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
998 c8fcde47 Guido Trotter
        self.default_bridge
999 c1b42c18 Guido Trotter
1000 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1001 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1002 b86a6bcd Guido Trotter
1003 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1004 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1005 b989b9d9 Ken Wehr
1006 9b31ca85 Guido Trotter
    # default_bridge is no longer used it 2.1. The slot is left there to
1007 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1008 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1009 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1010 9b31ca85 Guido Trotter
      self.default_bridge = None
1011 9b31ca85 Guido Trotter
1012 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1013 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1014 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1015 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1016 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1017 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1018 066f465d Guido Trotter
      self.default_hypervisor = None
1019 066f465d Guido Trotter
1020 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1021 3953242f Iustin Pop
    if self.maintain_node_health is None:
1022 3953242f Iustin Pop
      self.maintain_node_health = False
1023 3953242f Iustin Pop
1024 4437d889 Balazs Lecz
    if self.uid_pool is None:
1025 4437d889 Balazs Lecz
      self.uid_pool = []
1026 4437d889 Balazs Lecz
1027 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1028 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1029 bf4af505 Apollon Oikonomopoulos
1030 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1031 999b183c Iustin Pop
    if self.reserved_lvs is None:
1032 999b183c Iustin Pop
      self.reserved_lvs = []
1033 999b183c Iustin Pop
1034 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1035 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1036 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1037 f4c9af7a Guido Trotter
1038 319856a9 Michael Hanselmann
  def ToDict(self):
1039 319856a9 Michael Hanselmann
    """Custom function for cluster.
1040 319856a9 Michael Hanselmann

1041 319856a9 Michael Hanselmann
    """
1042 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1043 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1044 319856a9 Michael Hanselmann
    return mydict
1045 319856a9 Michael Hanselmann
1046 319856a9 Michael Hanselmann
  @classmethod
1047 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1048 319856a9 Michael Hanselmann
    """Custom function for cluster.
1049 319856a9 Michael Hanselmann

1050 319856a9 Michael Hanselmann
    """
1051 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1052 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1053 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1054 319856a9 Michael Hanselmann
    return obj
1055 319856a9 Michael Hanselmann
1056 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1057 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1058 d63479b5 Iustin Pop

1059 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1060 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1061 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1062 d63479b5 Iustin Pop
    @return: the defaults dict
1063 d63479b5 Iustin Pop

1064 d63479b5 Iustin Pop
    """
1065 d63479b5 Iustin Pop
    if skip_keys is None:
1066 d63479b5 Iustin Pop
      skip_keys = []
1067 d63479b5 Iustin Pop
1068 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1069 d63479b5 Iustin Pop
    if os_name is not None:
1070 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1071 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1072 d63479b5 Iustin Pop
1073 d63479b5 Iustin Pop
    ret_dict = {}
1074 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1075 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1076 d63479b5 Iustin Pop
1077 d63479b5 Iustin Pop
    return ret_dict
1078 d63479b5 Iustin Pop
1079 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1080 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1081 73e0328b Iustin Pop

1082 73e0328b Iustin Pop
    @type hv_name: string
1083 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1084 73e0328b Iustin Pop
    @type os_name: string
1085 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1086 73e0328b Iustin Pop
    @type skip_globals: boolean
1087 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1088 73e0328b Iustin Pop
        not be filled
1089 73e0328b Iustin Pop
    @rtype: dict
1090 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1091 73e0328b Iustin Pop
        the cluster defaults
1092 73e0328b Iustin Pop

1093 73e0328b Iustin Pop
    """
1094 73e0328b Iustin Pop
    if skip_globals:
1095 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1096 73e0328b Iustin Pop
    else:
1097 73e0328b Iustin Pop
      skip_keys = []
1098 73e0328b Iustin Pop
1099 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1100 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1101 d63479b5 Iustin Pop
1102 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1103 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1104 5bf7b5cf Iustin Pop

1105 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1106 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1107 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1108 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1109 7736a5f2 Iustin Pop
        not be filled
1110 5bf7b5cf Iustin Pop
    @rtype: dict
1111 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1112 5bf7b5cf Iustin Pop
        the cluster defaults
1113 5bf7b5cf Iustin Pop

1114 5bf7b5cf Iustin Pop
    """
1115 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1116 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1117 17463d22 Renรฉ Nussbaumer
1118 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1119 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1120 73e0328b Iustin Pop

1121 06596a60 Guido Trotter
    @type beparams: dict
1122 06596a60 Guido Trotter
    @param beparams: the dict to fill
1123 73e0328b Iustin Pop
    @rtype: dict
1124 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1125 73e0328b Iustin Pop
        from the cluster defaults
1126 73e0328b Iustin Pop

1127 73e0328b Iustin Pop
    """
1128 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1129 5bf7b5cf Iustin Pop
1130 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1131 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1132 5bf7b5cf Iustin Pop

1133 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1134 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1135 5bf7b5cf Iustin Pop
    @rtype: dict
1136 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1137 5bf7b5cf Iustin Pop
        the cluster defaults
1138 5bf7b5cf Iustin Pop

1139 5bf7b5cf Iustin Pop
    """
1140 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1141 73e0328b Iustin Pop
1142 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1143 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1144 73e0328b Iustin Pop

1145 06596a60 Guido Trotter
    @type nicparams: dict
1146 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1147 73e0328b Iustin Pop
    @rtype: dict
1148 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1149 73e0328b Iustin Pop
        from the cluster defaults
1150 73e0328b Iustin Pop

1151 73e0328b Iustin Pop
    """
1152 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1153 5bf7b5cf Iustin Pop
1154 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1155 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1156 1bdcbbab Iustin Pop

1157 1bdcbbab Iustin Pop
    @type os_name: string
1158 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1159 1bdcbbab Iustin Pop
    @type os_params: dict
1160 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1161 1bdcbbab Iustin Pop
    @rtype: dict
1162 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1163 1bdcbbab Iustin Pop
        the cluster defaults
1164 1bdcbbab Iustin Pop

1165 1bdcbbab Iustin Pop
    """
1166 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1167 1bdcbbab Iustin Pop
    # base OS
1168 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1169 1bdcbbab Iustin Pop
    # OS with variant
1170 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1171 1bdcbbab Iustin Pop
    # specified params
1172 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1173 1bdcbbab Iustin Pop
1174 5c947f38 Iustin Pop
1175 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1176 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1177 96acbc09 Michael Hanselmann
  __slots__ = [
1178 96acbc09 Michael Hanselmann
    "dev_path",
1179 96acbc09 Michael Hanselmann
    "major",
1180 96acbc09 Michael Hanselmann
    "minor",
1181 96acbc09 Michael Hanselmann
    "sync_percent",
1182 96acbc09 Michael Hanselmann
    "estimated_time",
1183 96acbc09 Michael Hanselmann
    "is_degraded",
1184 f208978a Michael Hanselmann
    "ldisk_status",
1185 96acbc09 Michael Hanselmann
    ]
1186 96acbc09 Michael Hanselmann
1187 96acbc09 Michael Hanselmann
1188 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1189 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1190 2d76b580 Michael Hanselmann
  __slots__ = [
1191 2d76b580 Michael Hanselmann
    "recent_output",
1192 2d76b580 Michael Hanselmann
    "listen_port",
1193 2d76b580 Michael Hanselmann
    "connected",
1194 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1195 c08d76f5 Michael Hanselmann
    "progress_throughput",
1196 c08d76f5 Michael Hanselmann
    "progress_eta",
1197 c08d76f5 Michael Hanselmann
    "progress_percent",
1198 2d76b580 Michael Hanselmann
    "exit_status",
1199 2d76b580 Michael Hanselmann
    "error_message",
1200 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1201 2d76b580 Michael Hanselmann
1202 2d76b580 Michael Hanselmann
1203 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1204 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1205 eb630f50 Michael Hanselmann

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

1211 eb630f50 Michael Hanselmann
  """
1212 eb630f50 Michael Hanselmann
  __slots__ = [
1213 eb630f50 Michael Hanselmann
    "key_name",
1214 eb630f50 Michael Hanselmann
    "ca_pem",
1215 a5310c2a Michael Hanselmann
    "compress",
1216 af1d39b1 Michael Hanselmann
    "magic",
1217 eb630f50 Michael Hanselmann
    ]
1218 eb630f50 Michael Hanselmann
1219 eb630f50 Michael Hanselmann
1220 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1221 18d750b9 Guido Trotter
  """Object holding a confd request.
1222 18d750b9 Guido Trotter

1223 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1224 18d750b9 Guido Trotter
  @ivar type: confd query type
1225 18d750b9 Guido Trotter
  @ivar query: query request
1226 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1227 18d750b9 Guido Trotter

1228 18d750b9 Guido Trotter
  """
1229 18d750b9 Guido Trotter
  __slots__ = [
1230 18d750b9 Guido Trotter
    "protocol",
1231 18d750b9 Guido Trotter
    "type",
1232 18d750b9 Guido Trotter
    "query",
1233 18d750b9 Guido Trotter
    "rsalt",
1234 18d750b9 Guido Trotter
    ]
1235 18d750b9 Guido Trotter
1236 18d750b9 Guido Trotter
1237 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1238 18d750b9 Guido Trotter
  """Object holding a confd reply.
1239 18d750b9 Guido Trotter

1240 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1241 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1242 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1243 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1244 18d750b9 Guido Trotter

1245 18d750b9 Guido Trotter
  """
1246 18d750b9 Guido Trotter
  __slots__ = [
1247 18d750b9 Guido Trotter
    "protocol",
1248 18d750b9 Guido Trotter
    "status",
1249 18d750b9 Guido Trotter
    "answer",
1250 18d750b9 Guido Trotter
    "serial",
1251 18d750b9 Guido Trotter
    ]
1252 18d750b9 Guido Trotter
1253 18d750b9 Guido Trotter
1254 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1255 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1256 a8083063 Iustin Pop

1257 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1258 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1259 a8083063 Iustin Pop
  buffer.
1260 a8083063 Iustin Pop

1261 a8083063 Iustin Pop
  """
1262 a8083063 Iustin Pop
  def Dumps(self):
1263 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1264 a8083063 Iustin Pop
    buf = StringIO()
1265 a8083063 Iustin Pop
    self.write(buf)
1266 a8083063 Iustin Pop
    return buf.getvalue()
1267 a8083063 Iustin Pop
1268 b39bf4bb Guido Trotter
  @classmethod
1269 b39bf4bb Guido Trotter
  def Loads(cls, data):
1270 a8083063 Iustin Pop
    """Load data from a string."""
1271 a8083063 Iustin Pop
    buf = StringIO(data)
1272 b39bf4bb Guido Trotter
    cfp = cls()
1273 a8083063 Iustin Pop
    cfp.readfp(buf)
1274 a8083063 Iustin Pop
    return cfp