Statistics
| Branch: | Tag: | Revision:

root / lib / objects.py @ 91c17910

History | View | Annotate | Download (60.5 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 473d87a3 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 250a9404 Bernardo Dal Seno
import logging
42 e11a1b77 Adeodato Simo
import time
43 d5835922 Michael Hanselmann
from cStringIO import StringIO
44 a8083063 Iustin Pop
45 a8083063 Iustin Pop
from ganeti import errors
46 5c947f38 Iustin Pop
from ganeti import constants
47 0007f3ab Andrea Spadaccini
from ganeti import netutils
48 473d87a3 Iustin Pop
from ganeti import outils
49 32017174 Agata Murawska
from ganeti import utils
50 a8083063 Iustin Pop
51 f4c9af7a Guido Trotter
from socket import AF_INET
52 f4c9af7a Guido Trotter
53 a8083063 Iustin Pop
54 a8083063 Iustin Pop
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
55 eaa4c57c Dimitris Aragiorgis
           "OS", "Node", "NodeGroup", "Cluster", "FillDict", "Network"]
56 a8083063 Iustin Pop
57 d693c864 Iustin Pop
_TIMESTAMPS = ["ctime", "mtime"]
58 e1dcc53a Iustin Pop
_UUID = ["uuid"]
59 96acbc09 Michael Hanselmann
60 8d8d650c Michael Hanselmann
61 e11ddf13 Iustin Pop
def FillDict(defaults_dict, custom_dict, skip_keys=None):
62 29921401 Iustin Pop
  """Basic function to apply settings on top a default dict.
63 abe609b2 Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

554 e51db2a6 Iustin Pop
    @warning: The path returned is not a normalized pathname; callers
555 e51db2a6 Iustin Pop
        should check that it is a valid path.
556 e51db2a6 Iustin Pop

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

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

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

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

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

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

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

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

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

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

656 6d33a6eb Iustin Pop
    This only works for VG-based disks.
657 6d33a6eb Iustin Pop

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

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

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

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

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

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

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

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

727 0402302c Iustin Pop
    Arguments:
728 0402302c Iustin Pop
      - target_node: the node we wish to configure for
729 0402302c Iustin Pop
      - nodes_ip: a mapping of node name to ip
730 0402302c Iustin Pop

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

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

765 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of
766 ff9c047c Iustin Pop
    standard python types.
767 ff9c047c Iustin Pop

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

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

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

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

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

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

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

923 ffa339ca Iustin Pop

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

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

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

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

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

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

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

993 ff6c5e55 Iustin Pop
    Currently we expect all parameters to be float values.
994 ff6c5e55 Iustin Pop

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

1024 cfcc5c6d Iustin Pop
    This is a simple wrapper over _ComputeAllNodes.
1025 cfcc5c6d Iustin Pop

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

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

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

1065 c41eea6e Iustin Pop
    This function figures out what logical volumes should belong on
1066 c41eea6e Iustin Pop
    which nodes, recursing through a device tree.
1067 a8083063 Iustin Pop

1068 c41eea6e Iustin Pop
    @param lvmap: optional dictionary to receive the
1069 c41eea6e Iustin Pop
        'node' : ['lv', ...] data.
1070 a8083063 Iustin Pop

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

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

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

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

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

1133 ff9c047c Iustin Pop
    This replaces the children lists of objects with lists of standard
1134 ff9c047c Iustin Pop
    python types.
1135 ff9c047c Iustin Pop

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

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

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

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

1191 870dc44c Iustin Pop
  @type VARIANT_DELIM: string
1192 870dc44c Iustin Pop
  @cvar VARIANT_DELIM: the variant delimiter
1193 870dc44c Iustin Pop

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

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

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

1229 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1230 870dc44c Iustin Pop

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

1238 870dc44c Iustin Pop
    @param name: the OS (unprocessed) name
1239 870dc44c Iustin Pop

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

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

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

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

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

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

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

1327 490acd18 Iustin Pop
    """
1328 b459a848 Andrea Spadaccini
    # pylint: disable=E0203
1329 490acd18 Iustin Pop
    # because these are "defined" via slots, not manually
1330 490acd18 Iustin Pop
    if self.master_capable is None:
1331 490acd18 Iustin Pop
      self.master_capable = True
1332 490acd18 Iustin Pop
1333 490acd18 Iustin Pop
    if self.vm_capable is None:
1334 490acd18 Iustin Pop
      self.vm_capable = True
1335 490acd18 Iustin Pop
1336 095e71aa René Nussbaumer
    if self.ndparams is None:
1337 095e71aa René Nussbaumer
      self.ndparams = {}
1338 250a9404 Bernardo Dal Seno
    # And remove any global parameter
1339 250a9404 Bernardo Dal Seno
    for key in constants.NDC_GLOBALS:
1340 250a9404 Bernardo Dal Seno
      if key in self.ndparams:
1341 250a9404 Bernardo Dal Seno
        logging.warning("Ignoring %s node parameter for node %s",
1342 250a9404 Bernardo Dal Seno
                        key, self.name)
1343 250a9404 Bernardo Dal Seno
        del self.ndparams[key]
1344 095e71aa René Nussbaumer
1345 25124d4a René Nussbaumer
    if self.powered is None:
1346 25124d4a René Nussbaumer
      self.powered = True
1347 25124d4a René Nussbaumer
1348 5f06ce5e Michael Hanselmann
  def ToDict(self):
1349 5f06ce5e Michael Hanselmann
    """Custom function for serializing.
1350 5f06ce5e Michael Hanselmann

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

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

1402 c60abd62 Guido Trotter
    This discards the members object, which gets recalculated and is only kept
1403 c60abd62 Guido Trotter
    in memory.
1404 24a3707f Guido Trotter

1405 24a3707f Guido Trotter
    """
1406 24a3707f Guido Trotter
    mydict = super(NodeGroup, self).ToDict()
1407 24a3707f Guido Trotter
    del mydict["members"]
1408 24a3707f Guido Trotter
    return mydict
1409 24a3707f Guido Trotter
1410 24a3707f Guido Trotter
  @classmethod
1411 24a3707f Guido Trotter
  def FromDict(cls, val):
1412 24a3707f Guido Trotter
    """Custom function for nodegroup.
1413 24a3707f Guido Trotter

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

1416 24a3707f Guido Trotter
    """
1417 24a3707f Guido Trotter
    obj = super(NodeGroup, cls).FromDict(val)
1418 24a3707f Guido Trotter
    obj.members = []
1419 24a3707f Guido Trotter
    return obj
1420 24a3707f Guido Trotter
1421 095e71aa René Nussbaumer
  def UpgradeConfig(self):
1422 095e71aa René Nussbaumer
    """Fill defaults for missing configuration values.
1423 095e71aa René Nussbaumer

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

1450 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1451 095e71aa René Nussbaumer
    @param node: A Node object to fill
1452 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1453 095e71aa René Nussbaumer

1454 095e71aa René Nussbaumer
    """
1455 095e71aa René Nussbaumer
    return self.SimpleFillND(node.ndparams)
1456 095e71aa René Nussbaumer
1457 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1458 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1459 095e71aa René Nussbaumer

1460 095e71aa René Nussbaumer
    @type ndparams: dict
1461 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1462 095e71aa René Nussbaumer
    @rtype: dict
1463 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1464 e6e88de6 Adeodato Simo
        from the node group defaults
1465 095e71aa René Nussbaumer

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

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

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

1627 0fbedb7a Michael Hanselmann
    """
1628 0fbedb7a Michael Hanselmann
    return self.enabled_hypervisors[0]
1629 0fbedb7a Michael Hanselmann
1630 319856a9 Michael Hanselmann
  def ToDict(self):
1631 319856a9 Michael Hanselmann
    """Custom function for cluster.
1632 319856a9 Michael Hanselmann

1633 319856a9 Michael Hanselmann
    """
1634 b60ae2ca Iustin Pop
    mydict = super(Cluster, self).ToDict()
1635 319856a9 Michael Hanselmann
    mydict["tcpudp_port_pool"] = list(self.tcpudp_port_pool)
1636 319856a9 Michael Hanselmann
    return mydict
1637 319856a9 Michael Hanselmann
1638 319856a9 Michael Hanselmann
  @classmethod
1639 319856a9 Michael Hanselmann
  def FromDict(cls, val):
1640 319856a9 Michael Hanselmann
    """Custom function for cluster.
1641 319856a9 Michael Hanselmann

1642 319856a9 Michael Hanselmann
    """
1643 b60ae2ca Iustin Pop
    obj = super(Cluster, cls).FromDict(val)
1644 319856a9 Michael Hanselmann
    if not isinstance(obj.tcpudp_port_pool, set):
1645 319856a9 Michael Hanselmann
      obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
1646 319856a9 Michael Hanselmann
    return obj
1647 319856a9 Michael Hanselmann
1648 8a147bba René Nussbaumer
  def SimpleFillDP(self, diskparams):
1649 8a147bba René Nussbaumer
    """Fill a given diskparams dict with cluster defaults.
1650 8a147bba René Nussbaumer

1651 8a147bba René Nussbaumer
    @param diskparams: The diskparams
1652 8a147bba René Nussbaumer
    @return: The defaults dict
1653 8a147bba René Nussbaumer

1654 8a147bba René Nussbaumer
    """
1655 8a147bba René Nussbaumer
    return FillDiskParams(self.diskparams, diskparams)
1656 8a147bba René Nussbaumer
1657 d63479b5 Iustin Pop
  def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
1658 d63479b5 Iustin Pop
    """Get the default hypervisor parameters for the cluster.
1659 d63479b5 Iustin Pop

1660 d63479b5 Iustin Pop
    @param hypervisor: the hypervisor name
1661 d63479b5 Iustin Pop
    @param os_name: if specified, we'll also update the defaults for this OS
1662 d63479b5 Iustin Pop
    @param skip_keys: if passed, list of keys not to use
1663 d63479b5 Iustin Pop
    @return: the defaults dict
1664 d63479b5 Iustin Pop

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

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

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

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

1715 5bf7b5cf Iustin Pop
    """
1716 73e0328b Iustin Pop
    return self.SimpleFillHV(instance.hypervisor, instance.os,
1717 73e0328b Iustin Pop
                             instance.hvparams, skip_globals)
1718 17463d22 René Nussbaumer
1719 73e0328b Iustin Pop
  def SimpleFillBE(self, beparams):
1720 73e0328b Iustin Pop
    """Fill a given beparams dict with cluster defaults.
1721 73e0328b Iustin Pop

1722 06596a60 Guido Trotter
    @type beparams: dict
1723 06596a60 Guido Trotter
    @param beparams: the dict to fill
1724 73e0328b Iustin Pop
    @rtype: dict
1725 73e0328b Iustin Pop
    @return: a copy of the passed in beparams with missing keys filled
1726 73e0328b Iustin Pop
        from the cluster defaults
1727 73e0328b Iustin Pop

1728 73e0328b Iustin Pop
    """
1729 73e0328b Iustin Pop
    return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams)
1730 5bf7b5cf Iustin Pop
1731 5bf7b5cf Iustin Pop
  def FillBE(self, instance):
1732 73e0328b Iustin Pop
    """Fill an instance's beparams dict with cluster defaults.
1733 5bf7b5cf Iustin Pop

1734 a2a24f4c Guido Trotter
    @type instance: L{objects.Instance}
1735 5bf7b5cf Iustin Pop
    @param instance: the instance parameter to fill
1736 5bf7b5cf Iustin Pop
    @rtype: dict
1737 5bf7b5cf Iustin Pop
    @return: a copy of the instance's beparams with missing keys filled from
1738 5bf7b5cf Iustin Pop
        the cluster defaults
1739 5bf7b5cf Iustin Pop

1740 5bf7b5cf Iustin Pop
    """
1741 73e0328b Iustin Pop
    return self.SimpleFillBE(instance.beparams)
1742 73e0328b Iustin Pop
1743 73e0328b Iustin Pop
  def SimpleFillNIC(self, nicparams):
1744 73e0328b Iustin Pop
    """Fill a given nicparams dict with cluster defaults.
1745 73e0328b Iustin Pop

1746 06596a60 Guido Trotter
    @type nicparams: dict
1747 06596a60 Guido Trotter
    @param nicparams: the dict to fill
1748 73e0328b Iustin Pop
    @rtype: dict
1749 73e0328b Iustin Pop
    @return: a copy of the passed in nicparams with missing keys filled
1750 73e0328b Iustin Pop
        from the cluster defaults
1751 73e0328b Iustin Pop

1752 73e0328b Iustin Pop
    """
1753 73e0328b Iustin Pop
    return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams)
1754 5bf7b5cf Iustin Pop
1755 1bdcbbab Iustin Pop
  def SimpleFillOS(self, os_name, os_params):
1756 1bdcbbab Iustin Pop
    """Fill an instance's osparams dict with cluster defaults.
1757 1bdcbbab Iustin Pop

1758 1bdcbbab Iustin Pop
    @type os_name: string
1759 1bdcbbab Iustin Pop
    @param os_name: the OS name to use
1760 1bdcbbab Iustin Pop
    @type os_params: dict
1761 1bdcbbab Iustin Pop
    @param os_params: the dict to fill with default values
1762 1bdcbbab Iustin Pop
    @rtype: dict
1763 1bdcbbab Iustin Pop
    @return: a copy of the instance's osparams with missing keys filled from
1764 1bdcbbab Iustin Pop
        the cluster defaults
1765 1bdcbbab Iustin Pop

1766 1bdcbbab Iustin Pop
    """
1767 1bdcbbab Iustin Pop
    name_only = os_name.split("+", 1)[0]
1768 1bdcbbab Iustin Pop
    # base OS
1769 1bdcbbab Iustin Pop
    result = self.osparams.get(name_only, {})
1770 1bdcbbab Iustin Pop
    # OS with variant
1771 1bdcbbab Iustin Pop
    result = FillDict(result, self.osparams.get(os_name, {}))
1772 1bdcbbab Iustin Pop
    # specified params
1773 1bdcbbab Iustin Pop
    return FillDict(result, os_params)
1774 1bdcbbab Iustin Pop
1775 2da9f556 René Nussbaumer
  @staticmethod
1776 2da9f556 René Nussbaumer
  def SimpleFillHvState(hv_state):
1777 2da9f556 René Nussbaumer
    """Fill an hv_state sub dict with cluster defaults.
1778 2da9f556 René Nussbaumer

1779 2da9f556 René Nussbaumer
    """
1780 2da9f556 René Nussbaumer
    return FillDict(constants.HVST_DEFAULTS, hv_state)
1781 2da9f556 René Nussbaumer
1782 2da9f556 René Nussbaumer
  @staticmethod
1783 2da9f556 René Nussbaumer
  def SimpleFillDiskState(disk_state):
1784 2da9f556 René Nussbaumer
    """Fill an disk_state sub dict with cluster defaults.
1785 2da9f556 René Nussbaumer

1786 2da9f556 René Nussbaumer
    """
1787 2da9f556 René Nussbaumer
    return FillDict(constants.DS_DEFAULTS, disk_state)
1788 2da9f556 René Nussbaumer
1789 095e71aa René Nussbaumer
  def FillND(self, node, nodegroup):
1790 ce523de1 Michael Hanselmann
    """Return filled out ndparams for L{objects.NodeGroup} and L{objects.Node}
1791 095e71aa René Nussbaumer

1792 095e71aa René Nussbaumer
    @type node: L{objects.Node}
1793 095e71aa René Nussbaumer
    @param node: A Node object to fill
1794 095e71aa René Nussbaumer
    @type nodegroup: L{objects.NodeGroup}
1795 095e71aa René Nussbaumer
    @param nodegroup: A Node object to fill
1796 095e71aa René Nussbaumer
    @return a copy of the node's ndparams with defaults filled
1797 095e71aa René Nussbaumer

1798 095e71aa René Nussbaumer
    """
1799 095e71aa René Nussbaumer
    return self.SimpleFillND(nodegroup.FillND(node))
1800 095e71aa René Nussbaumer
1801 095e71aa René Nussbaumer
  def SimpleFillND(self, ndparams):
1802 095e71aa René Nussbaumer
    """Fill a given ndparams dict with defaults.
1803 095e71aa René Nussbaumer

1804 095e71aa René Nussbaumer
    @type ndparams: dict
1805 095e71aa René Nussbaumer
    @param ndparams: the dict to fill
1806 095e71aa René Nussbaumer
    @rtype: dict
1807 095e71aa René Nussbaumer
    @return: a copy of the passed in ndparams with missing keys filled
1808 095e71aa René Nussbaumer
        from the cluster defaults
1809 095e71aa René Nussbaumer

1810 095e71aa René Nussbaumer
    """
1811 095e71aa René Nussbaumer
    return FillDict(self.ndparams, ndparams)
1812 095e71aa René Nussbaumer
1813 918eb80b Agata Murawska
  def SimpleFillIPolicy(self, ipolicy):
1814 918eb80b Agata Murawska
    """ Fill instance policy dict with defaults.
1815 918eb80b Agata Murawska

1816 918eb80b Agata Murawska
    @type ipolicy: dict
1817 918eb80b Agata Murawska
    @param ipolicy: the dict to fill
1818 918eb80b Agata Murawska
    @rtype: dict
1819 918eb80b Agata Murawska
    @return: a copy of passed ipolicy with missing keys filled from
1820 918eb80b Agata Murawska
      the cluster defaults
1821 918eb80b Agata Murawska

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

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

1864 eb630f50 Michael Hanselmann
  """
1865 eb630f50 Michael Hanselmann
  __slots__ = [
1866 eb630f50 Michael Hanselmann
    "key_name",
1867 eb630f50 Michael Hanselmann
    "ca_pem",
1868 a5310c2a Michael Hanselmann
    "compress",
1869 af1d39b1 Michael Hanselmann
    "magic",
1870 855d2fc7 Michael Hanselmann
    "ipv6",
1871 4478301b Michael Hanselmann
    "connect_timeout",
1872 eb630f50 Michael Hanselmann
    ]
1873 eb630f50 Michael Hanselmann
1874 eb630f50 Michael Hanselmann
1875 18d750b9 Guido Trotter
class ConfdRequest(ConfigObject):
1876 18d750b9 Guido Trotter
  """Object holding a confd request.
1877 18d750b9 Guido Trotter

1878 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1879 18d750b9 Guido Trotter
  @ivar type: confd query type
1880 18d750b9 Guido Trotter
  @ivar query: query request
1881 18d750b9 Guido Trotter
  @ivar rsalt: requested reply salt
1882 18d750b9 Guido Trotter

1883 18d750b9 Guido Trotter
  """
1884 18d750b9 Guido Trotter
  __slots__ = [
1885 18d750b9 Guido Trotter
    "protocol",
1886 18d750b9 Guido Trotter
    "type",
1887 18d750b9 Guido Trotter
    "query",
1888 18d750b9 Guido Trotter
    "rsalt",
1889 18d750b9 Guido Trotter
    ]
1890 18d750b9 Guido Trotter
1891 18d750b9 Guido Trotter
1892 18d750b9 Guido Trotter
class ConfdReply(ConfigObject):
1893 18d750b9 Guido Trotter
  """Object holding a confd reply.
1894 18d750b9 Guido Trotter

1895 18d750b9 Guido Trotter
  @ivar protocol: confd protocol version
1896 18d750b9 Guido Trotter
  @ivar status: reply status code (ok, error)
1897 18d750b9 Guido Trotter
  @ivar answer: confd query reply
1898 18d750b9 Guido Trotter
  @ivar serial: configuration serial number
1899 18d750b9 Guido Trotter

1900 18d750b9 Guido Trotter
  """
1901 18d750b9 Guido Trotter
  __slots__ = [
1902 18d750b9 Guido Trotter
    "protocol",
1903 18d750b9 Guido Trotter
    "status",
1904 18d750b9 Guido Trotter
    "answer",
1905 18d750b9 Guido Trotter
    "serial",
1906 18d750b9 Guido Trotter
    ]
1907 18d750b9 Guido Trotter
1908 18d750b9 Guido Trotter
1909 707f23b5 Michael Hanselmann
class QueryFieldDefinition(ConfigObject):
1910 707f23b5 Michael Hanselmann
  """Object holding a query field definition.
1911 707f23b5 Michael Hanselmann

1912 24d6d3e2 Michael Hanselmann
  @ivar name: Field name
1913 707f23b5 Michael Hanselmann
  @ivar title: Human-readable title
1914 707f23b5 Michael Hanselmann
  @ivar kind: Field type
1915 1ae17369 Michael Hanselmann
  @ivar doc: Human-readable description
1916 707f23b5 Michael Hanselmann

1917 707f23b5 Michael Hanselmann
  """
1918 707f23b5 Michael Hanselmann
  __slots__ = [
1919 707f23b5 Michael Hanselmann
    "name",
1920 707f23b5 Michael Hanselmann
    "title",
1921 707f23b5 Michael Hanselmann
    "kind",
1922 1ae17369 Michael Hanselmann
    "doc",
1923 707f23b5 Michael Hanselmann
    ]
1924 707f23b5 Michael Hanselmann
1925 707f23b5 Michael Hanselmann
1926 0538c375 Michael Hanselmann
class _QueryResponseBase(ConfigObject):
1927 0538c375 Michael Hanselmann
  __slots__ = [
1928 0538c375 Michael Hanselmann
    "fields",
1929 0538c375 Michael Hanselmann
    ]
1930 0538c375 Michael Hanselmann
1931 0538c375 Michael Hanselmann
  def ToDict(self):
1932 0538c375 Michael Hanselmann
    """Custom function for serializing.
1933 0538c375 Michael Hanselmann

1934 0538c375 Michael Hanselmann
    """
1935 0538c375 Michael Hanselmann
    mydict = super(_QueryResponseBase, self).ToDict()
1936 0538c375 Michael Hanselmann
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1937 0538c375 Michael Hanselmann
    return mydict
1938 0538c375 Michael Hanselmann
1939 0538c375 Michael Hanselmann
  @classmethod
1940 0538c375 Michael Hanselmann
  def FromDict(cls, val):
1941 0538c375 Michael Hanselmann
    """Custom function for de-serializing.
1942 0538c375 Michael Hanselmann

1943 0538c375 Michael Hanselmann
    """
1944 0538c375 Michael Hanselmann
    obj = super(_QueryResponseBase, cls).FromDict(val)
1945 0538c375 Michael Hanselmann
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1946 0538c375 Michael Hanselmann
    return obj
1947 0538c375 Michael Hanselmann
1948 0538c375 Michael Hanselmann
1949 0538c375 Michael Hanselmann
class QueryResponse(_QueryResponseBase):
1950 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query.
1951 24d6d3e2 Michael Hanselmann

1952 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1953 24d6d3e2 Michael Hanselmann
  @ivar data: Requested data
1954 24d6d3e2 Michael Hanselmann

1955 24d6d3e2 Michael Hanselmann
  """
1956 24d6d3e2 Michael Hanselmann
  __slots__ = [
1957 24d6d3e2 Michael Hanselmann
    "data",
1958 24d6d3e2 Michael Hanselmann
    ]
1959 24d6d3e2 Michael Hanselmann
1960 24d6d3e2 Michael Hanselmann
1961 24d6d3e2 Michael Hanselmann
class QueryFieldsRequest(ConfigObject):
1962 24d6d3e2 Michael Hanselmann
  """Object holding a request for querying available fields.
1963 24d6d3e2 Michael Hanselmann

1964 24d6d3e2 Michael Hanselmann
  """
1965 24d6d3e2 Michael Hanselmann
  __slots__ = [
1966 24d6d3e2 Michael Hanselmann
    "what",
1967 24d6d3e2 Michael Hanselmann
    "fields",
1968 24d6d3e2 Michael Hanselmann
    ]
1969 24d6d3e2 Michael Hanselmann
1970 24d6d3e2 Michael Hanselmann
1971 0538c375 Michael Hanselmann
class QueryFieldsResponse(_QueryResponseBase):
1972 24d6d3e2 Michael Hanselmann
  """Object holding the response to a query for fields.
1973 24d6d3e2 Michael Hanselmann

1974 24d6d3e2 Michael Hanselmann
  @ivar fields: List of L{QueryFieldDefinition} objects
1975 24d6d3e2 Michael Hanselmann

1976 24d6d3e2 Michael Hanselmann
  """
1977 5ae4945a Iustin Pop
  __slots__ = []
1978 24d6d3e2 Michael Hanselmann
1979 24d6d3e2 Michael Hanselmann
1980 6a1434d7 Andrea Spadaccini
class MigrationStatus(ConfigObject):
1981 6a1434d7 Andrea Spadaccini
  """Object holding the status of a migration.
1982 6a1434d7 Andrea Spadaccini

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

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

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

2033 eaa4c57c Dimitris Aragiorgis
  """
2034 eaa4c57c Dimitris Aragiorgis
  __slots__ = [
2035 eaa4c57c Dimitris Aragiorgis
    "name",
2036 eaa4c57c Dimitris Aragiorgis
    "serial_no",
2037 eaa4c57c Dimitris Aragiorgis
    "mac_prefix",
2038 eaa4c57c Dimitris Aragiorgis
    "network",
2039 eaa4c57c Dimitris Aragiorgis
    "network6",
2040 eaa4c57c Dimitris Aragiorgis
    "gateway",
2041 eaa4c57c Dimitris Aragiorgis
    "gateway6",
2042 eaa4c57c Dimitris Aragiorgis
    "reservations",
2043 eaa4c57c Dimitris Aragiorgis
    "ext_reservations",
2044 eaa4c57c Dimitris Aragiorgis
    ] + _TIMESTAMPS + _UUID
2045 eaa4c57c Dimitris Aragiorgis
2046 7e8f03e3 Dimitris Aragiorgis
  def HooksDict(self, prefix=""):
2047 d89168ff Guido Trotter
    """Export a dictionary used by hooks with a network's information.
2048 d89168ff Guido Trotter

2049 d89168ff Guido Trotter
    @type prefix: String
2050 d89168ff Guido Trotter
    @param prefix: Prefix to prepend to the dict entries
2051 d89168ff Guido Trotter

2052 d89168ff Guido Trotter
    """
2053 d89168ff Guido Trotter
    result = {
2054 7e8f03e3 Dimitris Aragiorgis
      "%sNETWORK_NAME" % prefix: self.name,
2055 d89168ff Guido Trotter
      "%sNETWORK_UUID" % prefix: self.uuid,
2056 5a76adf7 Dimitris Aragiorgis
      "%sNETWORK_TAGS" % prefix: " ".join(self.GetTags()),
2057 d89168ff Guido Trotter
    }
2058 d89168ff Guido Trotter
    if self.network:
2059 d89168ff Guido Trotter
      result["%sNETWORK_SUBNET" % prefix] = self.network
2060 d89168ff Guido Trotter
    if self.gateway:
2061 d89168ff Guido Trotter
      result["%sNETWORK_GATEWAY" % prefix] = self.gateway
2062 d89168ff Guido Trotter
    if self.network6:
2063 d89168ff Guido Trotter
      result["%sNETWORK_SUBNET6" % prefix] = self.network6
2064 d89168ff Guido Trotter
    if self.gateway6:
2065 d89168ff Guido Trotter
      result["%sNETWORK_GATEWAY6" % prefix] = self.gateway6
2066 d89168ff Guido Trotter
    if self.mac_prefix:
2067 d89168ff Guido Trotter
      result["%sNETWORK_MAC_PREFIX" % prefix] = self.mac_prefix
2068 d89168ff Guido Trotter
2069 d89168ff Guido Trotter
    return result
2070 d89168ff Guido Trotter
2071 5cfa6c37 Dimitris Aragiorgis
  @classmethod
2072 5cfa6c37 Dimitris Aragiorgis
  def FromDict(cls, val):
2073 5cfa6c37 Dimitris Aragiorgis
    """Custom function for networks.
2074 5cfa6c37 Dimitris Aragiorgis

2075 48616625 Dimitris Aragiorgis
    Remove deprecated network_type and family.
2076 5cfa6c37 Dimitris Aragiorgis

2077 5cfa6c37 Dimitris Aragiorgis
    """
2078 5cfa6c37 Dimitris Aragiorgis
    if "network_type" in val:
2079 5cfa6c37 Dimitris Aragiorgis
      del val["network_type"]
2080 48616625 Dimitris Aragiorgis
    if "family" in val:
2081 48616625 Dimitris Aragiorgis
      del val["family"]
2082 5cfa6c37 Dimitris Aragiorgis
    obj = super(Network, cls).FromDict(val)
2083 5cfa6c37 Dimitris Aragiorgis
    return obj
2084 5cfa6c37 Dimitris Aragiorgis
2085 eaa4c57c Dimitris Aragiorgis
2086 a8083063 Iustin Pop
class SerializableConfigParser(ConfigParser.SafeConfigParser):
2087 a8083063 Iustin Pop
  """Simple wrapper over ConfigParse that allows serialization.
2088 a8083063 Iustin Pop

2089 a8083063 Iustin Pop
  This class is basically ConfigParser.SafeConfigParser with two
2090 a8083063 Iustin Pop
  additional methods that allow it to serialize/unserialize to/from a
2091 a8083063 Iustin Pop
  buffer.
2092 a8083063 Iustin Pop

2093 a8083063 Iustin Pop
  """
2094 a8083063 Iustin Pop
  def Dumps(self):
2095 a8083063 Iustin Pop
    """Dump this instance and return the string representation."""
2096 a8083063 Iustin Pop
    buf = StringIO()
2097 a8083063 Iustin Pop
    self.write(buf)
2098 a8083063 Iustin Pop
    return buf.getvalue()
2099 a8083063 Iustin Pop
2100 b39bf4bb Guido Trotter
  @classmethod
2101 b39bf4bb Guido Trotter
  def Loads(cls, data):
2102 a8083063 Iustin Pop
    """Load data from a string."""
2103 a8083063 Iustin Pop
    buf = StringIO(data)
2104 b39bf4bb Guido Trotter
    cfp = cls()
2105 a8083063 Iustin Pop
    cfp.readfp(buf)
2106 a8083063 Iustin Pop
    return cfp
2107 59726e15 Bernardo Dal Seno
2108 59726e15 Bernardo Dal Seno
2109 59726e15 Bernardo Dal Seno
class LvmPvInfo(ConfigObject):
2110 59726e15 Bernardo Dal Seno
  """Information about an LVM physical volume (PV).
2111 59726e15 Bernardo Dal Seno

2112 59726e15 Bernardo Dal Seno
  @type name: string
2113 59726e15 Bernardo Dal Seno
  @ivar name: name of the PV
2114 59726e15 Bernardo Dal Seno
  @type vg_name: string
2115 59726e15 Bernardo Dal Seno
  @ivar vg_name: name of the volume group containing the PV
2116 59726e15 Bernardo Dal Seno
  @type size: float
2117 59726e15 Bernardo Dal Seno
  @ivar size: size of the PV in MiB
2118 59726e15 Bernardo Dal Seno
  @type free: float
2119 59726e15 Bernardo Dal Seno
  @ivar free: free space in the PV, in MiB
2120 59726e15 Bernardo Dal Seno
  @type attributes: string
2121 59726e15 Bernardo Dal Seno
  @ivar attributes: PV attributes
2122 b496abdb Bernardo Dal Seno
  @type lv_list: list of strings
2123 b496abdb Bernardo Dal Seno
  @ivar lv_list: names of the LVs hosted on the PV
2124 59726e15 Bernardo Dal Seno
  """
2125 59726e15 Bernardo Dal Seno
  __slots__ = [
2126 59726e15 Bernardo Dal Seno
    "name",
2127 59726e15 Bernardo Dal Seno
    "vg_name",
2128 59726e15 Bernardo Dal Seno
    "size",
2129 59726e15 Bernardo Dal Seno
    "free",
2130 59726e15 Bernardo Dal Seno
    "attributes",
2131 b496abdb Bernardo Dal Seno
    "lv_list"
2132 59726e15 Bernardo Dal Seno
    ]
2133 59726e15 Bernardo Dal Seno
2134 59726e15 Bernardo Dal Seno
  def IsEmpty(self):
2135 59726e15 Bernardo Dal Seno
    """Is this PV empty?
2136 59726e15 Bernardo Dal Seno

2137 59726e15 Bernardo Dal Seno
    """
2138 59726e15 Bernardo Dal Seno
    return self.size <= (self.free + 1)
2139 59726e15 Bernardo Dal Seno
2140 59726e15 Bernardo Dal Seno
  def IsAllocatable(self):
2141 59726e15 Bernardo Dal Seno
    """Is this PV allocatable?
2142 59726e15 Bernardo Dal Seno

2143 59726e15 Bernardo Dal Seno
    """
2144 59726e15 Bernardo Dal Seno
    return ("a" in self.attributes)