Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 63c73073

History | View | Annotate | Download (59.1 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 2ed0e208 Iustin Pop
# objects.py which doesn't explicitly 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 32683096 René Nussbaumer
from ganeti import objectutils
48 32017174 Agata Murawska
from ganeti import utils
49 a8083063 Iustin Pop
50 f4c9af7a Guido Trotter
from socket import AF_INET
51 f4c9af7a Guido Trotter
52 a8083063 Iustin Pop
53 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
54 eaa4c57c Dimitris Aragiorgis
           "OS", "Node", "NodeGroup", "Cluster", "FillDict", "Network"]
55 a8083063 Iustin Pop
56 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
57 e1dcc53a Iustin Pop
_UUID = ["uuid"]
58 96acbc09 Michael Hanselmann
59 8d8d650c Michael Hanselmann
60 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
61 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
62 abe609b2 Guido Trotter

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

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

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

107 af9fb4cc René Nussbaumer
  @see: L{FillDict} for parameters and return value
108 57987785 René Nussbaumer

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

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

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

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

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

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

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

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

173 2a27dac3 Iustin Pop
  """
174 2a27dac3 Iustin Pop
  if ndparams is None:
175 2a27dac3 Iustin Pop
    ndparams = {}
176 2a27dac3 Iustin Pop
177 1df4d430 Iustin Pop
  if (constants.ND_OOB_PROGRAM in ndparams and
178 1df4d430 Iustin Pop
      ndparams[constants.ND_OOB_PROGRAM] is None):
179 1df4d430 Iustin Pop
    # will be reset by the line below
180 1df4d430 Iustin Pop
    del ndparams[constants.ND_OOB_PROGRAM]
181 2a27dac3 Iustin Pop
  return FillDict(constants.NDC_DEFAULTS, ndparams)
182 2a27dac3 Iustin Pop
183 2a27dac3 Iustin Pop
184 918eb80b Agata Murawska
def MakeEmptyIPolicy():
185 918eb80b Agata Murawska
  """Create empty IPolicy dictionary.
186 918eb80b Agata Murawska

187 918eb80b Agata Murawska
  """
188 918eb80b Agata Murawska
  return dict([
189 2cc673a3 Iustin Pop
    (constants.ISPECS_MIN, {}),
190 2cc673a3 Iustin Pop
    (constants.ISPECS_MAX, {}),
191 2cc673a3 Iustin Pop
    (constants.ISPECS_STD, {}),
192 918eb80b Agata Murawska
    ])
193 918eb80b Agata Murawska
194 918eb80b Agata Murawska
195 32683096 René Nussbaumer
class ConfigObject(objectutils.ValidatedSlots):
196 a8083063 Iustin Pop
  """A generic config object.
197 a8083063 Iustin Pop

198 a8083063 Iustin Pop
  It has the following properties:
199 a8083063 Iustin Pop

200 a8083063 Iustin Pop
    - provides somewhat safe recursive unpickling and pickling for its classes
201 a8083063 Iustin Pop
    - unset attributes which are defined in slots are always returned
202 a8083063 Iustin Pop
      as None instead of raising an error
203 a8083063 Iustin Pop

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

207 a8083063 Iustin Pop
  """
208 a8083063 Iustin Pop
  __slots__ = []
209 a8083063 Iustin Pop
210 a8083063 Iustin Pop
  def __getattr__(self, name):
211 32683096 René Nussbaumer
    if name not in self.GetAllSlots():
212 3ecf6786 Iustin Pop
      raise AttributeError("Invalid object attribute %s.%s" %
213 3ecf6786 Iustin Pop
                           (type(self).__name__, name))
214 a8083063 Iustin Pop
    return None
215 a8083063 Iustin Pop
216 a8083063 Iustin Pop
  def __setstate__(self, state):
217 32683096 René Nussbaumer
    slots = self.GetAllSlots()
218 a8083063 Iustin Pop
    for name in state:
219 adf385c7 Iustin Pop
      if name in slots:
220 a8083063 Iustin Pop
        setattr(self, name, state[name])
221 a8083063 Iustin Pop
222 32683096 René Nussbaumer
  def Validate(self):
223 32683096 René Nussbaumer
    """Validates the slots.
224 adf385c7 Iustin Pop

225 adf385c7 Iustin Pop
    """
226 415feb2e René Nussbaumer
227 ff9c047c Iustin Pop
  def ToDict(self):
228 ff9c047c Iustin Pop
    """Convert to a dict holding only standard python types.
229 ff9c047c Iustin Pop

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

236 ff9c047c Iustin Pop
    """
237 4c14965f Guido Trotter
    result = {}
238 32683096 René Nussbaumer
    for name in self.GetAllSlots():
239 4c14965f Guido Trotter
      value = getattr(self, name, None)
240 4c14965f Guido Trotter
      if value is not None:
241 4c14965f Guido Trotter
        result[name] = value
242 4c14965f Guido Trotter
    return result
243 4c14965f Guido Trotter
244 4c14965f Guido Trotter
  __getstate__ = ToDict
245 ff9c047c Iustin Pop
246 ff9c047c Iustin Pop
  @classmethod
247 ff9c047c Iustin Pop
  def FromDict(cls, val):
248 ff9c047c Iustin Pop
    """Create an object from a dictionary.
249 ff9c047c Iustin Pop

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

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

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

270 ff9c047c Iustin Pop
    This method converts a container with elements derived from
271 ff9c047c Iustin Pop
    ConfigData to standard python types. If the container is a dict,
272 ff9c047c Iustin Pop
    we don't touch the keys, only the values.
273 ff9c047c Iustin Pop

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

288 ff9c047c Iustin Pop
    This method converts a container with standard python types to
289 ff9c047c Iustin Pop
    ConfigData objects. If the container is a dict, we don't touch the
290 ff9c047c Iustin Pop
    keys, only the values.
291 ff9c047c Iustin Pop

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

310 e8d563f3 Iustin Pop
    """
311 e8d563f3 Iustin Pop
    dict_form = self.ToDict()
312 e8d563f3 Iustin Pop
    clone_obj = self.__class__.FromDict(dict_form)
313 e8d563f3 Iustin Pop
    return clone_obj
314 e8d563f3 Iustin Pop
315 ff9c047c Iustin Pop
  def __repr__(self):
316 ff9c047c Iustin Pop
    """Implement __repr__ for ConfigObjects."""
317 ff9c047c Iustin Pop
    return repr(self.ToDict())
318 ff9c047c Iustin Pop
319 560428be Guido Trotter
  def UpgradeConfig(self):
320 560428be Guido Trotter
    """Fill defaults for missing configuration values.
321 560428be Guido Trotter

322 90d726a8 Iustin Pop
    This method will be called at configuration load time, and its
323 90d726a8 Iustin Pop
    implementation will be object dependent.
324 560428be Guido Trotter

325 560428be Guido Trotter
    """
326 560428be Guido Trotter
    pass
327 560428be Guido Trotter
328 a8083063 Iustin Pop
329 ec29fe40 Iustin Pop
class TaggableObject(ConfigObject):
330 5c947f38 Iustin Pop
  """An generic class supporting tags.
331 5c947f38 Iustin Pop

332 5c947f38 Iustin Pop
  """
333 154b9580 Balazs Lecz
  __slots__ = ["tags"]
334 b5e5632e Iustin Pop
  VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
335 2057f6c7 Iustin Pop
336 b5e5632e Iustin Pop
  @classmethod
337 b5e5632e Iustin Pop
  def ValidateTag(cls, tag):
338 5c947f38 Iustin Pop
    """Check if a tag is valid.
339 5c947f38 Iustin Pop

340 5c947f38 Iustin Pop
    If the tag is invalid, an errors.TagError will be raised. The
341 5c947f38 Iustin Pop
    function has no return value.
342 5c947f38 Iustin Pop

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

357 5c947f38 Iustin Pop
    """
358 5c947f38 Iustin Pop
    tags = getattr(self, "tags", None)
359 5c947f38 Iustin Pop
    if tags is None:
360 5c947f38 Iustin Pop
      tags = self.tags = set()
361 5c947f38 Iustin Pop
    return tags
362 5c947f38 Iustin Pop
363 5c947f38 Iustin Pop
  def AddTag(self, tag):
364 5c947f38 Iustin Pop
    """Add a new tag.
365 5c947f38 Iustin Pop

366 5c947f38 Iustin Pop
    """
367 5c947f38 Iustin Pop
    self.ValidateTag(tag)
368 5c947f38 Iustin Pop
    tags = self.GetTags()
369 5c947f38 Iustin Pop
    if len(tags) >= constants.MAX_TAGS_PER_OBJ:
370 3ecf6786 Iustin Pop
      raise errors.TagError("Too many tags")
371 5c947f38 Iustin Pop
    self.GetTags().add(tag)
372 5c947f38 Iustin Pop
373 5c947f38 Iustin Pop
  def RemoveTag(self, tag):
374 5c947f38 Iustin Pop
    """Remove a tag.
375 5c947f38 Iustin Pop

376 5c947f38 Iustin Pop
    """
377 5c947f38 Iustin Pop
    self.ValidateTag(tag)
378 5c947f38 Iustin Pop
    tags = self.GetTags()
379 5c947f38 Iustin Pop
    try:
380 5c947f38 Iustin Pop
      tags.remove(tag)
381 5c947f38 Iustin Pop
    except KeyError:
382 3ecf6786 Iustin Pop
      raise errors.TagError("Tag not found")
383 5c947f38 Iustin Pop
384 ff9c047c Iustin Pop
  def ToDict(self):
385 ff9c047c Iustin Pop
    """Taggable-object-specific conversion to standard python types.
386 ff9c047c Iustin Pop

387 ff9c047c Iustin Pop
    This replaces the tags set with a list.
388 ff9c047c Iustin Pop

389 ff9c047c Iustin Pop
    """
390 ff9c047c Iustin Pop
    bo = super(TaggableObject, self).ToDict()
391 ff9c047c Iustin Pop
392 ff9c047c Iustin Pop
    tags = bo.get("tags", None)
393 ff9c047c Iustin Pop
    if isinstance(tags, set):
394 ff9c047c Iustin Pop
      bo["tags"] = list(tags)
395 ff9c047c Iustin Pop
    return bo
396 ff9c047c Iustin Pop
397 ff9c047c Iustin Pop
  @classmethod
398 ff9c047c Iustin Pop
  def FromDict(cls, val):
399 ff9c047c Iustin Pop
    """Custom function for instances.
400 ff9c047c Iustin Pop

401 ff9c047c Iustin Pop
    """
402 ff9c047c Iustin Pop
    obj = super(TaggableObject, cls).FromDict(val)
403 ff9c047c Iustin Pop
    if hasattr(obj, "tags") and isinstance(obj.tags, list):
404 ff9c047c Iustin Pop
      obj.tags = set(obj.tags)
405 ff9c047c Iustin Pop
    return obj
406 ff9c047c Iustin Pop
407 5c947f38 Iustin Pop
408 061af273 Andrea Spadaccini
class MasterNetworkParameters(ConfigObject):
409 061af273 Andrea Spadaccini
  """Network configuration parameters for the master
410 061af273 Andrea Spadaccini

411 061af273 Andrea Spadaccini
  @ivar name: master name
412 061af273 Andrea Spadaccini
  @ivar ip: master IP
413 061af273 Andrea Spadaccini
  @ivar netmask: master netmask
414 061af273 Andrea Spadaccini
  @ivar netdev: master network device
415 061af273 Andrea Spadaccini
  @ivar ip_family: master IP family
416 061af273 Andrea Spadaccini

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

442 ff9c047c Iustin Pop
    This just replaces the list of instances, nodes and the cluster
443 ff9c047c Iustin Pop
    with standard python types.
444 ff9c047c Iustin Pop

445 ff9c047c Iustin Pop
    """
446 ff9c047c Iustin Pop
    mydict = super(ConfigData, self).ToDict()
447 ff9c047c Iustin Pop
    mydict["cluster"] = mydict["cluster"].ToDict()
448 eaa4c57c Dimitris Aragiorgis
    for key in "nodes", "instances", "nodegroups", "networks":
449 ff9c047c Iustin Pop
      mydict[key] = self._ContainerToDicts(mydict[key])
450 ff9c047c Iustin Pop
451 ff9c047c Iustin Pop
    return mydict
452 ff9c047c Iustin Pop
453 ff9c047c Iustin Pop
  @classmethod
454 ff9c047c Iustin Pop
  def FromDict(cls, val):
455 ff9c047c Iustin Pop
    """Custom function for top-level config data
456 ff9c047c Iustin Pop

457 ff9c047c Iustin Pop
    """
458 ff9c047c Iustin Pop
    obj = super(ConfigData, cls).FromDict(val)
459 ff9c047c Iustin Pop
    obj.cluster = Cluster.FromDict(obj.cluster)
460 ff9c047c Iustin Pop
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
461 ff9c047c Iustin Pop
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
462 3df43542 Guido Trotter
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
463 eaa4c57c Dimitris Aragiorgis
    obj.networks = cls._ContainerFromDicts(obj.networks, dict, Network)
464 ff9c047c Iustin Pop
    return obj
465 ff9c047c Iustin Pop
466 51cb1581 Luca Bigliardi
  def HasAnyDiskOfType(self, dev_type):
467 51cb1581 Luca Bigliardi
    """Check if in there is at disk of the given type in the configuration.
468 51cb1581 Luca Bigliardi

469 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
470 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
471 51cb1581 Luca Bigliardi
    @rtype: boolean
472 51cb1581 Luca Bigliardi
    @return: boolean indicating if a disk of the given type was found or not
473 51cb1581 Luca Bigliardi

474 51cb1581 Luca Bigliardi
    """
475 51cb1581 Luca Bigliardi
    for instance in self.instances.values():
476 51cb1581 Luca Bigliardi
      for disk in instance.disks:
477 51cb1581 Luca Bigliardi
        if disk.IsBasedOnDiskType(dev_type):
478 51cb1581 Luca Bigliardi
          return True
479 51cb1581 Luca Bigliardi
    return False
480 51cb1581 Luca Bigliardi
481 90d726a8 Iustin Pop
  def UpgradeConfig(self):
482 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
483 90d726a8 Iustin Pop

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

512 255e19d4 Guido Trotter
    @type nicparams:  dict
513 255e19d4 Guido Trotter
    @param nicparams: dictionary with parameter names/value
514 255e19d4 Guido Trotter
    @raise errors.ConfigurationError: when a parameter is not valid
515 255e19d4 Guido Trotter

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

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

551 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
552 e51db2a6 Iustin Pop
        should check that it is a valid path.
553 e51db2a6 Iustin Pop

554 222f2dd5 Iustin Pop
    """
555 222f2dd5 Iustin Pop
    if self.dev_type == constants.LD_LV:
556 222f2dd5 Iustin Pop
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
557 b6135bbc Apollon Oikonomopoulos
    elif self.dev_type == constants.LD_BLOCKDEV:
558 b6135bbc Apollon Oikonomopoulos
      return self.logical_id[1]
559 7181fba0 Constantinos Venetsanopoulos
    elif self.dev_type == constants.LD_RBD:
560 7181fba0 Constantinos Venetsanopoulos
      return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
561 222f2dd5 Iustin Pop
    return None
562 222f2dd5 Iustin Pop
563 fc1dc9d7 Iustin Pop
  def ChildrenNeeded(self):
564 fc1dc9d7 Iustin Pop
    """Compute the needed number of children for activation.
565 fc1dc9d7 Iustin Pop

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

570 fc1dc9d7 Iustin Pop
    Currently, only DRBD8 supports diskless activation (therefore we
571 fc1dc9d7 Iustin Pop
    return 0), for all other we keep the previous semantics and return
572 fc1dc9d7 Iustin Pop
    -1.
573 fc1dc9d7 Iustin Pop

574 fc1dc9d7 Iustin Pop
    """
575 fc1dc9d7 Iustin Pop
    if self.dev_type == constants.LD_DRBD8:
576 fc1dc9d7 Iustin Pop
      return 0
577 fc1dc9d7 Iustin Pop
    return -1
578 fc1dc9d7 Iustin Pop
579 51cb1581 Luca Bigliardi
  def IsBasedOnDiskType(self, dev_type):
580 51cb1581 Luca Bigliardi
    """Check if the disk or its children are based on the given type.
581 51cb1581 Luca Bigliardi

582 51cb1581 Luca Bigliardi
    @type dev_type: L{constants.LDS_BLOCK}
583 51cb1581 Luca Bigliardi
    @param dev_type: the type to look for
584 51cb1581 Luca Bigliardi
    @rtype: boolean
585 51cb1581 Luca Bigliardi
    @return: boolean indicating if a device of the given type was found or not
586 51cb1581 Luca Bigliardi

587 51cb1581 Luca Bigliardi
    """
588 51cb1581 Luca Bigliardi
    if self.children:
589 51cb1581 Luca Bigliardi
      for child in self.children:
590 51cb1581 Luca Bigliardi
        if child.IsBasedOnDiskType(dev_type):
591 51cb1581 Luca Bigliardi
          return True
592 51cb1581 Luca Bigliardi
    return self.dev_type == dev_type
593 51cb1581 Luca Bigliardi
594 a8083063 Iustin Pop
  def GetNodes(self, node):
595 a8083063 Iustin Pop
    """This function returns the nodes this device lives on.
596 a8083063 Iustin Pop

597 a8083063 Iustin Pop
    Given the node on which the parent of the device lives on (or, in
598 a8083063 Iustin Pop
    case of a top-level device, the primary node of the devices'
599 a8083063 Iustin Pop
    instance), this function will return a list of nodes on which this
600 a8083063 Iustin Pop
    devices needs to (or can) be assembled.
601 a8083063 Iustin Pop

602 a8083063 Iustin Pop
    """
603 b6135bbc Apollon Oikonomopoulos
    if self.dev_type in [constants.LD_LV, constants.LD_FILE,
604 376631d1 Constantinos Venetsanopoulos
                         constants.LD_BLOCKDEV, constants.LD_RBD,
605 376631d1 Constantinos Venetsanopoulos
                         constants.LD_EXT]:
606 a8083063 Iustin Pop
      result = [node]
607 a1f445d3 Iustin Pop
    elif self.dev_type in constants.LDS_DRBD:
608 a8083063 Iustin Pop
      result = [self.logical_id[0], self.logical_id[1]]
609 a8083063 Iustin Pop
      if node not in result:
610 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("DRBD device passed unknown node")
611 a8083063 Iustin Pop
    else:
612 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Unhandled device type %s" % self.dev_type)
613 a8083063 Iustin Pop
    return result
614 a8083063 Iustin Pop
615 a8083063 Iustin Pop
  def ComputeNodeTree(self, parent_node):
616 a8083063 Iustin Pop
    """Compute the node/disk tree for this disk and its children.
617 a8083063 Iustin Pop

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

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

653 6d33a6eb Iustin Pop
    This only works for VG-based disks.
654 6d33a6eb Iustin Pop

655 6d33a6eb Iustin Pop
    @type amount: integer
656 6d33a6eb Iustin Pop
    @param amount: the desired increase in (user-visible) disk space
657 6d33a6eb Iustin Pop
    @rtype: dict
658 6d33a6eb Iustin Pop
    @return: a dictionary of volume-groups and the required size
659 6d33a6eb Iustin Pop

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

675 acec9d51 Iustin Pop
    This method recurses over the disks's children and updates their
676 acec9d51 Iustin Pop
    size correspondigly. The method needs to be kept in sync with the
677 acec9d51 Iustin Pop
    actual algorithms from bdev.
678 acec9d51 Iustin Pop

679 acec9d51 Iustin Pop
    """
680 7181fba0 Constantinos Venetsanopoulos
    if self.dev_type in (constants.LD_LV, constants.LD_FILE,
681 376631d1 Constantinos Venetsanopoulos
                         constants.LD_RBD, constants.LD_EXT):
682 acec9d51 Iustin Pop
      self.size += amount
683 acec9d51 Iustin Pop
    elif self.dev_type == constants.LD_DRBD8:
684 acec9d51 Iustin Pop
      if self.children:
685 acec9d51 Iustin Pop
        self.children[0].RecordGrow(amount)
686 acec9d51 Iustin Pop
      self.size += amount
687 acec9d51 Iustin Pop
    else:
688 acec9d51 Iustin Pop
      raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
689 acec9d51 Iustin Pop
                                   " disk type %s" % self.dev_type)
690 acec9d51 Iustin Pop
691 735e1318 Michael Hanselmann
  def Update(self, size=None, mode=None):
692 735e1318 Michael Hanselmann
    """Apply changes to size and mode.
693 735e1318 Michael Hanselmann

694 735e1318 Michael Hanselmann
    """
695 735e1318 Michael Hanselmann
    if self.dev_type == constants.LD_DRBD8:
696 735e1318 Michael Hanselmann
      if self.children:
697 735e1318 Michael Hanselmann
        self.children[0].Update(size=size, mode=mode)
698 735e1318 Michael Hanselmann
    else:
699 735e1318 Michael Hanselmann
      assert not self.children
700 735e1318 Michael Hanselmann
701 735e1318 Michael Hanselmann
    if size is not None:
702 735e1318 Michael Hanselmann
      self.size = size
703 735e1318 Michael Hanselmann
    if mode is not None:
704 735e1318 Michael Hanselmann
      self.mode = mode
705 735e1318 Michael Hanselmann
706 a805ec18 Iustin Pop
  def UnsetSize(self):
707 a805ec18 Iustin Pop
    """Sets recursively the size to zero for the disk and its children.
708 a805ec18 Iustin Pop

709 a805ec18 Iustin Pop
    """
710 a805ec18 Iustin Pop
    if self.children:
711 a805ec18 Iustin Pop
      for child in self.children:
712 a805ec18 Iustin Pop
        child.UnsetSize()
713 a805ec18 Iustin Pop
    self.size = 0
714 a805ec18 Iustin Pop
715 0402302c Iustin Pop
  def SetPhysicalID(self, target_node, nodes_ip):
716 0402302c Iustin Pop
    """Convert the logical ID to the physical ID.
717 0402302c Iustin Pop

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

720 0402302c Iustin Pop
    The routine descends down and updates its children also, because
721 0402302c Iustin Pop
    this helps when the only the top device is passed to the remote
722 0402302c Iustin Pop
    node.
723 0402302c Iustin Pop

724 0402302c Iustin Pop
    Arguments:
725 0402302c Iustin Pop
      - target_node: the node we wish to configure for
726 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
727 0402302c Iustin Pop

728 0402302c Iustin Pop
    The target_node must exist in in nodes_ip, and must be one of the
729 0402302c Iustin Pop
    nodes in the logical ID for each of the DRBD devices encountered
730 0402302c Iustin Pop
    in the disk tree.
731 0402302c Iustin Pop

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

762 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
763 ff9c047c Iustin Pop
    standard python types.
764 ff9c047c Iustin Pop

765 ff9c047c Iustin Pop
    """
766 ff9c047c Iustin Pop
    bo = super(Disk, self).ToDict()
767 ff9c047c Iustin Pop
768 ff9c047c Iustin Pop
    for attr in ("children",):
769 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
770 ff9c047c Iustin Pop
      if alist:
771 ff9c047c Iustin Pop
        bo[attr] = self._ContainerToDicts(alist)
772 ff9c047c Iustin Pop
    return bo
773 ff9c047c Iustin Pop
774 ff9c047c Iustin Pop
  @classmethod
775 ff9c047c Iustin Pop
  def FromDict(cls, val):
776 ff9c047c Iustin Pop
    """Custom function for Disks
777 ff9c047c Iustin Pop

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

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

830 332d0e37 Iustin Pop
    """
831 7c4d6c7b Michael Hanselmann
    all_errors = []
832 332d0e37 Iustin Pop
    if self.mode not in constants.DISK_ACCESS_SET:
833 7c4d6c7b Michael Hanselmann
      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
834 7c4d6c7b Michael Hanselmann
    return all_errors
835 332d0e37 Iustin Pop
836 90d726a8 Iustin Pop
  def UpgradeConfig(self):
837 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
838 90d726a8 Iustin Pop

839 90d726a8 Iustin Pop
    """
840 90d726a8 Iustin Pop
    if self.children:
841 90d726a8 Iustin Pop
      for child in self.children:
842 90d726a8 Iustin Pop
        child.UpgradeConfig()
843 bc5d0215 Andrea Spadaccini
844 cce46164 René Nussbaumer
    # FIXME: Make this configurable in Ganeti 2.7
845 5dbee5ea Iustin Pop
    self.params = {}
846 90d726a8 Iustin Pop
    # add here config upgrade for this disk
847 90d726a8 Iustin Pop
848 cd46491f René Nussbaumer
  @staticmethod
849 cd46491f René Nussbaumer
  def ComputeLDParams(disk_template, disk_params):
850 cd46491f René Nussbaumer
    """Computes Logical Disk parameters from Disk Template parameters.
851 cd46491f René Nussbaumer

852 cd46491f René Nussbaumer
    @type disk_template: string
853 cd46491f René Nussbaumer
    @param disk_template: disk template, one of L{constants.DISK_TEMPLATES}
854 cd46491f René Nussbaumer
    @type disk_params: dict
855 cd46491f René Nussbaumer
    @param disk_params: disk template parameters;
856 cd46491f René Nussbaumer
                        dict(template_name -> parameters
857 cd46491f René Nussbaumer
    @rtype: list(dict)
858 cd46491f René Nussbaumer
    @return: a list of dicts, one for each node of the disk hierarchy. Each dict
859 cd46491f René Nussbaumer
      contains the LD parameters of the node. The tree is flattened in-order.
860 cd46491f René Nussbaumer

861 cd46491f René Nussbaumer
    """
862 cd46491f René Nussbaumer
    if disk_template not in constants.DISK_TEMPLATES:
863 cd46491f René Nussbaumer
      raise errors.ProgrammerError("Unknown disk template %s" % disk_template)
864 cd46491f René Nussbaumer
865 cd46491f René Nussbaumer
    assert disk_template in disk_params
866 cd46491f René Nussbaumer
867 cd46491f René Nussbaumer
    result = list()
868 cd46491f René Nussbaumer
    dt_params = disk_params[disk_template]
869 cd46491f René Nussbaumer
    if disk_template == constants.DT_DRBD8:
870 52f93ffd Michael Hanselmann
      result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8], {
871 cd46491f René Nussbaumer
        constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE],
872 cd46491f René Nussbaumer
        constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS],
873 cd46491f René Nussbaumer
        constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS],
874 cd46491f René Nussbaumer
        constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG],
875 cd46491f René Nussbaumer
        constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM],
876 cd46491f René Nussbaumer
        constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM],
877 cd46491f René Nussbaumer
        constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC],
878 cd46491f René Nussbaumer
        constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD],
879 cd46491f René Nussbaumer
        constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET],
880 cd46491f René Nussbaumer
        constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET],
881 cd46491f René Nussbaumer
        constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE],
882 cd46491f René Nussbaumer
        constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE],
883 52f93ffd Michael Hanselmann
        }))
884 cd46491f René Nussbaumer
885 cd46491f René Nussbaumer
      # data LV
886 52f93ffd Michael Hanselmann
      result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
887 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
888 52f93ffd Michael Hanselmann
        }))
889 cd46491f René Nussbaumer
890 cd46491f René Nussbaumer
      # metadata LV
891 52f93ffd Michael Hanselmann
      result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
892 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
893 52f93ffd Michael Hanselmann
        }))
894 52f93ffd Michael Hanselmann
895 52f93ffd Michael Hanselmann
    elif disk_template in (constants.DT_FILE, constants.DT_SHARED_FILE):
896 cd46491f René Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
897 cd46491f René Nussbaumer
898 cd46491f René Nussbaumer
    elif disk_template == constants.DT_PLAIN:
899 52f93ffd Michael Hanselmann
      result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
900 cd46491f René Nussbaumer
        constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
901 52f93ffd Michael Hanselmann
        }))
902 cd46491f René Nussbaumer
903 cd46491f René Nussbaumer
    elif disk_template == constants.DT_BLOCK:
904 cd46491f René Nussbaumer
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
905 cd46491f René Nussbaumer
906 cd46491f René Nussbaumer
    elif disk_template == constants.DT_RBD:
907 52f93ffd Michael Hanselmann
      result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD], {
908 3c286190 Dimitris Aragiorgis
        constants.LDP_POOL: dt_params[constants.RBD_POOL],
909 52f93ffd Michael Hanselmann
        }))
910 cd46491f René Nussbaumer
911 938adc87 Constantinos Venetsanopoulos
    elif disk_template == constants.DT_EXT:
912 938adc87 Constantinos Venetsanopoulos
      result.append(constants.DISK_LD_DEFAULTS[constants.LD_EXT])
913 938adc87 Constantinos Venetsanopoulos
914 cd46491f René Nussbaumer
    return result
915 cd46491f René Nussbaumer
916 a8083063 Iustin Pop
917 918eb80b Agata Murawska
class InstancePolicy(ConfigObject):
918 ffa339ca Iustin Pop
  """Config object representing instance policy limits dictionary.
919 918eb80b Agata Murawska

920 ffa339ca Iustin Pop

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

924 ffa339ca Iustin Pop
  """
925 918eb80b Agata Murawska
  @classmethod
926 8b057218 René Nussbaumer
  def CheckParameterSyntax(cls, ipolicy, check_std):
927 918eb80b Agata Murawska
    """ Check the instance policy for validity.
928 918eb80b Agata Murawska

929 918eb80b Agata Murawska
    """
930 918eb80b Agata Murawska
    for param in constants.ISPECS_PARAMETERS:
931 8b057218 René Nussbaumer
      InstancePolicy.CheckISpecSyntax(ipolicy, param, check_std)
932 d04c9d45 Iustin Pop
    if constants.IPOLICY_DTS in ipolicy:
933 d04c9d45 Iustin Pop
      InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
934 ff6c5e55 Iustin Pop
    for key in constants.IPOLICY_PARAMETERS:
935 ff6c5e55 Iustin Pop
      if key in ipolicy:
936 ff6c5e55 Iustin Pop
        InstancePolicy.CheckParameter(key, ipolicy[key])
937 57dc299a Iustin Pop
    wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
938 57dc299a Iustin Pop
    if wrong_keys:
939 57dc299a Iustin Pop
      raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
940 57dc299a Iustin Pop
                                      utils.CommaJoin(wrong_keys))
941 918eb80b Agata Murawska
942 918eb80b Agata Murawska
  @classmethod
943 8b057218 René Nussbaumer
  def CheckISpecSyntax(cls, ipolicy, name, check_std):
944 918eb80b Agata Murawska
    """Check the instance policy for validity on a given key.
945 918eb80b Agata Murawska

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

949 918eb80b Agata Murawska
    @type ipolicy: dict
950 918eb80b Agata Murawska
    @param ipolicy: dictionary with min, max, std specs
951 918eb80b Agata Murawska
    @type name: string
952 918eb80b Agata Murawska
    @param name: what are the limits for
953 8b057218 René Nussbaumer
    @type check_std: bool
954 8b057218 René Nussbaumer
    @param check_std: Whether to check std value or just assume compliance
955 918eb80b Agata Murawska
    @raise errors.ConfigureError: when specs for given name are not valid
956 918eb80b Agata Murawska

957 918eb80b Agata Murawska
    """
958 4f725341 Agata Murawska
    min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
959 8b057218 René Nussbaumer
960 8b057218 René Nussbaumer
    if check_std:
961 8b057218 René Nussbaumer
      std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
962 8b057218 René Nussbaumer
      std_msg = std_v
963 8b057218 René Nussbaumer
    else:
964 8b057218 René Nussbaumer
      std_v = min_v
965 8b057218 René Nussbaumer
      std_msg = "-"
966 8b057218 René Nussbaumer
967 4f725341 Agata Murawska
    max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
968 918eb80b Agata Murawska
    err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
969 918eb80b Agata Murawska
           (name,
970 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MIN].get(name, "-"),
971 4f725341 Agata Murawska
            ipolicy[constants.ISPECS_MAX].get(name, "-"),
972 8b057218 René Nussbaumer
            std_msg))
973 918eb80b Agata Murawska
    if min_v > std_v or std_v > max_v:
974 918eb80b Agata Murawska
      raise errors.ConfigurationError(err)
975 918eb80b Agata Murawska
976 2cc673a3 Iustin Pop
  @classmethod
977 2cc673a3 Iustin Pop
  def CheckDiskTemplates(cls, disk_templates):
978 2cc673a3 Iustin Pop
    """Checks the disk templates for validity.
979 2cc673a3 Iustin Pop

980 2cc673a3 Iustin Pop
    """
981 2cc673a3 Iustin Pop
    wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
982 2cc673a3 Iustin Pop
    if wrong:
983 2cc673a3 Iustin Pop
      raise errors.ConfigurationError("Invalid disk template(s) %s" %
984 2cc673a3 Iustin Pop
                                      utils.CommaJoin(wrong))
985 2cc673a3 Iustin Pop
986 ff6c5e55 Iustin Pop
  @classmethod
987 ff6c5e55 Iustin Pop
  def CheckParameter(cls, key, value):
988 ff6c5e55 Iustin Pop
    """Checks a parameter.
989 ff6c5e55 Iustin Pop

990 ff6c5e55 Iustin Pop
    Currently we expect all parameters to be float values.
991 ff6c5e55 Iustin Pop

992 ff6c5e55 Iustin Pop
    """
993 ff6c5e55 Iustin Pop
    try:
994 ff6c5e55 Iustin Pop
      float(value)
995 ff6c5e55 Iustin Pop
    except (TypeError, ValueError), err:
996 ff6c5e55 Iustin Pop
      raise errors.ConfigurationError("Invalid value for key" " '%s':"
997 ff6c5e55 Iustin Pop
                                      " '%s', error: %s" % (key, value, err))
998 ff6c5e55 Iustin Pop
999 918eb80b Agata Murawska
1000 ec29fe40 Iustin Pop
class Instance(TaggableObject):
1001 a8083063 Iustin Pop
  """Config object representing an instance."""
1002 154b9580 Balazs Lecz
  __slots__ = [
1003 a8083063 Iustin Pop
    "name",
1004 a8083063 Iustin Pop
    "primary_node",
1005 a8083063 Iustin Pop
    "os",
1006 e69d05fd Iustin Pop
    "hypervisor",
1007 5bf7b5cf Iustin Pop
    "hvparams",
1008 5bf7b5cf Iustin Pop
    "beparams",
1009 1bdcbbab Iustin Pop
    "osparams",
1010 9ca8a7c5 Agata Murawska
    "admin_state",
1011 a8083063 Iustin Pop
    "nics",
1012 a8083063 Iustin Pop
    "disks",
1013 a8083063 Iustin Pop
    "disk_template",
1014 58acb49d Alexander Schreiber
    "network_port",
1015 be1fa613 Iustin Pop
    "serial_no",
1016 e1dcc53a Iustin Pop
    ] + _TIMESTAMPS + _UUID
1017 a8083063 Iustin Pop
1018 a8083063 Iustin Pop
  def _ComputeSecondaryNodes(self):
1019 a8083063 Iustin Pop
    """Compute the list of secondary nodes.
1020 a8083063 Iustin Pop

1021 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
1022 cfcc5c6d Iustin Pop

1023 cfcc5c6d Iustin Pop
    """
1024 cfcc5c6d Iustin Pop
    all_nodes = set(self._ComputeAllNodes())
1025 cfcc5c6d Iustin Pop
    all_nodes.discard(self.primary_node)
1026 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1027 cfcc5c6d Iustin Pop
1028 cfcc5c6d Iustin Pop
  secondary_nodes = property(_ComputeSecondaryNodes, None, None,
1029 05325a35 Bernardo Dal Seno
                             "List of names of secondary nodes")
1030 cfcc5c6d Iustin Pop
1031 cfcc5c6d Iustin Pop
  def _ComputeAllNodes(self):
1032 cfcc5c6d Iustin Pop
    """Compute the list of all nodes.
1033 cfcc5c6d Iustin Pop

1034 a8083063 Iustin Pop
    Since the data is already there (in the drbd disks), keeping it as
1035 a8083063 Iustin Pop
    a separate normal attribute is redundant and if not properly
1036 a8083063 Iustin Pop
    synchronised can cause problems. Thus it's better to compute it
1037 a8083063 Iustin Pop
    dynamically.
1038 a8083063 Iustin Pop

1039 a8083063 Iustin Pop
    """
1040 cfcc5c6d Iustin Pop
    def _Helper(nodes, device):
1041 cfcc5c6d Iustin Pop
      """Recursively computes nodes given a top device."""
1042 a1f445d3 Iustin Pop
      if device.dev_type in constants.LDS_DRBD:
1043 cfcc5c6d Iustin Pop
        nodea, nodeb = device.logical_id[:2]
1044 cfcc5c6d Iustin Pop
        nodes.add(nodea)
1045 cfcc5c6d Iustin Pop
        nodes.add(nodeb)
1046 a8083063 Iustin Pop
      if device.children:
1047 a8083063 Iustin Pop
        for child in device.children:
1048 cfcc5c6d Iustin Pop
          _Helper(nodes, child)
1049 a8083063 Iustin Pop
1050 cfcc5c6d Iustin Pop
    all_nodes = set()
1051 99c7b2a1 Iustin Pop
    all_nodes.add(self.primary_node)
1052 a8083063 Iustin Pop
    for device in self.disks:
1053 cfcc5c6d Iustin Pop
      _Helper(all_nodes, device)
1054 cfcc5c6d Iustin Pop
    return tuple(all_nodes)
1055 a8083063 Iustin Pop
1056 cfcc5c6d Iustin Pop
  all_nodes = property(_ComputeAllNodes, None, None,
1057 05325a35 Bernardo Dal Seno
                       "List of names of all the nodes of the instance")
1058 a8083063 Iustin Pop
1059 a8083063 Iustin Pop
  def MapLVsByNode(self, lvmap=None, devs=None, node=None):
1060 a8083063 Iustin Pop
    """Provide a mapping of nodes to LVs this instance owns.
1061 a8083063 Iustin Pop

1062 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
1063 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
1064 a8083063 Iustin Pop

1065 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
1066 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
1067 a8083063 Iustin Pop

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

1073 a8083063 Iustin Pop
    """
1074 5ae4945a Iustin Pop
    if node is None:
1075 a8083063 Iustin Pop
      node = self.primary_node
1076 a8083063 Iustin Pop
1077 a8083063 Iustin Pop
    if lvmap is None:
1078 e687ec01 Michael Hanselmann
      lvmap = {
1079 e687ec01 Michael Hanselmann
        node: [],
1080 e687ec01 Michael Hanselmann
        }
1081 a8083063 Iustin Pop
      ret = lvmap
1082 a8083063 Iustin Pop
    else:
1083 a8083063 Iustin Pop
      if not node in lvmap:
1084 a8083063 Iustin Pop
        lvmap[node] = []
1085 a8083063 Iustin Pop
      ret = None
1086 a8083063 Iustin Pop
1087 a8083063 Iustin Pop
    if not devs:
1088 a8083063 Iustin Pop
      devs = self.disks
1089 a8083063 Iustin Pop
1090 a8083063 Iustin Pop
    for dev in devs:
1091 fe96220b Iustin Pop
      if dev.dev_type == constants.LD_LV:
1092 e687ec01 Michael Hanselmann
        lvmap[node].append(dev.logical_id[0] + "/" + dev.logical_id[1])
1093 a8083063 Iustin Pop
1094 a1f445d3 Iustin Pop
      elif dev.dev_type in constants.LDS_DRBD:
1095 a8083063 Iustin Pop
        if dev.children:
1096 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
1097 a8083063 Iustin Pop
          self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
1098 a8083063 Iustin Pop
1099 a8083063 Iustin Pop
      elif dev.children:
1100 a8083063 Iustin Pop
        self.MapLVsByNode(lvmap, dev.children, node)
1101 a8083063 Iustin Pop
1102 a8083063 Iustin Pop
    return ret
1103 a8083063 Iustin Pop
1104 ad24e046 Iustin Pop
  def FindDisk(self, idx):
1105 ad24e046 Iustin Pop
    """Find a disk given having a specified index.
1106 644eeef9 Iustin Pop

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

1109 ad24e046 Iustin Pop
    @type idx: int
1110 ad24e046 Iustin Pop
    @param idx: the disk index
1111 ad24e046 Iustin Pop
    @rtype: L{Disk}
1112 ad24e046 Iustin Pop
    @return: the corresponding disk
1113 ad24e046 Iustin Pop
    @raise errors.OpPrereqError: when the given index is not valid
1114 644eeef9 Iustin Pop

1115 ad24e046 Iustin Pop
    """
1116 ad24e046 Iustin Pop
    try:
1117 ad24e046 Iustin Pop
      idx = int(idx)
1118 ad24e046 Iustin Pop
      return self.disks[idx]
1119 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
1120 debac808 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: '%s'" % str(err),
1121 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1122 ad24e046 Iustin Pop
    except IndexError:
1123 ad24e046 Iustin Pop
      raise errors.OpPrereqError("Invalid disk index: %d (instace has disks"
1124 daa55b04 Michael Hanselmann
                                 " 0 to %d" % (idx, len(self.disks) - 1),
1125 debac808 Iustin Pop
                                 errors.ECODE_INVAL)
1126 644eeef9 Iustin Pop
1127 ff9c047c Iustin Pop
  def ToDict(self):
1128 ff9c047c Iustin Pop
    """Instance-specific conversion to standard python types.
1129 ff9c047c Iustin Pop

1130 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
1131 ff9c047c Iustin Pop
    python types.
1132 ff9c047c Iustin Pop

1133 ff9c047c Iustin Pop
    """
1134 ff9c047c Iustin Pop
    bo = super(Instance, self).ToDict()
1135 ff9c047c Iustin Pop
1136 ff9c047c Iustin Pop
    for attr in "nics", "disks":
1137 ff9c047c Iustin Pop
      alist = bo.get(attr, None)
1138 ff9c047c Iustin Pop
      if alist:
1139 ff9c047c Iustin Pop
        nlist = self._ContainerToDicts(alist)
1140 ff9c047c Iustin Pop
      else:
1141 ff9c047c Iustin Pop
        nlist = []
1142 ff9c047c Iustin Pop
      bo[attr] = nlist
1143 ff9c047c Iustin Pop
    return bo
1144 ff9c047c Iustin Pop
1145 ff9c047c Iustin Pop
  @classmethod
1146 ff9c047c Iustin Pop
  def FromDict(cls, val):
1147 ff9c047c Iustin Pop
    """Custom function for instances.
1148 ff9c047c Iustin Pop

1149 ff9c047c Iustin Pop
    """
1150 9ca8a7c5 Agata Murawska
    if "admin_state" not in val:
1151 9ca8a7c5 Agata Murawska
      if val.get("admin_up", False):
1152 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_UP
1153 9ca8a7c5 Agata Murawska
      else:
1154 9ca8a7c5 Agata Murawska
        val["admin_state"] = constants.ADMINST_DOWN
1155 9ca8a7c5 Agata Murawska
    if "admin_up" in val:
1156 9ca8a7c5 Agata Murawska
      del val["admin_up"]
1157 ff9c047c Iustin Pop
    obj = super(Instance, cls).FromDict(val)
1158 ff9c047c Iustin Pop
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
1159 ff9c047c Iustin Pop
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
1160 ff9c047c Iustin Pop
    return obj
1161 ff9c047c Iustin Pop
1162 90d726a8 Iustin Pop
  def UpgradeConfig(self):
1163 90d726a8 Iustin Pop
    """Fill defaults for missing configuration values.
1164 90d726a8 Iustin Pop

1165 90d726a8 Iustin Pop
    """
1166 90d726a8 Iustin Pop
    for nic in self.nics:
1167 90d726a8 Iustin Pop
      nic.UpgradeConfig()
1168 90d726a8 Iustin Pop
    for disk in self.disks:
1169 90d726a8 Iustin Pop
      disk.UpgradeConfig()
1170 7736a5f2 Iustin Pop
    if self.hvparams:
1171 7736a5f2 Iustin Pop
      for key in constants.HVC_GLOBALS:
1172 7736a5f2 Iustin Pop
        try:
1173 7736a5f2 Iustin Pop
          del self.hvparams[key]
1174 7736a5f2 Iustin Pop
        except KeyError:
1175 7736a5f2 Iustin Pop
          pass
1176 1bdcbbab Iustin Pop
    if self.osparams is None:
1177 1bdcbbab Iustin Pop
      self.osparams = {}
1178 8c72ab2b Guido Trotter
    UpgradeBeParams(self.beparams)
1179 90d726a8 Iustin Pop
1180 a8083063 Iustin Pop
1181 a8083063 Iustin Pop
class OS(ConfigObject):
1182 b41b3516 Iustin Pop
  """Config object representing an operating system.
1183 b41b3516 Iustin Pop

1184 b41b3516 Iustin Pop
  @type supported_parameters: list
1185 b41b3516 Iustin Pop
  @ivar supported_parameters: a list of tuples, name and description,
1186 b41b3516 Iustin Pop
      containing the supported parameters by this OS
1187 b41b3516 Iustin Pop

1188 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
1189 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
1190 870dc44c Iustin Pop

1191 b41b3516 Iustin Pop
  """
1192 a8083063 Iustin Pop
  __slots__ = [
1193 a8083063 Iustin Pop
    "name",
1194 a8083063 Iustin Pop
    "path",
1195 082a7f91 Guido Trotter
    "api_versions",
1196 a8083063 Iustin Pop
    "create_script",
1197 a8083063 Iustin Pop
    "export_script",
1198 386b57af Iustin Pop
    "import_script",
1199 386b57af Iustin Pop
    "rename_script",
1200 b41b3516 Iustin Pop
    "verify_script",
1201 6d79896b Guido Trotter
    "supported_variants",
1202 b41b3516 Iustin Pop
    "supported_parameters",
1203 a8083063 Iustin Pop
    ]
1204 a8083063 Iustin Pop
1205 870dc44c Iustin Pop
  VARIANT_DELIM = "+"
1206 870dc44c Iustin Pop
1207 870dc44c Iustin Pop
  @classmethod
1208 870dc44c Iustin Pop
  def SplitNameVariant(cls, name):
1209 870dc44c Iustin Pop
    """Splits the name into the proper name and variant.
1210 870dc44c Iustin Pop

1211 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1212 870dc44c Iustin Pop
    @rtype: list
1213 870dc44c Iustin Pop
    @return: a list of two elements; if the original name didn't
1214 870dc44c Iustin Pop
        contain a variant, it's returned as an empty string
1215 870dc44c Iustin Pop

1216 870dc44c Iustin Pop
    """
1217 870dc44c Iustin Pop
    nv = name.split(cls.VARIANT_DELIM, 1)
1218 870dc44c Iustin Pop
    if len(nv) == 1:
1219 870dc44c Iustin Pop
      nv.append("")
1220 870dc44c Iustin Pop
    return nv
1221 870dc44c Iustin Pop
1222 870dc44c Iustin Pop
  @classmethod
1223 870dc44c Iustin Pop
  def GetName(cls, name):
1224 870dc44c Iustin Pop
    """Returns the proper name of the os (without the variant).
1225 870dc44c Iustin Pop

1226 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1227 870dc44c Iustin Pop

1228 870dc44c Iustin Pop
    """
1229 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[0]
1230 870dc44c Iustin Pop
1231 870dc44c Iustin Pop
  @classmethod
1232 870dc44c Iustin Pop
  def GetVariant(cls, name):
1233 870dc44c Iustin Pop
    """Returns the variant the os (without the base name).
1234 870dc44c Iustin Pop

1235 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1236 870dc44c Iustin Pop

1237 870dc44c Iustin Pop
    """
1238 870dc44c Iustin Pop
    return cls.SplitNameVariant(name)[1]
1239 870dc44c Iustin Pop
1240 7c0d6283 Michael Hanselmann
1241 376631d1 Constantinos Venetsanopoulos
class ExtStorage(ConfigObject):
1242 376631d1 Constantinos Venetsanopoulos
  """Config object representing an External Storage Provider.
1243 376631d1 Constantinos Venetsanopoulos

1244 376631d1 Constantinos Venetsanopoulos
  """
1245 376631d1 Constantinos Venetsanopoulos
  __slots__ = [
1246 376631d1 Constantinos Venetsanopoulos
    "name",
1247 376631d1 Constantinos Venetsanopoulos
    "path",
1248 376631d1 Constantinos Venetsanopoulos
    "create_script",
1249 376631d1 Constantinos Venetsanopoulos
    "remove_script",
1250 376631d1 Constantinos Venetsanopoulos
    "grow_script",
1251 376631d1 Constantinos Venetsanopoulos
    "attach_script",
1252 376631d1 Constantinos Venetsanopoulos
    "detach_script",
1253 376631d1 Constantinos Venetsanopoulos
    "setinfo_script",
1254 938adc87 Constantinos Venetsanopoulos
    "verify_script",
1255 938adc87 Constantinos Venetsanopoulos
    "supported_parameters",
1256 376631d1 Constantinos Venetsanopoulos
    ]
1257 376631d1 Constantinos Venetsanopoulos
1258 376631d1 Constantinos Venetsanopoulos
1259 5f06ce5e Michael Hanselmann
class NodeHvState(ConfigObject):
1260 5f06ce5e Michael Hanselmann
  """Hypvervisor state on a node.
1261 5f06ce5e Michael Hanselmann

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

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

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

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

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

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

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

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

1393 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1394 c60abd62 Guido Trotter
    in memory.
1395 24a3707f Guido Trotter

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

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

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

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

1441 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1442 095e71aa René Nussbaumer
    @param node: A Node object to fill
1443 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1444 095e71aa René Nussbaumer

1445 095e71aa René Nussbaumer
    """
1446 095e71aa René Nussbaumer
    return self.SimpleFillND(node.ndparams)
1447 095e71aa René Nussbaumer
1448 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1449 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1450 095e71aa René Nussbaumer

1451 095e71aa René Nussbaumer
    @type ndparams: dict
1452 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1453 095e71aa René Nussbaumer
    @rtype: dict
1454 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1455 e6e88de6 Adeodato Simo
        from the node group defaults
1456 095e71aa René Nussbaumer

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

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

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

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

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

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

1642 8a147bba René Nussbaumer
    @param diskparams: The diskparams
1643 8a147bba René Nussbaumer
    @return: The defaults dict
1644 8a147bba René Nussbaumer

1645 8a147bba René Nussbaumer
    """
1646 8a147bba René Nussbaumer
    return FillDiskParams(self.diskparams, diskparams)
1647 8a147bba René Nussbaumer
1648 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1649 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1650 d63479b5 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1770 2da9f556 René Nussbaumer
    """
1771 2da9f556 René Nussbaumer
    return FillDict(constants.HVST_DEFAULTS, hv_state)
1772 2da9f556 René Nussbaumer
1773 2da9f556 René Nussbaumer
  @staticmethod
1774 2da9f556 René Nussbaumer
  def SimpleFillDiskState(disk_state):
1775 2da9f556 René Nussbaumer
    """Fill an disk_state sub dict with cluster defaults.
1776 2da9f556 René Nussbaumer

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

1783 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1784 095e71aa René Nussbaumer
    @param node: A Node object to fill
1785 095e71aa René Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1786 095e71aa René Nussbaumer
    @param nodegroup: A Node object to fill
1787 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1788 095e71aa René Nussbaumer

1789 095e71aa René Nussbaumer
    """
1790 095e71aa René Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1791 095e71aa René Nussbaumer
1792 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1793 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1794 095e71aa René Nussbaumer

1795 095e71aa René Nussbaumer
    @type ndparams: dict
1796 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1797 095e71aa René Nussbaumer
    @rtype: dict
1798 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1799 095e71aa René Nussbaumer
        from the cluster defaults
1800 095e71aa René Nussbaumer

1801 095e71aa René Nussbaumer
    """
1802 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1803 095e71aa René Nussbaumer
1804 918eb80b Agata Murawska
  def SimpleFillIPolicy(self, ipolicy):
1805 918eb80b Agata Murawska
    """ Fill instance policy dict with defaults.
1806 918eb80b Agata Murawska

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

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

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

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

1869 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1870 18d750b9 Guido Trotter
  @ivar type: confd query type
1871 18d750b9 Guido Trotter
  @ivar query: query request
1872 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1873 18d750b9 Guido Trotter

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

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

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

1903 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1904 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1905 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1906 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1907 707f23b5 Michael Hanselmann

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

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

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

1943 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1944 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1945 24d6d3e2 Michael Hanselmann

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

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

1965 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1966 24d6d3e2 Michael Hanselmann

1967 24d6d3e2 Michael Hanselmann
  """
1968 5ae4945a Iustin Pop
  __slots__ = []
1969 24d6d3e2 Michael Hanselmann
1970 24d6d3e2 Michael Hanselmann
1971 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
1972 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
1973 6a1434d7 Andrea Spadaccini

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

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

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

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

2044 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
2045 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
2046 a8083063 Iustin Pop
  buffer.
2047 a8083063 Iustin Pop

2048 a8083063 Iustin Pop
  """
2049 a8083063 Iustin Pop
  def Dumps(self):
2050 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
2051 a8083063 Iustin Pop
    buf = StringIO()
2052 a8083063 Iustin Pop
    self.write(buf)
2053 a8083063 Iustin Pop
    return buf.getvalue()
2054 a8083063 Iustin Pop
2055 b39bf4bb Guido Trotter
  @classmethod
2056 b39bf4bb Guido Trotter
  def Loads(cls, data):
2057 a8083063 Iustin Pop
    """Load data from a string."""
2058 a8083063 Iustin Pop
    buf = StringIO(data)
2059 b39bf4bb Guido Trotter
    cfp = cls()
2060 a8083063 Iustin Pop
    cfp.readfp(buf)
2061 a8083063 Iustin Pop
    return cfp
2062 59726e15 Bernardo Dal Seno
2063 59726e15 Bernardo Dal Seno
2064 59726e15 Bernardo Dal Seno
class LvmPvInfo(ConfigObject):
2065 59726e15 Bernardo Dal Seno
  """Information about an LVM physical volume (PV).
2066 59726e15 Bernardo Dal Seno

2067 59726e15 Bernardo Dal Seno
  @type name: string
2068 59726e15 Bernardo Dal Seno
  @ivar name: name of the PV
2069 59726e15 Bernardo Dal Seno
  @type vg_name: string
2070 59726e15 Bernardo Dal Seno
  @ivar vg_name: name of the volume group containing the PV
2071 59726e15 Bernardo Dal Seno
  @type size: float
2072 59726e15 Bernardo Dal Seno
  @ivar size: size of the PV in MiB
2073 59726e15 Bernardo Dal Seno
  @type free: float
2074 59726e15 Bernardo Dal Seno
  @ivar free: free space in the PV, in MiB
2075 59726e15 Bernardo Dal Seno
  @type attributes: string
2076 59726e15 Bernardo Dal Seno
  @ivar attributes: PV attributes
2077 59726e15 Bernardo Dal Seno
  """
2078 59726e15 Bernardo Dal Seno
  __slots__ = [
2079 59726e15 Bernardo Dal Seno
    "name",
2080 59726e15 Bernardo Dal Seno
    "vg_name",
2081 59726e15 Bernardo Dal Seno
    "size",
2082 59726e15 Bernardo Dal Seno
    "free",
2083 59726e15 Bernardo Dal Seno
    "attributes",
2084 59726e15 Bernardo Dal Seno
    ]
2085 59726e15 Bernardo Dal Seno
2086 59726e15 Bernardo Dal Seno
  def IsEmpty(self):
2087 59726e15 Bernardo Dal Seno
    """Is this PV empty?
2088 59726e15 Bernardo Dal Seno

2089 59726e15 Bernardo Dal Seno
    """
2090 59726e15 Bernardo Dal Seno
    return self.size <= (self.free + 1)
2091 59726e15 Bernardo Dal Seno
2092 59726e15 Bernardo Dal Seno
  def IsAllocatable(self):
2093 59726e15 Bernardo Dal Seno
    """Is this PV allocatable?
2094 59726e15 Bernardo Dal Seno

2095 59726e15 Bernardo Dal Seno
    """
2096 59726e15 Bernardo Dal Seno
    return ("a" in self.attributes)