Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 035566e3

History | View | Annotate | Download (26.2 kB)

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

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

27 a8083063 Iustin Pop
"""
28 a8083063 Iustin Pop
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
import ConfigParser
31 5c947f38 Iustin Pop
import re
32 5bf7b5cf Iustin Pop
import copy
33 d5835922 Michael Hanselmann
from cStringIO import StringIO
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti import errors
36 5c947f38 Iustin Pop
from ganeti import constants
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
40 abe609b2 Guido Trotter
           "OS", "Node", "Cluster", "FillDict"]
41 a8083063 Iustin Pop
42 abe609b2 Guido Trotter
def FillDict(defaults_dict, custom_dict):
43 abe609b2 Guido Trotter
    """Basic function to apply settings on top a default dict.
44 abe609b2 Guido Trotter

45 abe609b2 Guido Trotter
    @type defaults_dict: dict
46 abe609b2 Guido Trotter
    @param defaults_dict: dictionary holding the default values
47 abe609b2 Guido Trotter
    @type custom_dict: dict
48 abe609b2 Guido Trotter
    @param custom_dict: dictionary holding customized value
49 abe609b2 Guido Trotter
    @rtype: dict
50 abe609b2 Guido Trotter
    @return: dict with the 'full' values
51 abe609b2 Guido Trotter

52 abe609b2 Guido Trotter
    """
53 abe609b2 Guido Trotter
    ret_dict = copy.deepcopy(defaults_dict)
54 abe609b2 Guido Trotter
    ret_dict.update(custom_dict)
55 abe609b2 Guido Trotter
    return ret_dict
56 a8083063 Iustin Pop
57 6e34b628 Guido Trotter
58 6e34b628 Guido Trotter
def UpgradeGroupedParams(target, defaults):
59 6e34b628 Guido Trotter
  """Update all groups for the target parameter.
60 6e34b628 Guido Trotter

61 6e34b628 Guido Trotter
  @type target: dict of dicts
62 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
63 6e34b628 Guido Trotter
  @type defaults: dict
64 6e34b628 Guido Trotter
  @param defaults: default parameter values
65 6e34b628 Guido Trotter

66 6e34b628 Guido Trotter
  """
67 6e34b628 Guido Trotter
  if target is None:
68 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
69 6e34b628 Guido Trotter
  else:
70 6e34b628 Guido Trotter
    for group in target:
71 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
72 6e34b628 Guido Trotter
  return target
73 6e34b628 Guido Trotter
74 6e34b628 Guido Trotter
75 a8083063 Iustin Pop
class ConfigObject(object):
76 a8083063 Iustin Pop
  """A generic config object.
77 a8083063 Iustin Pop

78 a8083063 Iustin Pop
  It has the following properties:
79 a8083063 Iustin Pop

80 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
81 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
82 a8083063 Iustin Pop
      as None instead of raising an error
83 a8083063 Iustin Pop

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

87 a8083063 Iustin Pop
  """
88 a8083063 Iustin Pop
  __slots__ = []
89 a8083063 Iustin Pop
90 a8083063 Iustin Pop
  def __init__(self, **kwargs):
91 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
92 319856a9 Michael Hanselmann
      setattr(self, k, v)
93 560428be Guido Trotter
    self.UpgradeConfig()
94 a8083063 Iustin Pop
95 a8083063 Iustin Pop
  def __getattr__(self, name):
96 a8083063 Iustin Pop
    if name not in self.__slots__:
97 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
98 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
99 a8083063 Iustin Pop
    return None
100 a8083063 Iustin Pop
101 47c28c5b Michael Hanselmann
  def __setitem__(self, key, value):
102 47c28c5b Michael Hanselmann
    if key not in self.__slots__:
103 3ecf6786 Iustin Pop
      raise KeyError(key)
104 47c28c5b Michael Hanselmann
    setattr(self, key, value)
105 47c28c5b Michael Hanselmann
106 a8083063 Iustin Pop
  def __getstate__(self):
107 a8083063 Iustin Pop
    state = {}
108 a8083063 Iustin Pop
    for name in self.__slots__:
109 a8083063 Iustin Pop
      if hasattr(self, name):
110 a8083063 Iustin Pop
        state[name] = getattr(self, name)
111 a8083063 Iustin Pop
    return state
112 a8083063 Iustin Pop
113 a8083063 Iustin Pop
  def __setstate__(self, state):
114 a8083063 Iustin Pop
    for name in state:
115 a8083063 Iustin Pop
      if name in self.__slots__:
116 a8083063 Iustin Pop
        setattr(self, name, state[name])
117 a8083063 Iustin Pop
118 ff9c047c Iustin Pop
  def ToDict(self):
119 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
120 ff9c047c Iustin Pop

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

127 ff9c047c Iustin Pop
    """
128 ff9c047c Iustin Pop
    return dict([(k, getattr(self, k, None)) for k in self.__slots__])
129 ff9c047c Iustin Pop
130 ff9c047c Iustin Pop
  @classmethod
131 ff9c047c Iustin Pop
  def FromDict(cls, val):
132 ff9c047c Iustin Pop
    """Create an object from a dictionary.
133 ff9c047c Iustin Pop

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

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

142 ff9c047c Iustin Pop
    """
143 ff9c047c Iustin Pop
    if not isinstance(val, dict):
144 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
145 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
146 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
147 319856a9 Michael Hanselmann
    obj = cls(**val_str)
148 ff9c047c Iustin Pop
    return obj
149 ff9c047c Iustin Pop
150 ff9c047c Iustin Pop
  @staticmethod
151 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
152 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
153 ff9c047c Iustin Pop

154 ff9c047c Iustin Pop
    This method converts a container with elements derived from
155 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
156 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
157 ff9c047c Iustin Pop

158 ff9c047c Iustin Pop
    """
159 ff9c047c Iustin Pop
    if isinstance(container, dict):
160 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
161 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
162 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
163 ff9c047c Iustin Pop
    else:
164 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
165 ff9c047c Iustin Pop
                      type(container))
166 ff9c047c Iustin Pop
    return ret
167 ff9c047c Iustin Pop
168 ff9c047c Iustin Pop
  @staticmethod
169 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
170 ff9c047c Iustin Pop
    """Convert a container from standard python types.
171 ff9c047c Iustin Pop

172 ff9c047c Iustin Pop
    This method converts a container with standard python types to
173 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
174 ff9c047c Iustin Pop
    keys, only the values.
175 ff9c047c Iustin Pop

176 ff9c047c Iustin Pop
    """
177 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
178 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
179 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
180 ff9c047c Iustin Pop
    if c_type is dict:
181 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
182 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
183 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
184 ff9c047c Iustin Pop
    else:
185 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
186 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
187 ff9c047c Iustin Pop
    return ret
188 ff9c047c Iustin Pop
189 ff9c047c Iustin Pop
  def __repr__(self):
190 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
191 ff9c047c Iustin Pop
    return repr(self.ToDict())
192 ff9c047c Iustin Pop
193 560428be Guido Trotter
  def UpgradeConfig(self):
194 560428be Guido Trotter
    """Fill defaults for missing configuration values.
195 560428be Guido Trotter

196 560428be Guido Trotter
    This method will be called at object init time, and its implementation will
197 560428be Guido Trotter
    be object dependent.
198 560428be Guido Trotter

199 560428be Guido Trotter
    """
200 560428be Guido Trotter
    pass
201 560428be Guido Trotter
202 a8083063 Iustin Pop
203 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
204 5c947f38 Iustin Pop
  """An generic class supporting tags.
205 5c947f38 Iustin Pop

206 5c947f38 Iustin Pop
  """
207 ec29fe40 Iustin Pop
  __slots__ = ConfigObject.__slots__ + ["tags"]
208 2057f6c7 Iustin Pop
209 5c947f38 Iustin Pop
  @staticmethod
210 5c947f38 Iustin Pop
  def ValidateTag(tag):
211 5c947f38 Iustin Pop
    """Check if a tag is valid.
212 5c947f38 Iustin Pop

213 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
214 5c947f38 Iustin Pop
    function has no return value.
215 5c947f38 Iustin Pop

216 5c947f38 Iustin Pop
    """
217 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
218 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
219 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
220 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
221 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
222 5c947f38 Iustin Pop
    if not tag:
223 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
224 28ab6fed Iustin Pop
    if not re.match("^[\w.+*/:-]+$", tag):
225 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
226 5c947f38 Iustin Pop
227 5c947f38 Iustin Pop
  def GetTags(self):
228 5c947f38 Iustin Pop
    """Return the tags list.
229 5c947f38 Iustin Pop

230 5c947f38 Iustin Pop
    """
231 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
232 5c947f38 Iustin Pop
    if tags is None:
233 5c947f38 Iustin Pop
      tags = self.tags = set()
234 5c947f38 Iustin Pop
    return tags
235 5c947f38 Iustin Pop
236 5c947f38 Iustin Pop
  def AddTag(self, tag):
237 5c947f38 Iustin Pop
    """Add a new tag.
238 5c947f38 Iustin Pop

239 5c947f38 Iustin Pop
    """
240 5c947f38 Iustin Pop
    self.ValidateTag(tag)
241 5c947f38 Iustin Pop
    tags = self.GetTags()
242 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
243 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
244 5c947f38 Iustin Pop
    self.GetTags().add(tag)
245 5c947f38 Iustin Pop
246 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
247 5c947f38 Iustin Pop
    """Remove a tag.
248 5c947f38 Iustin Pop

249 5c947f38 Iustin Pop
    """
250 5c947f38 Iustin Pop
    self.ValidateTag(tag)
251 5c947f38 Iustin Pop
    tags = self.GetTags()
252 5c947f38 Iustin Pop
    try:
253 5c947f38 Iustin Pop
      tags.remove(tag)
254 5c947f38 Iustin Pop
    except KeyError:
255 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
256 5c947f38 Iustin Pop
257 ff9c047c Iustin Pop
  def ToDict(self):
258 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
259 ff9c047c Iustin Pop

260 ff9c047c Iustin Pop
    This replaces the tags set with a list.
261 ff9c047c Iustin Pop

262 ff9c047c Iustin Pop
    """
263 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
264 ff9c047c Iustin Pop
265 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
266 ff9c047c Iustin Pop
    if isinstance(tags, set):
267 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
268 ff9c047c Iustin Pop
    return bo
269 ff9c047c Iustin Pop
270 ff9c047c Iustin Pop
  @classmethod
271 ff9c047c Iustin Pop
  def FromDict(cls, val):
272 ff9c047c Iustin Pop
    """Custom function for instances.
273 ff9c047c Iustin Pop

274 ff9c047c Iustin Pop
    """
275 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
276 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
277 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
278 ff9c047c Iustin Pop
    return obj
279 ff9c047c Iustin Pop
280 5c947f38 Iustin Pop
281 a8083063 Iustin Pop
class ConfigData(ConfigObject):
282 a8083063 Iustin Pop
  """Top-level config object."""
283 f6bd6e98 Michael Hanselmann
  __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"]
284 a8083063 Iustin Pop
285 ff9c047c Iustin Pop
  def ToDict(self):
286 ff9c047c Iustin Pop
    """Custom function for top-level config data.
287 ff9c047c Iustin Pop

288 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
289 ff9c047c Iustin Pop
    with standard python types.
290 ff9c047c Iustin Pop

291 ff9c047c Iustin Pop
    """
292 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
293 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
294 ff9c047c Iustin Pop
    for key in "nodes", "instances":
295 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
296 ff9c047c Iustin Pop
297 ff9c047c Iustin Pop
    return mydict
298 ff9c047c Iustin Pop
299 ff9c047c Iustin Pop
  @classmethod
300 ff9c047c Iustin Pop
  def FromDict(cls, val):
301 ff9c047c Iustin Pop
    """Custom function for top-level config data
302 ff9c047c Iustin Pop

303 ff9c047c Iustin Pop
    """
304 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
305 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
306 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
307 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
308 ff9c047c Iustin Pop
    return obj
309 ff9c047c Iustin Pop
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
class NIC(ConfigObject):
312 a8083063 Iustin Pop
  """Config object representing a network card."""
313 a8083063 Iustin Pop
  __slots__ = ["mac", "ip", "bridge"]
314 a8083063 Iustin Pop
315 255e19d4 Guido Trotter
  @classmethod
316 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
317 255e19d4 Guido Trotter
    """Check the given parameters for validity.
318 255e19d4 Guido Trotter

319 255e19d4 Guido Trotter
    @type nicparams:  dict
320 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
321 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
322 255e19d4 Guido Trotter

323 255e19d4 Guido Trotter
    """
324 255e19d4 Guido Trotter
    if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES:
325 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
326 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
327 255e19d4 Guido Trotter
328 255e19d4 Guido Trotter
    if (nicparams[constants.NIC_MODE] is constants.NIC_MODE_BRIDGED and
329 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
330 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
331 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
332 255e19d4 Guido Trotter
333 a8083063 Iustin Pop
334 a8083063 Iustin Pop
class Disk(ConfigObject):
335 a8083063 Iustin Pop
  """Config object representing a block device."""
336 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
337 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
338 a8083063 Iustin Pop
339 a8083063 Iustin Pop
  def CreateOnSecondary(self):
340 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
341 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
342 a8083063 Iustin Pop
343 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
344 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
345 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
346 a8083063 Iustin Pop
347 a8083063 Iustin Pop
  def OpenOnSecondary(self):
348 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
349 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
350 a8083063 Iustin Pop
351 222f2dd5 Iustin Pop
  def StaticDevPath(self):
352 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
353 222f2dd5 Iustin Pop

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

358 222f2dd5 Iustin Pop
    """
359 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
360 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
361 222f2dd5 Iustin Pop
    return None
362 222f2dd5 Iustin Pop
363 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
364 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
365 fc1dc9d7 Iustin Pop

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

370 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
371 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
372 fc1dc9d7 Iustin Pop
    -1.
373 fc1dc9d7 Iustin Pop

374 fc1dc9d7 Iustin Pop
    """
375 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
376 fc1dc9d7 Iustin Pop
      return 0
377 fc1dc9d7 Iustin Pop
    return -1
378 fc1dc9d7 Iustin Pop
379 a8083063 Iustin Pop
  def GetNodes(self, node):
380 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
381 a8083063 Iustin Pop

382 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
383 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
384 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
385 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
386 a8083063 Iustin Pop

387 a8083063 Iustin Pop
    """
388 00fb8246 Michael Hanselmann
    if self.dev_type in [constants.LD_LV, constants.LD_FILE]:
389 a8083063 Iustin Pop
      result = [node]
390 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
391 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
392 a8083063 Iustin Pop
      if node not in result:
393 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
394 a8083063 Iustin Pop
    else:
395 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
396 a8083063 Iustin Pop
    return result
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
399 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
400 a8083063 Iustin Pop

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

407 a8083063 Iustin Pop
    """
408 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
409 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
410 a8083063 Iustin Pop
    if not self.children:
411 a8083063 Iustin Pop
      # leaf device
412 a8083063 Iustin Pop
      return result
413 a8083063 Iustin Pop
    for node in my_nodes:
414 a8083063 Iustin Pop
      for child in self.children:
415 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
416 a8083063 Iustin Pop
        if len(child_result) == 1:
417 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
418 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
419 a8083063 Iustin Pop
          # own entry for this node describes it completely
420 a8083063 Iustin Pop
          continue
421 a8083063 Iustin Pop
        else:
422 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
423 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
424 a8083063 Iustin Pop
          # one of its descendants
425 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
426 a8083063 Iustin Pop
            if subnode not in my_nodes:
427 a8083063 Iustin Pop
              result.append((subnode, subdisk))
428 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
429 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
430 a8083063 Iustin Pop
            # be different)
431 a8083063 Iustin Pop
    return result
432 a8083063 Iustin Pop
433 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
434 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
435 acec9d51 Iustin Pop

436 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
437 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
438 acec9d51 Iustin Pop
    actual algorithms from bdev.
439 acec9d51 Iustin Pop

440 acec9d51 Iustin Pop
    """
441 acec9d51 Iustin Pop
    if self.dev_type == constants.LD_LV:
442 acec9d51 Iustin Pop
      self.size += amount
443 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
444 acec9d51 Iustin Pop
      if self.children:
445 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
446 acec9d51 Iustin Pop
      self.size += amount
447 acec9d51 Iustin Pop
    else:
448 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
449 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
450 acec9d51 Iustin Pop
451 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
452 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
453 0402302c Iustin Pop

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

456 0402302c Iustin Pop
    The routine descends down and updates its children also, because
457 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
458 0402302c Iustin Pop
    node.
459 0402302c Iustin Pop

460 0402302c Iustin Pop
    Arguments:
461 0402302c Iustin Pop
      - target_node: the node we wish to configure for
462 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
463 0402302c Iustin Pop

464 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
465 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
466 0402302c Iustin Pop
    in the disk tree.
467 0402302c Iustin Pop

468 0402302c Iustin Pop
    """
469 0402302c Iustin Pop
    if self.children:
470 0402302c Iustin Pop
      for child in self.children:
471 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
472 0402302c Iustin Pop
473 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
474 0402302c Iustin Pop
      return
475 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
476 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
477 0402302c Iustin Pop
      if target_node not in (pnode, snode):
478 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
479 0402302c Iustin Pop
                                        target_node)
480 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
481 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
482 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
483 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
484 0402302c Iustin Pop
                                        " for %s" % str(self))
485 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
486 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
487 0402302c Iustin Pop
      if pnode == target_node:
488 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
489 0402302c Iustin Pop
      else: # it must be secondary, we tested above
490 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
491 0402302c Iustin Pop
    else:
492 0402302c Iustin Pop
      self.physical_id = self.logical_id
493 0402302c Iustin Pop
    return
494 0402302c Iustin Pop
495 ff9c047c Iustin Pop
  def ToDict(self):
496 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
497 ff9c047c Iustin Pop

498 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
499 ff9c047c Iustin Pop
    standard python types.
500 ff9c047c Iustin Pop

501 ff9c047c Iustin Pop
    """
502 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
503 ff9c047c Iustin Pop
504 ff9c047c Iustin Pop
    for attr in ("children",):
505 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
506 ff9c047c Iustin Pop
      if alist:
507 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
508 ff9c047c Iustin Pop
    return bo
509 ff9c047c Iustin Pop
510 ff9c047c Iustin Pop
  @classmethod
511 ff9c047c Iustin Pop
  def FromDict(cls, val):
512 ff9c047c Iustin Pop
    """Custom function for Disks
513 ff9c047c Iustin Pop

514 ff9c047c Iustin Pop
    """
515 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
516 ff9c047c Iustin Pop
    if obj.children:
517 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
518 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
519 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
520 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
521 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
522 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
523 f9518d38 Iustin Pop
      # we need a tuple of length six here
524 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
525 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
526 ff9c047c Iustin Pop
    return obj
527 ff9c047c Iustin Pop
528 65a15336 Iustin Pop
  def __str__(self):
529 65a15336 Iustin Pop
    """Custom str() formatter for disks.
530 65a15336 Iustin Pop

531 65a15336 Iustin Pop
    """
532 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
533 65a15336 Iustin Pop
      val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
534 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
535 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
536 00fb8246 Michael Hanselmann
      val = "<DRBD8("
537 073ca59e Iustin Pop
      if self.physical_id is None:
538 073ca59e Iustin Pop
        phy = "unconfigured"
539 073ca59e Iustin Pop
      else:
540 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
541 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
542 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
543 073ca59e Iustin Pop
544 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
545 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
546 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
547 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
548 65a15336 Iustin Pop
      else:
549 65a15336 Iustin Pop
        val += "no local storage"
550 65a15336 Iustin Pop
    else:
551 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
552 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
553 65a15336 Iustin Pop
    if self.iv_name is None:
554 65a15336 Iustin Pop
      val += ", not visible"
555 65a15336 Iustin Pop
    else:
556 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
557 fd965830 Iustin Pop
    if isinstance(self.size, int):
558 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
559 fd965830 Iustin Pop
    else:
560 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
561 65a15336 Iustin Pop
    return val
562 65a15336 Iustin Pop
563 332d0e37 Iustin Pop
  def Verify(self):
564 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
565 332d0e37 Iustin Pop

566 332d0e37 Iustin Pop
    """
567 332d0e37 Iustin Pop
    errors = []
568 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
569 332d0e37 Iustin Pop
      errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
570 332d0e37 Iustin Pop
    return errors
571 332d0e37 Iustin Pop
572 a8083063 Iustin Pop
573 ec29fe40 Iustin Pop
class Instance(TaggableObject):
574 a8083063 Iustin Pop
  """Config object representing an instance."""
575 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
576 a8083063 Iustin Pop
    "name",
577 a8083063 Iustin Pop
    "primary_node",
578 a8083063 Iustin Pop
    "os",
579 e69d05fd Iustin Pop
    "hypervisor",
580 5bf7b5cf Iustin Pop
    "hvparams",
581 5bf7b5cf Iustin Pop
    "beparams",
582 0d68c45d Iustin Pop
    "admin_up",
583 a8083063 Iustin Pop
    "nics",
584 a8083063 Iustin Pop
    "disks",
585 a8083063 Iustin Pop
    "disk_template",
586 58acb49d Alexander Schreiber
    "network_port",
587 be1fa613 Iustin Pop
    "serial_no",
588 a8083063 Iustin Pop
    ]
589 a8083063 Iustin Pop
590 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
591 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
592 a8083063 Iustin Pop

593 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
594 cfcc5c6d Iustin Pop

595 cfcc5c6d Iustin Pop
    """
596 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
597 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
598 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
599 cfcc5c6d Iustin Pop
600 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
601 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
602 cfcc5c6d Iustin Pop
603 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
604 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
605 cfcc5c6d Iustin Pop

606 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
607 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
608 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
609 a8083063 Iustin Pop
    dynamically.
610 a8083063 Iustin Pop

611 a8083063 Iustin Pop
    """
612 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
613 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
614 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
615 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
616 cfcc5c6d Iustin Pop
        nodes.add(nodea)
617 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
618 a8083063 Iustin Pop
      if device.children:
619 a8083063 Iustin Pop
        for child in device.children:
620 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
621 a8083063 Iustin Pop
622 cfcc5c6d Iustin Pop
    all_nodes = set()
623 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
624 a8083063 Iustin Pop
    for device in self.disks:
625 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
626 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
627 a8083063 Iustin Pop
628 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
629 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
630 a8083063 Iustin Pop
631 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
632 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
633 a8083063 Iustin Pop

634 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
635 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
636 a8083063 Iustin Pop

637 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
638 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
639 a8083063 Iustin Pop

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

643 a8083063 Iustin Pop
    """
644 a8083063 Iustin Pop
    if node == None:
645 a8083063 Iustin Pop
      node = self.primary_node
646 a8083063 Iustin Pop
647 a8083063 Iustin Pop
    if lvmap is None:
648 a8083063 Iustin Pop
      lvmap = { node : [] }
649 a8083063 Iustin Pop
      ret = lvmap
650 a8083063 Iustin Pop
    else:
651 a8083063 Iustin Pop
      if not node in lvmap:
652 a8083063 Iustin Pop
        lvmap[node] = []
653 a8083063 Iustin Pop
      ret = None
654 a8083063 Iustin Pop
655 a8083063 Iustin Pop
    if not devs:
656 a8083063 Iustin Pop
      devs = self.disks
657 a8083063 Iustin Pop
658 a8083063 Iustin Pop
    for dev in devs:
659 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
660 a8083063 Iustin Pop
        lvmap[node].append(dev.logical_id[1])
661 a8083063 Iustin Pop
662 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
663 a8083063 Iustin Pop
        if dev.children:
664 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
665 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
666 a8083063 Iustin Pop
667 a8083063 Iustin Pop
      elif dev.children:
668 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
669 a8083063 Iustin Pop
670 a8083063 Iustin Pop
    return ret
671 a8083063 Iustin Pop
672 ad24e046 Iustin Pop
  def FindDisk(self, idx):
673 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
674 644eeef9 Iustin Pop

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

677 ad24e046 Iustin Pop
    @type idx: int
678 ad24e046 Iustin Pop
    @param idx: the disk index
679 ad24e046 Iustin Pop
    @rtype: L{Disk}
680 ad24e046 Iustin Pop
    @return: the corresponding disk
681 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
682 644eeef9 Iustin Pop

683 ad24e046 Iustin Pop
    """
684 ad24e046 Iustin Pop
    try:
685 ad24e046 Iustin Pop
      idx = int(idx)
686 ad24e046 Iustin Pop
      return self.disks[idx]
687 ad24e046 Iustin Pop
    except ValueError, err:
688 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err))
689 ad24e046 Iustin Pop
    except IndexError:
690 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
691 ad24e046 Iustin Pop
                                 " 0 to %d" % (idx, len(self.disks)))
692 644eeef9 Iustin Pop
693 ff9c047c Iustin Pop
  def ToDict(self):
694 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
695 ff9c047c Iustin Pop

696 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
697 ff9c047c Iustin Pop
    python types.
698 ff9c047c Iustin Pop

699 ff9c047c Iustin Pop
    """
700 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
701 ff9c047c Iustin Pop
702 ff9c047c Iustin Pop
    for attr in "nics", "disks":
703 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
704 ff9c047c Iustin Pop
      if alist:
705 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
706 ff9c047c Iustin Pop
      else:
707 ff9c047c Iustin Pop
        nlist = []
708 ff9c047c Iustin Pop
      bo[attr] = nlist
709 ff9c047c Iustin Pop
    return bo
710 ff9c047c Iustin Pop
711 ff9c047c Iustin Pop
  @classmethod
712 ff9c047c Iustin Pop
  def FromDict(cls, val):
713 ff9c047c Iustin Pop
    """Custom function for instances.
714 ff9c047c Iustin Pop

715 ff9c047c Iustin Pop
    """
716 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
717 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
718 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
719 ff9c047c Iustin Pop
    return obj
720 ff9c047c Iustin Pop
721 a8083063 Iustin Pop
722 a8083063 Iustin Pop
class OS(ConfigObject):
723 a8083063 Iustin Pop
  """Config object representing an operating system."""
724 a8083063 Iustin Pop
  __slots__ = [
725 a8083063 Iustin Pop
    "name",
726 a8083063 Iustin Pop
    "path",
727 37482e7b Guido Trotter
    "status",
728 082a7f91 Guido Trotter
    "api_versions",
729 a8083063 Iustin Pop
    "create_script",
730 a8083063 Iustin Pop
    "export_script",
731 386b57af Iustin Pop
    "import_script",
732 386b57af Iustin Pop
    "rename_script",
733 a8083063 Iustin Pop
    ]
734 a8083063 Iustin Pop
735 d2c807e4 Guido Trotter
  @classmethod
736 d2c807e4 Guido Trotter
  def FromInvalidOS(cls, err):
737 d2c807e4 Guido Trotter
    """Create an OS from an InvalidOS error.
738 d2c807e4 Guido Trotter

739 d2c807e4 Guido Trotter
    This routine knows how to convert an InvalidOS error to an OS
740 d2c807e4 Guido Trotter
    object representing the broken OS with a meaningful error message.
741 d2c807e4 Guido Trotter

742 d2c807e4 Guido Trotter
    """
743 d2c807e4 Guido Trotter
    if not isinstance(err, errors.InvalidOS):
744 d2c807e4 Guido Trotter
      raise errors.ProgrammerError("Trying to initialize an OS from an"
745 d2c807e4 Guido Trotter
                                   " invalid object of type %s" % type(err))
746 d2c807e4 Guido Trotter
747 d2c807e4 Guido Trotter
    return cls(name=err.args[0], path=err.args[1], status=err.args[2])
748 d2c807e4 Guido Trotter
749 37482e7b Guido Trotter
  def __nonzero__(self):
750 37482e7b Guido Trotter
    return self.status == constants.OS_VALID_STATUS
751 37482e7b Guido Trotter
752 37482e7b Guido Trotter
  __bool__ = __nonzero__
753 a8083063 Iustin Pop
754 7c0d6283 Michael Hanselmann
755 ec29fe40 Iustin Pop
class Node(TaggableObject):
756 a8083063 Iustin Pop
  """Config object representing a node."""
757 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
758 ec29fe40 Iustin Pop
    "name",
759 ec29fe40 Iustin Pop
    "primary_ip",
760 ec29fe40 Iustin Pop
    "secondary_ip",
761 be1fa613 Iustin Pop
    "serial_no",
762 8b8b8b81 Iustin Pop
    "master_candidate",
763 fc0fe88c Iustin Pop
    "offline",
764 af64c0ea Iustin Pop
    "drained",
765 ec29fe40 Iustin Pop
    ]
766 a8083063 Iustin Pop
767 a8083063 Iustin Pop
768 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
769 a8083063 Iustin Pop
  """Config object representing the cluster."""
770 ec29fe40 Iustin Pop
  __slots__ = TaggableObject.__slots__ + [
771 a8083063 Iustin Pop
    "serial_no",
772 a8083063 Iustin Pop
    "rsahostkeypub",
773 a8083063 Iustin Pop
    "highest_used_port",
774 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
775 a8083063 Iustin Pop
    "mac_prefix",
776 a8083063 Iustin Pop
    "volume_group_name",
777 a8083063 Iustin Pop
    "default_bridge",
778 02691904 Alexander Schreiber
    "default_hypervisor",
779 f6bd6e98 Michael Hanselmann
    "master_node",
780 f6bd6e98 Michael Hanselmann
    "master_ip",
781 f6bd6e98 Michael Hanselmann
    "master_netdev",
782 f6bd6e98 Michael Hanselmann
    "cluster_name",
783 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
784 e69d05fd Iustin Pop
    "enabled_hypervisors",
785 5bf7b5cf Iustin Pop
    "hvparams",
786 5bf7b5cf Iustin Pop
    "beparams",
787 c8fcde47 Guido Trotter
    "nicparams",
788 4b7735f9 Iustin Pop
    "candidate_pool_size",
789 b86a6bcd Guido Trotter
    "modify_etc_hosts",
790 a8083063 Iustin Pop
    ]
791 a8083063 Iustin Pop
792 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
793 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
794 b86a6bcd Guido Trotter

795 b86a6bcd Guido Trotter
    """
796 c1b42c18 Guido Trotter
    if self.hvparams is None:
797 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
798 c1b42c18 Guido Trotter
    else:
799 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
800 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
801 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
802 c1b42c18 Guido Trotter
803 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
804 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
805 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
806 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
807 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
808 c8fcde47 Guido Trotter
    if migrate_default_bridge:
809 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
810 c8fcde47 Guido Trotter
        self.default_bridge
811 c1b42c18 Guido Trotter
812 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
813 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
814 b86a6bcd Guido Trotter
815 319856a9 Michael Hanselmann
  def ToDict(self):
816 319856a9 Michael Hanselmann
    """Custom function for cluster.
817 319856a9 Michael Hanselmann

818 319856a9 Michael Hanselmann
    """
819 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
820 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
821 319856a9 Michael Hanselmann
    return mydict
822 319856a9 Michael Hanselmann
823 319856a9 Michael Hanselmann
  @classmethod
824 319856a9 Michael Hanselmann
  def FromDict(cls, val):
825 319856a9 Michael Hanselmann
    """Custom function for cluster.
826 319856a9 Michael Hanselmann

827 319856a9 Michael Hanselmann
    """
828 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
829 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
830 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
831 319856a9 Michael Hanselmann
    return obj
832 319856a9 Michael Hanselmann
833 5bf7b5cf Iustin Pop
  def FillHV(self, instance):
834 5bf7b5cf Iustin Pop
    """Fill an instance's hvparams dict.
835 5bf7b5cf Iustin Pop

836 5bf7b5cf Iustin Pop
    @type instance: object
837 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
838 5bf7b5cf Iustin Pop
    @rtype: dict
839 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
840 5bf7b5cf Iustin Pop
        the cluster defaults
841 5bf7b5cf Iustin Pop

842 5bf7b5cf Iustin Pop
    """
843 abe609b2 Guido Trotter
    return FillDict(self.hvparams.get(instance.hypervisor, {}),
844 5bf7b5cf Iustin Pop
                         instance.hvparams)
845 5bf7b5cf Iustin Pop
846 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
847 5bf7b5cf Iustin Pop
    """Fill an instance's beparams dict.
848 5bf7b5cf Iustin Pop

849 5bf7b5cf Iustin Pop
    @type instance: object
850 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
851 5bf7b5cf Iustin Pop
    @rtype: dict
852 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
853 5bf7b5cf Iustin Pop
        the cluster defaults
854 5bf7b5cf Iustin Pop

855 5bf7b5cf Iustin Pop
    """
856 4ef7f423 Guido Trotter
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}),
857 4ef7f423 Guido Trotter
                          instance.beparams)
858 5bf7b5cf Iustin Pop
859 5c947f38 Iustin Pop
860 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
861 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
862 a8083063 Iustin Pop

863 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
864 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
865 a8083063 Iustin Pop
  buffer.
866 a8083063 Iustin Pop

867 a8083063 Iustin Pop
  """
868 a8083063 Iustin Pop
  def Dumps(self):
869 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
870 a8083063 Iustin Pop
    buf = StringIO()
871 a8083063 Iustin Pop
    self.write(buf)
872 a8083063 Iustin Pop
    return buf.getvalue()
873 a8083063 Iustin Pop
874 a8083063 Iustin Pop
  @staticmethod
875 a8083063 Iustin Pop
  def Loads(data):
876 a8083063 Iustin Pop
    """Load data from a string."""
877 a8083063 Iustin Pop
    buf = StringIO(data)
878 a8083063 Iustin Pop
    cfp = SerializableConfigParser()
879 a8083063 Iustin Pop
    cfp.readfp(buf)
880 a8083063 Iustin Pop
    return cfp