Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ f3044516

History | View | Annotate | Download (35.7 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 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 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
344 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
345 51cb1581 Luca Bigliardi

346 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
347 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
348 51cb1581 Luca Bigliardi
    @rtype: boolean
349 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
350 51cb1581 Luca Bigliardi

351 51cb1581 Luca Bigliardi
    """
352 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
353 51cb1581 Luca Bigliardi
      for disk in instance.disks:
354 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
355 51cb1581 Luca Bigliardi
          return True
356 51cb1581 Luca Bigliardi
    return False
357 51cb1581 Luca Bigliardi
358 90d726a8 Iustin Pop
  def UpgradeConfig(self):
359 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
360 90d726a8 Iustin Pop

361 90d726a8 Iustin Pop
    """
362 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
363 90d726a8 Iustin Pop
    for node in self.nodes.values():
364 90d726a8 Iustin Pop
      node.UpgradeConfig()
365 90d726a8 Iustin Pop
    for instance in self.instances.values():
366 90d726a8 Iustin Pop
      instance.UpgradeConfig()
367 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
368 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
369 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
370 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
371 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
372 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
373 90d726a8 Iustin Pop
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
class NIC(ConfigObject):
376 a8083063 Iustin Pop
  """Config object representing a network card."""
377 13f1af63 Guido Trotter
  __slots__ = ["mac", "ip", "bridge", "nicparams"]
378 a8083063 Iustin Pop
379 255e19d4 Guido Trotter
  @classmethod
380 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
381 255e19d4 Guido Trotter
    """Check the given parameters for validity.
382 255e19d4 Guido Trotter

383 255e19d4 Guido Trotter
    @type nicparams:  dict
384 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
385 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
386 255e19d4 Guido Trotter

387 255e19d4 Guido Trotter
    """
388 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
389 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
390 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
391 255e19d4 Guido Trotter
392 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
393 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
394 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
395 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
396 255e19d4 Guido Trotter
397 13f1af63 Guido Trotter
  def UpgradeConfig(self):
398 13f1af63 Guido Trotter
    """Fill defaults for missing configuration values.
399 13f1af63 Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

814 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
815 ff9c047c Iustin Pop
    python types.
816 ff9c047c Iustin Pop

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

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

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

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

864 b41b3516 Iustin Pop
  """
865 a8083063 Iustin Pop
  __slots__ = [
866 a8083063 Iustin Pop
    "name",
867 a8083063 Iustin Pop
    "path",
868 082a7f91 Guido Trotter
    "api_versions",
869 a8083063 Iustin Pop
    "create_script",
870 a8083063 Iustin Pop
    "export_script",
871 386b57af Iustin Pop
    "import_script",
872 386b57af Iustin Pop
    "rename_script",
873 b41b3516 Iustin Pop
    "verify_script",
874 6d79896b Guido Trotter
    "supported_variants",
875 b41b3516 Iustin Pop
    "supported_parameters",
876 a8083063 Iustin Pop
    ]
877 a8083063 Iustin Pop
878 7c0d6283 Michael Hanselmann
879 ec29fe40 Iustin Pop
class Node(TaggableObject):
880 a8083063 Iustin Pop
  """Config object representing a node."""
881 154b9580 Balazs Lecz
  __slots__ = [
882 ec29fe40 Iustin Pop
    "name",
883 ec29fe40 Iustin Pop
    "primary_ip",
884 ec29fe40 Iustin Pop
    "secondary_ip",
885 be1fa613 Iustin Pop
    "serial_no",
886 8b8b8b81 Iustin Pop
    "master_candidate",
887 fc0fe88c Iustin Pop
    "offline",
888 af64c0ea Iustin Pop
    "drained",
889 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
890 a8083063 Iustin Pop
891 a8083063 Iustin Pop
892 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
893 a8083063 Iustin Pop
  """Config object representing the cluster."""
894 154b9580 Balazs Lecz
  __slots__ = [
895 a8083063 Iustin Pop
    "serial_no",
896 a8083063 Iustin Pop
    "rsahostkeypub",
897 a8083063 Iustin Pop
    "highest_used_port",
898 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
899 a8083063 Iustin Pop
    "mac_prefix",
900 a8083063 Iustin Pop
    "volume_group_name",
901 999b183c Iustin Pop
    "reserved_lvs",
902 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
903 a8083063 Iustin Pop
    "default_bridge",
904 02691904 Alexander Schreiber
    "default_hypervisor",
905 f6bd6e98 Michael Hanselmann
    "master_node",
906 f6bd6e98 Michael Hanselmann
    "master_ip",
907 f6bd6e98 Michael Hanselmann
    "master_netdev",
908 f6bd6e98 Michael Hanselmann
    "cluster_name",
909 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
910 e69d05fd Iustin Pop
    "enabled_hypervisors",
911 5bf7b5cf Iustin Pop
    "hvparams",
912 17463d22 René Nussbaumer
    "os_hvp",
913 5bf7b5cf Iustin Pop
    "beparams",
914 1bdcbbab Iustin Pop
    "osparams",
915 c8fcde47 Guido Trotter
    "nicparams",
916 4b7735f9 Iustin Pop
    "candidate_pool_size",
917 b86a6bcd Guido Trotter
    "modify_etc_hosts",
918 b989b9d9 Ken Wehr
    "modify_ssh_setup",
919 3953242f Iustin Pop
    "maintain_node_health",
920 4437d889 Balazs Lecz
    "uid_pool",
921 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
922 2f20d07b Manuel Franceschini
    "primary_ip_family",
923 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
924 a8083063 Iustin Pop
925 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
926 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
927 b86a6bcd Guido Trotter

928 b86a6bcd Guido Trotter
    """
929 fe267188 Iustin Pop
    # pylint: disable-msg=E0203
930 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
931 c1b42c18 Guido Trotter
    if self.hvparams is None:
932 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
933 c1b42c18 Guido Trotter
    else:
934 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
935 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
936 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
937 c1b42c18 Guido Trotter
938 17463d22 René Nussbaumer
    if self.os_hvp is None:
939 17463d22 René Nussbaumer
      self.os_hvp = {}
940 17463d22 René Nussbaumer
941 1bdcbbab Iustin Pop
    # osparams added before 2.2
942 1bdcbbab Iustin Pop
    if self.osparams is None:
943 1bdcbbab Iustin Pop
      self.osparams = {}
944 1bdcbbab Iustin Pop
945 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
946 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
947 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
948 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
949 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
950 c8fcde47 Guido Trotter
    if migrate_default_bridge:
951 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
952 c8fcde47 Guido Trotter
        self.default_bridge
953 c1b42c18 Guido Trotter
954 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
955 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
956 b86a6bcd Guido Trotter
957 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
958 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
959 b989b9d9 Ken Wehr
960 9b31ca85 Guido Trotter
    # default_bridge is no longer used it 2.1. The slot is left there to
961 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
962 90d118fd Guido Trotter
    # upgrading straight from 2.0.
963 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
964 9b31ca85 Guido Trotter
      self.default_bridge = None
965 9b31ca85 Guido Trotter
966 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
967 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
968 066f465d Guido Trotter
    if self.default_hypervisor is not None:
969 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
970 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
971 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
972 066f465d Guido Trotter
      self.default_hypervisor = None
973 066f465d Guido Trotter
974 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
975 3953242f Iustin Pop
    if self.maintain_node_health is None:
976 3953242f Iustin Pop
      self.maintain_node_health = False
977 3953242f Iustin Pop
978 4437d889 Balazs Lecz
    if self.uid_pool is None:
979 4437d889 Balazs Lecz
      self.uid_pool = []
980 4437d889 Balazs Lecz
981 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
982 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
983 bf4af505 Apollon Oikonomopoulos
984 999b183c Iustin Pop
    # reserved_lvs added before 2.2
985 999b183c Iustin Pop
    if self.reserved_lvs is None:
986 999b183c Iustin Pop
      self.reserved_lvs = []
987 999b183c Iustin Pop
988 319856a9 Michael Hanselmann
  def ToDict(self):
989 319856a9 Michael Hanselmann
    """Custom function for cluster.
990 319856a9 Michael Hanselmann

991 319856a9 Michael Hanselmann
    """
992 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
993 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
994 319856a9 Michael Hanselmann
    return mydict
995 319856a9 Michael Hanselmann
996 319856a9 Michael Hanselmann
  @classmethod
997 319856a9 Michael Hanselmann
  def FromDict(cls, val):
998 319856a9 Michael Hanselmann
    """Custom function for cluster.
999 319856a9 Michael Hanselmann

1000 319856a9 Michael Hanselmann
    """
1001 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1002 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1003 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1004 319856a9 Michael Hanselmann
    return obj
1005 319856a9 Michael Hanselmann
1006 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1007 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1008 d63479b5 Iustin Pop

1009 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1010 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1011 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1012 d63479b5 Iustin Pop
    @return: the defaults dict
1013 d63479b5 Iustin Pop

1014 d63479b5 Iustin Pop
    """
1015 d63479b5 Iustin Pop
    if skip_keys is None:
1016 d63479b5 Iustin Pop
      skip_keys = []
1017 d63479b5 Iustin Pop
1018 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1019 d63479b5 Iustin Pop
    if os_name is not None:
1020 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1021 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1022 d63479b5 Iustin Pop
1023 d63479b5 Iustin Pop
    ret_dict = {}
1024 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1025 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1026 d63479b5 Iustin Pop
1027 d63479b5 Iustin Pop
    return ret_dict
1028 d63479b5 Iustin Pop
1029 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1030 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1031 73e0328b Iustin Pop

1032 73e0328b Iustin Pop
    @type hv_name: string
1033 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1034 73e0328b Iustin Pop
    @type os_name: string
1035 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1036 73e0328b Iustin Pop
    @type skip_globals: boolean
1037 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1038 73e0328b Iustin Pop
        not be filled
1039 73e0328b Iustin Pop
    @rtype: dict
1040 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1041 73e0328b Iustin Pop
        the cluster defaults
1042 73e0328b Iustin Pop

1043 73e0328b Iustin Pop
    """
1044 73e0328b Iustin Pop
    if skip_globals:
1045 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1046 73e0328b Iustin Pop
    else:
1047 73e0328b Iustin Pop
      skip_keys = []
1048 73e0328b Iustin Pop
1049 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1050 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1051 d63479b5 Iustin Pop
1052 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1053 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1054 5bf7b5cf Iustin Pop

1055 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1056 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1057 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1058 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1059 7736a5f2 Iustin Pop
        not be filled
1060 5bf7b5cf Iustin Pop
    @rtype: dict
1061 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1062 5bf7b5cf Iustin Pop
        the cluster defaults
1063 5bf7b5cf Iustin Pop

1064 5bf7b5cf Iustin Pop
    """
1065 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1066 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1067 17463d22 René Nussbaumer
1068 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1069 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1070 73e0328b Iustin Pop

1071 06596a60 Guido Trotter
    @type beparams: dict
1072 06596a60 Guido Trotter
    @param beparams: the dict to fill
1073 73e0328b Iustin Pop
    @rtype: dict
1074 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1075 73e0328b Iustin Pop
        from the cluster defaults
1076 73e0328b Iustin Pop

1077 73e0328b Iustin Pop
    """
1078 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1079 5bf7b5cf Iustin Pop
1080 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1081 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1082 5bf7b5cf Iustin Pop

1083 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1084 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1085 5bf7b5cf Iustin Pop
    @rtype: dict
1086 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1087 5bf7b5cf Iustin Pop
        the cluster defaults
1088 5bf7b5cf Iustin Pop

1089 5bf7b5cf Iustin Pop
    """
1090 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1091 73e0328b Iustin Pop
1092 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1093 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1094 73e0328b Iustin Pop

1095 06596a60 Guido Trotter
    @type nicparams: dict
1096 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1097 73e0328b Iustin Pop
    @rtype: dict
1098 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1099 73e0328b Iustin Pop
        from the cluster defaults
1100 73e0328b Iustin Pop

1101 73e0328b Iustin Pop
    """
1102 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1103 5bf7b5cf Iustin Pop
1104 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1105 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1106 1bdcbbab Iustin Pop

1107 1bdcbbab Iustin Pop
    @type os_name: string
1108 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1109 1bdcbbab Iustin Pop
    @type os_params: dict
1110 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1111 1bdcbbab Iustin Pop
    @rtype: dict
1112 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1113 1bdcbbab Iustin Pop
        the cluster defaults
1114 1bdcbbab Iustin Pop

1115 1bdcbbab Iustin Pop
    """
1116 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1117 1bdcbbab Iustin Pop
    # base OS
1118 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1119 1bdcbbab Iustin Pop
    # OS with variant
1120 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1121 1bdcbbab Iustin Pop
    # specified params
1122 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1123 1bdcbbab Iustin Pop
1124 5c947f38 Iustin Pop
1125 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1126 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1127 96acbc09 Michael Hanselmann
  __slots__ = [
1128 96acbc09 Michael Hanselmann
    "dev_path",
1129 96acbc09 Michael Hanselmann
    "major",
1130 96acbc09 Michael Hanselmann
    "minor",
1131 96acbc09 Michael Hanselmann
    "sync_percent",
1132 96acbc09 Michael Hanselmann
    "estimated_time",
1133 96acbc09 Michael Hanselmann
    "is_degraded",
1134 f208978a Michael Hanselmann
    "ldisk_status",
1135 96acbc09 Michael Hanselmann
    ]
1136 96acbc09 Michael Hanselmann
1137 96acbc09 Michael Hanselmann
1138 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1139 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1140 2d76b580 Michael Hanselmann
  __slots__ = [
1141 2d76b580 Michael Hanselmann
    "recent_output",
1142 2d76b580 Michael Hanselmann
    "listen_port",
1143 2d76b580 Michael Hanselmann
    "connected",
1144 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1145 c08d76f5 Michael Hanselmann
    "progress_throughput",
1146 c08d76f5 Michael Hanselmann
    "progress_eta",
1147 c08d76f5 Michael Hanselmann
    "progress_percent",
1148 2d76b580 Michael Hanselmann
    "exit_status",
1149 2d76b580 Michael Hanselmann
    "error_message",
1150 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1151 2d76b580 Michael Hanselmann
1152 2d76b580 Michael Hanselmann
1153 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1154 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1155 eb630f50 Michael Hanselmann

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

1161 eb630f50 Michael Hanselmann
  """
1162 eb630f50 Michael Hanselmann
  __slots__ = [
1163 eb630f50 Michael Hanselmann
    "key_name",
1164 eb630f50 Michael Hanselmann
    "ca_pem",
1165 a5310c2a Michael Hanselmann
    "compress",
1166 af1d39b1 Michael Hanselmann
    "magic",
1167 eb630f50 Michael Hanselmann
    ]
1168 eb630f50 Michael Hanselmann
1169 eb630f50 Michael Hanselmann
1170 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1171 18d750b9 Guido Trotter
  """Object holding a confd request.
1172 18d750b9 Guido Trotter

1173 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1174 18d750b9 Guido Trotter
  @ivar type: confd query type
1175 18d750b9 Guido Trotter
  @ivar query: query request
1176 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1177 18d750b9 Guido Trotter

1178 18d750b9 Guido Trotter
  """
1179 18d750b9 Guido Trotter
  __slots__ = [
1180 18d750b9 Guido Trotter
    "protocol",
1181 18d750b9 Guido Trotter
    "type",
1182 18d750b9 Guido Trotter
    "query",
1183 18d750b9 Guido Trotter
    "rsalt",
1184 18d750b9 Guido Trotter
    ]
1185 18d750b9 Guido Trotter
1186 18d750b9 Guido Trotter
1187 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1188 18d750b9 Guido Trotter
  """Object holding a confd reply.
1189 18d750b9 Guido Trotter

1190 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1191 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1192 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1193 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1194 18d750b9 Guido Trotter

1195 18d750b9 Guido Trotter
  """
1196 18d750b9 Guido Trotter
  __slots__ = [
1197 18d750b9 Guido Trotter
    "protocol",
1198 18d750b9 Guido Trotter
    "status",
1199 18d750b9 Guido Trotter
    "answer",
1200 18d750b9 Guido Trotter
    "serial",
1201 18d750b9 Guido Trotter
    ]
1202 18d750b9 Guido Trotter
1203 18d750b9 Guido Trotter
1204 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1205 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1206 a8083063 Iustin Pop

1207 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1208 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1209 a8083063 Iustin Pop
  buffer.
1210 a8083063 Iustin Pop

1211 a8083063 Iustin Pop
  """
1212 a8083063 Iustin Pop
  def Dumps(self):
1213 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1214 a8083063 Iustin Pop
    buf = StringIO()
1215 a8083063 Iustin Pop
    self.write(buf)
1216 a8083063 Iustin Pop
    return buf.getvalue()
1217 a8083063 Iustin Pop
1218 b39bf4bb Guido Trotter
  @classmethod
1219 b39bf4bb Guido Trotter
  def Loads(cls, data):
1220 a8083063 Iustin Pop
    """Load data from a string."""
1221 a8083063 Iustin Pop
    buf = StringIO(data)
1222 b39bf4bb Guido Trotter
    cfp = cls()
1223 a8083063 Iustin Pop
    cfp.readfp(buf)
1224 a8083063 Iustin Pop
    return cfp