Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 5f06ce5e

History | View | Annotate | Download (47.5 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 6d33a6eb Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 0007f3ab Andrea Spadaccini
# pylint: disable=E0203,W0201,R0902
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 0007f3ab Andrea Spadaccini
# R0902: Allow instances of these objects to have more than 20 attributes
37 0007f3ab Andrea Spadaccini
38 a8083063 Iustin Pop
import ConfigParser
39 5c947f38 Iustin Pop
import re
40 5bf7b5cf Iustin Pop
import copy
41 e11a1b77 Adeodato Simo
import time
42 d5835922 Michael Hanselmann
from cStringIO import StringIO
43 a8083063 Iustin Pop
44 a8083063 Iustin Pop
from ganeti import errors
45 5c947f38 Iustin Pop
from ganeti import constants
46 0007f3ab Andrea Spadaccini
from ganeti import netutils
47 a8083063 Iustin Pop
48 f4c9af7a Guido Trotter
from socket import AF_INET
49 f4c9af7a Guido Trotter
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
52 24a3707f Guido Trotter
           "OS", "Node", "NodeGroup", "Cluster", "FillDict"]
53 a8083063 Iustin Pop
54 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
55 e1dcc53a Iustin Pop
_UUID = ["uuid"]
56 96acbc09 Michael Hanselmann
57 8d8d650c Michael Hanselmann
58 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
59 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
60 abe609b2 Guido Trotter

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

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

85 6e34b628 Guido Trotter
  @type target: dict of dicts
86 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
87 6e34b628 Guido Trotter
  @type defaults: dict
88 6e34b628 Guido Trotter
  @param defaults: default parameter values
89 6e34b628 Guido Trotter

90 6e34b628 Guido Trotter
  """
91 6e34b628 Guido Trotter
  if target is None:
92 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
93 6e34b628 Guido Trotter
  else:
94 6e34b628 Guido Trotter
    for group in target:
95 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
96 6e34b628 Guido Trotter
  return target
97 6e34b628 Guido Trotter
98 6e34b628 Guido Trotter
99 8c72ab2b Guido Trotter
def UpgradeBeParams(target):
100 8c72ab2b Guido Trotter
  """Update the be parameters dict to the new format.
101 8c72ab2b Guido Trotter

102 8c72ab2b Guido Trotter
  @type target: dict
103 8c72ab2b Guido Trotter
  @param target: "be" parameters dict
104 8c72ab2b Guido Trotter

105 8c72ab2b Guido Trotter
  """
106 8c72ab2b Guido Trotter
  if constants.BE_MEMORY in target:
107 8c72ab2b Guido Trotter
    memory = target[constants.BE_MEMORY]
108 8c72ab2b Guido Trotter
    target[constants.BE_MAXMEM] = memory
109 8c72ab2b Guido Trotter
    target[constants.BE_MINMEM] = memory
110 b2e233a5 Guido Trotter
    del target[constants.BE_MEMORY]
111 8c72ab2b Guido Trotter
112 8c72ab2b Guido Trotter
113 a8083063 Iustin Pop
class ConfigObject(object):
114 a8083063 Iustin Pop
  """A generic config object.
115 a8083063 Iustin Pop

116 a8083063 Iustin Pop
  It has the following properties:
117 a8083063 Iustin Pop

118 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
119 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
120 a8083063 Iustin Pop
      as None instead of raising an error
121 a8083063 Iustin Pop

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

125 a8083063 Iustin Pop
  """
126 a8083063 Iustin Pop
  __slots__ = []
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
  def __init__(self, **kwargs):
129 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
130 319856a9 Michael Hanselmann
      setattr(self, k, v)
131 a8083063 Iustin Pop
132 a8083063 Iustin Pop
  def __getattr__(self, name):
133 adf385c7 Iustin Pop
    if name not in self._all_slots():
134 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
135 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
136 a8083063 Iustin Pop
    return None
137 a8083063 Iustin Pop
138 a8083063 Iustin Pop
  def __setstate__(self, state):
139 adf385c7 Iustin Pop
    slots = self._all_slots()
140 a8083063 Iustin Pop
    for name in state:
141 adf385c7 Iustin Pop
      if name in slots:
142 a8083063 Iustin Pop
        setattr(self, name, state[name])
143 a8083063 Iustin Pop
144 adf385c7 Iustin Pop
  @classmethod
145 adf385c7 Iustin Pop
  def _all_slots(cls):
146 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
147 adf385c7 Iustin Pop

148 adf385c7 Iustin Pop
    """
149 adf385c7 Iustin Pop
    slots = []
150 adf385c7 Iustin Pop
    for parent in cls.__mro__:
151 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
152 adf385c7 Iustin Pop
    return slots
153 adf385c7 Iustin Pop
154 ff9c047c Iustin Pop
  def ToDict(self):
155 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
156 ff9c047c Iustin Pop

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

163 ff9c047c Iustin Pop
    """
164 4c14965f Guido Trotter
    result = {}
165 adf385c7 Iustin Pop
    for name in self._all_slots():
166 4c14965f Guido Trotter
      value = getattr(self, name, None)
167 4c14965f Guido Trotter
      if value is not None:
168 4c14965f Guido Trotter
        result[name] = value
169 4c14965f Guido Trotter
    return result
170 4c14965f Guido Trotter
171 4c14965f Guido Trotter
  __getstate__ = ToDict
172 ff9c047c Iustin Pop
173 ff9c047c Iustin Pop
  @classmethod
174 ff9c047c Iustin Pop
  def FromDict(cls, val):
175 ff9c047c Iustin Pop
    """Create an object from a dictionary.
176 ff9c047c Iustin Pop

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

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

185 ff9c047c Iustin Pop
    """
186 ff9c047c Iustin Pop
    if not isinstance(val, dict):
187 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
188 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
189 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
190 b459a848 Andrea Spadaccini
    obj = cls(**val_str) # pylint: disable=W0142
191 ff9c047c Iustin Pop
    return obj
192 ff9c047c Iustin Pop
193 ff9c047c Iustin Pop
  @staticmethod
194 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
195 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
196 ff9c047c Iustin Pop

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

201 ff9c047c Iustin Pop
    """
202 ff9c047c Iustin Pop
    if isinstance(container, dict):
203 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
204 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
205 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
206 ff9c047c Iustin Pop
    else:
207 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
208 ff9c047c Iustin Pop
                      type(container))
209 ff9c047c Iustin Pop
    return ret
210 ff9c047c Iustin Pop
211 ff9c047c Iustin Pop
  @staticmethod
212 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
213 ff9c047c Iustin Pop
    """Convert a container from standard python types.
214 ff9c047c Iustin Pop

215 ff9c047c Iustin Pop
    This method converts a container with standard python types to
216 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
217 ff9c047c Iustin Pop
    keys, only the values.
218 ff9c047c Iustin Pop

219 ff9c047c Iustin Pop
    """
220 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
221 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
222 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
223 fe25a79a Guido Trotter
    if source is None:
224 fe25a79a Guido Trotter
      source = c_type()
225 ff9c047c Iustin Pop
    if c_type is dict:
226 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
227 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
228 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
229 ff9c047c Iustin Pop
    else:
230 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
231 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
232 ff9c047c Iustin Pop
    return ret
233 ff9c047c Iustin Pop
234 e8d563f3 Iustin Pop
  def Copy(self):
235 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
236 e8d563f3 Iustin Pop

237 e8d563f3 Iustin Pop
    """
238 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
239 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
240 e8d563f3 Iustin Pop
    return clone_obj
241 e8d563f3 Iustin Pop
242 ff9c047c Iustin Pop
  def __repr__(self):
243 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
244 ff9c047c Iustin Pop
    return repr(self.ToDict())
245 ff9c047c Iustin Pop
246 560428be Guido Trotter
  def UpgradeConfig(self):
247 560428be Guido Trotter
    """Fill defaults for missing configuration values.
248 560428be Guido Trotter

249 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
250 90d726a8 Iustin Pop
    implementation will be object dependent.
251 560428be Guido Trotter

252 560428be Guido Trotter
    """
253 560428be Guido Trotter
    pass
254 560428be Guido Trotter
255 a8083063 Iustin Pop
256 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
257 5c947f38 Iustin Pop
  """An generic class supporting tags.
258 5c947f38 Iustin Pop

259 5c947f38 Iustin Pop
  """
260 154b9580 Balazs Lecz
  __slots__ = ["tags"]
261 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
262 2057f6c7 Iustin Pop
263 b5e5632e Iustin Pop
  @classmethod
264 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
265 5c947f38 Iustin Pop
    """Check if a tag is valid.
266 5c947f38 Iustin Pop

267 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
268 5c947f38 Iustin Pop
    function has no return value.
269 5c947f38 Iustin Pop

270 5c947f38 Iustin Pop
    """
271 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
272 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
273 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
274 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
275 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
276 5c947f38 Iustin Pop
    if not tag:
277 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
278 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
279 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
280 5c947f38 Iustin Pop
281 5c947f38 Iustin Pop
  def GetTags(self):
282 5c947f38 Iustin Pop
    """Return the tags list.
283 5c947f38 Iustin Pop

284 5c947f38 Iustin Pop
    """
285 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
286 5c947f38 Iustin Pop
    if tags is None:
287 5c947f38 Iustin Pop
      tags = self.tags = set()
288 5c947f38 Iustin Pop
    return tags
289 5c947f38 Iustin Pop
290 5c947f38 Iustin Pop
  def AddTag(self, tag):
291 5c947f38 Iustin Pop
    """Add a new tag.
292 5c947f38 Iustin Pop

293 5c947f38 Iustin Pop
    """
294 5c947f38 Iustin Pop
    self.ValidateTag(tag)
295 5c947f38 Iustin Pop
    tags = self.GetTags()
296 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
297 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
298 5c947f38 Iustin Pop
    self.GetTags().add(tag)
299 5c947f38 Iustin Pop
300 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
301 5c947f38 Iustin Pop
    """Remove a tag.
302 5c947f38 Iustin Pop

303 5c947f38 Iustin Pop
    """
304 5c947f38 Iustin Pop
    self.ValidateTag(tag)
305 5c947f38 Iustin Pop
    tags = self.GetTags()
306 5c947f38 Iustin Pop
    try:
307 5c947f38 Iustin Pop
      tags.remove(tag)
308 5c947f38 Iustin Pop
    except KeyError:
309 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
310 5c947f38 Iustin Pop
311 ff9c047c Iustin Pop
  def ToDict(self):
312 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
313 ff9c047c Iustin Pop

314 ff9c047c Iustin Pop
    This replaces the tags set with a list.
315 ff9c047c Iustin Pop

316 ff9c047c Iustin Pop
    """
317 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
318 ff9c047c Iustin Pop
319 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
320 ff9c047c Iustin Pop
    if isinstance(tags, set):
321 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
322 ff9c047c Iustin Pop
    return bo
323 ff9c047c Iustin Pop
324 ff9c047c Iustin Pop
  @classmethod
325 ff9c047c Iustin Pop
  def FromDict(cls, val):
326 ff9c047c Iustin Pop
    """Custom function for instances.
327 ff9c047c Iustin Pop

328 ff9c047c Iustin Pop
    """
329 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
330 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
331 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
332 ff9c047c Iustin Pop
    return obj
333 ff9c047c Iustin Pop
334 5c947f38 Iustin Pop
335 061af273 Andrea Spadaccini
class MasterNetworkParameters(ConfigObject):
336 061af273 Andrea Spadaccini
  """Network configuration parameters for the master
337 061af273 Andrea Spadaccini

338 061af273 Andrea Spadaccini
  @ivar name: master name
339 061af273 Andrea Spadaccini
  @ivar ip: master IP
340 061af273 Andrea Spadaccini
  @ivar netmask: master netmask
341 061af273 Andrea Spadaccini
  @ivar netdev: master network device
342 061af273 Andrea Spadaccini
  @ivar ip_family: master IP family
343 061af273 Andrea Spadaccini

344 061af273 Andrea Spadaccini
  """
345 061af273 Andrea Spadaccini
  __slots__ = [
346 061af273 Andrea Spadaccini
    "name",
347 061af273 Andrea Spadaccini
    "ip",
348 061af273 Andrea Spadaccini
    "netmask",
349 061af273 Andrea Spadaccini
    "netdev",
350 061af273 Andrea Spadaccini
    "ip_family"
351 061af273 Andrea Spadaccini
    ]
352 061af273 Andrea Spadaccini
353 061af273 Andrea Spadaccini
354 a8083063 Iustin Pop
class ConfigData(ConfigObject):
355 a8083063 Iustin Pop
  """Top-level config object."""
356 3df43542 Guido Trotter
  __slots__ = [
357 3df43542 Guido Trotter
    "version",
358 3df43542 Guido Trotter
    "cluster",
359 3df43542 Guido Trotter
    "nodes",
360 3df43542 Guido Trotter
    "nodegroups",
361 3df43542 Guido Trotter
    "instances",
362 3df43542 Guido Trotter
    "serial_no",
363 3df43542 Guido Trotter
    ] + _TIMESTAMPS
364 a8083063 Iustin Pop
365 ff9c047c Iustin Pop
  def ToDict(self):
366 ff9c047c Iustin Pop
    """Custom function for top-level config data.
367 ff9c047c Iustin Pop

368 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
369 ff9c047c Iustin Pop
    with standard python types.
370 ff9c047c Iustin Pop

371 ff9c047c Iustin Pop
    """
372 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
373 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
374 3df43542 Guido Trotter
    for key in "nodes", "instances", "nodegroups":
375 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
376 ff9c047c Iustin Pop
377 ff9c047c Iustin Pop
    return mydict
378 ff9c047c Iustin Pop
379 ff9c047c Iustin Pop
  @classmethod
380 ff9c047c Iustin Pop
  def FromDict(cls, val):
381 ff9c047c Iustin Pop
    """Custom function for top-level config data
382 ff9c047c Iustin Pop

383 ff9c047c Iustin Pop
    """
384 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
385 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
386 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
387 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
388 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
389 ff9c047c Iustin Pop
    return obj
390 ff9c047c Iustin Pop
391 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
392 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
393 51cb1581 Luca Bigliardi

394 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
395 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
396 51cb1581 Luca Bigliardi
    @rtype: boolean
397 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
398 51cb1581 Luca Bigliardi

399 51cb1581 Luca Bigliardi
    """
400 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
401 51cb1581 Luca Bigliardi
      for disk in instance.disks:
402 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
403 51cb1581 Luca Bigliardi
          return True
404 51cb1581 Luca Bigliardi
    return False
405 51cb1581 Luca Bigliardi
406 90d726a8 Iustin Pop
  def UpgradeConfig(self):
407 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
408 90d726a8 Iustin Pop

409 90d726a8 Iustin Pop
    """
410 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
411 90d726a8 Iustin Pop
    for node in self.nodes.values():
412 90d726a8 Iustin Pop
      node.UpgradeConfig()
413 90d726a8 Iustin Pop
    for instance in self.instances.values():
414 90d726a8 Iustin Pop
      instance.UpgradeConfig()
415 3df43542 Guido Trotter
    if self.nodegroups is None:
416 3df43542 Guido Trotter
      self.nodegroups = {}
417 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
418 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
419 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
420 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
421 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
422 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
423 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
424 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
425 90d726a8 Iustin Pop
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
class NIC(ConfigObject):
428 a8083063 Iustin Pop
  """Config object representing a network card."""
429 1177d70e Guido Trotter
  __slots__ = ["mac", "ip", "nicparams"]
430 a8083063 Iustin Pop
431 255e19d4 Guido Trotter
  @classmethod
432 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
433 255e19d4 Guido Trotter
    """Check the given parameters for validity.
434 255e19d4 Guido Trotter

435 255e19d4 Guido Trotter
    @type nicparams:  dict
436 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
437 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
438 255e19d4 Guido Trotter

439 255e19d4 Guido Trotter
    """
440 e8448672 Agata Murawska
    if (nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES and
441 e8448672 Agata Murawska
        nicparams[constants.NIC_MODE] != constants.VALUE_AUTO):
442 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
443 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
444 255e19d4 Guido Trotter
445 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
446 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
447 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
448 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
449 255e19d4 Guido Trotter
450 a8083063 Iustin Pop
451 a8083063 Iustin Pop
class Disk(ConfigObject):
452 a8083063 Iustin Pop
  """Config object representing a block device."""
453 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
454 08db7c5c Iustin Pop
               "children", "iv_name", "size", "mode"]
455 a8083063 Iustin Pop
456 a8083063 Iustin Pop
  def CreateOnSecondary(self):
457 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
458 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
459 a8083063 Iustin Pop
460 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
461 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
462 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
463 a8083063 Iustin Pop
464 a8083063 Iustin Pop
  def OpenOnSecondary(self):
465 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
466 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
467 a8083063 Iustin Pop
468 222f2dd5 Iustin Pop
  def StaticDevPath(self):
469 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
470 222f2dd5 Iustin Pop

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

475 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
476 e51db2a6 Iustin Pop
        should check that it is a valid path.
477 e51db2a6 Iustin Pop

478 222f2dd5 Iustin Pop
    """
479 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
480 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
481 b6135bbc Apollon Oikonomopoulos
    elif self.dev_type == constants.LD_BLOCKDEV:
482 b6135bbc Apollon Oikonomopoulos
      return self.logical_id[1]
483 222f2dd5 Iustin Pop
    return None
484 222f2dd5 Iustin Pop
485 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
486 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
487 fc1dc9d7 Iustin Pop

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

492 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
493 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
494 fc1dc9d7 Iustin Pop
    -1.
495 fc1dc9d7 Iustin Pop

496 fc1dc9d7 Iustin Pop
    """
497 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
498 fc1dc9d7 Iustin Pop
      return 0
499 fc1dc9d7 Iustin Pop
    return -1
500 fc1dc9d7 Iustin Pop
501 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
502 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
503 51cb1581 Luca Bigliardi

504 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
505 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
506 51cb1581 Luca Bigliardi
    @rtype: boolean
507 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
508 51cb1581 Luca Bigliardi

509 51cb1581 Luca Bigliardi
    """
510 51cb1581 Luca Bigliardi
    if self.children:
511 51cb1581 Luca Bigliardi
      for child in self.children:
512 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
513 51cb1581 Luca Bigliardi
          return True
514 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
515 51cb1581 Luca Bigliardi
516 a8083063 Iustin Pop
  def GetNodes(self, node):
517 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
518 a8083063 Iustin Pop

519 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
520 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
521 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
522 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
523 a8083063 Iustin Pop

524 a8083063 Iustin Pop
    """
525 b6135bbc Apollon Oikonomopoulos
    if self.dev_type in [constants.LD_LV, constants.LD_FILE,
526 b6135bbc Apollon Oikonomopoulos
                         constants.LD_BLOCKDEV]:
527 a8083063 Iustin Pop
      result = [node]
528 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
529 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
530 a8083063 Iustin Pop
      if node not in result:
531 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
532 a8083063 Iustin Pop
    else:
533 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
534 a8083063 Iustin Pop
    return result
535 a8083063 Iustin Pop
536 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
537 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
538 a8083063 Iustin Pop

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

545 a8083063 Iustin Pop
    """
546 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
547 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
548 a8083063 Iustin Pop
    if not self.children:
549 a8083063 Iustin Pop
      # leaf device
550 a8083063 Iustin Pop
      return result
551 a8083063 Iustin Pop
    for node in my_nodes:
552 a8083063 Iustin Pop
      for child in self.children:
553 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
554 a8083063 Iustin Pop
        if len(child_result) == 1:
555 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
556 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
557 a8083063 Iustin Pop
          # own entry for this node describes it completely
558 a8083063 Iustin Pop
          continue
559 a8083063 Iustin Pop
        else:
560 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
561 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
562 a8083063 Iustin Pop
          # one of its descendants
563 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
564 a8083063 Iustin Pop
            if subnode not in my_nodes:
565 a8083063 Iustin Pop
              result.append((subnode, subdisk))
566 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
567 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
568 a8083063 Iustin Pop
            # be different)
569 a8083063 Iustin Pop
    return result
570 a8083063 Iustin Pop
571 6d33a6eb Iustin Pop
  def ComputeGrowth(self, amount):
572 6d33a6eb Iustin Pop
    """Compute the per-VG growth requirements.
573 6d33a6eb Iustin Pop

574 6d33a6eb Iustin Pop
    This only works for VG-based disks.
575 6d33a6eb Iustin Pop

576 6d33a6eb Iustin Pop
    @type amount: integer
577 6d33a6eb Iustin Pop
    @param amount: the desired increase in (user-visible) disk space
578 6d33a6eb Iustin Pop
    @rtype: dict
579 6d33a6eb Iustin Pop
    @return: a dictionary of volume-groups and the required size
580 6d33a6eb Iustin Pop

581 6d33a6eb Iustin Pop
    """
582 6d33a6eb Iustin Pop
    if self.dev_type == constants.LD_LV:
583 6d33a6eb Iustin Pop
      return {self.logical_id[0]: amount}
584 6d33a6eb Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
585 6d33a6eb Iustin Pop
      if self.children:
586 6d33a6eb Iustin Pop
        return self.children[0].ComputeGrowth(amount)
587 6d33a6eb Iustin Pop
      else:
588 6d33a6eb Iustin Pop
        return {}
589 6d33a6eb Iustin Pop
    else:
590 6d33a6eb Iustin Pop
      # Other disk types do not require VG space
591 6d33a6eb Iustin Pop
      return {}
592 6d33a6eb Iustin Pop
593 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
594 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
595 acec9d51 Iustin Pop

596 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
597 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
598 acec9d51 Iustin Pop
    actual algorithms from bdev.
599 acec9d51 Iustin Pop

600 acec9d51 Iustin Pop
    """
601 4b97f902 Apollon Oikonomopoulos
    if self.dev_type in (constants.LD_LV, constants.LD_FILE):
602 acec9d51 Iustin Pop
      self.size += amount
603 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
604 acec9d51 Iustin Pop
      if self.children:
605 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
606 acec9d51 Iustin Pop
      self.size += amount
607 acec9d51 Iustin Pop
    else:
608 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
609 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
610 acec9d51 Iustin Pop
611 a805ec18 Iustin Pop
  def UnsetSize(self):
612 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
613 a805ec18 Iustin Pop

614 a805ec18 Iustin Pop
    """
615 a805ec18 Iustin Pop
    if self.children:
616 a805ec18 Iustin Pop
      for child in self.children:
617 a805ec18 Iustin Pop
        child.UnsetSize()
618 a805ec18 Iustin Pop
    self.size = 0
619 a805ec18 Iustin Pop
620 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
621 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
622 0402302c Iustin Pop

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

625 0402302c Iustin Pop
    The routine descends down and updates its children also, because
626 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
627 0402302c Iustin Pop
    node.
628 0402302c Iustin Pop

629 0402302c Iustin Pop
    Arguments:
630 0402302c Iustin Pop
      - target_node: the node we wish to configure for
631 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
632 0402302c Iustin Pop

633 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
634 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
635 0402302c Iustin Pop
    in the disk tree.
636 0402302c Iustin Pop

637 0402302c Iustin Pop
    """
638 0402302c Iustin Pop
    if self.children:
639 0402302c Iustin Pop
      for child in self.children:
640 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
641 0402302c Iustin Pop
642 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
643 0402302c Iustin Pop
      return
644 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
645 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
646 0402302c Iustin Pop
      if target_node not in (pnode, snode):
647 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
648 0402302c Iustin Pop
                                        target_node)
649 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
650 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
651 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
652 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
653 0402302c Iustin Pop
                                        " for %s" % str(self))
654 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
655 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
656 0402302c Iustin Pop
      if pnode == target_node:
657 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
658 0402302c Iustin Pop
      else: # it must be secondary, we tested above
659 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
660 0402302c Iustin Pop
    else:
661 0402302c Iustin Pop
      self.physical_id = self.logical_id
662 0402302c Iustin Pop
    return
663 0402302c Iustin Pop
664 ff9c047c Iustin Pop
  def ToDict(self):
665 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
666 ff9c047c Iustin Pop

667 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
668 ff9c047c Iustin Pop
    standard python types.
669 ff9c047c Iustin Pop

670 ff9c047c Iustin Pop
    """
671 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
672 ff9c047c Iustin Pop
673 ff9c047c Iustin Pop
    for attr in ("children",):
674 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
675 ff9c047c Iustin Pop
      if alist:
676 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
677 ff9c047c Iustin Pop
    return bo
678 ff9c047c Iustin Pop
679 ff9c047c Iustin Pop
  @classmethod
680 ff9c047c Iustin Pop
  def FromDict(cls, val):
681 ff9c047c Iustin Pop
    """Custom function for Disks
682 ff9c047c Iustin Pop

683 ff9c047c Iustin Pop
    """
684 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
685 ff9c047c Iustin Pop
    if obj.children:
686 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
687 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
688 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
689 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
690 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
691 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
692 f9518d38 Iustin Pop
      # we need a tuple of length six here
693 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
694 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
695 ff9c047c Iustin Pop
    return obj
696 ff9c047c Iustin Pop
697 65a15336 Iustin Pop
  def __str__(self):
698 65a15336 Iustin Pop
    """Custom str() formatter for disks.
699 65a15336 Iustin Pop

700 65a15336 Iustin Pop
    """
701 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
702 e687ec01 Michael Hanselmann
      val = "<LogicalVolume(/dev/%s/%s" % self.logical_id
703 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
704 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
705 00fb8246 Michael Hanselmann
      val = "<DRBD8("
706 073ca59e Iustin Pop
      if self.physical_id is None:
707 073ca59e Iustin Pop
        phy = "unconfigured"
708 073ca59e Iustin Pop
      else:
709 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
710 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
711 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
712 073ca59e Iustin Pop
713 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
714 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
715 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
716 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
717 65a15336 Iustin Pop
      else:
718 65a15336 Iustin Pop
        val += "no local storage"
719 65a15336 Iustin Pop
    else:
720 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
721 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
722 65a15336 Iustin Pop
    if self.iv_name is None:
723 65a15336 Iustin Pop
      val += ", not visible"
724 65a15336 Iustin Pop
    else:
725 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
726 fd965830 Iustin Pop
    if isinstance(self.size, int):
727 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
728 fd965830 Iustin Pop
    else:
729 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
730 65a15336 Iustin Pop
    return val
731 65a15336 Iustin Pop
732 332d0e37 Iustin Pop
  def Verify(self):
733 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
734 332d0e37 Iustin Pop

735 332d0e37 Iustin Pop
    """
736 7c4d6c7b Michael Hanselmann
    all_errors = []
737 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
738 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
739 7c4d6c7b Michael Hanselmann
    return all_errors
740 332d0e37 Iustin Pop
741 90d726a8 Iustin Pop
  def UpgradeConfig(self):
742 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
743 90d726a8 Iustin Pop

744 90d726a8 Iustin Pop
    """
745 90d726a8 Iustin Pop
    if self.children:
746 90d726a8 Iustin Pop
      for child in self.children:
747 90d726a8 Iustin Pop
        child.UpgradeConfig()
748 90d726a8 Iustin Pop
    # add here config upgrade for this disk
749 90d726a8 Iustin Pop
750 a8083063 Iustin Pop
751 ec29fe40 Iustin Pop
class Instance(TaggableObject):
752 a8083063 Iustin Pop
  """Config object representing an instance."""
753 154b9580 Balazs Lecz
  __slots__ = [
754 a8083063 Iustin Pop
    "name",
755 a8083063 Iustin Pop
    "primary_node",
756 a8083063 Iustin Pop
    "os",
757 e69d05fd Iustin Pop
    "hypervisor",
758 5bf7b5cf Iustin Pop
    "hvparams",
759 5bf7b5cf Iustin Pop
    "beparams",
760 1bdcbbab Iustin Pop
    "osparams",
761 9ca8a7c5 Agata Murawska
    "admin_state",
762 a8083063 Iustin Pop
    "nics",
763 a8083063 Iustin Pop
    "disks",
764 a8083063 Iustin Pop
    "disk_template",
765 58acb49d Alexander Schreiber
    "network_port",
766 be1fa613 Iustin Pop
    "serial_no",
767 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
768 a8083063 Iustin Pop
769 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
770 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
771 a8083063 Iustin Pop

772 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
773 cfcc5c6d Iustin Pop

774 cfcc5c6d Iustin Pop
    """
775 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
776 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
777 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
778 cfcc5c6d Iustin Pop
779 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
780 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
781 cfcc5c6d Iustin Pop
782 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
783 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
784 cfcc5c6d Iustin Pop

785 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
786 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
787 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
788 a8083063 Iustin Pop
    dynamically.
789 a8083063 Iustin Pop

790 a8083063 Iustin Pop
    """
791 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
792 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
793 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
794 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
795 cfcc5c6d Iustin Pop
        nodes.add(nodea)
796 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
797 a8083063 Iustin Pop
      if device.children:
798 a8083063 Iustin Pop
        for child in device.children:
799 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
800 a8083063 Iustin Pop
801 cfcc5c6d Iustin Pop
    all_nodes = set()
802 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
803 a8083063 Iustin Pop
    for device in self.disks:
804 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
805 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
806 a8083063 Iustin Pop
807 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
808 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
809 a8083063 Iustin Pop
810 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
811 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
812 a8083063 Iustin Pop

813 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
814 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
815 a8083063 Iustin Pop

816 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
817 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
818 a8083063 Iustin Pop

819 84d7e26b Dmitry Chernyak
    @return: None if lvmap arg is given, otherwise, a dictionary of
820 84d7e26b Dmitry Chernyak
        the form { 'nodename' : ['volume1', 'volume2', ...], ... };
821 84d7e26b Dmitry Chernyak
        volumeN is of the form "vg_name/lv_name", compatible with
822 84d7e26b Dmitry Chernyak
        GetVolumeList()
823 a8083063 Iustin Pop

824 a8083063 Iustin Pop
    """
825 a8083063 Iustin Pop
    if node == None:
826 a8083063 Iustin Pop
      node = self.primary_node
827 a8083063 Iustin Pop
828 a8083063 Iustin Pop
    if lvmap is None:
829 e687ec01 Michael Hanselmann
      lvmap = {
830 e687ec01 Michael Hanselmann
        node: [],
831 e687ec01 Michael Hanselmann
        }
832 a8083063 Iustin Pop
      ret = lvmap
833 a8083063 Iustin Pop
    else:
834 a8083063 Iustin Pop
      if not node in lvmap:
835 a8083063 Iustin Pop
        lvmap[node] = []
836 a8083063 Iustin Pop
      ret = None
837 a8083063 Iustin Pop
838 a8083063 Iustin Pop
    if not devs:
839 a8083063 Iustin Pop
      devs = self.disks
840 a8083063 Iustin Pop
841 a8083063 Iustin Pop
    for dev in devs:
842 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
843 e687ec01 Michael Hanselmann
        lvmap[node].append(dev.logical_id[0] + "/" + dev.logical_id[1])
844 a8083063 Iustin Pop
845 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
846 a8083063 Iustin Pop
        if dev.children:
847 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
848 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
849 a8083063 Iustin Pop
850 a8083063 Iustin Pop
      elif dev.children:
851 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
852 a8083063 Iustin Pop
853 a8083063 Iustin Pop
    return ret
854 a8083063 Iustin Pop
855 ad24e046 Iustin Pop
  def FindDisk(self, idx):
856 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
857 644eeef9 Iustin Pop

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

860 ad24e046 Iustin Pop
    @type idx: int
861 ad24e046 Iustin Pop
    @param idx: the disk index
862 ad24e046 Iustin Pop
    @rtype: L{Disk}
863 ad24e046 Iustin Pop
    @return: the corresponding disk
864 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
865 644eeef9 Iustin Pop

866 ad24e046 Iustin Pop
    """
867 ad24e046 Iustin Pop
    try:
868 ad24e046 Iustin Pop
      idx = int(idx)
869 ad24e046 Iustin Pop
      return self.disks[idx]
870 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
871 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
872 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
873 ad24e046 Iustin Pop
    except IndexError:
874 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
875 daa55b04 Michael Hanselmann
                                 " 0 to %d" % (idx, len(self.disks) - 1),
876 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
877 644eeef9 Iustin Pop
878 ff9c047c Iustin Pop
  def ToDict(self):
879 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
880 ff9c047c Iustin Pop

881 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
882 ff9c047c Iustin Pop
    python types.
883 ff9c047c Iustin Pop

884 ff9c047c Iustin Pop
    """
885 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
886 ff9c047c Iustin Pop
887 ff9c047c Iustin Pop
    for attr in "nics", "disks":
888 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
889 ff9c047c Iustin Pop
      if alist:
890 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
891 ff9c047c Iustin Pop
      else:
892 ff9c047c Iustin Pop
        nlist = []
893 ff9c047c Iustin Pop
      bo[attr] = nlist
894 ff9c047c Iustin Pop
    return bo
895 ff9c047c Iustin Pop
896 ff9c047c Iustin Pop
  @classmethod
897 ff9c047c Iustin Pop
  def FromDict(cls, val):
898 ff9c047c Iustin Pop
    """Custom function for instances.
899 ff9c047c Iustin Pop

900 ff9c047c Iustin Pop
    """
901 9ca8a7c5 Agata Murawska
    if "admin_state" not in val:
902 9ca8a7c5 Agata Murawska
      if val.get("admin_up", False):
903 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_UP
904 9ca8a7c5 Agata Murawska
      else:
905 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_DOWN
906 9ca8a7c5 Agata Murawska
    if "admin_up" in val:
907 9ca8a7c5 Agata Murawska
      del val["admin_up"]
908 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
909 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
910 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
911 ff9c047c Iustin Pop
    return obj
912 ff9c047c Iustin Pop
913 90d726a8 Iustin Pop
  def UpgradeConfig(self):
914 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
915 90d726a8 Iustin Pop

916 90d726a8 Iustin Pop
    """
917 90d726a8 Iustin Pop
    for nic in self.nics:
918 90d726a8 Iustin Pop
      nic.UpgradeConfig()
919 90d726a8 Iustin Pop
    for disk in self.disks:
920 90d726a8 Iustin Pop
      disk.UpgradeConfig()
921 7736a5f2 Iustin Pop
    if self.hvparams:
922 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
923 7736a5f2 Iustin Pop
        try:
924 7736a5f2 Iustin Pop
          del self.hvparams[key]
925 7736a5f2 Iustin Pop
        except KeyError:
926 7736a5f2 Iustin Pop
          pass
927 1bdcbbab Iustin Pop
    if self.osparams is None:
928 1bdcbbab Iustin Pop
      self.osparams = {}
929 8c72ab2b Guido Trotter
    UpgradeBeParams(self.beparams)
930 90d726a8 Iustin Pop
931 a8083063 Iustin Pop
932 a8083063 Iustin Pop
class OS(ConfigObject):
933 b41b3516 Iustin Pop
  """Config object representing an operating system.
934 b41b3516 Iustin Pop

935 b41b3516 Iustin Pop
  @type supported_parameters: list
936 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
937 b41b3516 Iustin Pop
      containing the supported parameters by this OS
938 b41b3516 Iustin Pop

939 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
940 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
941 870dc44c Iustin Pop

942 b41b3516 Iustin Pop
  """
943 a8083063 Iustin Pop
  __slots__ = [
944 a8083063 Iustin Pop
    "name",
945 a8083063 Iustin Pop
    "path",
946 082a7f91 Guido Trotter
    "api_versions",
947 a8083063 Iustin Pop
    "create_script",
948 a8083063 Iustin Pop
    "export_script",
949 386b57af Iustin Pop
    "import_script",
950 386b57af Iustin Pop
    "rename_script",
951 b41b3516 Iustin Pop
    "verify_script",
952 6d79896b Guido Trotter
    "supported_variants",
953 b41b3516 Iustin Pop
    "supported_parameters",
954 a8083063 Iustin Pop
    ]
955 a8083063 Iustin Pop
956 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
957 870dc44c Iustin Pop
958 870dc44c Iustin Pop
  @classmethod
959 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
960 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
961 870dc44c Iustin Pop

962 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
963 870dc44c Iustin Pop
    @rtype: list
964 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
965 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
966 870dc44c Iustin Pop

967 870dc44c Iustin Pop
    """
968 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
969 870dc44c Iustin Pop
    if len(nv) == 1:
970 870dc44c Iustin Pop
      nv.append("")
971 870dc44c Iustin Pop
    return nv
972 870dc44c Iustin Pop
973 870dc44c Iustin Pop
  @classmethod
974 870dc44c Iustin Pop
  def GetName(cls, name):
975 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
976 870dc44c Iustin Pop

977 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
978 870dc44c Iustin Pop

979 870dc44c Iustin Pop
    """
980 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
981 870dc44c Iustin Pop
982 870dc44c Iustin Pop
  @classmethod
983 870dc44c Iustin Pop
  def GetVariant(cls, name):
984 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
985 870dc44c Iustin Pop

986 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
987 870dc44c Iustin Pop

988 870dc44c Iustin Pop
    """
989 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
990 870dc44c Iustin Pop
991 7c0d6283 Michael Hanselmann
992 5f06ce5e Michael Hanselmann
class NodeHvState(ConfigObject):
993 5f06ce5e Michael Hanselmann
  """Hypvervisor state on a node.
994 5f06ce5e Michael Hanselmann

995 5f06ce5e Michael Hanselmann
  @ivar mem_total: Total amount of memory
996 5f06ce5e Michael Hanselmann
  @ivar mem_node: Memory used by, or reserved for, the node itself (not always
997 5f06ce5e Michael Hanselmann
    available)
998 5f06ce5e Michael Hanselmann
  @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation
999 5f06ce5e Michael Hanselmann
    rounding
1000 5f06ce5e Michael Hanselmann
  @ivar mem_inst: Memory used by instances living on node
1001 5f06ce5e Michael Hanselmann
  @ivar cpu_total: Total node CPU core count
1002 5f06ce5e Michael Hanselmann
  @ivar cpu_node: Number of CPU cores reserved for the node itself
1003 5f06ce5e Michael Hanselmann

1004 5f06ce5e Michael Hanselmann
  """
1005 5f06ce5e Michael Hanselmann
  __slots__ = [
1006 5f06ce5e Michael Hanselmann
    "mem_total",
1007 5f06ce5e Michael Hanselmann
    "mem_node",
1008 5f06ce5e Michael Hanselmann
    "mem_hv",
1009 5f06ce5e Michael Hanselmann
    "mem_inst",
1010 5f06ce5e Michael Hanselmann
    "cpu_total",
1011 5f06ce5e Michael Hanselmann
    "cpu_node",
1012 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1013 5f06ce5e Michael Hanselmann
1014 5f06ce5e Michael Hanselmann
1015 5f06ce5e Michael Hanselmann
class NodeDiskState(ConfigObject):
1016 5f06ce5e Michael Hanselmann
  """Disk state on a node.
1017 5f06ce5e Michael Hanselmann

1018 5f06ce5e Michael Hanselmann
  """
1019 5f06ce5e Michael Hanselmann
  __slots__ = [
1020 5f06ce5e Michael Hanselmann
    "total",
1021 5f06ce5e Michael Hanselmann
    "reserved",
1022 5f06ce5e Michael Hanselmann
    "overhead",
1023 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1024 5f06ce5e Michael Hanselmann
1025 5f06ce5e Michael Hanselmann
1026 ec29fe40 Iustin Pop
class Node(TaggableObject):
1027 634d30f4 Michael Hanselmann
  """Config object representing a node.
1028 634d30f4 Michael Hanselmann

1029 634d30f4 Michael Hanselmann
  @ivar hv_state: Hypervisor state (e.g. number of CPUs)
1030 634d30f4 Michael Hanselmann
  @ivar hv_state_static: Hypervisor state overriden by user
1031 634d30f4 Michael Hanselmann
  @ivar disk_state: Disk state (e.g. free space)
1032 634d30f4 Michael Hanselmann
  @ivar disk_state_static: Disk state overriden by user
1033 634d30f4 Michael Hanselmann

1034 634d30f4 Michael Hanselmann
  """
1035 154b9580 Balazs Lecz
  __slots__ = [
1036 ec29fe40 Iustin Pop
    "name",
1037 ec29fe40 Iustin Pop
    "primary_ip",
1038 ec29fe40 Iustin Pop
    "secondary_ip",
1039 be1fa613 Iustin Pop
    "serial_no",
1040 8b8b8b81 Iustin Pop
    "master_candidate",
1041 fc0fe88c Iustin Pop
    "offline",
1042 af64c0ea Iustin Pop
    "drained",
1043 f936c153 Iustin Pop
    "group",
1044 490acd18 Iustin Pop
    "master_capable",
1045 490acd18 Iustin Pop
    "vm_capable",
1046 095e71aa Renรฉ Nussbaumer
    "ndparams",
1047 25124d4a Renรฉ Nussbaumer
    "powered",
1048 5b49ed09 Renรฉ Nussbaumer
    "hv_state",
1049 634d30f4 Michael Hanselmann
    "hv_state_static",
1050 5b49ed09 Renรฉ Nussbaumer
    "disk_state",
1051 634d30f4 Michael Hanselmann
    "disk_state_static",
1052 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1053 a8083063 Iustin Pop
1054 490acd18 Iustin Pop
  def UpgradeConfig(self):
1055 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
1056 490acd18 Iustin Pop

1057 490acd18 Iustin Pop
    """
1058 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1059 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
1060 490acd18 Iustin Pop
    if self.master_capable is None:
1061 490acd18 Iustin Pop
      self.master_capable = True
1062 490acd18 Iustin Pop
1063 490acd18 Iustin Pop
    if self.vm_capable is None:
1064 490acd18 Iustin Pop
      self.vm_capable = True
1065 490acd18 Iustin Pop
1066 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1067 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1068 095e71aa Renรฉ Nussbaumer
1069 25124d4a Renรฉ Nussbaumer
    if self.powered is None:
1070 25124d4a Renรฉ Nussbaumer
      self.powered = True
1071 25124d4a Renรฉ Nussbaumer
1072 5f06ce5e Michael Hanselmann
  def ToDict(self):
1073 5f06ce5e Michael Hanselmann
    """Custom function for serializing.
1074 5f06ce5e Michael Hanselmann

1075 5f06ce5e Michael Hanselmann
    """
1076 5f06ce5e Michael Hanselmann
    data = super(Node, self).ToDict()
1077 5f06ce5e Michael Hanselmann
1078 5f06ce5e Michael Hanselmann
    hv_state = data.get("hv_state", None)
1079 5f06ce5e Michael Hanselmann
    if hv_state is not None:
1080 5f06ce5e Michael Hanselmann
      data["hv_state"] = self._ContainerToDicts(hv_state)
1081 5f06ce5e Michael Hanselmann
1082 5f06ce5e Michael Hanselmann
    disk_state = data.get("disk_state", None)
1083 5f06ce5e Michael Hanselmann
    if disk_state is not None:
1084 5f06ce5e Michael Hanselmann
      data["disk_state"] = \
1085 5f06ce5e Michael Hanselmann
        dict((key, self._ContainerToDicts(value))
1086 5f06ce5e Michael Hanselmann
             for (key, value) in disk_state.items())
1087 5f06ce5e Michael Hanselmann
1088 5f06ce5e Michael Hanselmann
    return data
1089 5f06ce5e Michael Hanselmann
1090 5f06ce5e Michael Hanselmann
  @classmethod
1091 5f06ce5e Michael Hanselmann
  def FromDict(cls, val):
1092 5f06ce5e Michael Hanselmann
    """Custom function for deserializing.
1093 5f06ce5e Michael Hanselmann

1094 5f06ce5e Michael Hanselmann
    """
1095 5f06ce5e Michael Hanselmann
    obj = super(Node, cls).FromDict(val)
1096 5f06ce5e Michael Hanselmann
1097 5f06ce5e Michael Hanselmann
    if obj.hv_state is not None:
1098 5f06ce5e Michael Hanselmann
      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1099 5f06ce5e Michael Hanselmann
1100 5f06ce5e Michael Hanselmann
    if obj.disk_state is not None:
1101 5f06ce5e Michael Hanselmann
      obj.disk_state = \
1102 5f06ce5e Michael Hanselmann
        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
1103 5f06ce5e Michael Hanselmann
             for (key, value) in obj.disk_state.items())
1104 5f06ce5e Michael Hanselmann
1105 5f06ce5e Michael Hanselmann
    return obj
1106 5f06ce5e Michael Hanselmann
1107 a8083063 Iustin Pop
1108 1ffd2673 Michael Hanselmann
class NodeGroup(TaggableObject):
1109 24a3707f Guido Trotter
  """Config object representing a node group."""
1110 24a3707f Guido Trotter
  __slots__ = [
1111 24a3707f Guido Trotter
    "name",
1112 24a3707f Guido Trotter
    "members",
1113 095e71aa Renรฉ Nussbaumer
    "ndparams",
1114 e11a1b77 Adeodato Simo
    "serial_no",
1115 90e99856 Adeodato Simo
    "alloc_policy",
1116 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
1117 24a3707f Guido Trotter
1118 24a3707f Guido Trotter
  def ToDict(self):
1119 24a3707f Guido Trotter
    """Custom function for nodegroup.
1120 24a3707f Guido Trotter

1121 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1122 c60abd62 Guido Trotter
    in memory.
1123 24a3707f Guido Trotter

1124 24a3707f Guido Trotter
    """
1125 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
1126 24a3707f Guido Trotter
    del mydict["members"]
1127 24a3707f Guido Trotter
    return mydict
1128 24a3707f Guido Trotter
1129 24a3707f Guido Trotter
  @classmethod
1130 24a3707f Guido Trotter
  def FromDict(cls, val):
1131 24a3707f Guido Trotter
    """Custom function for nodegroup.
1132 24a3707f Guido Trotter

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

1135 24a3707f Guido Trotter
    """
1136 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
1137 24a3707f Guido Trotter
    obj.members = []
1138 24a3707f Guido Trotter
    return obj
1139 24a3707f Guido Trotter
1140 095e71aa Renรฉ Nussbaumer
  def UpgradeConfig(self):
1141 095e71aa Renรฉ Nussbaumer
    """Fill defaults for missing configuration values.
1142 095e71aa Renรฉ Nussbaumer

1143 095e71aa Renรฉ Nussbaumer
    """
1144 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1145 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1146 095e71aa Renรฉ Nussbaumer
1147 e11a1b77 Adeodato Simo
    if self.serial_no is None:
1148 e11a1b77 Adeodato Simo
      self.serial_no = 1
1149 e11a1b77 Adeodato Simo
1150 90e99856 Adeodato Simo
    if self.alloc_policy is None:
1151 90e99856 Adeodato Simo
      self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
1152 90e99856 Adeodato Simo
1153 e11a1b77 Adeodato Simo
    # We only update mtime, and not ctime, since we would not be able to provide
1154 e11a1b77 Adeodato Simo
    # a correct value for creation time.
1155 e11a1b77 Adeodato Simo
    if self.mtime is None:
1156 e11a1b77 Adeodato Simo
      self.mtime = time.time()
1157 e11a1b77 Adeodato Simo
1158 095e71aa Renรฉ Nussbaumer
  def FillND(self, node):
1159 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.Node}
1160 095e71aa Renรฉ Nussbaumer

1161 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1162 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1163 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1164 095e71aa Renรฉ Nussbaumer

1165 095e71aa Renรฉ Nussbaumer
    """
1166 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(node.ndparams)
1167 095e71aa Renรฉ Nussbaumer
1168 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1169 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1170 095e71aa Renรฉ Nussbaumer

1171 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1172 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1173 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1174 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1175 e6e88de6 Adeodato Simo
        from the node group defaults
1176 095e71aa Renรฉ Nussbaumer

1177 095e71aa Renรฉ Nussbaumer
    """
1178 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1179 095e71aa Renรฉ Nussbaumer
1180 24a3707f Guido Trotter
1181 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
1182 a8083063 Iustin Pop
  """Config object representing the cluster."""
1183 154b9580 Balazs Lecz
  __slots__ = [
1184 a8083063 Iustin Pop
    "serial_no",
1185 a8083063 Iustin Pop
    "rsahostkeypub",
1186 a8083063 Iustin Pop
    "highest_used_port",
1187 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
1188 a8083063 Iustin Pop
    "mac_prefix",
1189 a8083063 Iustin Pop
    "volume_group_name",
1190 999b183c Iustin Pop
    "reserved_lvs",
1191 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
1192 a8083063 Iustin Pop
    "default_bridge",
1193 02691904 Alexander Schreiber
    "default_hypervisor",
1194 f6bd6e98 Michael Hanselmann
    "master_node",
1195 f6bd6e98 Michael Hanselmann
    "master_ip",
1196 f6bd6e98 Michael Hanselmann
    "master_netdev",
1197 5a8648eb Andrea Spadaccini
    "master_netmask",
1198 33be7576 Andrea Spadaccini
    "use_external_mip_script",
1199 f6bd6e98 Michael Hanselmann
    "cluster_name",
1200 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
1201 4b97f902 Apollon Oikonomopoulos
    "shared_file_storage_dir",
1202 e69d05fd Iustin Pop
    "enabled_hypervisors",
1203 5bf7b5cf Iustin Pop
    "hvparams",
1204 17463d22 Renรฉ Nussbaumer
    "os_hvp",
1205 5bf7b5cf Iustin Pop
    "beparams",
1206 1bdcbbab Iustin Pop
    "osparams",
1207 c8fcde47 Guido Trotter
    "nicparams",
1208 095e71aa Renรฉ Nussbaumer
    "ndparams",
1209 4b7735f9 Iustin Pop
    "candidate_pool_size",
1210 b86a6bcd Guido Trotter
    "modify_etc_hosts",
1211 b989b9d9 Ken Wehr
    "modify_ssh_setup",
1212 3953242f Iustin Pop
    "maintain_node_health",
1213 4437d889 Balazs Lecz
    "uid_pool",
1214 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
1215 87b2cd45 Iustin Pop
    "hidden_os",
1216 87b2cd45 Iustin Pop
    "blacklisted_os",
1217 2f20d07b Manuel Franceschini
    "primary_ip_family",
1218 3d914585 Renรฉ Nussbaumer
    "prealloc_wipe_disks",
1219 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1220 a8083063 Iustin Pop
1221 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
1222 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
1223 b86a6bcd Guido Trotter

1224 b86a6bcd Guido Trotter
    """
1225 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1226 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
1227 c1b42c18 Guido Trotter
    if self.hvparams is None:
1228 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
1229 c1b42c18 Guido Trotter
    else:
1230 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
1231 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
1232 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
1233 c1b42c18 Guido Trotter
1234 17463d22 Renรฉ Nussbaumer
    if self.os_hvp is None:
1235 17463d22 Renรฉ Nussbaumer
      self.os_hvp = {}
1236 17463d22 Renรฉ Nussbaumer
1237 1bdcbbab Iustin Pop
    # osparams added before 2.2
1238 1bdcbbab Iustin Pop
    if self.osparams is None:
1239 1bdcbbab Iustin Pop
      self.osparams = {}
1240 1bdcbbab Iustin Pop
1241 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1242 095e71aa Renรฉ Nussbaumer
      self.ndparams = constants.NDC_DEFAULTS
1243 095e71aa Renรฉ Nussbaumer
1244 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
1245 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
1246 8c72ab2b Guido Trotter
    for beparams_group in self.beparams:
1247 8c72ab2b Guido Trotter
      UpgradeBeParams(self.beparams[beparams_group])
1248 8c72ab2b Guido Trotter
1249 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
1250 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
1251 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
1252 c8fcde47 Guido Trotter
    if migrate_default_bridge:
1253 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
1254 c8fcde47 Guido Trotter
        self.default_bridge
1255 c1b42c18 Guido Trotter
1256 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1257 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1258 b86a6bcd Guido Trotter
1259 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1260 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1261 b989b9d9 Ken Wehr
1262 73f1d185 Stephen Shirley
    # default_bridge is no longer used in 2.1. The slot is left there to
1263 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1264 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1265 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1266 9b31ca85 Guido Trotter
      self.default_bridge = None
1267 9b31ca85 Guido Trotter
1268 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1269 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1270 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1271 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1272 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1273 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1274 066f465d Guido Trotter
      self.default_hypervisor = None
1275 066f465d Guido Trotter
1276 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1277 3953242f Iustin Pop
    if self.maintain_node_health is None:
1278 3953242f Iustin Pop
      self.maintain_node_health = False
1279 3953242f Iustin Pop
1280 4437d889 Balazs Lecz
    if self.uid_pool is None:
1281 4437d889 Balazs Lecz
      self.uid_pool = []
1282 4437d889 Balazs Lecz
1283 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1284 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1285 bf4af505 Apollon Oikonomopoulos
1286 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1287 999b183c Iustin Pop
    if self.reserved_lvs is None:
1288 999b183c Iustin Pop
      self.reserved_lvs = []
1289 999b183c Iustin Pop
1290 546b1111 Iustin Pop
    # hidden and blacklisted operating systems added before 2.2.1
1291 87b2cd45 Iustin Pop
    if self.hidden_os is None:
1292 87b2cd45 Iustin Pop
      self.hidden_os = []
1293 546b1111 Iustin Pop
1294 87b2cd45 Iustin Pop
    if self.blacklisted_os is None:
1295 87b2cd45 Iustin Pop
      self.blacklisted_os = []
1296 546b1111 Iustin Pop
1297 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1298 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1299 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1300 f4c9af7a Guido Trotter
1301 0007f3ab Andrea Spadaccini
    if self.master_netmask is None:
1302 0007f3ab Andrea Spadaccini
      ipcls = netutils.IPAddress.GetClassFromIpFamily(self.primary_ip_family)
1303 0007f3ab Andrea Spadaccini
      self.master_netmask = ipcls.iplen
1304 0007f3ab Andrea Spadaccini
1305 3d914585 Renรฉ Nussbaumer
    if self.prealloc_wipe_disks is None:
1306 3d914585 Renรฉ Nussbaumer
      self.prealloc_wipe_disks = False
1307 3d914585 Renรฉ Nussbaumer
1308 e8f472d1 Iustin Pop
    # shared_file_storage_dir added before 2.5
1309 e8f472d1 Iustin Pop
    if self.shared_file_storage_dir is None:
1310 e8f472d1 Iustin Pop
      self.shared_file_storage_dir = ""
1311 e8f472d1 Iustin Pop
1312 33be7576 Andrea Spadaccini
    if self.use_external_mip_script is None:
1313 33be7576 Andrea Spadaccini
      self.use_external_mip_script = False
1314 33be7576 Andrea Spadaccini
1315 319856a9 Michael Hanselmann
  def ToDict(self):
1316 319856a9 Michael Hanselmann
    """Custom function for cluster.
1317 319856a9 Michael Hanselmann

1318 319856a9 Michael Hanselmann
    """
1319 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1320 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1321 319856a9 Michael Hanselmann
    return mydict
1322 319856a9 Michael Hanselmann
1323 319856a9 Michael Hanselmann
  @classmethod
1324 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1325 319856a9 Michael Hanselmann
    """Custom function for cluster.
1326 319856a9 Michael Hanselmann

1327 319856a9 Michael Hanselmann
    """
1328 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1329 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1330 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1331 319856a9 Michael Hanselmann
    return obj
1332 319856a9 Michael Hanselmann
1333 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1334 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1335 d63479b5 Iustin Pop

1336 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1337 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1338 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1339 d63479b5 Iustin Pop
    @return: the defaults dict
1340 d63479b5 Iustin Pop

1341 d63479b5 Iustin Pop
    """
1342 d63479b5 Iustin Pop
    if skip_keys is None:
1343 d63479b5 Iustin Pop
      skip_keys = []
1344 d63479b5 Iustin Pop
1345 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1346 d63479b5 Iustin Pop
    if os_name is not None:
1347 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1348 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1349 d63479b5 Iustin Pop
1350 d63479b5 Iustin Pop
    ret_dict = {}
1351 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1352 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1353 d63479b5 Iustin Pop
1354 d63479b5 Iustin Pop
    return ret_dict
1355 d63479b5 Iustin Pop
1356 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1357 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1358 73e0328b Iustin Pop

1359 73e0328b Iustin Pop
    @type hv_name: string
1360 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1361 73e0328b Iustin Pop
    @type os_name: string
1362 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1363 73e0328b Iustin Pop
    @type skip_globals: boolean
1364 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1365 73e0328b Iustin Pop
        not be filled
1366 73e0328b Iustin Pop
    @rtype: dict
1367 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1368 73e0328b Iustin Pop
        the cluster defaults
1369 73e0328b Iustin Pop

1370 73e0328b Iustin Pop
    """
1371 73e0328b Iustin Pop
    if skip_globals:
1372 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1373 73e0328b Iustin Pop
    else:
1374 73e0328b Iustin Pop
      skip_keys = []
1375 73e0328b Iustin Pop
1376 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1377 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1378 d63479b5 Iustin Pop
1379 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1380 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1381 5bf7b5cf Iustin Pop

1382 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1383 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1384 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1385 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1386 7736a5f2 Iustin Pop
        not be filled
1387 5bf7b5cf Iustin Pop
    @rtype: dict
1388 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1389 5bf7b5cf Iustin Pop
        the cluster defaults
1390 5bf7b5cf Iustin Pop

1391 5bf7b5cf Iustin Pop
    """
1392 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1393 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1394 17463d22 Renรฉ Nussbaumer
1395 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1396 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1397 73e0328b Iustin Pop

1398 06596a60 Guido Trotter
    @type beparams: dict
1399 06596a60 Guido Trotter
    @param beparams: the dict to fill
1400 73e0328b Iustin Pop
    @rtype: dict
1401 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1402 73e0328b Iustin Pop
        from the cluster defaults
1403 73e0328b Iustin Pop

1404 73e0328b Iustin Pop
    """
1405 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1406 5bf7b5cf Iustin Pop
1407 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1408 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1409 5bf7b5cf Iustin Pop

1410 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1411 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1412 5bf7b5cf Iustin Pop
    @rtype: dict
1413 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1414 5bf7b5cf Iustin Pop
        the cluster defaults
1415 5bf7b5cf Iustin Pop

1416 5bf7b5cf Iustin Pop
    """
1417 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1418 73e0328b Iustin Pop
1419 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1420 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1421 73e0328b Iustin Pop

1422 06596a60 Guido Trotter
    @type nicparams: dict
1423 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1424 73e0328b Iustin Pop
    @rtype: dict
1425 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1426 73e0328b Iustin Pop
        from the cluster defaults
1427 73e0328b Iustin Pop

1428 73e0328b Iustin Pop
    """
1429 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1430 5bf7b5cf Iustin Pop
1431 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1432 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1433 1bdcbbab Iustin Pop

1434 1bdcbbab Iustin Pop
    @type os_name: string
1435 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1436 1bdcbbab Iustin Pop
    @type os_params: dict
1437 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1438 1bdcbbab Iustin Pop
    @rtype: dict
1439 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1440 1bdcbbab Iustin Pop
        the cluster defaults
1441 1bdcbbab Iustin Pop

1442 1bdcbbab Iustin Pop
    """
1443 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1444 1bdcbbab Iustin Pop
    # base OS
1445 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1446 1bdcbbab Iustin Pop
    # OS with variant
1447 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1448 1bdcbbab Iustin Pop
    # specified params
1449 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1450 1bdcbbab Iustin Pop
1451 095e71aa Renรฉ Nussbaumer
  def FillND(self, node, nodegroup):
1452 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.NodeGroup} and L{objects.Node}
1453 095e71aa Renรฉ Nussbaumer

1454 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1455 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1456 095e71aa Renรฉ Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1457 095e71aa Renรฉ Nussbaumer
    @param nodegroup: A Node object to fill
1458 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1459 095e71aa Renรฉ Nussbaumer

1460 095e71aa Renรฉ Nussbaumer
    """
1461 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1462 095e71aa Renรฉ Nussbaumer
1463 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1464 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1465 095e71aa Renรฉ Nussbaumer

1466 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1467 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1468 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1469 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1470 095e71aa Renรฉ Nussbaumer
        from the cluster defaults
1471 095e71aa Renรฉ Nussbaumer

1472 095e71aa Renรฉ Nussbaumer
    """
1473 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1474 095e71aa Renรฉ Nussbaumer
1475 5c947f38 Iustin Pop
1476 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1477 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1478 96acbc09 Michael Hanselmann
  __slots__ = [
1479 96acbc09 Michael Hanselmann
    "dev_path",
1480 96acbc09 Michael Hanselmann
    "major",
1481 96acbc09 Michael Hanselmann
    "minor",
1482 96acbc09 Michael Hanselmann
    "sync_percent",
1483 96acbc09 Michael Hanselmann
    "estimated_time",
1484 96acbc09 Michael Hanselmann
    "is_degraded",
1485 f208978a Michael Hanselmann
    "ldisk_status",
1486 96acbc09 Michael Hanselmann
    ]
1487 96acbc09 Michael Hanselmann
1488 96acbc09 Michael Hanselmann
1489 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1490 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1491 2d76b580 Michael Hanselmann
  __slots__ = [
1492 2d76b580 Michael Hanselmann
    "recent_output",
1493 2d76b580 Michael Hanselmann
    "listen_port",
1494 2d76b580 Michael Hanselmann
    "connected",
1495 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1496 c08d76f5 Michael Hanselmann
    "progress_throughput",
1497 c08d76f5 Michael Hanselmann
    "progress_eta",
1498 c08d76f5 Michael Hanselmann
    "progress_percent",
1499 2d76b580 Michael Hanselmann
    "exit_status",
1500 2d76b580 Michael Hanselmann
    "error_message",
1501 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1502 2d76b580 Michael Hanselmann
1503 2d76b580 Michael Hanselmann
1504 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1505 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1506 eb630f50 Michael Hanselmann

1507 eb630f50 Michael Hanselmann
  @ivar key_name: X509 key name (None for cluster certificate)
1508 eb630f50 Michael Hanselmann
  @ivar ca_pem: Remote peer CA in PEM format (None for cluster certificate)
1509 a5310c2a Michael Hanselmann
  @ivar compress: Compression method (one of L{constants.IEC_ALL})
1510 af1d39b1 Michael Hanselmann
  @ivar magic: Used to ensure the connection goes to the right disk
1511 855d2fc7 Michael Hanselmann
  @ivar ipv6: Whether to use IPv6
1512 4478301b Michael Hanselmann
  @ivar connect_timeout: Number of seconds for establishing connection
1513 eb630f50 Michael Hanselmann

1514 eb630f50 Michael Hanselmann
  """
1515 eb630f50 Michael Hanselmann
  __slots__ = [
1516 eb630f50 Michael Hanselmann
    "key_name",
1517 eb630f50 Michael Hanselmann
    "ca_pem",
1518 a5310c2a Michael Hanselmann
    "compress",
1519 af1d39b1 Michael Hanselmann
    "magic",
1520 855d2fc7 Michael Hanselmann
    "ipv6",
1521 4478301b Michael Hanselmann
    "connect_timeout",
1522 eb630f50 Michael Hanselmann
    ]
1523 eb630f50 Michael Hanselmann
1524 eb630f50 Michael Hanselmann
1525 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1526 18d750b9 Guido Trotter
  """Object holding a confd request.
1527 18d750b9 Guido Trotter

1528 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1529 18d750b9 Guido Trotter
  @ivar type: confd query type
1530 18d750b9 Guido Trotter
  @ivar query: query request
1531 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1532 18d750b9 Guido Trotter

1533 18d750b9 Guido Trotter
  """
1534 18d750b9 Guido Trotter
  __slots__ = [
1535 18d750b9 Guido Trotter
    "protocol",
1536 18d750b9 Guido Trotter
    "type",
1537 18d750b9 Guido Trotter
    "query",
1538 18d750b9 Guido Trotter
    "rsalt",
1539 18d750b9 Guido Trotter
    ]
1540 18d750b9 Guido Trotter
1541 18d750b9 Guido Trotter
1542 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1543 18d750b9 Guido Trotter
  """Object holding a confd reply.
1544 18d750b9 Guido Trotter

1545 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1546 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1547 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1548 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1549 18d750b9 Guido Trotter

1550 18d750b9 Guido Trotter
  """
1551 18d750b9 Guido Trotter
  __slots__ = [
1552 18d750b9 Guido Trotter
    "protocol",
1553 18d750b9 Guido Trotter
    "status",
1554 18d750b9 Guido Trotter
    "answer",
1555 18d750b9 Guido Trotter
    "serial",
1556 18d750b9 Guido Trotter
    ]
1557 18d750b9 Guido Trotter
1558 18d750b9 Guido Trotter
1559 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1560 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1561 707f23b5 Michael Hanselmann

1562 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1563 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1564 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1565 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1566 707f23b5 Michael Hanselmann

1567 707f23b5 Michael Hanselmann
  """
1568 707f23b5 Michael Hanselmann
  __slots__ = [
1569 707f23b5 Michael Hanselmann
    "name",
1570 707f23b5 Michael Hanselmann
    "title",
1571 707f23b5 Michael Hanselmann
    "kind",
1572 1ae17369 Michael Hanselmann
    "doc",
1573 707f23b5 Michael Hanselmann
    ]
1574 707f23b5 Michael Hanselmann
1575 707f23b5 Michael Hanselmann
1576 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1577 0538c375 Michael Hanselmann
  __slots__ = [
1578 0538c375 Michael Hanselmann
    "fields",
1579 0538c375 Michael Hanselmann
    ]
1580 0538c375 Michael Hanselmann
1581 0538c375 Michael Hanselmann
  def ToDict(self):
1582 0538c375 Michael Hanselmann
    """Custom function for serializing.
1583 0538c375 Michael Hanselmann

1584 0538c375 Michael Hanselmann
    """
1585 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1586 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1587 0538c375 Michael Hanselmann
    return mydict
1588 0538c375 Michael Hanselmann
1589 0538c375 Michael Hanselmann
  @classmethod
1590 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1591 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1592 0538c375 Michael Hanselmann

1593 0538c375 Michael Hanselmann
    """
1594 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1595 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1596 0538c375 Michael Hanselmann
    return obj
1597 0538c375 Michael Hanselmann
1598 0538c375 Michael Hanselmann
1599 24d6d3e2 Michael Hanselmann
class QueryRequest(ConfigObject):
1600 24d6d3e2 Michael Hanselmann
  """Object holding a query request.
1601 24d6d3e2 Michael Hanselmann

1602 24d6d3e2 Michael Hanselmann
  """
1603 24d6d3e2 Michael Hanselmann
  __slots__ = [
1604 24d6d3e2 Michael Hanselmann
    "what",
1605 24d6d3e2 Michael Hanselmann
    "fields",
1606 2e5c33db Iustin Pop
    "qfilter",
1607 24d6d3e2 Michael Hanselmann
    ]
1608 24d6d3e2 Michael Hanselmann
1609 24d6d3e2 Michael Hanselmann
1610 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
1611 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
1612 24d6d3e2 Michael Hanselmann

1613 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1614 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1615 24d6d3e2 Michael Hanselmann

1616 24d6d3e2 Michael Hanselmann
  """
1617 24d6d3e2 Michael Hanselmann
  __slots__ = [
1618 24d6d3e2 Michael Hanselmann
    "data",
1619 24d6d3e2 Michael Hanselmann
    ]
1620 24d6d3e2 Michael Hanselmann
1621 24d6d3e2 Michael Hanselmann
1622 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
1623 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
1624 24d6d3e2 Michael Hanselmann

1625 24d6d3e2 Michael Hanselmann
  """
1626 24d6d3e2 Michael Hanselmann
  __slots__ = [
1627 24d6d3e2 Michael Hanselmann
    "what",
1628 24d6d3e2 Michael Hanselmann
    "fields",
1629 24d6d3e2 Michael Hanselmann
    ]
1630 24d6d3e2 Michael Hanselmann
1631 24d6d3e2 Michael Hanselmann
1632 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
1633 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
1634 24d6d3e2 Michael Hanselmann

1635 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1636 24d6d3e2 Michael Hanselmann

1637 24d6d3e2 Michael Hanselmann
  """
1638 24d6d3e2 Michael Hanselmann
  __slots__ = [
1639 24d6d3e2 Michael Hanselmann
    ]
1640 24d6d3e2 Michael Hanselmann
1641 24d6d3e2 Michael Hanselmann
1642 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
1643 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
1644 6a1434d7 Andrea Spadaccini

1645 6a1434d7 Andrea Spadaccini
  """
1646 6a1434d7 Andrea Spadaccini
  __slots__ = [
1647 6a1434d7 Andrea Spadaccini
    "status",
1648 6a1434d7 Andrea Spadaccini
    "transferred_ram",
1649 6a1434d7 Andrea Spadaccini
    "total_ram",
1650 6a1434d7 Andrea Spadaccini
    ]
1651 6a1434d7 Andrea Spadaccini
1652 6a1434d7 Andrea Spadaccini
1653 25ce3ec4 Michael Hanselmann
class InstanceConsole(ConfigObject):
1654 25ce3ec4 Michael Hanselmann
  """Object describing how to access the console of an instance.
1655 25ce3ec4 Michael Hanselmann

1656 25ce3ec4 Michael Hanselmann
  """
1657 25ce3ec4 Michael Hanselmann
  __slots__ = [
1658 25ce3ec4 Michael Hanselmann
    "instance",
1659 25ce3ec4 Michael Hanselmann
    "kind",
1660 25ce3ec4 Michael Hanselmann
    "message",
1661 25ce3ec4 Michael Hanselmann
    "host",
1662 25ce3ec4 Michael Hanselmann
    "port",
1663 25ce3ec4 Michael Hanselmann
    "user",
1664 25ce3ec4 Michael Hanselmann
    "command",
1665 25ce3ec4 Michael Hanselmann
    "display",
1666 25ce3ec4 Michael Hanselmann
    ]
1667 25ce3ec4 Michael Hanselmann
1668 25ce3ec4 Michael Hanselmann
  def Validate(self):
1669 25ce3ec4 Michael Hanselmann
    """Validates contents of this object.
1670 25ce3ec4 Michael Hanselmann

1671 25ce3ec4 Michael Hanselmann
    """
1672 25ce3ec4 Michael Hanselmann
    assert self.kind in constants.CONS_ALL, "Unknown console type"
1673 25ce3ec4 Michael Hanselmann
    assert self.instance, "Missing instance name"
1674 4d2cdb5a Andrea Spadaccini
    assert self.message or self.kind in [constants.CONS_SSH,
1675 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1676 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_VNC]
1677 25ce3ec4 Michael Hanselmann
    assert self.host or self.kind == constants.CONS_MESSAGE
1678 25ce3ec4 Michael Hanselmann
    assert self.port or self.kind in [constants.CONS_MESSAGE,
1679 25ce3ec4 Michael Hanselmann
                                      constants.CONS_SSH]
1680 25ce3ec4 Michael Hanselmann
    assert self.user or self.kind in [constants.CONS_MESSAGE,
1681 4d2cdb5a Andrea Spadaccini
                                      constants.CONS_SPICE,
1682 25ce3ec4 Michael Hanselmann
                                      constants.CONS_VNC]
1683 25ce3ec4 Michael Hanselmann
    assert self.command or self.kind in [constants.CONS_MESSAGE,
1684 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1685 25ce3ec4 Michael Hanselmann
                                         constants.CONS_VNC]
1686 25ce3ec4 Michael Hanselmann
    assert self.display or self.kind in [constants.CONS_MESSAGE,
1687 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
1688 25ce3ec4 Michael Hanselmann
                                         constants.CONS_SSH]
1689 25ce3ec4 Michael Hanselmann
    return True
1690 25ce3ec4 Michael Hanselmann
1691 25ce3ec4 Michael Hanselmann
1692 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
1693 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
1694 a8083063 Iustin Pop

1695 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
1696 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
1697 a8083063 Iustin Pop
  buffer.
1698 a8083063 Iustin Pop

1699 a8083063 Iustin Pop
  """
1700 a8083063 Iustin Pop
  def Dumps(self):
1701 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
1702 a8083063 Iustin Pop
    buf = StringIO()
1703 a8083063 Iustin Pop
    self.write(buf)
1704 a8083063 Iustin Pop
    return buf.getvalue()
1705 a8083063 Iustin Pop
1706 b39bf4bb Guido Trotter
  @classmethod
1707 b39bf4bb Guido Trotter
  def Loads(cls, data):
1708 a8083063 Iustin Pop
    """Load data from a string."""
1709 a8083063 Iustin Pop
    buf = StringIO(data)
1710 b39bf4bb Guido Trotter
    cfp = cls()
1711 a8083063 Iustin Pop
    cfp.readfp(buf)
1712 a8083063 Iustin Pop
    return cfp