Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ dca1f84a

History | View | Annotate | Download (58.4 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 2cc673a3 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 32017174 Agata Murawska
from ganeti import utils
48 a8083063 Iustin Pop
49 f4c9af7a Guido Trotter
from socket import AF_INET
50 f4c9af7a Guido Trotter
51 a8083063 Iustin Pop
52 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
53 08208574 Dimitris Aragiorgis
           "OS", "Node", "NodeGroup", "Cluster", "FillDict", "Network"]
54 a8083063 Iustin Pop
55 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
56 e1dcc53a Iustin Pop
_UUID = ["uuid"]
57 96acbc09 Michael Hanselmann
58 8d8d650c Michael Hanselmann
59 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
60 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
61 abe609b2 Guido Trotter

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

71 29921401 Iustin Pop
  """
72 29921401 Iustin Pop
  ret_dict = copy.deepcopy(defaults_dict)
73 29921401 Iustin Pop
  ret_dict.update(custom_dict)
74 e11ddf13 Iustin Pop
  if skip_keys:
75 e11ddf13 Iustin Pop
    for k in skip_keys:
76 e11ddf13 Iustin Pop
      try:
77 e11ddf13 Iustin Pop
        del ret_dict[k]
78 e11ddf13 Iustin Pop
      except KeyError:
79 e11ddf13 Iustin Pop
        pass
80 29921401 Iustin Pop
  return ret_dict
81 a8083063 Iustin Pop
82 6e34b628 Guido Trotter
83 2cc673a3 Iustin Pop
def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
84 2cc673a3 Iustin Pop
  """Fills an instance policy with defaults.
85 918eb80b Agata Murawska

86 918eb80b Agata Murawska
  """
87 2cc673a3 Iustin Pop
  assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS
88 918eb80b Agata Murawska
  ret_dict = {}
89 12378fe3 Iustin Pop
  for key in constants.IPOLICY_ISPECS:
90 2cc673a3 Iustin Pop
    ret_dict[key] = FillDict(default_ipolicy[key],
91 2cc673a3 Iustin Pop
                             custom_ipolicy.get(key, {}),
92 918eb80b Agata Murawska
                             skip_keys=skip_keys)
93 2cc673a3 Iustin Pop
  # list items
94 d04c9d45 Iustin Pop
  for key in [constants.IPOLICY_DTS]:
95 2cc673a3 Iustin Pop
    ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
96 ff6c5e55 Iustin Pop
  # other items which we know we can directly copy (immutables)
97 ff6c5e55 Iustin Pop
  for key in constants.IPOLICY_PARAMETERS:
98 ff6c5e55 Iustin Pop
    ret_dict[key] = custom_ipolicy.get(key, default_ipolicy[key])
99 2cc673a3 Iustin Pop
100 918eb80b Agata Murawska
  return ret_dict
101 918eb80b Agata Murawska
102 918eb80b Agata Murawska
103 57987785 Renรฉ Nussbaumer
def FillDiskParams(default_dparams, custom_dparams, skip_keys=None):
104 57987785 Renรฉ Nussbaumer
  """Fills the disk parameter defaults.
105 57987785 Renรฉ Nussbaumer

106 af9fb4cc Renรฉ Nussbaumer
  @see: L{FillDict} for parameters and return value
107 57987785 Renรฉ Nussbaumer

108 57987785 Renรฉ Nussbaumer
  """
109 57987785 Renรฉ Nussbaumer
  assert frozenset(default_dparams.keys()) == constants.DISK_TEMPLATES
110 57987785 Renรฉ Nussbaumer
111 57987785 Renรฉ Nussbaumer
  return dict((dt, FillDict(default_dparams[dt], custom_dparams.get(dt, {}),
112 57987785 Renรฉ Nussbaumer
                             skip_keys=skip_keys))
113 57987785 Renรฉ Nussbaumer
              for dt in constants.DISK_TEMPLATES)
114 57987785 Renรฉ Nussbaumer
115 57987785 Renรฉ Nussbaumer
116 6e34b628 Guido Trotter
def UpgradeGroupedParams(target, defaults):
117 6e34b628 Guido Trotter
  """Update all groups for the target parameter.
118 6e34b628 Guido Trotter

119 6e34b628 Guido Trotter
  @type target: dict of dicts
120 6e34b628 Guido Trotter
  @param target: {group: {parameter: value}}
121 6e34b628 Guido Trotter
  @type defaults: dict
122 6e34b628 Guido Trotter
  @param defaults: default parameter values
123 6e34b628 Guido Trotter

124 6e34b628 Guido Trotter
  """
125 6e34b628 Guido Trotter
  if target is None:
126 6e34b628 Guido Trotter
    target = {constants.PP_DEFAULT: defaults}
127 6e34b628 Guido Trotter
  else:
128 6e34b628 Guido Trotter
    for group in target:
129 6e34b628 Guido Trotter
      target[group] = FillDict(defaults, target[group])
130 6e34b628 Guido Trotter
  return target
131 6e34b628 Guido Trotter
132 6e34b628 Guido Trotter
133 8c72ab2b Guido Trotter
def UpgradeBeParams(target):
134 8c72ab2b Guido Trotter
  """Update the be parameters dict to the new format.
135 8c72ab2b Guido Trotter

136 8c72ab2b Guido Trotter
  @type target: dict
137 8c72ab2b Guido Trotter
  @param target: "be" parameters dict
138 8c72ab2b Guido Trotter

139 8c72ab2b Guido Trotter
  """
140 8c72ab2b Guido Trotter
  if constants.BE_MEMORY in target:
141 8c72ab2b Guido Trotter
    memory = target[constants.BE_MEMORY]
142 8c72ab2b Guido Trotter
    target[constants.BE_MAXMEM] = memory
143 8c72ab2b Guido Trotter
    target[constants.BE_MINMEM] = memory
144 b2e233a5 Guido Trotter
    del target[constants.BE_MEMORY]
145 8c72ab2b Guido Trotter
146 8c72ab2b Guido Trotter
147 bc5d0215 Andrea Spadaccini
def UpgradeDiskParams(diskparams):
148 bc5d0215 Andrea Spadaccini
  """Upgrade the disk parameters.
149 bc5d0215 Andrea Spadaccini

150 bc5d0215 Andrea Spadaccini
  @type diskparams: dict
151 bc5d0215 Andrea Spadaccini
  @param diskparams: disk parameters to upgrade
152 bc5d0215 Andrea Spadaccini
  @rtype: dict
153 765ada2b Iustin Pop
  @return: the upgraded disk parameters dict
154 bc5d0215 Andrea Spadaccini

155 bc5d0215 Andrea Spadaccini
  """
156 99ccf8b9 Renรฉ Nussbaumer
  if not diskparams:
157 99ccf8b9 Renรฉ Nussbaumer
    result = {}
158 bc5d0215 Andrea Spadaccini
  else:
159 57987785 Renรฉ Nussbaumer
    result = FillDiskParams(constants.DISK_DT_DEFAULTS, diskparams)
160 bc5d0215 Andrea Spadaccini
161 bc5d0215 Andrea Spadaccini
  return result
162 bc5d0215 Andrea Spadaccini
163 bc5d0215 Andrea Spadaccini
164 2a27dac3 Iustin Pop
def UpgradeNDParams(ndparams):
165 2a27dac3 Iustin Pop
  """Upgrade ndparams structure.
166 2a27dac3 Iustin Pop

167 2a27dac3 Iustin Pop
  @type ndparams: dict
168 2a27dac3 Iustin Pop
  @param ndparams: disk parameters to upgrade
169 2a27dac3 Iustin Pop
  @rtype: dict
170 2a27dac3 Iustin Pop
  @return: the upgraded node parameters dict
171 2a27dac3 Iustin Pop

172 2a27dac3 Iustin Pop
  """
173 2a27dac3 Iustin Pop
  if ndparams is None:
174 2a27dac3 Iustin Pop
    ndparams = {}
175 2a27dac3 Iustin Pop
176 2a27dac3 Iustin Pop
  return FillDict(constants.NDC_DEFAULTS, ndparams)
177 2a27dac3 Iustin Pop
178 2a27dac3 Iustin Pop
179 918eb80b Agata Murawska
def MakeEmptyIPolicy():
180 918eb80b Agata Murawska
  """Create empty IPolicy dictionary.
181 918eb80b Agata Murawska

182 918eb80b Agata Murawska
  """
183 918eb80b Agata Murawska
  return dict([
184 2cc673a3 Iustin Pop
    (constants.ISPECS_MIN, {}),
185 2cc673a3 Iustin Pop
    (constants.ISPECS_MAX, {}),
186 2cc673a3 Iustin Pop
    (constants.ISPECS_STD, {}),
187 918eb80b Agata Murawska
    ])
188 918eb80b Agata Murawska
189 918eb80b Agata Murawska
190 a8083063 Iustin Pop
class ConfigObject(object):
191 a8083063 Iustin Pop
  """A generic config object.
192 a8083063 Iustin Pop

193 a8083063 Iustin Pop
  It has the following properties:
194 a8083063 Iustin Pop

195 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
196 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
197 a8083063 Iustin Pop
      as None instead of raising an error
198 a8083063 Iustin Pop

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

202 a8083063 Iustin Pop
  """
203 a8083063 Iustin Pop
  __slots__ = []
204 a8083063 Iustin Pop
205 a8083063 Iustin Pop
  def __init__(self, **kwargs):
206 319856a9 Michael Hanselmann
    for k, v in kwargs.iteritems():
207 319856a9 Michael Hanselmann
      setattr(self, k, v)
208 a8083063 Iustin Pop
209 a8083063 Iustin Pop
  def __getattr__(self, name):
210 adf385c7 Iustin Pop
    if name not in self._all_slots():
211 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
212 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
213 a8083063 Iustin Pop
    return None
214 a8083063 Iustin Pop
215 a8083063 Iustin Pop
  def __setstate__(self, state):
216 adf385c7 Iustin Pop
    slots = self._all_slots()
217 a8083063 Iustin Pop
    for name in state:
218 adf385c7 Iustin Pop
      if name in slots:
219 a8083063 Iustin Pop
        setattr(self, name, state[name])
220 a8083063 Iustin Pop
221 adf385c7 Iustin Pop
  @classmethod
222 adf385c7 Iustin Pop
  def _all_slots(cls):
223 adf385c7 Iustin Pop
    """Compute the list of all declared slots for a class.
224 adf385c7 Iustin Pop

225 adf385c7 Iustin Pop
    """
226 adf385c7 Iustin Pop
    slots = []
227 adf385c7 Iustin Pop
    for parent in cls.__mro__:
228 adf385c7 Iustin Pop
      slots.extend(getattr(parent, "__slots__", []))
229 adf385c7 Iustin Pop
    return slots
230 adf385c7 Iustin Pop
231 415feb2e Renรฉ Nussbaumer
  #: Public getter for the defined slots
232 415feb2e Renรฉ Nussbaumer
  GetAllSlots = _all_slots
233 415feb2e Renรฉ Nussbaumer
234 ff9c047c Iustin Pop
  def ToDict(self):
235 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
236 ff9c047c Iustin Pop

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

243 ff9c047c Iustin Pop
    """
244 4c14965f Guido Trotter
    result = {}
245 adf385c7 Iustin Pop
    for name in self._all_slots():
246 4c14965f Guido Trotter
      value = getattr(self, name, None)
247 4c14965f Guido Trotter
      if value is not None:
248 4c14965f Guido Trotter
        result[name] = value
249 4c14965f Guido Trotter
    return result
250 4c14965f Guido Trotter
251 4c14965f Guido Trotter
  __getstate__ = ToDict
252 ff9c047c Iustin Pop
253 ff9c047c Iustin Pop
  @classmethod
254 ff9c047c Iustin Pop
  def FromDict(cls, val):
255 ff9c047c Iustin Pop
    """Create an object from a dictionary.
256 ff9c047c Iustin Pop

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

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

265 ff9c047c Iustin Pop
    """
266 ff9c047c Iustin Pop
    if not isinstance(val, dict):
267 ff9c047c Iustin Pop
      raise errors.ConfigurationError("Invalid object passed to FromDict:"
268 ff9c047c Iustin Pop
                                      " expected dict, got %s" % type(val))
269 319856a9 Michael Hanselmann
    val_str = dict([(str(k), v) for k, v in val.iteritems()])
270 b459a848 Andrea Spadaccini
    obj = cls(**val_str) # pylint: disable=W0142
271 ff9c047c Iustin Pop
    return obj
272 ff9c047c Iustin Pop
273 ff9c047c Iustin Pop
  @staticmethod
274 ff9c047c Iustin Pop
  def _ContainerToDicts(container):
275 ff9c047c Iustin Pop
    """Convert the elements of a container to standard python types.
276 ff9c047c Iustin Pop

277 ff9c047c Iustin Pop
    This method converts a container with elements derived from
278 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
279 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
280 ff9c047c Iustin Pop

281 ff9c047c Iustin Pop
    """
282 ff9c047c Iustin Pop
    if isinstance(container, dict):
283 ff9c047c Iustin Pop
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
284 ff9c047c Iustin Pop
    elif isinstance(container, (list, tuple, set, frozenset)):
285 ff9c047c Iustin Pop
      ret = [elem.ToDict() for elem in container]
286 ff9c047c Iustin Pop
    else:
287 ff9c047c Iustin Pop
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
288 ff9c047c Iustin Pop
                      type(container))
289 ff9c047c Iustin Pop
    return ret
290 ff9c047c Iustin Pop
291 ff9c047c Iustin Pop
  @staticmethod
292 ff9c047c Iustin Pop
  def _ContainerFromDicts(source, c_type, e_type):
293 ff9c047c Iustin Pop
    """Convert a container from standard python types.
294 ff9c047c Iustin Pop

295 ff9c047c Iustin Pop
    This method converts a container with standard python types to
296 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
297 ff9c047c Iustin Pop
    keys, only the values.
298 ff9c047c Iustin Pop

299 ff9c047c Iustin Pop
    """
300 ff9c047c Iustin Pop
    if not isinstance(c_type, type):
301 ff9c047c Iustin Pop
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
302 ff9c047c Iustin Pop
                      " not a type" % type(c_type))
303 fe25a79a Guido Trotter
    if source is None:
304 fe25a79a Guido Trotter
      source = c_type()
305 ff9c047c Iustin Pop
    if c_type is dict:
306 ff9c047c Iustin Pop
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
307 ff9c047c Iustin Pop
    elif c_type in (list, tuple, set, frozenset):
308 ff9c047c Iustin Pop
      ret = c_type([e_type.FromDict(elem) for elem in source])
309 ff9c047c Iustin Pop
    else:
310 ff9c047c Iustin Pop
      raise TypeError("Invalid container type %s passed to"
311 ff9c047c Iustin Pop
                      " _ContainerFromDicts" % c_type)
312 ff9c047c Iustin Pop
    return ret
313 ff9c047c Iustin Pop
314 e8d563f3 Iustin Pop
  def Copy(self):
315 e8d563f3 Iustin Pop
    """Makes a deep copy of the current object and its children.
316 e8d563f3 Iustin Pop

317 e8d563f3 Iustin Pop
    """
318 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
319 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
320 e8d563f3 Iustin Pop
    return clone_obj
321 e8d563f3 Iustin Pop
322 ff9c047c Iustin Pop
  def __repr__(self):
323 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
324 ff9c047c Iustin Pop
    return repr(self.ToDict())
325 ff9c047c Iustin Pop
326 560428be Guido Trotter
  def UpgradeConfig(self):
327 560428be Guido Trotter
    """Fill defaults for missing configuration values.
328 560428be Guido Trotter

329 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
330 90d726a8 Iustin Pop
    implementation will be object dependent.
331 560428be Guido Trotter

332 560428be Guido Trotter
    """
333 560428be Guido Trotter
    pass
334 560428be Guido Trotter
335 a8083063 Iustin Pop
336 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
337 5c947f38 Iustin Pop
  """An generic class supporting tags.
338 5c947f38 Iustin Pop

339 5c947f38 Iustin Pop
  """
340 154b9580 Balazs Lecz
  __slots__ = ["tags"]
341 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
342 2057f6c7 Iustin Pop
343 b5e5632e Iustin Pop
  @classmethod
344 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
345 5c947f38 Iustin Pop
    """Check if a tag is valid.
346 5c947f38 Iustin Pop

347 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
348 5c947f38 Iustin Pop
    function has no return value.
349 5c947f38 Iustin Pop

350 5c947f38 Iustin Pop
    """
351 5c947f38 Iustin Pop
    if not isinstance(tag, basestring):
352 3ecf6786 Iustin Pop
      raise errors.TagError("Invalid tag type (not a string)")
353 5c947f38 Iustin Pop
    if len(tag) > constants.MAX_TAG_LEN:
354 319856a9 Michael Hanselmann
      raise errors.TagError("Tag too long (>%d characters)" %
355 319856a9 Michael Hanselmann
                            constants.MAX_TAG_LEN)
356 5c947f38 Iustin Pop
    if not tag:
357 3ecf6786 Iustin Pop
      raise errors.TagError("Tags cannot be empty")
358 b5e5632e Iustin Pop
    if not cls.VALID_TAG_RE.match(tag):
359 3ecf6786 Iustin Pop
      raise errors.TagError("Tag contains invalid characters")
360 5c947f38 Iustin Pop
361 5c947f38 Iustin Pop
  def GetTags(self):
362 5c947f38 Iustin Pop
    """Return the tags list.
363 5c947f38 Iustin Pop

364 5c947f38 Iustin Pop
    """
365 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
366 5c947f38 Iustin Pop
    if tags is None:
367 5c947f38 Iustin Pop
      tags = self.tags = set()
368 5c947f38 Iustin Pop
    return tags
369 5c947f38 Iustin Pop
370 5c947f38 Iustin Pop
  def AddTag(self, tag):
371 5c947f38 Iustin Pop
    """Add a new tag.
372 5c947f38 Iustin Pop

373 5c947f38 Iustin Pop
    """
374 5c947f38 Iustin Pop
    self.ValidateTag(tag)
375 5c947f38 Iustin Pop
    tags = self.GetTags()
376 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
377 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
378 5c947f38 Iustin Pop
    self.GetTags().add(tag)
379 5c947f38 Iustin Pop
380 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
381 5c947f38 Iustin Pop
    """Remove a tag.
382 5c947f38 Iustin Pop

383 5c947f38 Iustin Pop
    """
384 5c947f38 Iustin Pop
    self.ValidateTag(tag)
385 5c947f38 Iustin Pop
    tags = self.GetTags()
386 5c947f38 Iustin Pop
    try:
387 5c947f38 Iustin Pop
      tags.remove(tag)
388 5c947f38 Iustin Pop
    except KeyError:
389 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
390 5c947f38 Iustin Pop
391 ff9c047c Iustin Pop
  def ToDict(self):
392 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
393 ff9c047c Iustin Pop

394 ff9c047c Iustin Pop
    This replaces the tags set with a list.
395 ff9c047c Iustin Pop

396 ff9c047c Iustin Pop
    """
397 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
398 ff9c047c Iustin Pop
399 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
400 ff9c047c Iustin Pop
    if isinstance(tags, set):
401 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
402 ff9c047c Iustin Pop
    return bo
403 ff9c047c Iustin Pop
404 ff9c047c Iustin Pop
  @classmethod
405 ff9c047c Iustin Pop
  def FromDict(cls, val):
406 ff9c047c Iustin Pop
    """Custom function for instances.
407 ff9c047c Iustin Pop

408 ff9c047c Iustin Pop
    """
409 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
410 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
411 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
412 ff9c047c Iustin Pop
    return obj
413 ff9c047c Iustin Pop
414 5c947f38 Iustin Pop
415 061af273 Andrea Spadaccini
class MasterNetworkParameters(ConfigObject):
416 061af273 Andrea Spadaccini
  """Network configuration parameters for the master
417 061af273 Andrea Spadaccini

418 061af273 Andrea Spadaccini
  @ivar name: master name
419 061af273 Andrea Spadaccini
  @ivar ip: master IP
420 061af273 Andrea Spadaccini
  @ivar netmask: master netmask
421 061af273 Andrea Spadaccini
  @ivar netdev: master network device
422 061af273 Andrea Spadaccini
  @ivar ip_family: master IP family
423 061af273 Andrea Spadaccini

424 061af273 Andrea Spadaccini
  """
425 061af273 Andrea Spadaccini
  __slots__ = [
426 061af273 Andrea Spadaccini
    "name",
427 061af273 Andrea Spadaccini
    "ip",
428 061af273 Andrea Spadaccini
    "netmask",
429 061af273 Andrea Spadaccini
    "netdev",
430 061af273 Andrea Spadaccini
    "ip_family"
431 061af273 Andrea Spadaccini
    ]
432 061af273 Andrea Spadaccini
433 061af273 Andrea Spadaccini
434 a8083063 Iustin Pop
class ConfigData(ConfigObject):
435 a8083063 Iustin Pop
  """Top-level config object."""
436 3df43542 Guido Trotter
  __slots__ = [
437 3df43542 Guido Trotter
    "version",
438 3df43542 Guido Trotter
    "cluster",
439 3df43542 Guido Trotter
    "nodes",
440 3df43542 Guido Trotter
    "nodegroups",
441 3df43542 Guido Trotter
    "instances",
442 08208574 Dimitris Aragiorgis
    "networks",
443 3df43542 Guido Trotter
    "serial_no",
444 3df43542 Guido Trotter
    ] + _TIMESTAMPS
445 a8083063 Iustin Pop
446 ff9c047c Iustin Pop
  def ToDict(self):
447 ff9c047c Iustin Pop
    """Custom function for top-level config data.
448 ff9c047c Iustin Pop

449 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
450 ff9c047c Iustin Pop
    with standard python types.
451 ff9c047c Iustin Pop

452 ff9c047c Iustin Pop
    """
453 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
454 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
455 08208574 Dimitris Aragiorgis
    for key in "nodes", "instances", "nodegroups", "networks":
456 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
457 ff9c047c Iustin Pop
458 ff9c047c Iustin Pop
    return mydict
459 ff9c047c Iustin Pop
460 ff9c047c Iustin Pop
  @classmethod
461 ff9c047c Iustin Pop
  def FromDict(cls, val):
462 ff9c047c Iustin Pop
    """Custom function for top-level config data
463 ff9c047c Iustin Pop

464 ff9c047c Iustin Pop
    """
465 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
466 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
467 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
468 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
469 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
470 08208574 Dimitris Aragiorgis
    obj.networks = cls._ContainerFromDicts(obj.networks, dict, Network)
471 ff9c047c Iustin Pop
    return obj
472 ff9c047c Iustin Pop
473 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
474 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
475 51cb1581 Luca Bigliardi

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

481 51cb1581 Luca Bigliardi
    """
482 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
483 51cb1581 Luca Bigliardi
      for disk in instance.disks:
484 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
485 51cb1581 Luca Bigliardi
          return True
486 51cb1581 Luca Bigliardi
    return False
487 51cb1581 Luca Bigliardi
488 90d726a8 Iustin Pop
  def UpgradeConfig(self):
489 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
490 90d726a8 Iustin Pop

491 90d726a8 Iustin Pop
    """
492 90d726a8 Iustin Pop
    self.cluster.UpgradeConfig()
493 90d726a8 Iustin Pop
    for node in self.nodes.values():
494 90d726a8 Iustin Pop
      node.UpgradeConfig()
495 90d726a8 Iustin Pop
    for instance in self.instances.values():
496 90d726a8 Iustin Pop
      instance.UpgradeConfig()
497 3df43542 Guido Trotter
    if self.nodegroups is None:
498 3df43542 Guido Trotter
      self.nodegroups = {}
499 3df43542 Guido Trotter
    for nodegroup in self.nodegroups.values():
500 3df43542 Guido Trotter
      nodegroup.UpgradeConfig()
501 ee2f0ed4 Luca Bigliardi
    if self.cluster.drbd_usermode_helper is None:
502 ee2f0ed4 Luca Bigliardi
      # To decide if we set an helper let's check if at least one instance has
503 ee2f0ed4 Luca Bigliardi
      # a DRBD disk. This does not cover all the possible scenarios but it
504 ee2f0ed4 Luca Bigliardi
      # gives a good approximation.
505 ee2f0ed4 Luca Bigliardi
      if self.HasAnyDiskOfType(constants.LD_DRBD8):
506 ee2f0ed4 Luca Bigliardi
        self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
507 08208574 Dimitris Aragiorgis
    if self.networks is None:
508 08208574 Dimitris Aragiorgis
      self.networks = {}
509 90d726a8 Iustin Pop
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
class NIC(ConfigObject):
512 a8083063 Iustin Pop
  """Config object representing a network card."""
513 dca1f84a Dimitris Aragiorgis
  __slots__ = ["mac", "ip", "network", "nicparams", "netinfo"]
514 a8083063 Iustin Pop
515 255e19d4 Guido Trotter
  @classmethod
516 255e19d4 Guido Trotter
  def CheckParameterSyntax(cls, nicparams):
517 255e19d4 Guido Trotter
    """Check the given parameters for validity.
518 255e19d4 Guido Trotter

519 255e19d4 Guido Trotter
    @type nicparams:  dict
520 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
521 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
522 255e19d4 Guido Trotter

523 255e19d4 Guido Trotter
    """
524 e8448672 Agata Murawska
    if (nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES and
525 e8448672 Agata Murawska
        nicparams[constants.NIC_MODE] != constants.VALUE_AUTO):
526 255e19d4 Guido Trotter
      err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE]
527 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
528 255e19d4 Guido Trotter
529 0c9d32c1 Guido Trotter
    if (nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED and
530 255e19d4 Guido Trotter
        not nicparams[constants.NIC_LINK]):
531 255e19d4 Guido Trotter
      err = "Missing bridged nic link"
532 255e19d4 Guido Trotter
      raise errors.ConfigurationError(err)
533 255e19d4 Guido Trotter
534 a8083063 Iustin Pop
535 a8083063 Iustin Pop
class Disk(ConfigObject):
536 a8083063 Iustin Pop
  """Config object representing a block device."""
537 a8083063 Iustin Pop
  __slots__ = ["dev_type", "logical_id", "physical_id",
538 bc5d0215 Andrea Spadaccini
               "children", "iv_name", "size", "mode", "params"]
539 a8083063 Iustin Pop
540 a8083063 Iustin Pop
  def CreateOnSecondary(self):
541 a8083063 Iustin Pop
    """Test if this device needs to be created on a secondary node."""
542 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
543 a8083063 Iustin Pop
544 a8083063 Iustin Pop
  def AssembleOnSecondary(self):
545 a8083063 Iustin Pop
    """Test if this device needs to be assembled on a secondary node."""
546 00fb8246 Michael Hanselmann
    return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
547 a8083063 Iustin Pop
548 a8083063 Iustin Pop
  def OpenOnSecondary(self):
549 a8083063 Iustin Pop
    """Test if this device needs to be opened on a secondary node."""
550 fe96220b Iustin Pop
    return self.dev_type in (constants.LD_LV,)
551 a8083063 Iustin Pop
552 222f2dd5 Iustin Pop
  def StaticDevPath(self):
553 222f2dd5 Iustin Pop
    """Return the device path if this device type has a static one.
554 222f2dd5 Iustin Pop

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

559 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
560 e51db2a6 Iustin Pop
        should check that it is a valid path.
561 e51db2a6 Iustin Pop

562 222f2dd5 Iustin Pop
    """
563 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
564 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
565 b6135bbc Apollon Oikonomopoulos
    elif self.dev_type == constants.LD_BLOCKDEV:
566 b6135bbc Apollon Oikonomopoulos
      return self.logical_id[1]
567 7181fba0 Constantinos Venetsanopoulos
    elif self.dev_type == constants.LD_RBD:
568 7181fba0 Constantinos Venetsanopoulos
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
569 222f2dd5 Iustin Pop
    return None
570 222f2dd5 Iustin Pop
571 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
572 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
573 fc1dc9d7 Iustin Pop

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

578 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
579 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
580 fc1dc9d7 Iustin Pop
    -1.
581 fc1dc9d7 Iustin Pop

582 fc1dc9d7 Iustin Pop
    """
583 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
584 fc1dc9d7 Iustin Pop
      return 0
585 fc1dc9d7 Iustin Pop
    return -1
586 fc1dc9d7 Iustin Pop
587 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
588 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
589 51cb1581 Luca Bigliardi

590 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
591 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
592 51cb1581 Luca Bigliardi
    @rtype: boolean
593 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
594 51cb1581 Luca Bigliardi

595 51cb1581 Luca Bigliardi
    """
596 51cb1581 Luca Bigliardi
    if self.children:
597 51cb1581 Luca Bigliardi
      for child in self.children:
598 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
599 51cb1581 Luca Bigliardi
          return True
600 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
601 51cb1581 Luca Bigliardi
602 a8083063 Iustin Pop
  def GetNodes(self, node):
603 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
604 a8083063 Iustin Pop

605 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
606 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
607 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
608 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
609 a8083063 Iustin Pop

610 a8083063 Iustin Pop
    """
611 b6135bbc Apollon Oikonomopoulos
    if self.dev_type in [constants.LD_LV, constants.LD_FILE,
612 7181fba0 Constantinos Venetsanopoulos
                         constants.LD_BLOCKDEV, constants.LD_RBD]:
613 a8083063 Iustin Pop
      result = [node]
614 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
615 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
616 a8083063 Iustin Pop
      if node not in result:
617 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
618 a8083063 Iustin Pop
    else:
619 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
620 a8083063 Iustin Pop
    return result
621 a8083063 Iustin Pop
622 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
623 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
624 a8083063 Iustin Pop

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

631 a8083063 Iustin Pop
    """
632 a8083063 Iustin Pop
    my_nodes = self.GetNodes(parent_node)
633 a8083063 Iustin Pop
    result = [(node, self) for node in my_nodes]
634 a8083063 Iustin Pop
    if not self.children:
635 a8083063 Iustin Pop
      # leaf device
636 a8083063 Iustin Pop
      return result
637 a8083063 Iustin Pop
    for node in my_nodes:
638 a8083063 Iustin Pop
      for child in self.children:
639 a8083063 Iustin Pop
        child_result = child.ComputeNodeTree(node)
640 a8083063 Iustin Pop
        if len(child_result) == 1:
641 a8083063 Iustin Pop
          # child (and all its descendants) is simple, doesn't split
642 a8083063 Iustin Pop
          # over multiple hosts, so we don't need to describe it, our
643 a8083063 Iustin Pop
          # own entry for this node describes it completely
644 a8083063 Iustin Pop
          continue
645 a8083063 Iustin Pop
        else:
646 a8083063 Iustin Pop
          # check if child nodes differ from my nodes; note that
647 a8083063 Iustin Pop
          # subdisk can differ from the child itself, and be instead
648 a8083063 Iustin Pop
          # one of its descendants
649 a8083063 Iustin Pop
          for subnode, subdisk in child_result:
650 a8083063 Iustin Pop
            if subnode not in my_nodes:
651 a8083063 Iustin Pop
              result.append((subnode, subdisk))
652 a8083063 Iustin Pop
            # otherwise child is under our own node, so we ignore this
653 a8083063 Iustin Pop
            # entry (but probably the other results in the list will
654 a8083063 Iustin Pop
            # be different)
655 a8083063 Iustin Pop
    return result
656 a8083063 Iustin Pop
657 6d33a6eb Iustin Pop
  def ComputeGrowth(self, amount):
658 6d33a6eb Iustin Pop
    """Compute the per-VG growth requirements.
659 6d33a6eb Iustin Pop

660 6d33a6eb Iustin Pop
    This only works for VG-based disks.
661 6d33a6eb Iustin Pop

662 6d33a6eb Iustin Pop
    @type amount: integer
663 6d33a6eb Iustin Pop
    @param amount: the desired increase in (user-visible) disk space
664 6d33a6eb Iustin Pop
    @rtype: dict
665 6d33a6eb Iustin Pop
    @return: a dictionary of volume-groups and the required size
666 6d33a6eb Iustin Pop

667 6d33a6eb Iustin Pop
    """
668 6d33a6eb Iustin Pop
    if self.dev_type == constants.LD_LV:
669 6d33a6eb Iustin Pop
      return {self.logical_id[0]: amount}
670 6d33a6eb Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
671 6d33a6eb Iustin Pop
      if self.children:
672 6d33a6eb Iustin Pop
        return self.children[0].ComputeGrowth(amount)
673 6d33a6eb Iustin Pop
      else:
674 6d33a6eb Iustin Pop
        return {}
675 6d33a6eb Iustin Pop
    else:
676 6d33a6eb Iustin Pop
      # Other disk types do not require VG space
677 6d33a6eb Iustin Pop
      return {}
678 6d33a6eb Iustin Pop
679 acec9d51 Iustin Pop
  def RecordGrow(self, amount):
680 acec9d51 Iustin Pop
    """Update the size of this disk after growth.
681 acec9d51 Iustin Pop

682 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
683 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
684 acec9d51 Iustin Pop
    actual algorithms from bdev.
685 acec9d51 Iustin Pop

686 acec9d51 Iustin Pop
    """
687 7181fba0 Constantinos Venetsanopoulos
    if self.dev_type in (constants.LD_LV, constants.LD_FILE,
688 7181fba0 Constantinos Venetsanopoulos
                         constants.LD_RBD):
689 acec9d51 Iustin Pop
      self.size += amount
690 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
691 acec9d51 Iustin Pop
      if self.children:
692 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
693 acec9d51 Iustin Pop
      self.size += amount
694 acec9d51 Iustin Pop
    else:
695 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
696 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
697 acec9d51 Iustin Pop
698 735e1318 Michael Hanselmann
  def Update(self, size=None, mode=None):
699 735e1318 Michael Hanselmann
    """Apply changes to size and mode.
700 735e1318 Michael Hanselmann

701 735e1318 Michael Hanselmann
    """
702 735e1318 Michael Hanselmann
    if self.dev_type == constants.LD_DRBD8:
703 735e1318 Michael Hanselmann
      if self.children:
704 735e1318 Michael Hanselmann
        self.children[0].Update(size=size, mode=mode)
705 735e1318 Michael Hanselmann
    else:
706 735e1318 Michael Hanselmann
      assert not self.children
707 735e1318 Michael Hanselmann
708 735e1318 Michael Hanselmann
    if size is not None:
709 735e1318 Michael Hanselmann
      self.size = size
710 735e1318 Michael Hanselmann
    if mode is not None:
711 735e1318 Michael Hanselmann
      self.mode = mode
712 735e1318 Michael Hanselmann
713 a805ec18 Iustin Pop
  def UnsetSize(self):
714 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
715 a805ec18 Iustin Pop

716 a805ec18 Iustin Pop
    """
717 a805ec18 Iustin Pop
    if self.children:
718 a805ec18 Iustin Pop
      for child in self.children:
719 a805ec18 Iustin Pop
        child.UnsetSize()
720 a805ec18 Iustin Pop
    self.size = 0
721 a805ec18 Iustin Pop
722 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
723 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
724 0402302c Iustin Pop

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

727 0402302c Iustin Pop
    The routine descends down and updates its children also, because
728 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
729 0402302c Iustin Pop
    node.
730 0402302c Iustin Pop

731 0402302c Iustin Pop
    Arguments:
732 0402302c Iustin Pop
      - target_node: the node we wish to configure for
733 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
734 0402302c Iustin Pop

735 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
736 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
737 0402302c Iustin Pop
    in the disk tree.
738 0402302c Iustin Pop

739 0402302c Iustin Pop
    """
740 0402302c Iustin Pop
    if self.children:
741 0402302c Iustin Pop
      for child in self.children:
742 0402302c Iustin Pop
        child.SetPhysicalID(target_node, nodes_ip)
743 0402302c Iustin Pop
744 0402302c Iustin Pop
    if self.logical_id is None and self.physical_id is not None:
745 0402302c Iustin Pop
      return
746 0402302c Iustin Pop
    if self.dev_type in constants.LDS_DRBD:
747 f9518d38 Iustin Pop
      pnode, snode, port, pminor, sminor, secret = self.logical_id
748 0402302c Iustin Pop
      if target_node not in (pnode, snode):
749 0402302c Iustin Pop
        raise errors.ConfigurationError("DRBD device not knowing node %s" %
750 0402302c Iustin Pop
                                        target_node)
751 0402302c Iustin Pop
      pnode_ip = nodes_ip.get(pnode, None)
752 0402302c Iustin Pop
      snode_ip = nodes_ip.get(snode, None)
753 0402302c Iustin Pop
      if pnode_ip is None or snode_ip is None:
754 0402302c Iustin Pop
        raise errors.ConfigurationError("Can't find primary or secondary node"
755 0402302c Iustin Pop
                                        " for %s" % str(self))
756 ffa1c0dc Iustin Pop
      p_data = (pnode_ip, port)
757 ffa1c0dc Iustin Pop
      s_data = (snode_ip, port)
758 0402302c Iustin Pop
      if pnode == target_node:
759 f9518d38 Iustin Pop
        self.physical_id = p_data + s_data + (pminor, secret)
760 0402302c Iustin Pop
      else: # it must be secondary, we tested above
761 f9518d38 Iustin Pop
        self.physical_id = s_data + p_data + (sminor, secret)
762 0402302c Iustin Pop
    else:
763 0402302c Iustin Pop
      self.physical_id = self.logical_id
764 0402302c Iustin Pop
    return
765 0402302c Iustin Pop
766 ff9c047c Iustin Pop
  def ToDict(self):
767 ff9c047c Iustin Pop
    """Disk-specific conversion to standard python types.
768 ff9c047c Iustin Pop

769 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
770 ff9c047c Iustin Pop
    standard python types.
771 ff9c047c Iustin Pop

772 ff9c047c Iustin Pop
    """
773 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
774 ff9c047c Iustin Pop
775 ff9c047c Iustin Pop
    for attr in ("children",):
776 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
777 ff9c047c Iustin Pop
      if alist:
778 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
779 ff9c047c Iustin Pop
    return bo
780 ff9c047c Iustin Pop
781 ff9c047c Iustin Pop
  @classmethod
782 ff9c047c Iustin Pop
  def FromDict(cls, val):
783 ff9c047c Iustin Pop
    """Custom function for Disks
784 ff9c047c Iustin Pop

785 ff9c047c Iustin Pop
    """
786 ff9c047c Iustin Pop
    obj = super(Disk, cls).FromDict(val)
787 ff9c047c Iustin Pop
    if obj.children:
788 ff9c047c Iustin Pop
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
789 ff9c047c Iustin Pop
    if obj.logical_id and isinstance(obj.logical_id, list):
790 ff9c047c Iustin Pop
      obj.logical_id = tuple(obj.logical_id)
791 ff9c047c Iustin Pop
    if obj.physical_id and isinstance(obj.physical_id, list):
792 ff9c047c Iustin Pop
      obj.physical_id = tuple(obj.physical_id)
793 f9518d38 Iustin Pop
    if obj.dev_type in constants.LDS_DRBD:
794 f9518d38 Iustin Pop
      # we need a tuple of length six here
795 f9518d38 Iustin Pop
      if len(obj.logical_id) < 6:
796 f9518d38 Iustin Pop
        obj.logical_id += (None,) * (6 - len(obj.logical_id))
797 ff9c047c Iustin Pop
    return obj
798 ff9c047c Iustin Pop
799 65a15336 Iustin Pop
  def __str__(self):
800 65a15336 Iustin Pop
    """Custom str() formatter for disks.
801 65a15336 Iustin Pop

802 65a15336 Iustin Pop
    """
803 65a15336 Iustin Pop
    if self.dev_type == constants.LD_LV:
804 e687ec01 Michael Hanselmann
      val = "<LogicalVolume(/dev/%s/%s" % self.logical_id
805 65a15336 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
806 89f28b76 Iustin Pop
      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
807 00fb8246 Michael Hanselmann
      val = "<DRBD8("
808 073ca59e Iustin Pop
      if self.physical_id is None:
809 073ca59e Iustin Pop
        phy = "unconfigured"
810 073ca59e Iustin Pop
      else:
811 073ca59e Iustin Pop
        phy = ("configured as %s:%s %s:%s" %
812 25a915d0 Iustin Pop
               (self.physical_id[0], self.physical_id[1],
813 25a915d0 Iustin Pop
                self.physical_id[2], self.physical_id[3]))
814 073ca59e Iustin Pop
815 89f28b76 Iustin Pop
      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
816 89f28b76 Iustin Pop
              (node_a, minor_a, node_b, minor_b, port, phy))
817 65a15336 Iustin Pop
      if self.children and self.children.count(None) == 0:
818 65a15336 Iustin Pop
        val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
819 65a15336 Iustin Pop
      else:
820 65a15336 Iustin Pop
        val += "no local storage"
821 65a15336 Iustin Pop
    else:
822 65a15336 Iustin Pop
      val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
823 65a15336 Iustin Pop
             (self.dev_type, self.logical_id, self.physical_id, self.children))
824 65a15336 Iustin Pop
    if self.iv_name is None:
825 65a15336 Iustin Pop
      val += ", not visible"
826 65a15336 Iustin Pop
    else:
827 65a15336 Iustin Pop
      val += ", visible as /dev/%s" % self.iv_name
828 fd965830 Iustin Pop
    if isinstance(self.size, int):
829 fd965830 Iustin Pop
      val += ", size=%dm)>" % self.size
830 fd965830 Iustin Pop
    else:
831 fd965830 Iustin Pop
      val += ", size='%s')>" % (self.size,)
832 65a15336 Iustin Pop
    return val
833 65a15336 Iustin Pop
834 332d0e37 Iustin Pop
  def Verify(self):
835 332d0e37 Iustin Pop
    """Checks that this disk is correctly configured.
836 332d0e37 Iustin Pop

837 332d0e37 Iustin Pop
    """
838 7c4d6c7b Michael Hanselmann
    all_errors = []
839 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
840 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
841 7c4d6c7b Michael Hanselmann
    return all_errors
842 332d0e37 Iustin Pop
843 90d726a8 Iustin Pop
  def UpgradeConfig(self):
844 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
845 90d726a8 Iustin Pop

846 90d726a8 Iustin Pop
    """
847 90d726a8 Iustin Pop
    if self.children:
848 90d726a8 Iustin Pop
      for child in self.children:
849 90d726a8 Iustin Pop
        child.UpgradeConfig()
850 bc5d0215 Andrea Spadaccini
851 bc5d0215 Andrea Spadaccini
    if not self.params:
852 bc5d0215 Andrea Spadaccini
      self.params = constants.DISK_LD_DEFAULTS[self.dev_type].copy()
853 bc5d0215 Andrea Spadaccini
    else:
854 bc5d0215 Andrea Spadaccini
      self.params = FillDict(constants.DISK_LD_DEFAULTS[self.dev_type],
855 bc5d0215 Andrea Spadaccini
                             self.params)
856 90d726a8 Iustin Pop
    # add here config upgrade for this disk
857 90d726a8 Iustin Pop
858 cd46491f Renรฉ Nussbaumer
  @staticmethod
859 cd46491f Renรฉ Nussbaumer
  def ComputeLDParams(disk_template, disk_params):
860 cd46491f Renรฉ Nussbaumer
    """Computes Logical Disk parameters from Disk Template parameters.
861 cd46491f Renรฉ Nussbaumer

862 cd46491f Renรฉ Nussbaumer
    @type disk_template: string
863 cd46491f Renรฉ Nussbaumer
    @param disk_template: disk template, one of L{constants.DISK_TEMPLATES}
864 cd46491f Renรฉ Nussbaumer
    @type disk_params: dict
865 cd46491f Renรฉ Nussbaumer
    @param disk_params: disk template parameters;
866 cd46491f Renรฉ Nussbaumer
                        dict(template_name -> parameters
867 cd46491f Renรฉ Nussbaumer
    @rtype: list(dict)
868 cd46491f Renรฉ Nussbaumer
    @return: a list of dicts, one for each node of the disk hierarchy. Each dict
869 cd46491f Renรฉ Nussbaumer
      contains the LD parameters of the node. The tree is flattened in-order.
870 cd46491f Renรฉ Nussbaumer

871 cd46491f Renรฉ Nussbaumer
    """
872 cd46491f Renรฉ Nussbaumer
    if disk_template not in constants.DISK_TEMPLATES:
873 cd46491f Renรฉ Nussbaumer
      raise errors.ProgrammerError("Unknown disk template %s" % disk_template)
874 cd46491f Renรฉ Nussbaumer
875 cd46491f Renรฉ Nussbaumer
    assert disk_template in disk_params
876 cd46491f Renรฉ Nussbaumer
877 cd46491f Renรฉ Nussbaumer
    result = list()
878 cd46491f Renรฉ Nussbaumer
    dt_params = disk_params[disk_template]
879 cd46491f Renรฉ Nussbaumer
    if disk_template == constants.DT_DRBD8:
880 cd46491f Renรฉ Nussbaumer
      drbd_params = {
881 cd46491f Renรฉ Nussbaumer
        constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE],
882 cd46491f Renรฉ Nussbaumer
        constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS],
883 cd46491f Renรฉ Nussbaumer
        constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS],
884 cd46491f Renรฉ Nussbaumer
        constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG],
885 cd46491f Renรฉ Nussbaumer
        constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM],
886 cd46491f Renรฉ Nussbaumer
        constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM],
887 cd46491f Renรฉ Nussbaumer
        constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC],
888 cd46491f Renรฉ Nussbaumer
        constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD],
889 cd46491f Renรฉ Nussbaumer
        constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET],
890 cd46491f Renรฉ Nussbaumer
        constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET],
891 cd46491f Renรฉ Nussbaumer
        constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE],
892 cd46491f Renรฉ Nussbaumer
        constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE],
893 cd46491f Renรฉ Nussbaumer
        }
894 cd46491f Renรฉ Nussbaumer
895 cd46491f Renรฉ Nussbaumer
      drbd_params = \
896 cd46491f Renรฉ Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8],
897 cd46491f Renรฉ Nussbaumer
                 drbd_params)
898 cd46491f Renรฉ Nussbaumer
899 cd46491f Renรฉ Nussbaumer
      result.append(drbd_params)
900 cd46491f Renรฉ Nussbaumer
901 cd46491f Renรฉ Nussbaumer
      # data LV
902 cd46491f Renรฉ Nussbaumer
      data_params = {
903 cd46491f Renรฉ Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
904 cd46491f Renรฉ Nussbaumer
        }
905 cd46491f Renรฉ Nussbaumer
      data_params = \
906 cd46491f Renรฉ Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
907 cd46491f Renรฉ Nussbaumer
                 data_params)
908 cd46491f Renรฉ Nussbaumer
      result.append(data_params)
909 cd46491f Renรฉ Nussbaumer
910 cd46491f Renรฉ Nussbaumer
      # metadata LV
911 cd46491f Renรฉ Nussbaumer
      meta_params = {
912 cd46491f Renรฉ Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
913 cd46491f Renรฉ Nussbaumer
        }
914 cd46491f Renรฉ Nussbaumer
      meta_params = \
915 cd46491f Renรฉ Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
916 cd46491f Renรฉ Nussbaumer
                 meta_params)
917 cd46491f Renรฉ Nussbaumer
      result.append(meta_params)
918 cd46491f Renรฉ Nussbaumer
919 cd46491f Renรฉ Nussbaumer
    elif (disk_template == constants.DT_FILE or
920 cd46491f Renรฉ Nussbaumer
          disk_template == constants.DT_SHARED_FILE):
921 cd46491f Renรฉ Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
922 cd46491f Renรฉ Nussbaumer
923 cd46491f Renรฉ Nussbaumer
    elif disk_template == constants.DT_PLAIN:
924 cd46491f Renรฉ Nussbaumer
      params = {
925 cd46491f Renรฉ Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
926 cd46491f Renรฉ Nussbaumer
        }
927 cd46491f Renรฉ Nussbaumer
      params = \
928 cd46491f Renรฉ Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
929 cd46491f Renรฉ Nussbaumer
                 params)
930 cd46491f Renรฉ Nussbaumer
      result.append(params)
931 cd46491f Renรฉ Nussbaumer
932 cd46491f Renรฉ Nussbaumer
    elif disk_template == constants.DT_BLOCK:
933 cd46491f Renรฉ Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
934 cd46491f Renรฉ Nussbaumer
935 cd46491f Renรฉ Nussbaumer
    elif disk_template == constants.DT_RBD:
936 cd46491f Renรฉ Nussbaumer
      params = {
937 cd46491f Renรฉ Nussbaumer
        constants.LDP_POOL: dt_params[constants.RBD_POOL]
938 cd46491f Renรฉ Nussbaumer
        }
939 cd46491f Renรฉ Nussbaumer
      params = \
940 cd46491f Renรฉ Nussbaumer
        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD],
941 cd46491f Renรฉ Nussbaumer
                 params)
942 cd46491f Renรฉ Nussbaumer
      result.append(params)
943 cd46491f Renรฉ Nussbaumer
944 cd46491f Renรฉ Nussbaumer
    return result
945 cd46491f Renรฉ Nussbaumer
946 a8083063 Iustin Pop
947 918eb80b Agata Murawska
class InstancePolicy(ConfigObject):
948 ffa339ca Iustin Pop
  """Config object representing instance policy limits dictionary.
949 918eb80b Agata Murawska

950 ffa339ca Iustin Pop

951 ffa339ca Iustin Pop
  Note that this object is not actually used in the config, it's just
952 ffa339ca Iustin Pop
  used as a placeholder for a few functions.
953 ffa339ca Iustin Pop

954 ffa339ca Iustin Pop
  """
955 918eb80b Agata Murawska
  @classmethod
956 918eb80b Agata Murawska
  def CheckParameterSyntax(cls, ipolicy):
957 918eb80b Agata Murawska
    """ Check the instance policy for validity.
958 918eb80b Agata Murawska

959 918eb80b Agata Murawska
    """
960 918eb80b Agata Murawska
    for param in constants.ISPECS_PARAMETERS:
961 918eb80b Agata Murawska
      InstancePolicy.CheckISpecSyntax(ipolicy, param)
962 d04c9d45 Iustin Pop
    if constants.IPOLICY_DTS in ipolicy:
963 d04c9d45 Iustin Pop
      InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
964 ff6c5e55 Iustin Pop
    for key in constants.IPOLICY_PARAMETERS:
965 ff6c5e55 Iustin Pop
      if key in ipolicy:
966 ff6c5e55 Iustin Pop
        InstancePolicy.CheckParameter(key, ipolicy[key])
967 57dc299a Iustin Pop
    wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
968 57dc299a Iustin Pop
    if wrong_keys:
969 57dc299a Iustin Pop
      raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
970 57dc299a Iustin Pop
                                      utils.CommaJoin(wrong_keys))
971 918eb80b Agata Murawska
972 918eb80b Agata Murawska
  @classmethod
973 918eb80b Agata Murawska
  def CheckISpecSyntax(cls, ipolicy, name):
974 918eb80b Agata Murawska
    """Check the instance policy for validity on a given key.
975 918eb80b Agata Murawska

976 918eb80b Agata Murawska
    We check if the instance policy makes sense for a given key, that is
977 918eb80b Agata Murawska
    if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name].
978 918eb80b Agata Murawska

979 918eb80b Agata Murawska
    @type ipolicy: dict
980 918eb80b Agata Murawska
    @param ipolicy: dictionary with min, max, std specs
981 918eb80b Agata Murawska
    @type name: string
982 918eb80b Agata Murawska
    @param name: what are the limits for
983 918eb80b Agata Murawska
    @raise errors.ConfigureError: when specs for given name are not valid
984 918eb80b Agata Murawska

985 918eb80b Agata Murawska
    """
986 4f725341 Agata Murawska
    min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
987 4f725341 Agata Murawska
    std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
988 4f725341 Agata Murawska
    max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
989 918eb80b Agata Murawska
    err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
990 918eb80b Agata Murawska
           (name,
991 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MIN].get(name, "-"),
992 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MAX].get(name, "-"),
993 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_STD].get(name, "-")))
994 918eb80b Agata Murawska
    if min_v > std_v or std_v > max_v:
995 918eb80b Agata Murawska
      raise errors.ConfigurationError(err)
996 918eb80b Agata Murawska
997 2cc673a3 Iustin Pop
  @classmethod
998 2cc673a3 Iustin Pop
  def CheckDiskTemplates(cls, disk_templates):
999 2cc673a3 Iustin Pop
    """Checks the disk templates for validity.
1000 2cc673a3 Iustin Pop

1001 2cc673a3 Iustin Pop
    """
1002 2cc673a3 Iustin Pop
    wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
1003 2cc673a3 Iustin Pop
    if wrong:
1004 2cc673a3 Iustin Pop
      raise errors.ConfigurationError("Invalid disk template(s) %s" %
1005 2cc673a3 Iustin Pop
                                      utils.CommaJoin(wrong))
1006 2cc673a3 Iustin Pop
1007 ff6c5e55 Iustin Pop
  @classmethod
1008 ff6c5e55 Iustin Pop
  def CheckParameter(cls, key, value):
1009 ff6c5e55 Iustin Pop
    """Checks a parameter.
1010 ff6c5e55 Iustin Pop

1011 ff6c5e55 Iustin Pop
    Currently we expect all parameters to be float values.
1012 ff6c5e55 Iustin Pop

1013 ff6c5e55 Iustin Pop
    """
1014 ff6c5e55 Iustin Pop
    try:
1015 ff6c5e55 Iustin Pop
      float(value)
1016 ff6c5e55 Iustin Pop
    except (TypeError, ValueError), err:
1017 ff6c5e55 Iustin Pop
      raise errors.ConfigurationError("Invalid value for key" " '%s':"
1018 ff6c5e55 Iustin Pop
                                      " '%s', error: %s" % (key, value, err))
1019 ff6c5e55 Iustin Pop
1020 918eb80b Agata Murawska
1021 ec29fe40 Iustin Pop
class Instance(TaggableObject):
1022 a8083063 Iustin Pop
  """Config object representing an instance."""
1023 154b9580 Balazs Lecz
  __slots__ = [
1024 a8083063 Iustin Pop
    "name",
1025 a8083063 Iustin Pop
    "primary_node",
1026 a8083063 Iustin Pop
    "os",
1027 e69d05fd Iustin Pop
    "hypervisor",
1028 5bf7b5cf Iustin Pop
    "hvparams",
1029 5bf7b5cf Iustin Pop
    "beparams",
1030 1bdcbbab Iustin Pop
    "osparams",
1031 9ca8a7c5 Agata Murawska
    "admin_state",
1032 a8083063 Iustin Pop
    "nics",
1033 a8083063 Iustin Pop
    "disks",
1034 a8083063 Iustin Pop
    "disk_template",
1035 58acb49d Alexander Schreiber
    "network_port",
1036 be1fa613 Iustin Pop
    "serial_no",
1037 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1038 a8083063 Iustin Pop
1039 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
1040 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
1041 a8083063 Iustin Pop

1042 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
1043 cfcc5c6d Iustin Pop

1044 cfcc5c6d Iustin Pop
    """
1045 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
1046 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
1047 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1048 cfcc5c6d Iustin Pop
1049 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
1050 cfcc5c6d Iustin Pop
                             "List of secondary nodes")
1051 cfcc5c6d Iustin Pop
1052 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
1053 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
1054 cfcc5c6d Iustin Pop

1055 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
1056 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
1057 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
1058 a8083063 Iustin Pop
    dynamically.
1059 a8083063 Iustin Pop

1060 a8083063 Iustin Pop
    """
1061 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
1062 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
1063 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
1064 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
1065 cfcc5c6d Iustin Pop
        nodes.add(nodea)
1066 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
1067 a8083063 Iustin Pop
      if device.children:
1068 a8083063 Iustin Pop
        for child in device.children:
1069 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
1070 a8083063 Iustin Pop
1071 cfcc5c6d Iustin Pop
    all_nodes = set()
1072 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
1073 a8083063 Iustin Pop
    for device in self.disks:
1074 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
1075 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1076 a8083063 Iustin Pop
1077 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
1078 cfcc5c6d Iustin Pop
                       "List of all nodes of the instance")
1079 a8083063 Iustin Pop
1080 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
1081 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
1082 a8083063 Iustin Pop

1083 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
1084 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
1085 a8083063 Iustin Pop

1086 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
1087 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
1088 a8083063 Iustin Pop

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

1094 a8083063 Iustin Pop
    """
1095 a8083063 Iustin Pop
    if node == None:
1096 a8083063 Iustin Pop
      node = self.primary_node
1097 a8083063 Iustin Pop
1098 a8083063 Iustin Pop
    if lvmap is None:
1099 e687ec01 Michael Hanselmann
      lvmap = {
1100 e687ec01 Michael Hanselmann
        node: [],
1101 e687ec01 Michael Hanselmann
        }
1102 a8083063 Iustin Pop
      ret = lvmap
1103 a8083063 Iustin Pop
    else:
1104 a8083063 Iustin Pop
      if not node in lvmap:
1105 a8083063 Iustin Pop
        lvmap[node] = []
1106 a8083063 Iustin Pop
      ret = None
1107 a8083063 Iustin Pop
1108 a8083063 Iustin Pop
    if not devs:
1109 a8083063 Iustin Pop
      devs = self.disks
1110 a8083063 Iustin Pop
1111 a8083063 Iustin Pop
    for dev in devs:
1112 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
1113 e687ec01 Michael Hanselmann
        lvmap[node].append(dev.logical_id[0] + "/" + dev.logical_id[1])
1114 a8083063 Iustin Pop
1115 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
1116 a8083063 Iustin Pop
        if dev.children:
1117 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
1118 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
1119 a8083063 Iustin Pop
1120 a8083063 Iustin Pop
      elif dev.children:
1121 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
1122 a8083063 Iustin Pop
1123 a8083063 Iustin Pop
    return ret
1124 a8083063 Iustin Pop
1125 ad24e046 Iustin Pop
  def FindDisk(self, idx):
1126 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
1127 644eeef9 Iustin Pop

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

1130 ad24e046 Iustin Pop
    @type idx: int
1131 ad24e046 Iustin Pop
    @param idx: the disk index
1132 ad24e046 Iustin Pop
    @rtype: L{Disk}
1133 ad24e046 Iustin Pop
    @return: the corresponding disk
1134 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
1135 644eeef9 Iustin Pop

1136 ad24e046 Iustin Pop
    """
1137 ad24e046 Iustin Pop
    try:
1138 ad24e046 Iustin Pop
      idx = int(idx)
1139 ad24e046 Iustin Pop
      return self.disks[idx]
1140 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
1141 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
1142 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1143 ad24e046 Iustin Pop
    except IndexError:
1144 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
1145 daa55b04 Michael Hanselmann
                                 " 0 to %d" % (idx, len(self.disks) - 1),
1146 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1147 644eeef9 Iustin Pop
1148 ff9c047c Iustin Pop
  def ToDict(self):
1149 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
1150 ff9c047c Iustin Pop

1151 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
1152 ff9c047c Iustin Pop
    python types.
1153 ff9c047c Iustin Pop

1154 ff9c047c Iustin Pop
    """
1155 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
1156 ff9c047c Iustin Pop
1157 ff9c047c Iustin Pop
    for attr in "nics", "disks":
1158 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
1159 ff9c047c Iustin Pop
      if alist:
1160 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
1161 ff9c047c Iustin Pop
      else:
1162 ff9c047c Iustin Pop
        nlist = []
1163 ff9c047c Iustin Pop
      bo[attr] = nlist
1164 ff9c047c Iustin Pop
    return bo
1165 ff9c047c Iustin Pop
1166 ff9c047c Iustin Pop
  @classmethod
1167 ff9c047c Iustin Pop
  def FromDict(cls, val):
1168 ff9c047c Iustin Pop
    """Custom function for instances.
1169 ff9c047c Iustin Pop

1170 ff9c047c Iustin Pop
    """
1171 9ca8a7c5 Agata Murawska
    if "admin_state" not in val:
1172 9ca8a7c5 Agata Murawska
      if val.get("admin_up", False):
1173 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_UP
1174 9ca8a7c5 Agata Murawska
      else:
1175 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_DOWN
1176 9ca8a7c5 Agata Murawska
    if "admin_up" in val:
1177 9ca8a7c5 Agata Murawska
      del val["admin_up"]
1178 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
1179 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
1180 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
1181 ff9c047c Iustin Pop
    return obj
1182 ff9c047c Iustin Pop
1183 90d726a8 Iustin Pop
  def UpgradeConfig(self):
1184 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
1185 90d726a8 Iustin Pop

1186 90d726a8 Iustin Pop
    """
1187 90d726a8 Iustin Pop
    for nic in self.nics:
1188 90d726a8 Iustin Pop
      nic.UpgradeConfig()
1189 90d726a8 Iustin Pop
    for disk in self.disks:
1190 90d726a8 Iustin Pop
      disk.UpgradeConfig()
1191 7736a5f2 Iustin Pop
    if self.hvparams:
1192 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
1193 7736a5f2 Iustin Pop
        try:
1194 7736a5f2 Iustin Pop
          del self.hvparams[key]
1195 7736a5f2 Iustin Pop
        except KeyError:
1196 7736a5f2 Iustin Pop
          pass
1197 1bdcbbab Iustin Pop
    if self.osparams is None:
1198 1bdcbbab Iustin Pop
      self.osparams = {}
1199 8c72ab2b Guido Trotter
    UpgradeBeParams(self.beparams)
1200 90d726a8 Iustin Pop
1201 a8083063 Iustin Pop
1202 a8083063 Iustin Pop
class OS(ConfigObject):
1203 b41b3516 Iustin Pop
  """Config object representing an operating system.
1204 b41b3516 Iustin Pop

1205 b41b3516 Iustin Pop
  @type supported_parameters: list
1206 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
1207 b41b3516 Iustin Pop
      containing the supported parameters by this OS
1208 b41b3516 Iustin Pop

1209 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
1210 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
1211 870dc44c Iustin Pop

1212 b41b3516 Iustin Pop
  """
1213 a8083063 Iustin Pop
  __slots__ = [
1214 a8083063 Iustin Pop
    "name",
1215 a8083063 Iustin Pop
    "path",
1216 082a7f91 Guido Trotter
    "api_versions",
1217 a8083063 Iustin Pop
    "create_script",
1218 a8083063 Iustin Pop
    "export_script",
1219 386b57af Iustin Pop
    "import_script",
1220 386b57af Iustin Pop
    "rename_script",
1221 b41b3516 Iustin Pop
    "verify_script",
1222 6d79896b Guido Trotter
    "supported_variants",
1223 b41b3516 Iustin Pop
    "supported_parameters",
1224 a8083063 Iustin Pop
    ]
1225 a8083063 Iustin Pop
1226 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
1227 870dc44c Iustin Pop
1228 870dc44c Iustin Pop
  @classmethod
1229 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
1230 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
1231 870dc44c Iustin Pop

1232 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1233 870dc44c Iustin Pop
    @rtype: list
1234 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
1235 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
1236 870dc44c Iustin Pop

1237 870dc44c Iustin Pop
    """
1238 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
1239 870dc44c Iustin Pop
    if len(nv) == 1:
1240 870dc44c Iustin Pop
      nv.append("")
1241 870dc44c Iustin Pop
    return nv
1242 870dc44c Iustin Pop
1243 870dc44c Iustin Pop
  @classmethod
1244 870dc44c Iustin Pop
  def GetName(cls, name):
1245 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
1246 870dc44c Iustin Pop

1247 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1248 870dc44c Iustin Pop

1249 870dc44c Iustin Pop
    """
1250 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
1251 870dc44c Iustin Pop
1252 870dc44c Iustin Pop
  @classmethod
1253 870dc44c Iustin Pop
  def GetVariant(cls, name):
1254 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
1255 870dc44c Iustin Pop

1256 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1257 870dc44c Iustin Pop

1258 870dc44c Iustin Pop
    """
1259 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
1260 870dc44c Iustin Pop
1261 7c0d6283 Michael Hanselmann
1262 5f06ce5e Michael Hanselmann
class NodeHvState(ConfigObject):
1263 5f06ce5e Michael Hanselmann
  """Hypvervisor state on a node.
1264 5f06ce5e Michael Hanselmann

1265 5f06ce5e Michael Hanselmann
  @ivar mem_total: Total amount of memory
1266 5f06ce5e Michael Hanselmann
  @ivar mem_node: Memory used by, or reserved for, the node itself (not always
1267 5f06ce5e Michael Hanselmann
    available)
1268 5f06ce5e Michael Hanselmann
  @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation
1269 5f06ce5e Michael Hanselmann
    rounding
1270 5f06ce5e Michael Hanselmann
  @ivar mem_inst: Memory used by instances living on node
1271 5f06ce5e Michael Hanselmann
  @ivar cpu_total: Total node CPU core count
1272 5f06ce5e Michael Hanselmann
  @ivar cpu_node: Number of CPU cores reserved for the node itself
1273 5f06ce5e Michael Hanselmann

1274 5f06ce5e Michael Hanselmann
  """
1275 5f06ce5e Michael Hanselmann
  __slots__ = [
1276 5f06ce5e Michael Hanselmann
    "mem_total",
1277 5f06ce5e Michael Hanselmann
    "mem_node",
1278 5f06ce5e Michael Hanselmann
    "mem_hv",
1279 5f06ce5e Michael Hanselmann
    "mem_inst",
1280 5f06ce5e Michael Hanselmann
    "cpu_total",
1281 5f06ce5e Michael Hanselmann
    "cpu_node",
1282 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1283 5f06ce5e Michael Hanselmann
1284 5f06ce5e Michael Hanselmann
1285 5f06ce5e Michael Hanselmann
class NodeDiskState(ConfigObject):
1286 5f06ce5e Michael Hanselmann
  """Disk state on a node.
1287 5f06ce5e Michael Hanselmann

1288 5f06ce5e Michael Hanselmann
  """
1289 5f06ce5e Michael Hanselmann
  __slots__ = [
1290 5f06ce5e Michael Hanselmann
    "total",
1291 5f06ce5e Michael Hanselmann
    "reserved",
1292 5f06ce5e Michael Hanselmann
    "overhead",
1293 5f06ce5e Michael Hanselmann
    ] + _TIMESTAMPS
1294 5f06ce5e Michael Hanselmann
1295 5f06ce5e Michael Hanselmann
1296 ec29fe40 Iustin Pop
class Node(TaggableObject):
1297 634d30f4 Michael Hanselmann
  """Config object representing a node.
1298 634d30f4 Michael Hanselmann

1299 634d30f4 Michael Hanselmann
  @ivar hv_state: Hypervisor state (e.g. number of CPUs)
1300 634d30f4 Michael Hanselmann
  @ivar hv_state_static: Hypervisor state overriden by user
1301 634d30f4 Michael Hanselmann
  @ivar disk_state: Disk state (e.g. free space)
1302 634d30f4 Michael Hanselmann
  @ivar disk_state_static: Disk state overriden by user
1303 634d30f4 Michael Hanselmann

1304 634d30f4 Michael Hanselmann
  """
1305 154b9580 Balazs Lecz
  __slots__ = [
1306 ec29fe40 Iustin Pop
    "name",
1307 ec29fe40 Iustin Pop
    "primary_ip",
1308 ec29fe40 Iustin Pop
    "secondary_ip",
1309 be1fa613 Iustin Pop
    "serial_no",
1310 8b8b8b81 Iustin Pop
    "master_candidate",
1311 fc0fe88c Iustin Pop
    "offline",
1312 af64c0ea Iustin Pop
    "drained",
1313 f936c153 Iustin Pop
    "group",
1314 490acd18 Iustin Pop
    "master_capable",
1315 490acd18 Iustin Pop
    "vm_capable",
1316 095e71aa Renรฉ Nussbaumer
    "ndparams",
1317 25124d4a Renรฉ Nussbaumer
    "powered",
1318 5b49ed09 Renรฉ Nussbaumer
    "hv_state",
1319 634d30f4 Michael Hanselmann
    "hv_state_static",
1320 5b49ed09 Renรฉ Nussbaumer
    "disk_state",
1321 634d30f4 Michael Hanselmann
    "disk_state_static",
1322 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1323 a8083063 Iustin Pop
1324 490acd18 Iustin Pop
  def UpgradeConfig(self):
1325 490acd18 Iustin Pop
    """Fill defaults for missing configuration values.
1326 490acd18 Iustin Pop

1327 490acd18 Iustin Pop
    """
1328 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1329 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
1330 490acd18 Iustin Pop
    if self.master_capable is None:
1331 490acd18 Iustin Pop
      self.master_capable = True
1332 490acd18 Iustin Pop
1333 490acd18 Iustin Pop
    if self.vm_capable is None:
1334 490acd18 Iustin Pop
      self.vm_capable = True
1335 490acd18 Iustin Pop
1336 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1337 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1338 095e71aa Renรฉ Nussbaumer
1339 25124d4a Renรฉ Nussbaumer
    if self.powered is None:
1340 25124d4a Renรฉ Nussbaumer
      self.powered = True
1341 25124d4a Renรฉ Nussbaumer
1342 5f06ce5e Michael Hanselmann
  def ToDict(self):
1343 5f06ce5e Michael Hanselmann
    """Custom function for serializing.
1344 5f06ce5e Michael Hanselmann

1345 5f06ce5e Michael Hanselmann
    """
1346 5f06ce5e Michael Hanselmann
    data = super(Node, self).ToDict()
1347 5f06ce5e Michael Hanselmann
1348 5f06ce5e Michael Hanselmann
    hv_state = data.get("hv_state", None)
1349 5f06ce5e Michael Hanselmann
    if hv_state is not None:
1350 5f06ce5e Michael Hanselmann
      data["hv_state"] = self._ContainerToDicts(hv_state)
1351 5f06ce5e Michael Hanselmann
1352 5f06ce5e Michael Hanselmann
    disk_state = data.get("disk_state", None)
1353 5f06ce5e Michael Hanselmann
    if disk_state is not None:
1354 5f06ce5e Michael Hanselmann
      data["disk_state"] = \
1355 5f06ce5e Michael Hanselmann
        dict((key, self._ContainerToDicts(value))
1356 5f06ce5e Michael Hanselmann
             for (key, value) in disk_state.items())
1357 5f06ce5e Michael Hanselmann
1358 5f06ce5e Michael Hanselmann
    return data
1359 5f06ce5e Michael Hanselmann
1360 5f06ce5e Michael Hanselmann
  @classmethod
1361 5f06ce5e Michael Hanselmann
  def FromDict(cls, val):
1362 5f06ce5e Michael Hanselmann
    """Custom function for deserializing.
1363 5f06ce5e Michael Hanselmann

1364 5f06ce5e Michael Hanselmann
    """
1365 5f06ce5e Michael Hanselmann
    obj = super(Node, cls).FromDict(val)
1366 5f06ce5e Michael Hanselmann
1367 5f06ce5e Michael Hanselmann
    if obj.hv_state is not None:
1368 5f06ce5e Michael Hanselmann
      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1369 5f06ce5e Michael Hanselmann
1370 5f06ce5e Michael Hanselmann
    if obj.disk_state is not None:
1371 5f06ce5e Michael Hanselmann
      obj.disk_state = \
1372 5f06ce5e Michael Hanselmann
        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
1373 5f06ce5e Michael Hanselmann
             for (key, value) in obj.disk_state.items())
1374 5f06ce5e Michael Hanselmann
1375 5f06ce5e Michael Hanselmann
    return obj
1376 5f06ce5e Michael Hanselmann
1377 a8083063 Iustin Pop
1378 1ffd2673 Michael Hanselmann
class NodeGroup(TaggableObject):
1379 24a3707f Guido Trotter
  """Config object representing a node group."""
1380 24a3707f Guido Trotter
  __slots__ = [
1381 24a3707f Guido Trotter
    "name",
1382 24a3707f Guido Trotter
    "members",
1383 095e71aa Renรฉ Nussbaumer
    "ndparams",
1384 bc5d0215 Andrea Spadaccini
    "diskparams",
1385 81e3ab4f Agata Murawska
    "ipolicy",
1386 e11a1b77 Adeodato Simo
    "serial_no",
1387 a8282327 Renรฉ Nussbaumer
    "hv_state_static",
1388 a8282327 Renรฉ Nussbaumer
    "disk_state_static",
1389 90e99856 Adeodato Simo
    "alloc_policy",
1390 08208574 Dimitris Aragiorgis
    "networks",
1391 24a3707f Guido Trotter
    ] + _TIMESTAMPS + _UUID
1392 24a3707f Guido Trotter
1393 24a3707f Guido Trotter
  def ToDict(self):
1394 24a3707f Guido Trotter
    """Custom function for nodegroup.
1395 24a3707f Guido Trotter

1396 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1397 c60abd62 Guido Trotter
    in memory.
1398 24a3707f Guido Trotter

1399 24a3707f Guido Trotter
    """
1400 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
1401 24a3707f Guido Trotter
    del mydict["members"]
1402 24a3707f Guido Trotter
    return mydict
1403 24a3707f Guido Trotter
1404 24a3707f Guido Trotter
  @classmethod
1405 24a3707f Guido Trotter
  def FromDict(cls, val):
1406 24a3707f Guido Trotter
    """Custom function for nodegroup.
1407 24a3707f Guido Trotter

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

1410 24a3707f Guido Trotter
    """
1411 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
1412 24a3707f Guido Trotter
    obj.members = []
1413 24a3707f Guido Trotter
    return obj
1414 24a3707f Guido Trotter
1415 095e71aa Renรฉ Nussbaumer
  def UpgradeConfig(self):
1416 095e71aa Renรฉ Nussbaumer
    """Fill defaults for missing configuration values.
1417 095e71aa Renรฉ Nussbaumer

1418 095e71aa Renรฉ Nussbaumer
    """
1419 095e71aa Renรฉ Nussbaumer
    if self.ndparams is None:
1420 095e71aa Renรฉ Nussbaumer
      self.ndparams = {}
1421 095e71aa Renรฉ Nussbaumer
1422 e11a1b77 Adeodato Simo
    if self.serial_no is None:
1423 e11a1b77 Adeodato Simo
      self.serial_no = 1
1424 e11a1b77 Adeodato Simo
1425 90e99856 Adeodato Simo
    if self.alloc_policy is None:
1426 90e99856 Adeodato Simo
      self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
1427 90e99856 Adeodato Simo
1428 4b97458c Iustin Pop
    # We only update mtime, and not ctime, since we would not be able
1429 4b97458c Iustin Pop
    # to provide a correct value for creation time.
1430 e11a1b77 Adeodato Simo
    if self.mtime is None:
1431 e11a1b77 Adeodato Simo
      self.mtime = time.time()
1432 e11a1b77 Adeodato Simo
1433 7228ca91 Renรฉ Nussbaumer
    if self.diskparams is None:
1434 7228ca91 Renรฉ Nussbaumer
      self.diskparams = {}
1435 81e3ab4f Agata Murawska
    if self.ipolicy is None:
1436 81e3ab4f Agata Murawska
      self.ipolicy = MakeEmptyIPolicy()
1437 bc5d0215 Andrea Spadaccini
1438 08208574 Dimitris Aragiorgis
    if self.networks is None:
1439 08208574 Dimitris Aragiorgis
      self.networks = {}
1440 08208574 Dimitris Aragiorgis
1441 095e71aa Renรฉ Nussbaumer
  def FillND(self, node):
1442 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.Node}
1443 095e71aa Renรฉ Nussbaumer

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

1448 095e71aa Renรฉ Nussbaumer
    """
1449 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(node.ndparams)
1450 095e71aa Renรฉ Nussbaumer
1451 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1452 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1453 095e71aa Renรฉ Nussbaumer

1454 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1455 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1456 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1457 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1458 e6e88de6 Adeodato Simo
        from the node group defaults
1459 095e71aa Renรฉ Nussbaumer

1460 095e71aa Renรฉ Nussbaumer
    """
1461 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1462 095e71aa Renรฉ Nussbaumer
1463 24a3707f Guido Trotter
1464 ec29fe40 Iustin Pop
class Cluster(TaggableObject):
1465 a8083063 Iustin Pop
  """Config object representing the cluster."""
1466 154b9580 Balazs Lecz
  __slots__ = [
1467 a8083063 Iustin Pop
    "serial_no",
1468 a8083063 Iustin Pop
    "rsahostkeypub",
1469 a8083063 Iustin Pop
    "highest_used_port",
1470 b2fddf63 Iustin Pop
    "tcpudp_port_pool",
1471 a8083063 Iustin Pop
    "mac_prefix",
1472 a8083063 Iustin Pop
    "volume_group_name",
1473 999b183c Iustin Pop
    "reserved_lvs",
1474 9e33896b Luca Bigliardi
    "drbd_usermode_helper",
1475 a8083063 Iustin Pop
    "default_bridge",
1476 02691904 Alexander Schreiber
    "default_hypervisor",
1477 f6bd6e98 Michael Hanselmann
    "master_node",
1478 f6bd6e98 Michael Hanselmann
    "master_ip",
1479 f6bd6e98 Michael Hanselmann
    "master_netdev",
1480 5a8648eb Andrea Spadaccini
    "master_netmask",
1481 33be7576 Andrea Spadaccini
    "use_external_mip_script",
1482 f6bd6e98 Michael Hanselmann
    "cluster_name",
1483 f6bd6e98 Michael Hanselmann
    "file_storage_dir",
1484 4b97f902 Apollon Oikonomopoulos
    "shared_file_storage_dir",
1485 e69d05fd Iustin Pop
    "enabled_hypervisors",
1486 5bf7b5cf Iustin Pop
    "hvparams",
1487 918eb80b Agata Murawska
    "ipolicy",
1488 17463d22 Renรฉ Nussbaumer
    "os_hvp",
1489 5bf7b5cf Iustin Pop
    "beparams",
1490 1bdcbbab Iustin Pop
    "osparams",
1491 c8fcde47 Guido Trotter
    "nicparams",
1492 095e71aa Renรฉ Nussbaumer
    "ndparams",
1493 bc5d0215 Andrea Spadaccini
    "diskparams",
1494 4b7735f9 Iustin Pop
    "candidate_pool_size",
1495 b86a6bcd Guido Trotter
    "modify_etc_hosts",
1496 b989b9d9 Ken Wehr
    "modify_ssh_setup",
1497 3953242f Iustin Pop
    "maintain_node_health",
1498 4437d889 Balazs Lecz
    "uid_pool",
1499 bf4af505 Apollon Oikonomopoulos
    "default_iallocator",
1500 87b2cd45 Iustin Pop
    "hidden_os",
1501 87b2cd45 Iustin Pop
    "blacklisted_os",
1502 2f20d07b Manuel Franceschini
    "primary_ip_family",
1503 3d914585 Renรฉ Nussbaumer
    "prealloc_wipe_disks",
1504 2da9f556 Renรฉ Nussbaumer
    "hv_state_static",
1505 2da9f556 Renรฉ Nussbaumer
    "disk_state_static",
1506 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1507 a8083063 Iustin Pop
1508 b86a6bcd Guido Trotter
  def UpgradeConfig(self):
1509 b86a6bcd Guido Trotter
    """Fill defaults for missing configuration values.
1510 b86a6bcd Guido Trotter

1511 b86a6bcd Guido Trotter
    """
1512 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1513 fe267188 Iustin Pop
    # because these are "defined" via slots, not manually
1514 c1b42c18 Guido Trotter
    if self.hvparams is None:
1515 c1b42c18 Guido Trotter
      self.hvparams = constants.HVC_DEFAULTS
1516 c1b42c18 Guido Trotter
    else:
1517 c1b42c18 Guido Trotter
      for hypervisor in self.hvparams:
1518 abe609b2 Guido Trotter
        self.hvparams[hypervisor] = FillDict(
1519 c1b42c18 Guido Trotter
            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
1520 c1b42c18 Guido Trotter
1521 17463d22 Renรฉ Nussbaumer
    if self.os_hvp is None:
1522 17463d22 Renรฉ Nussbaumer
      self.os_hvp = {}
1523 17463d22 Renรฉ Nussbaumer
1524 1bdcbbab Iustin Pop
    # osparams added before 2.2
1525 1bdcbbab Iustin Pop
    if self.osparams is None:
1526 1bdcbbab Iustin Pop
      self.osparams = {}
1527 1bdcbbab Iustin Pop
1528 2a27dac3 Iustin Pop
    self.ndparams = UpgradeNDParams(self.ndparams)
1529 095e71aa Renรฉ Nussbaumer
1530 6e34b628 Guido Trotter
    self.beparams = UpgradeGroupedParams(self.beparams,
1531 6e34b628 Guido Trotter
                                         constants.BEC_DEFAULTS)
1532 8c72ab2b Guido Trotter
    for beparams_group in self.beparams:
1533 8c72ab2b Guido Trotter
      UpgradeBeParams(self.beparams[beparams_group])
1534 8c72ab2b Guido Trotter
1535 c8fcde47 Guido Trotter
    migrate_default_bridge = not self.nicparams
1536 c8fcde47 Guido Trotter
    self.nicparams = UpgradeGroupedParams(self.nicparams,
1537 c8fcde47 Guido Trotter
                                          constants.NICC_DEFAULTS)
1538 c8fcde47 Guido Trotter
    if migrate_default_bridge:
1539 c8fcde47 Guido Trotter
      self.nicparams[constants.PP_DEFAULT][constants.NIC_LINK] = \
1540 c8fcde47 Guido Trotter
        self.default_bridge
1541 c1b42c18 Guido Trotter
1542 b86a6bcd Guido Trotter
    if self.modify_etc_hosts is None:
1543 b86a6bcd Guido Trotter
      self.modify_etc_hosts = True
1544 b86a6bcd Guido Trotter
1545 b989b9d9 Ken Wehr
    if self.modify_ssh_setup is None:
1546 b989b9d9 Ken Wehr
      self.modify_ssh_setup = True
1547 b989b9d9 Ken Wehr
1548 73f1d185 Stephen Shirley
    # default_bridge is no longer used in 2.1. The slot is left there to
1549 90d118fd Guido Trotter
    # support auto-upgrading. It can be removed once we decide to deprecate
1550 90d118fd Guido Trotter
    # upgrading straight from 2.0.
1551 9b31ca85 Guido Trotter
    if self.default_bridge is not None:
1552 9b31ca85 Guido Trotter
      self.default_bridge = None
1553 9b31ca85 Guido Trotter
1554 90d118fd Guido Trotter
    # default_hypervisor is just the first enabled one in 2.1. This slot and
1555 90d118fd Guido Trotter
    # code can be removed once upgrading straight from 2.0 is deprecated.
1556 066f465d Guido Trotter
    if self.default_hypervisor is not None:
1557 016d04b3 Michael Hanselmann
      self.enabled_hypervisors = ([self.default_hypervisor] +
1558 066f465d Guido Trotter
        [hvname for hvname in self.enabled_hypervisors
1559 016d04b3 Michael Hanselmann
         if hvname != self.default_hypervisor])
1560 066f465d Guido Trotter
      self.default_hypervisor = None
1561 066f465d Guido Trotter
1562 3953242f Iustin Pop
    # maintain_node_health added after 2.1.1
1563 3953242f Iustin Pop
    if self.maintain_node_health is None:
1564 3953242f Iustin Pop
      self.maintain_node_health = False
1565 3953242f Iustin Pop
1566 4437d889 Balazs Lecz
    if self.uid_pool is None:
1567 4437d889 Balazs Lecz
      self.uid_pool = []
1568 4437d889 Balazs Lecz
1569 bf4af505 Apollon Oikonomopoulos
    if self.default_iallocator is None:
1570 bf4af505 Apollon Oikonomopoulos
      self.default_iallocator = ""
1571 bf4af505 Apollon Oikonomopoulos
1572 999b183c Iustin Pop
    # reserved_lvs added before 2.2
1573 999b183c Iustin Pop
    if self.reserved_lvs is None:
1574 999b183c Iustin Pop
      self.reserved_lvs = []
1575 999b183c Iustin Pop
1576 546b1111 Iustin Pop
    # hidden and blacklisted operating systems added before 2.2.1
1577 87b2cd45 Iustin Pop
    if self.hidden_os is None:
1578 87b2cd45 Iustin Pop
      self.hidden_os = []
1579 546b1111 Iustin Pop
1580 87b2cd45 Iustin Pop
    if self.blacklisted_os is None:
1581 87b2cd45 Iustin Pop
      self.blacklisted_os = []
1582 546b1111 Iustin Pop
1583 f4c9af7a Guido Trotter
    # primary_ip_family added before 2.3
1584 f4c9af7a Guido Trotter
    if self.primary_ip_family is None:
1585 f4c9af7a Guido Trotter
      self.primary_ip_family = AF_INET
1586 f4c9af7a Guido Trotter
1587 0007f3ab Andrea Spadaccini
    if self.master_netmask is None:
1588 0007f3ab Andrea Spadaccini
      ipcls = netutils.IPAddress.GetClassFromIpFamily(self.primary_ip_family)
1589 0007f3ab Andrea Spadaccini
      self.master_netmask = ipcls.iplen
1590 0007f3ab Andrea Spadaccini
1591 3d914585 Renรฉ Nussbaumer
    if self.prealloc_wipe_disks is None:
1592 3d914585 Renรฉ Nussbaumer
      self.prealloc_wipe_disks = False
1593 3d914585 Renรฉ Nussbaumer
1594 e8f472d1 Iustin Pop
    # shared_file_storage_dir added before 2.5
1595 e8f472d1 Iustin Pop
    if self.shared_file_storage_dir is None:
1596 e8f472d1 Iustin Pop
      self.shared_file_storage_dir = ""
1597 e8f472d1 Iustin Pop
1598 33be7576 Andrea Spadaccini
    if self.use_external_mip_script is None:
1599 33be7576 Andrea Spadaccini
      self.use_external_mip_script = False
1600 33be7576 Andrea Spadaccini
1601 99ccf8b9 Renรฉ Nussbaumer
    if self.diskparams:
1602 99ccf8b9 Renรฉ Nussbaumer
      self.diskparams = UpgradeDiskParams(self.diskparams)
1603 99ccf8b9 Renรฉ Nussbaumer
    else:
1604 99ccf8b9 Renรฉ Nussbaumer
      self.diskparams = constants.DISK_DT_DEFAULTS.copy()
1605 bc5d0215 Andrea Spadaccini
1606 918eb80b Agata Murawska
    # instance policy added before 2.6
1607 918eb80b Agata Murawska
    if self.ipolicy is None:
1608 2cc673a3 Iustin Pop
      self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, {})
1609 38a6e2e1 Iustin Pop
    else:
1610 38a6e2e1 Iustin Pop
      # we can either make sure to upgrade the ipolicy always, or only
1611 38a6e2e1 Iustin Pop
      # do it in some corner cases (e.g. missing keys); note that this
1612 38a6e2e1 Iustin Pop
      # will break any removal of keys from the ipolicy dict
1613 38a6e2e1 Iustin Pop
      self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, self.ipolicy)
1614 918eb80b Agata Murawska
1615 0fbedb7a Michael Hanselmann
  @property
1616 0fbedb7a Michael Hanselmann
  def primary_hypervisor(self):
1617 0fbedb7a Michael Hanselmann
    """The first hypervisor is the primary.
1618 0fbedb7a Michael Hanselmann

1619 0fbedb7a Michael Hanselmann
    Useful, for example, for L{Node}'s hv/disk state.
1620 0fbedb7a Michael Hanselmann

1621 0fbedb7a Michael Hanselmann
    """
1622 0fbedb7a Michael Hanselmann
    return self.enabled_hypervisors[0]
1623 0fbedb7a Michael Hanselmann
1624 319856a9 Michael Hanselmann
  def ToDict(self):
1625 319856a9 Michael Hanselmann
    """Custom function for cluster.
1626 319856a9 Michael Hanselmann

1627 319856a9 Michael Hanselmann
    """
1628 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1629 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1630 319856a9 Michael Hanselmann
    return mydict
1631 319856a9 Michael Hanselmann
1632 319856a9 Michael Hanselmann
  @classmethod
1633 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1634 319856a9 Michael Hanselmann
    """Custom function for cluster.
1635 319856a9 Michael Hanselmann

1636 319856a9 Michael Hanselmann
    """
1637 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1638 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1639 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1640 319856a9 Michael Hanselmann
    return obj
1641 319856a9 Michael Hanselmann
1642 8a147bba Renรฉ Nussbaumer
  def SimpleFillDP(self, diskparams):
1643 8a147bba Renรฉ Nussbaumer
    """Fill a given diskparams dict with cluster defaults.
1644 8a147bba Renรฉ Nussbaumer

1645 8a147bba Renรฉ Nussbaumer
    @param diskparams: The diskparams
1646 8a147bba Renรฉ Nussbaumer
    @return: The defaults dict
1647 8a147bba Renรฉ Nussbaumer

1648 8a147bba Renรฉ Nussbaumer
    """
1649 8a147bba Renรฉ Nussbaumer
    return FillDiskParams(self.diskparams, diskparams)
1650 8a147bba Renรฉ Nussbaumer
1651 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1652 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1653 d63479b5 Iustin Pop

1654 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1655 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1656 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1657 d63479b5 Iustin Pop
    @return: the defaults dict
1658 d63479b5 Iustin Pop

1659 d63479b5 Iustin Pop
    """
1660 d63479b5 Iustin Pop
    if skip_keys is None:
1661 d63479b5 Iustin Pop
      skip_keys = []
1662 d63479b5 Iustin Pop
1663 d63479b5 Iustin Pop
    fill_stack = [self.hvparams.get(hypervisor, {})]
1664 d63479b5 Iustin Pop
    if os_name is not None:
1665 d63479b5 Iustin Pop
      os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {})
1666 d63479b5 Iustin Pop
      fill_stack.append(os_hvp)
1667 d63479b5 Iustin Pop
1668 d63479b5 Iustin Pop
    ret_dict = {}
1669 d63479b5 Iustin Pop
    for o_dict in fill_stack:
1670 d63479b5 Iustin Pop
      ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys)
1671 d63479b5 Iustin Pop
1672 d63479b5 Iustin Pop
    return ret_dict
1673 d63479b5 Iustin Pop
1674 73e0328b Iustin Pop
  def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False):
1675 73e0328b Iustin Pop
    """Fill a given hvparams dict with cluster defaults.
1676 73e0328b Iustin Pop

1677 73e0328b Iustin Pop
    @type hv_name: string
1678 73e0328b Iustin Pop
    @param hv_name: the hypervisor to use
1679 73e0328b Iustin Pop
    @type os_name: string
1680 73e0328b Iustin Pop
    @param os_name: the OS to use for overriding the hypervisor defaults
1681 73e0328b Iustin Pop
    @type skip_globals: boolean
1682 73e0328b Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1683 73e0328b Iustin Pop
        not be filled
1684 73e0328b Iustin Pop
    @rtype: dict
1685 73e0328b Iustin Pop
    @return: a copy of the given hvparams with missing keys filled from
1686 73e0328b Iustin Pop
        the cluster defaults
1687 73e0328b Iustin Pop

1688 73e0328b Iustin Pop
    """
1689 73e0328b Iustin Pop
    if skip_globals:
1690 73e0328b Iustin Pop
      skip_keys = constants.HVC_GLOBALS
1691 73e0328b Iustin Pop
    else:
1692 73e0328b Iustin Pop
      skip_keys = []
1693 73e0328b Iustin Pop
1694 73e0328b Iustin Pop
    def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys)
1695 73e0328b Iustin Pop
    return FillDict(def_dict, hvparams, skip_keys=skip_keys)
1696 d63479b5 Iustin Pop
1697 7736a5f2 Iustin Pop
  def FillHV(self, instance, skip_globals=False):
1698 73e0328b Iustin Pop
    """Fill an instance's hvparams dict with cluster defaults.
1699 5bf7b5cf Iustin Pop

1700 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1701 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1702 7736a5f2 Iustin Pop
    @type skip_globals: boolean
1703 7736a5f2 Iustin Pop
    @param skip_globals: if True, the global hypervisor parameters will
1704 7736a5f2 Iustin Pop
        not be filled
1705 5bf7b5cf Iustin Pop
    @rtype: dict
1706 5bf7b5cf Iustin Pop
    @return: a copy of the instance's hvparams with missing keys filled from
1707 5bf7b5cf Iustin Pop
        the cluster defaults
1708 5bf7b5cf Iustin Pop

1709 5bf7b5cf Iustin Pop
    """
1710 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1711 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1712 17463d22 Renรฉ Nussbaumer
1713 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1714 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1715 73e0328b Iustin Pop

1716 06596a60 Guido Trotter
    @type beparams: dict
1717 06596a60 Guido Trotter
    @param beparams: the dict to fill
1718 73e0328b Iustin Pop
    @rtype: dict
1719 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1720 73e0328b Iustin Pop
        from the cluster defaults
1721 73e0328b Iustin Pop

1722 73e0328b Iustin Pop
    """
1723 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1724 5bf7b5cf Iustin Pop
1725 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1726 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1727 5bf7b5cf Iustin Pop

1728 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1729 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1730 5bf7b5cf Iustin Pop
    @rtype: dict
1731 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1732 5bf7b5cf Iustin Pop
        the cluster defaults
1733 5bf7b5cf Iustin Pop

1734 5bf7b5cf Iustin Pop
    """
1735 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1736 73e0328b Iustin Pop
1737 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1738 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1739 73e0328b Iustin Pop

1740 06596a60 Guido Trotter
    @type nicparams: dict
1741 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1742 73e0328b Iustin Pop
    @rtype: dict
1743 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1744 73e0328b Iustin Pop
        from the cluster defaults
1745 73e0328b Iustin Pop

1746 73e0328b Iustin Pop
    """
1747 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1748 5bf7b5cf Iustin Pop
1749 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1750 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1751 1bdcbbab Iustin Pop

1752 1bdcbbab Iustin Pop
    @type os_name: string
1753 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1754 1bdcbbab Iustin Pop
    @type os_params: dict
1755 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1756 1bdcbbab Iustin Pop
    @rtype: dict
1757 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1758 1bdcbbab Iustin Pop
        the cluster defaults
1759 1bdcbbab Iustin Pop

1760 1bdcbbab Iustin Pop
    """
1761 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1762 1bdcbbab Iustin Pop
    # base OS
1763 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1764 1bdcbbab Iustin Pop
    # OS with variant
1765 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1766 1bdcbbab Iustin Pop
    # specified params
1767 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1768 1bdcbbab Iustin Pop
1769 2da9f556 Renรฉ Nussbaumer
  @staticmethod
1770 2da9f556 Renรฉ Nussbaumer
  def SimpleFillHvState(hv_state):
1771 2da9f556 Renรฉ Nussbaumer
    """Fill an hv_state sub dict with cluster defaults.
1772 2da9f556 Renรฉ Nussbaumer

1773 2da9f556 Renรฉ Nussbaumer
    """
1774 2da9f556 Renรฉ Nussbaumer
    return FillDict(constants.HVST_DEFAULTS, hv_state)
1775 2da9f556 Renรฉ Nussbaumer
1776 2da9f556 Renรฉ Nussbaumer
  @staticmethod
1777 2da9f556 Renรฉ Nussbaumer
  def SimpleFillDiskState(disk_state):
1778 2da9f556 Renรฉ Nussbaumer
    """Fill an disk_state sub dict with cluster defaults.
1779 2da9f556 Renรฉ Nussbaumer

1780 2da9f556 Renรฉ Nussbaumer
    """
1781 2da9f556 Renรฉ Nussbaumer
    return FillDict(constants.DS_DEFAULTS, disk_state)
1782 2da9f556 Renรฉ Nussbaumer
1783 095e71aa Renรฉ Nussbaumer
  def FillND(self, node, nodegroup):
1784 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.NodeGroup} and L{objects.Node}
1785 095e71aa Renรฉ Nussbaumer

1786 095e71aa Renรฉ Nussbaumer
    @type node: L{objects.Node}
1787 095e71aa Renรฉ Nussbaumer
    @param node: A Node object to fill
1788 095e71aa Renรฉ Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1789 095e71aa Renรฉ Nussbaumer
    @param nodegroup: A Node object to fill
1790 095e71aa Renรฉ Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1791 095e71aa Renรฉ Nussbaumer

1792 095e71aa Renรฉ Nussbaumer
    """
1793 095e71aa Renรฉ Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1794 095e71aa Renรฉ Nussbaumer
1795 095e71aa Renรฉ Nussbaumer
  def SimpleFillND(self, ndparams):
1796 095e71aa Renรฉ Nussbaumer
    """Fill a given ndparams dict with defaults.
1797 095e71aa Renรฉ Nussbaumer

1798 095e71aa Renรฉ Nussbaumer
    @type ndparams: dict
1799 095e71aa Renรฉ Nussbaumer
    @param ndparams: the dict to fill
1800 095e71aa Renรฉ Nussbaumer
    @rtype: dict
1801 095e71aa Renรฉ Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1802 095e71aa Renรฉ Nussbaumer
        from the cluster defaults
1803 095e71aa Renรฉ Nussbaumer

1804 095e71aa Renรฉ Nussbaumer
    """
1805 095e71aa Renรฉ Nussbaumer
    return FillDict(self.ndparams, ndparams)
1806 095e71aa Renรฉ Nussbaumer
1807 918eb80b Agata Murawska
  def SimpleFillIPolicy(self, ipolicy):
1808 918eb80b Agata Murawska
    """ Fill instance policy dict with defaults.
1809 918eb80b Agata Murawska

1810 918eb80b Agata Murawska
    @type ipolicy: dict
1811 918eb80b Agata Murawska
    @param ipolicy: the dict to fill
1812 918eb80b Agata Murawska
    @rtype: dict
1813 918eb80b Agata Murawska
    @return: a copy of passed ipolicy with missing keys filled from
1814 918eb80b Agata Murawska
      the cluster defaults
1815 918eb80b Agata Murawska

1816 918eb80b Agata Murawska
    """
1817 2cc673a3 Iustin Pop
    return FillIPolicy(self.ipolicy, ipolicy)
1818 918eb80b Agata Murawska
1819 5c947f38 Iustin Pop
1820 96acbc09 Michael Hanselmann
class BlockDevStatus(ConfigObject):
1821 96acbc09 Michael Hanselmann
  """Config object representing the status of a block device."""
1822 96acbc09 Michael Hanselmann
  __slots__ = [
1823 96acbc09 Michael Hanselmann
    "dev_path",
1824 96acbc09 Michael Hanselmann
    "major",
1825 96acbc09 Michael Hanselmann
    "minor",
1826 96acbc09 Michael Hanselmann
    "sync_percent",
1827 96acbc09 Michael Hanselmann
    "estimated_time",
1828 96acbc09 Michael Hanselmann
    "is_degraded",
1829 f208978a Michael Hanselmann
    "ldisk_status",
1830 96acbc09 Michael Hanselmann
    ]
1831 96acbc09 Michael Hanselmann
1832 96acbc09 Michael Hanselmann
1833 2d76b580 Michael Hanselmann
class ImportExportStatus(ConfigObject):
1834 2d76b580 Michael Hanselmann
  """Config object representing the status of an import or export."""
1835 2d76b580 Michael Hanselmann
  __slots__ = [
1836 2d76b580 Michael Hanselmann
    "recent_output",
1837 2d76b580 Michael Hanselmann
    "listen_port",
1838 2d76b580 Michael Hanselmann
    "connected",
1839 c08d76f5 Michael Hanselmann
    "progress_mbytes",
1840 c08d76f5 Michael Hanselmann
    "progress_throughput",
1841 c08d76f5 Michael Hanselmann
    "progress_eta",
1842 c08d76f5 Michael Hanselmann
    "progress_percent",
1843 2d76b580 Michael Hanselmann
    "exit_status",
1844 2d76b580 Michael Hanselmann
    "error_message",
1845 2d76b580 Michael Hanselmann
    ] + _TIMESTAMPS
1846 2d76b580 Michael Hanselmann
1847 2d76b580 Michael Hanselmann
1848 eb630f50 Michael Hanselmann
class ImportExportOptions(ConfigObject):
1849 eb630f50 Michael Hanselmann
  """Options for import/export daemon
1850 eb630f50 Michael Hanselmann

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

1858 eb630f50 Michael Hanselmann
  """
1859 eb630f50 Michael Hanselmann
  __slots__ = [
1860 eb630f50 Michael Hanselmann
    "key_name",
1861 eb630f50 Michael Hanselmann
    "ca_pem",
1862 a5310c2a Michael Hanselmann
    "compress",
1863 af1d39b1 Michael Hanselmann
    "magic",
1864 855d2fc7 Michael Hanselmann
    "ipv6",
1865 4478301b Michael Hanselmann
    "connect_timeout",
1866 eb630f50 Michael Hanselmann
    ]
1867 eb630f50 Michael Hanselmann
1868 eb630f50 Michael Hanselmann
1869 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1870 18d750b9 Guido Trotter
  """Object holding a confd request.
1871 18d750b9 Guido Trotter

1872 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1873 18d750b9 Guido Trotter
  @ivar type: confd query type
1874 18d750b9 Guido Trotter
  @ivar query: query request
1875 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1876 18d750b9 Guido Trotter

1877 18d750b9 Guido Trotter
  """
1878 18d750b9 Guido Trotter
  __slots__ = [
1879 18d750b9 Guido Trotter
    "protocol",
1880 18d750b9 Guido Trotter
    "type",
1881 18d750b9 Guido Trotter
    "query",
1882 18d750b9 Guido Trotter
    "rsalt",
1883 18d750b9 Guido Trotter
    ]
1884 18d750b9 Guido Trotter
1885 18d750b9 Guido Trotter
1886 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1887 18d750b9 Guido Trotter
  """Object holding a confd reply.
1888 18d750b9 Guido Trotter

1889 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1890 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1891 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1892 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1893 18d750b9 Guido Trotter

1894 18d750b9 Guido Trotter
  """
1895 18d750b9 Guido Trotter
  __slots__ = [
1896 18d750b9 Guido Trotter
    "protocol",
1897 18d750b9 Guido Trotter
    "status",
1898 18d750b9 Guido Trotter
    "answer",
1899 18d750b9 Guido Trotter
    "serial",
1900 18d750b9 Guido Trotter
    ]
1901 18d750b9 Guido Trotter
1902 18d750b9 Guido Trotter
1903 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1904 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1905 707f23b5 Michael Hanselmann

1906 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1907 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1908 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1909 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1910 707f23b5 Michael Hanselmann

1911 707f23b5 Michael Hanselmann
  """
1912 707f23b5 Michael Hanselmann
  __slots__ = [
1913 707f23b5 Michael Hanselmann
    "name",
1914 707f23b5 Michael Hanselmann
    "title",
1915 707f23b5 Michael Hanselmann
    "kind",
1916 1ae17369 Michael Hanselmann
    "doc",
1917 707f23b5 Michael Hanselmann
    ]
1918 707f23b5 Michael Hanselmann
1919 707f23b5 Michael Hanselmann
1920 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1921 0538c375 Michael Hanselmann
  __slots__ = [
1922 0538c375 Michael Hanselmann
    "fields",
1923 0538c375 Michael Hanselmann
    ]
1924 0538c375 Michael Hanselmann
1925 0538c375 Michael Hanselmann
  def ToDict(self):
1926 0538c375 Michael Hanselmann
    """Custom function for serializing.
1927 0538c375 Michael Hanselmann

1928 0538c375 Michael Hanselmann
    """
1929 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1930 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1931 0538c375 Michael Hanselmann
    return mydict
1932 0538c375 Michael Hanselmann
1933 0538c375 Michael Hanselmann
  @classmethod
1934 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1935 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1936 0538c375 Michael Hanselmann

1937 0538c375 Michael Hanselmann
    """
1938 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1939 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1940 0538c375 Michael Hanselmann
    return obj
1941 0538c375 Michael Hanselmann
1942 0538c375 Michael Hanselmann
1943 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
1944 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
1945 24d6d3e2 Michael Hanselmann

1946 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1947 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1948 24d6d3e2 Michael Hanselmann

1949 24d6d3e2 Michael Hanselmann
  """
1950 24d6d3e2 Michael Hanselmann
  __slots__ = [
1951 24d6d3e2 Michael Hanselmann
    "data",
1952 24d6d3e2 Michael Hanselmann
    ]
1953 24d6d3e2 Michael Hanselmann
1954 24d6d3e2 Michael Hanselmann
1955 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
1956 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
1957 24d6d3e2 Michael Hanselmann

1958 24d6d3e2 Michael Hanselmann
  """
1959 24d6d3e2 Michael Hanselmann
  __slots__ = [
1960 24d6d3e2 Michael Hanselmann
    "what",
1961 24d6d3e2 Michael Hanselmann
    "fields",
1962 24d6d3e2 Michael Hanselmann
    ]
1963 24d6d3e2 Michael Hanselmann
1964 24d6d3e2 Michael Hanselmann
1965 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
1966 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
1967 24d6d3e2 Michael Hanselmann

1968 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1969 24d6d3e2 Michael Hanselmann

1970 24d6d3e2 Michael Hanselmann
  """
1971 24d6d3e2 Michael Hanselmann
  __slots__ = [
1972 24d6d3e2 Michael Hanselmann
    ]
1973 24d6d3e2 Michael Hanselmann
1974 24d6d3e2 Michael Hanselmann
1975 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
1976 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
1977 6a1434d7 Andrea Spadaccini

1978 6a1434d7 Andrea Spadaccini
  """
1979 6a1434d7 Andrea Spadaccini
  __slots__ = [
1980 6a1434d7 Andrea Spadaccini
    "status",
1981 6a1434d7 Andrea Spadaccini
    "transferred_ram",
1982 6a1434d7 Andrea Spadaccini
    "total_ram",
1983 6a1434d7 Andrea Spadaccini
    ]
1984 6a1434d7 Andrea Spadaccini
1985 6a1434d7 Andrea Spadaccini
1986 25ce3ec4 Michael Hanselmann
class InstanceConsole(ConfigObject):
1987 25ce3ec4 Michael Hanselmann
  """Object describing how to access the console of an instance.
1988 25ce3ec4 Michael Hanselmann

1989 25ce3ec4 Michael Hanselmann
  """
1990 25ce3ec4 Michael Hanselmann
  __slots__ = [
1991 25ce3ec4 Michael Hanselmann
    "instance",
1992 25ce3ec4 Michael Hanselmann
    "kind",
1993 25ce3ec4 Michael Hanselmann
    "message",
1994 25ce3ec4 Michael Hanselmann
    "host",
1995 25ce3ec4 Michael Hanselmann
    "port",
1996 25ce3ec4 Michael Hanselmann
    "user",
1997 25ce3ec4 Michael Hanselmann
    "command",
1998 25ce3ec4 Michael Hanselmann
    "display",
1999 25ce3ec4 Michael Hanselmann
    ]
2000 25ce3ec4 Michael Hanselmann
2001 25ce3ec4 Michael Hanselmann
  def Validate(self):
2002 25ce3ec4 Michael Hanselmann
    """Validates contents of this object.
2003 25ce3ec4 Michael Hanselmann

2004 25ce3ec4 Michael Hanselmann
    """
2005 25ce3ec4 Michael Hanselmann
    assert self.kind in constants.CONS_ALL, "Unknown console type"
2006 25ce3ec4 Michael Hanselmann
    assert self.instance, "Missing instance name"
2007 4d2cdb5a Andrea Spadaccini
    assert self.message or self.kind in [constants.CONS_SSH,
2008 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2009 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_VNC]
2010 25ce3ec4 Michael Hanselmann
    assert self.host or self.kind == constants.CONS_MESSAGE
2011 25ce3ec4 Michael Hanselmann
    assert self.port or self.kind in [constants.CONS_MESSAGE,
2012 25ce3ec4 Michael Hanselmann
                                      constants.CONS_SSH]
2013 25ce3ec4 Michael Hanselmann
    assert self.user or self.kind in [constants.CONS_MESSAGE,
2014 4d2cdb5a Andrea Spadaccini
                                      constants.CONS_SPICE,
2015 25ce3ec4 Michael Hanselmann
                                      constants.CONS_VNC]
2016 25ce3ec4 Michael Hanselmann
    assert self.command or self.kind in [constants.CONS_MESSAGE,
2017 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2018 25ce3ec4 Michael Hanselmann
                                         constants.CONS_VNC]
2019 25ce3ec4 Michael Hanselmann
    assert self.display or self.kind in [constants.CONS_MESSAGE,
2020 4d2cdb5a Andrea Spadaccini
                                         constants.CONS_SPICE,
2021 25ce3ec4 Michael Hanselmann
                                         constants.CONS_SSH]
2022 25ce3ec4 Michael Hanselmann
    return True
2023 25ce3ec4 Michael Hanselmann
2024 25ce3ec4 Michael Hanselmann
2025 08208574 Dimitris Aragiorgis
class Network(ConfigObject):
2026 08208574 Dimitris Aragiorgis
  """Object representing a network definition for ganeti.
2027 08208574 Dimitris Aragiorgis

2028 08208574 Dimitris Aragiorgis
  """
2029 08208574 Dimitris Aragiorgis
  __slots__ = [
2030 08208574 Dimitris Aragiorgis
    "name",
2031 08208574 Dimitris Aragiorgis
    "serial_no",
2032 08208574 Dimitris Aragiorgis
    "network_type",
2033 08208574 Dimitris Aragiorgis
    "mac_prefix",
2034 08208574 Dimitris Aragiorgis
    "family",
2035 08208574 Dimitris Aragiorgis
    "network",
2036 08208574 Dimitris Aragiorgis
    "network6",
2037 08208574 Dimitris Aragiorgis
    "gateway",
2038 08208574 Dimitris Aragiorgis
    "gateway6",
2039 08208574 Dimitris Aragiorgis
    "size",
2040 08208574 Dimitris Aragiorgis
    "reservations",
2041 08208574 Dimitris Aragiorgis
    "ext_reservations",
2042 08208574 Dimitris Aragiorgis
    ] + _TIMESTAMPS + _UUID
2043 08208574 Dimitris Aragiorgis
2044 08208574 Dimitris Aragiorgis
2045 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
2046 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
2047 a8083063 Iustin Pop

2048 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
2049 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
2050 a8083063 Iustin Pop
  buffer.
2051 a8083063 Iustin Pop

2052 a8083063 Iustin Pop
  """
2053 a8083063 Iustin Pop
  def Dumps(self):
2054 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
2055 a8083063 Iustin Pop
    buf = StringIO()
2056 a8083063 Iustin Pop
    self.write(buf)
2057 a8083063 Iustin Pop
    return buf.getvalue()
2058 a8083063 Iustin Pop
2059 b39bf4bb Guido Trotter
  @classmethod
2060 b39bf4bb Guido Trotter
  def Loads(cls, data):
2061 a8083063 Iustin Pop
    """Load data from a string."""
2062 a8083063 Iustin Pop
    buf = StringIO(data)
2063 b39bf4bb Guido Trotter
    cfp = cls()
2064 a8083063 Iustin Pop
    cfp.readfp(buf)
2065 a8083063 Iustin Pop
    return cfp