Statistics
| Branch: | Tag: | Revision:

root / lib / config.py @ fc6ccde4

History | View | Annotate | Download (97.4 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 04db1880 Bernardo Dal Seno
# 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
"""Configuration management for Ganeti
23 a8083063 Iustin Pop

24 319856a9 Michael Hanselmann
This module provides the interface to the Ganeti cluster configuration.
25 a8083063 Iustin Pop

26 319856a9 Michael Hanselmann
The configuration data is stored on every node but is updated on the master
27 319856a9 Michael Hanselmann
only. After each update, the master distributes the data to the other nodes.
28 a8083063 Iustin Pop

29 319856a9 Michael Hanselmann
Currently, the data storage format is JSON. YAML was slow and consuming too
30 319856a9 Michael Hanselmann
much memory.
31 a8083063 Iustin Pop

32 a8083063 Iustin Pop
"""
33 a8083063 Iustin Pop
34 b459a848 Andrea Spadaccini
# pylint: disable=R0904
35 d367b66c Manuel Franceschini
# R0904: Too many public methods
36 d367b66c Manuel Franceschini
37 45f62156 Bernardo Dal Seno
import copy
38 a8083063 Iustin Pop
import os
39 a8083063 Iustin Pop
import random
40 d8470559 Michael Hanselmann
import logging
41 d693c864 Iustin Pop
import time
42 54c31fd3 Michael Hanselmann
import itertools
43 a8083063 Iustin Pop
44 a8083063 Iustin Pop
from ganeti import errors
45 f78ede4e Guido Trotter
from ganeti import locking
46 a8083063 Iustin Pop
from ganeti import utils
47 a8083063 Iustin Pop
from ganeti import constants
48 4869595d Petr Pudlak
import ganeti.rpc.node as rpc
49 a8083063 Iustin Pop
from ganeti import objects
50 8d14b30d Iustin Pop
from ganeti import serializer
51 0fbae49a Balazs Lecz
from ganeti import uidpool
52 a744b676 Manuel Franceschini
from ganeti import netutils
53 e60c73a1 René Nussbaumer
from ganeti import runtime
54 57407093 Michael Hanselmann
from ganeti import pathutils
55 6c0a75db Dimitris Aragiorgis
from ganeti import network
56 243cdbcc Michael Hanselmann
57 243cdbcc Michael Hanselmann
58 7f93570a Iustin Pop
_config_lock = locking.SharedLock("ConfigWriter")
59 f78ede4e Guido Trotter
60 4fae38c5 Guido Trotter
# job id used for resource management at config upgrade time
61 8d9c3bef Michael Hanselmann
_UPGRADE_CONFIG_JID = "jid-cfg-upgrade"
62 4fae38c5 Guido Trotter
63 f78ede4e Guido Trotter
64 5b263ed7 Michael Hanselmann
def _ValidateConfig(data):
65 c41eea6e Iustin Pop
  """Verifies that a configuration objects looks valid.
66 c41eea6e Iustin Pop

67 c41eea6e Iustin Pop
  This only verifies the version of the configuration.
68 c41eea6e Iustin Pop

69 c41eea6e Iustin Pop
  @raise errors.ConfigurationError: if the version differs from what
70 c41eea6e Iustin Pop
      we expect
71 c41eea6e Iustin Pop

72 c41eea6e Iustin Pop
  """
73 5b263ed7 Michael Hanselmann
  if data.version != constants.CONFIG_VERSION:
74 4b63dc7a Iustin Pop
    raise errors.ConfigVersionMismatch(constants.CONFIG_VERSION, data.version)
75 a8083063 Iustin Pop
76 319856a9 Michael Hanselmann
77 013da361 Guido Trotter
class TemporaryReservationManager:
78 013da361 Guido Trotter
  """A temporary resource reservation manager.
79 013da361 Guido Trotter

80 013da361 Guido Trotter
  This is used to reserve resources in a job, before using them, making sure
81 013da361 Guido Trotter
  other jobs cannot get them in the meantime.
82 013da361 Guido Trotter

83 013da361 Guido Trotter
  """
84 013da361 Guido Trotter
  def __init__(self):
85 013da361 Guido Trotter
    self._ec_reserved = {}
86 013da361 Guido Trotter
87 013da361 Guido Trotter
  def Reserved(self, resource):
88 a7359d91 David Knowles
    for holder_reserved in self._ec_reserved.values():
89 013da361 Guido Trotter
      if resource in holder_reserved:
90 013da361 Guido Trotter
        return True
91 013da361 Guido Trotter
    return False
92 013da361 Guido Trotter
93 013da361 Guido Trotter
  def Reserve(self, ec_id, resource):
94 013da361 Guido Trotter
    if self.Reserved(resource):
95 28a7318f Iustin Pop
      raise errors.ReservationError("Duplicate reservation for resource '%s'"
96 28a7318f Iustin Pop
                                    % str(resource))
97 013da361 Guido Trotter
    if ec_id not in self._ec_reserved:
98 013da361 Guido Trotter
      self._ec_reserved[ec_id] = set([resource])
99 013da361 Guido Trotter
    else:
100 013da361 Guido Trotter
      self._ec_reserved[ec_id].add(resource)
101 013da361 Guido Trotter
102 013da361 Guido Trotter
  def DropECReservations(self, ec_id):
103 013da361 Guido Trotter
    if ec_id in self._ec_reserved:
104 013da361 Guido Trotter
      del self._ec_reserved[ec_id]
105 013da361 Guido Trotter
106 013da361 Guido Trotter
  def GetReserved(self):
107 013da361 Guido Trotter
    all_reserved = set()
108 013da361 Guido Trotter
    for holder_reserved in self._ec_reserved.values():
109 013da361 Guido Trotter
      all_reserved.update(holder_reserved)
110 013da361 Guido Trotter
    return all_reserved
111 013da361 Guido Trotter
112 ad4a9ae7 Dimitris Aragiorgis
  def GetECReserved(self, ec_id):
113 7f033fb3 Dimitris Aragiorgis
    """ Used when you want to retrieve all reservations for a specific
114 7f033fb3 Dimitris Aragiorgis
        execution context. E.g when commiting reserved IPs for a specific
115 7f033fb3 Dimitris Aragiorgis
        network.
116 7f033fb3 Dimitris Aragiorgis

117 7f033fb3 Dimitris Aragiorgis
    """
118 ad4a9ae7 Dimitris Aragiorgis
    ec_reserved = set()
119 ad4a9ae7 Dimitris Aragiorgis
    if ec_id in self._ec_reserved:
120 ad4a9ae7 Dimitris Aragiorgis
      ec_reserved.update(self._ec_reserved[ec_id])
121 ad4a9ae7 Dimitris Aragiorgis
    return ec_reserved
122 ad4a9ae7 Dimitris Aragiorgis
123 013da361 Guido Trotter
  def Generate(self, existing, generate_one_fn, ec_id):
124 013da361 Guido Trotter
    """Generate a new resource of this type
125 013da361 Guido Trotter

126 013da361 Guido Trotter
    """
127 013da361 Guido Trotter
    assert callable(generate_one_fn)
128 013da361 Guido Trotter
129 013da361 Guido Trotter
    all_elems = self.GetReserved()
130 013da361 Guido Trotter
    all_elems.update(existing)
131 013da361 Guido Trotter
    retries = 64
132 013da361 Guido Trotter
    while retries > 0:
133 013da361 Guido Trotter
      new_resource = generate_one_fn()
134 013da361 Guido Trotter
      if new_resource is not None and new_resource not in all_elems:
135 013da361 Guido Trotter
        break
136 013da361 Guido Trotter
    else:
137 013da361 Guido Trotter
      raise errors.ConfigurationError("Not able generate new resource"
138 013da361 Guido Trotter
                                      " (last tried: %s)" % new_resource)
139 013da361 Guido Trotter
    self.Reserve(ec_id, new_resource)
140 013da361 Guido Trotter
    return new_resource
141 013da361 Guido Trotter
142 013da361 Guido Trotter
143 fe698b38 Michael Hanselmann
def _MatchNameComponentIgnoreCase(short_name, names):
144 3a93eebb Michael Hanselmann
  """Wrapper around L{utils.text.MatchNameComponent}.
145 fe698b38 Michael Hanselmann

146 fe698b38 Michael Hanselmann
  """
147 fe698b38 Michael Hanselmann
  return utils.MatchNameComponent(short_name, names, case_sensitive=False)
148 fe698b38 Michael Hanselmann
149 fe698b38 Michael Hanselmann
150 82c54b5b Michael Hanselmann
def _CheckInstanceDiskIvNames(disks):
151 82c54b5b Michael Hanselmann
  """Checks if instance's disks' C{iv_name} attributes are in order.
152 82c54b5b Michael Hanselmann

153 82c54b5b Michael Hanselmann
  @type disks: list of L{objects.Disk}
154 82c54b5b Michael Hanselmann
  @param disks: List of disks
155 82c54b5b Michael Hanselmann
  @rtype: list of tuples; (int, string, string)
156 82c54b5b Michael Hanselmann
  @return: List of wrongly named disks, each tuple contains disk index,
157 82c54b5b Michael Hanselmann
    expected and actual name
158 82c54b5b Michael Hanselmann

159 82c54b5b Michael Hanselmann
  """
160 82c54b5b Michael Hanselmann
  result = []
161 82c54b5b Michael Hanselmann
162 82c54b5b Michael Hanselmann
  for (idx, disk) in enumerate(disks):
163 82c54b5b Michael Hanselmann
    exp_iv_name = "disk/%s" % idx
164 82c54b5b Michael Hanselmann
    if disk.iv_name != exp_iv_name:
165 82c54b5b Michael Hanselmann
      result.append((idx, exp_iv_name, disk.iv_name))
166 82c54b5b Michael Hanselmann
167 82c54b5b Michael Hanselmann
  return result
168 82c54b5b Michael Hanselmann
169 3c286190 Dimitris Aragiorgis
170 3efa7659 Thomas Thrainer
class ConfigWriter(object):
171 098c0958 Michael Hanselmann
  """The interface to the cluster configuration.
172 a8083063 Iustin Pop

173 d8aee57e Iustin Pop
  @ivar _temporary_lvs: reservation manager for temporary LVs
174 d8aee57e Iustin Pop
  @ivar _all_rms: a list of all temporary reservation managers
175 d8aee57e Iustin Pop

176 098c0958 Michael Hanselmann
  """
177 eb180fe2 Iustin Pop
  def __init__(self, cfg_file=None, offline=False, _getents=runtime.GetEnts,
178 eb180fe2 Iustin Pop
               accept_foreign=False):
179 14e15659 Iustin Pop
    self.write_count = 0
180 f78ede4e Guido Trotter
    self._lock = _config_lock
181 a8083063 Iustin Pop
    self._config_data = None
182 a8083063 Iustin Pop
    self._offline = offline
183 a8083063 Iustin Pop
    if cfg_file is None:
184 57407093 Michael Hanselmann
      self._cfg_file = pathutils.CLUSTER_CONF_FILE
185 a8083063 Iustin Pop
    else:
186 a8083063 Iustin Pop
      self._cfg_file = cfg_file
187 e60c73a1 René Nussbaumer
    self._getents = _getents
188 4fae38c5 Guido Trotter
    self._temporary_ids = TemporaryReservationManager()
189 a81c53c9 Iustin Pop
    self._temporary_drbds = {}
190 36b66e6e Guido Trotter
    self._temporary_macs = TemporaryReservationManager()
191 afa1386e Guido Trotter
    self._temporary_secrets = TemporaryReservationManager()
192 d8aee57e Iustin Pop
    self._temporary_lvs = TemporaryReservationManager()
193 ad4a9ae7 Dimitris Aragiorgis
    self._temporary_ips = TemporaryReservationManager()
194 d8aee57e Iustin Pop
    self._all_rms = [self._temporary_ids, self._temporary_macs,
195 ad4a9ae7 Dimitris Aragiorgis
                     self._temporary_secrets, self._temporary_lvs,
196 ad4a9ae7 Dimitris Aragiorgis
                     self._temporary_ips]
197 89e1fc26 Iustin Pop
    # Note: in order to prevent errors when resolving our name in
198 89e1fc26 Iustin Pop
    # _DistributeConfig, we compute it here once and reuse it; it's
199 89e1fc26 Iustin Pop
    # better to raise an error before starting to modify the config
200 89e1fc26 Iustin Pop
    # file than after it was modified
201 b705c7a6 Manuel Franceschini
    self._my_hostname = netutils.Hostname.GetSysName()
202 3c7f6c44 Iustin Pop
    self._last_cluster_serial = -1
203 bd407597 Iustin Pop
    self._cfg_id = None
204 b2acdbdc Michael Hanselmann
    self._context = None
205 eb180fe2 Iustin Pop
    self._OpenConfig(accept_foreign)
206 a8083063 Iustin Pop
207 b2acdbdc Michael Hanselmann
  def _GetRpc(self, address_list):
208 b2acdbdc Michael Hanselmann
    """Returns RPC runner for configuration.
209 b2acdbdc Michael Hanselmann

210 b2acdbdc Michael Hanselmann
    """
211 b2acdbdc Michael Hanselmann
    return rpc.ConfigRunner(self._context, address_list)
212 b2acdbdc Michael Hanselmann
213 b2acdbdc Michael Hanselmann
  def SetContext(self, context):
214 b2acdbdc Michael Hanselmann
    """Sets Ganeti context.
215 b2acdbdc Michael Hanselmann

216 b2acdbdc Michael Hanselmann
    """
217 b2acdbdc Michael Hanselmann
    self._context = context
218 b2acdbdc Michael Hanselmann
219 a8083063 Iustin Pop
  # this method needs to be static, so that we can call it on the class
220 a8083063 Iustin Pop
  @staticmethod
221 a8083063 Iustin Pop
  def IsCluster():
222 a8083063 Iustin Pop
    """Check if the cluster is configured.
223 a8083063 Iustin Pop

224 a8083063 Iustin Pop
    """
225 57407093 Michael Hanselmann
    return os.path.exists(pathutils.CLUSTER_CONF_FILE)
226 a8083063 Iustin Pop
227 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
228 5768e6a6 René Nussbaumer
  def GetNdParams(self, node):
229 5768e6a6 René Nussbaumer
    """Get the node params populated with cluster defaults.
230 5768e6a6 René Nussbaumer

231 ce523de1 Michael Hanselmann
    @type node: L{objects.Node}
232 5768e6a6 René Nussbaumer
    @param node: The node we want to know the params for
233 5768e6a6 René Nussbaumer
    @return: A dict with the filled in node params
234 5768e6a6 René Nussbaumer

235 5768e6a6 René Nussbaumer
    """
236 5768e6a6 René Nussbaumer
    nodegroup = self._UnlockedGetNodeGroup(node.group)
237 5768e6a6 René Nussbaumer
    return self._config_data.cluster.FillND(node, nodegroup)
238 5768e6a6 René Nussbaumer
239 5768e6a6 René Nussbaumer
  @locking.ssynchronized(_config_lock, shared=1)
240 6b2a2942 Petr Pudlak
  def GetNdGroupParams(self, nodegroup):
241 6b2a2942 Petr Pudlak
    """Get the node groups params populated with cluster defaults.
242 6b2a2942 Petr Pudlak

243 6b2a2942 Petr Pudlak
    @type nodegroup: L{objects.NodeGroup}
244 6b2a2942 Petr Pudlak
    @param nodegroup: The node group we want to know the params for
245 6b2a2942 Petr Pudlak
    @return: A dict with the filled in node group params
246 6b2a2942 Petr Pudlak

247 6b2a2942 Petr Pudlak
    """
248 6b2a2942 Petr Pudlak
    return self._config_data.cluster.FillNDGroup(nodegroup)
249 6b2a2942 Petr Pudlak
250 6b2a2942 Petr Pudlak
  @locking.ssynchronized(_config_lock, shared=1)
251 8a147bba René Nussbaumer
  def GetInstanceDiskParams(self, instance):
252 8a147bba René Nussbaumer
    """Get the disk params populated with inherit chain.
253 8a147bba René Nussbaumer

254 8a147bba René Nussbaumer
    @type instance: L{objects.Instance}
255 8a147bba René Nussbaumer
    @param instance: The instance we want to know the params for
256 8a147bba René Nussbaumer
    @return: A dict with the filled in disk params
257 8a147bba René Nussbaumer

258 8a147bba René Nussbaumer
    """
259 8a147bba René Nussbaumer
    node = self._UnlockedGetNodeInfo(instance.primary_node)
260 8a147bba René Nussbaumer
    nodegroup = self._UnlockedGetNodeGroup(node.group)
261 99ccf8b9 René Nussbaumer
    return self._UnlockedGetGroupDiskParams(nodegroup)
262 99ccf8b9 René Nussbaumer
263 99ccf8b9 René Nussbaumer
  @locking.ssynchronized(_config_lock, shared=1)
264 99ccf8b9 René Nussbaumer
  def GetGroupDiskParams(self, group):
265 99ccf8b9 René Nussbaumer
    """Get the disk params populated with inherit chain.
266 99ccf8b9 René Nussbaumer

267 af9fb4cc René Nussbaumer
    @type group: L{objects.NodeGroup}
268 99ccf8b9 René Nussbaumer
    @param group: The group we want to know the params for
269 99ccf8b9 René Nussbaumer
    @return: A dict with the filled in disk params
270 99ccf8b9 René Nussbaumer

271 99ccf8b9 René Nussbaumer
    """
272 99ccf8b9 René Nussbaumer
    return self._UnlockedGetGroupDiskParams(group)
273 99ccf8b9 René Nussbaumer
274 99ccf8b9 René Nussbaumer
  def _UnlockedGetGroupDiskParams(self, group):
275 99ccf8b9 René Nussbaumer
    """Get the disk params populated with inherit chain down to node-group.
276 99ccf8b9 René Nussbaumer

277 af9fb4cc René Nussbaumer
    @type group: L{objects.NodeGroup}
278 99ccf8b9 René Nussbaumer
    @param group: The group we want to know the params for
279 99ccf8b9 René Nussbaumer
    @return: A dict with the filled in disk params
280 99ccf8b9 René Nussbaumer

281 99ccf8b9 René Nussbaumer
    """
282 99ccf8b9 René Nussbaumer
    return self._config_data.cluster.SimpleFillDP(group.diskparams)
283 8a147bba René Nussbaumer
284 9ccacbc8 Dimitris Aragiorgis
  def _UnlockedGetNetworkMACPrefix(self, net_uuid):
285 032a7d71 Dimitris Aragiorgis
    """Return the network mac prefix if it exists or the cluster level default.
286 032a7d71 Dimitris Aragiorgis

287 032a7d71 Dimitris Aragiorgis
    """
288 032a7d71 Dimitris Aragiorgis
    prefix = None
289 9ccacbc8 Dimitris Aragiorgis
    if net_uuid:
290 1b68f268 Helga Velroyen
      nobj = self._UnlockedGetNetwork(net_uuid)
291 1b68f268 Helga Velroyen
      if nobj.mac_prefix:
292 1b68f268 Helga Velroyen
        prefix = nobj.mac_prefix
293 032a7d71 Dimitris Aragiorgis
294 032a7d71 Dimitris Aragiorgis
    return prefix
295 032a7d71 Dimitris Aragiorgis
296 032a7d71 Dimitris Aragiorgis
  def _GenerateOneMAC(self, prefix=None):
297 032a7d71 Dimitris Aragiorgis
    """Return a function that randomly generates a MAC suffic
298 032a7d71 Dimitris Aragiorgis
       and appends it to the given prefix. If prefix is not given get
299 032a7d71 Dimitris Aragiorgis
       the cluster level default.
300 032a7d71 Dimitris Aragiorgis

301 032a7d71 Dimitris Aragiorgis
    """
302 032a7d71 Dimitris Aragiorgis
    if not prefix:
303 032a7d71 Dimitris Aragiorgis
      prefix = self._config_data.cluster.mac_prefix
304 032a7d71 Dimitris Aragiorgis
305 032a7d71 Dimitris Aragiorgis
    def GenMac():
306 032a7d71 Dimitris Aragiorgis
      byte1 = random.randrange(0, 256)
307 032a7d71 Dimitris Aragiorgis
      byte2 = random.randrange(0, 256)
308 032a7d71 Dimitris Aragiorgis
      byte3 = random.randrange(0, 256)
309 032a7d71 Dimitris Aragiorgis
      mac = "%s:%02x:%02x:%02x" % (prefix, byte1, byte2, byte3)
310 032a7d71 Dimitris Aragiorgis
      return mac
311 032a7d71 Dimitris Aragiorgis
312 032a7d71 Dimitris Aragiorgis
    return GenMac
313 032a7d71 Dimitris Aragiorgis
314 8a147bba René Nussbaumer
  @locking.ssynchronized(_config_lock, shared=1)
315 9ccacbc8 Dimitris Aragiorgis
  def GenerateMAC(self, net_uuid, ec_id):
316 a8083063 Iustin Pop
    """Generate a MAC for an instance.
317 a8083063 Iustin Pop

318 a8083063 Iustin Pop
    This should check the current instances for duplicates.
319 a8083063 Iustin Pop

320 a8083063 Iustin Pop
    """
321 36b66e6e Guido Trotter
    existing = self._AllMACs()
322 9ccacbc8 Dimitris Aragiorgis
    prefix = self._UnlockedGetNetworkMACPrefix(net_uuid)
323 032a7d71 Dimitris Aragiorgis
    gen_mac = self._GenerateOneMAC(prefix)
324 a0af6c80 Dimitris Aragiorgis
    return self._temporary_ids.Generate(existing, gen_mac, ec_id)
325 a8083063 Iustin Pop
326 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
327 36b66e6e Guido Trotter
  def ReserveMAC(self, mac, ec_id):
328 36b66e6e Guido Trotter
    """Reserve a MAC for an instance.
329 1862d460 Alexander Schreiber

330 1862d460 Alexander Schreiber
    This only checks instances managed by this cluster, it does not
331 1862d460 Alexander Schreiber
    check for potential collisions elsewhere.
332 1862d460 Alexander Schreiber

333 1862d460 Alexander Schreiber
    """
334 1862d460 Alexander Schreiber
    all_macs = self._AllMACs()
335 36b66e6e Guido Trotter
    if mac in all_macs:
336 36b66e6e Guido Trotter
      raise errors.ReservationError("mac already in use")
337 36b66e6e Guido Trotter
    else:
338 8785b71b Apollon Oikonomopoulos
      self._temporary_macs.Reserve(ec_id, mac)
339 1862d460 Alexander Schreiber
340 ad4a9ae7 Dimitris Aragiorgis
  def _UnlockedCommitTemporaryIps(self, ec_id):
341 ad4a9ae7 Dimitris Aragiorgis
    """Commit all reserved IP address to their respective pools
342 ad4a9ae7 Dimitris Aragiorgis

343 ad4a9ae7 Dimitris Aragiorgis
    """
344 ad4a9ae7 Dimitris Aragiorgis
    for action, address, net_uuid in self._temporary_ips.GetECReserved(ec_id):
345 ad4a9ae7 Dimitris Aragiorgis
      self._UnlockedCommitIp(action, net_uuid, address)
346 ad4a9ae7 Dimitris Aragiorgis
347 ad4a9ae7 Dimitris Aragiorgis
  def _UnlockedCommitIp(self, action, net_uuid, address):
348 ad4a9ae7 Dimitris Aragiorgis
    """Commit a reserved IP address to an IP pool.
349 ad4a9ae7 Dimitris Aragiorgis

350 ad4a9ae7 Dimitris Aragiorgis
    The IP address is taken from the network's IP pool and marked as reserved.
351 ad4a9ae7 Dimitris Aragiorgis

352 ad4a9ae7 Dimitris Aragiorgis
    """
353 ad4a9ae7 Dimitris Aragiorgis
    nobj = self._UnlockedGetNetwork(net_uuid)
354 ad4a9ae7 Dimitris Aragiorgis
    pool = network.AddressPool(nobj)
355 e81eef56 Dimitris Aragiorgis
    if action == constants.RESERVE_ACTION:
356 ad4a9ae7 Dimitris Aragiorgis
      pool.Reserve(address)
357 e81eef56 Dimitris Aragiorgis
    elif action == constants.RELEASE_ACTION:
358 ad4a9ae7 Dimitris Aragiorgis
      pool.Release(address)
359 ad4a9ae7 Dimitris Aragiorgis
360 ad4a9ae7 Dimitris Aragiorgis
  def _UnlockedReleaseIp(self, net_uuid, address, ec_id):
361 ad4a9ae7 Dimitris Aragiorgis
    """Give a specific IP address back to an IP pool.
362 ad4a9ae7 Dimitris Aragiorgis

363 ad4a9ae7 Dimitris Aragiorgis
    The IP address is returned to the IP pool designated by pool_id and marked
364 ad4a9ae7 Dimitris Aragiorgis
    as reserved.
365 ad4a9ae7 Dimitris Aragiorgis

366 ad4a9ae7 Dimitris Aragiorgis
    """
367 e81eef56 Dimitris Aragiorgis
    self._temporary_ips.Reserve(ec_id,
368 e81eef56 Dimitris Aragiorgis
                                (constants.RELEASE_ACTION, address, net_uuid))
369 ad4a9ae7 Dimitris Aragiorgis
370 ad4a9ae7 Dimitris Aragiorgis
  @locking.ssynchronized(_config_lock, shared=1)
371 9ccacbc8 Dimitris Aragiorgis
  def ReleaseIp(self, net_uuid, address, ec_id):
372 ad4a9ae7 Dimitris Aragiorgis
    """Give a specified IP address back to an IP pool.
373 ad4a9ae7 Dimitris Aragiorgis

374 ad4a9ae7 Dimitris Aragiorgis
    This is just a wrapper around _UnlockedReleaseIp.
375 ad4a9ae7 Dimitris Aragiorgis

376 ad4a9ae7 Dimitris Aragiorgis
    """
377 9ccacbc8 Dimitris Aragiorgis
    if net_uuid:
378 9ccacbc8 Dimitris Aragiorgis
      self._UnlockedReleaseIp(net_uuid, address, ec_id)
379 ad4a9ae7 Dimitris Aragiorgis
380 ad4a9ae7 Dimitris Aragiorgis
  @locking.ssynchronized(_config_lock, shared=1)
381 9ccacbc8 Dimitris Aragiorgis
  def GenerateIp(self, net_uuid, ec_id):
382 ad4a9ae7 Dimitris Aragiorgis
    """Find a free IPv4 address for an instance.
383 ad4a9ae7 Dimitris Aragiorgis

384 ad4a9ae7 Dimitris Aragiorgis
    """
385 ad4a9ae7 Dimitris Aragiorgis
    nobj = self._UnlockedGetNetwork(net_uuid)
386 ad4a9ae7 Dimitris Aragiorgis
    pool = network.AddressPool(nobj)
387 ad4a9ae7 Dimitris Aragiorgis
388 ad4a9ae7 Dimitris Aragiorgis
    def gen_one():
389 ad4a9ae7 Dimitris Aragiorgis
      try:
390 1f1d3bf2 Dimitris Aragiorgis
        ip = pool.GenerateFree()
391 1f1d3bf2 Dimitris Aragiorgis
      except errors.AddressPoolError:
392 ad4a9ae7 Dimitris Aragiorgis
        raise errors.ReservationError("Cannot generate IP. Network is full")
393 e81eef56 Dimitris Aragiorgis
      return (constants.RESERVE_ACTION, ip, net_uuid)
394 ad4a9ae7 Dimitris Aragiorgis
395 beb81ea5 Dimitris Aragiorgis
    _, address, _ = self._temporary_ips.Generate([], gen_one, ec_id)
396 ad4a9ae7 Dimitris Aragiorgis
    return address
397 ad4a9ae7 Dimitris Aragiorgis
398 031d2db1 Dimitris Aragiorgis
  def _UnlockedReserveIp(self, net_uuid, address, ec_id, check=True):
399 ad4a9ae7 Dimitris Aragiorgis
    """Reserve a given IPv4 address for use by an instance.
400 ad4a9ae7 Dimitris Aragiorgis

401 ad4a9ae7 Dimitris Aragiorgis
    """
402 ad4a9ae7 Dimitris Aragiorgis
    nobj = self._UnlockedGetNetwork(net_uuid)
403 ad4a9ae7 Dimitris Aragiorgis
    pool = network.AddressPool(nobj)
404 ad4a9ae7 Dimitris Aragiorgis
    try:
405 ad4a9ae7 Dimitris Aragiorgis
      isreserved = pool.IsReserved(address)
406 031d2db1 Dimitris Aragiorgis
      isextreserved = pool.IsReserved(address, external=True)
407 ad4a9ae7 Dimitris Aragiorgis
    except errors.AddressPoolError:
408 ad4a9ae7 Dimitris Aragiorgis
      raise errors.ReservationError("IP address not in network")
409 ad4a9ae7 Dimitris Aragiorgis
    if isreserved:
410 ad4a9ae7 Dimitris Aragiorgis
      raise errors.ReservationError("IP address already in use")
411 031d2db1 Dimitris Aragiorgis
    if check and isextreserved:
412 031d2db1 Dimitris Aragiorgis
      raise errors.ReservationError("IP is externally reserved")
413 ad4a9ae7 Dimitris Aragiorgis
414 e81eef56 Dimitris Aragiorgis
    return self._temporary_ips.Reserve(ec_id,
415 e81eef56 Dimitris Aragiorgis
                                       (constants.RESERVE_ACTION,
416 e81eef56 Dimitris Aragiorgis
                                        address, net_uuid))
417 ad4a9ae7 Dimitris Aragiorgis
418 ad4a9ae7 Dimitris Aragiorgis
  @locking.ssynchronized(_config_lock, shared=1)
419 031d2db1 Dimitris Aragiorgis
  def ReserveIp(self, net_uuid, address, ec_id, check=True):
420 ad4a9ae7 Dimitris Aragiorgis
    """Reserve a given IPv4 address for use by an instance.
421 ad4a9ae7 Dimitris Aragiorgis

422 ad4a9ae7 Dimitris Aragiorgis
    """
423 9ccacbc8 Dimitris Aragiorgis
    if net_uuid:
424 031d2db1 Dimitris Aragiorgis
      return self._UnlockedReserveIp(net_uuid, address, ec_id, check)
425 ad4a9ae7 Dimitris Aragiorgis
426 f9518d38 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
427 d8aee57e Iustin Pop
  def ReserveLV(self, lv_name, ec_id):
428 d8aee57e Iustin Pop
    """Reserve an VG/LV pair for an instance.
429 d8aee57e Iustin Pop

430 d8aee57e Iustin Pop
    @type lv_name: string
431 d8aee57e Iustin Pop
    @param lv_name: the logical volume name to reserve
432 d8aee57e Iustin Pop

433 d8aee57e Iustin Pop
    """
434 d8aee57e Iustin Pop
    all_lvs = self._AllLVs()
435 d8aee57e Iustin Pop
    if lv_name in all_lvs:
436 d8aee57e Iustin Pop
      raise errors.ReservationError("LV already in use")
437 d8aee57e Iustin Pop
    else:
438 8785b71b Apollon Oikonomopoulos
      self._temporary_lvs.Reserve(ec_id, lv_name)
439 d8aee57e Iustin Pop
440 d8aee57e Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
441 afa1386e Guido Trotter
  def GenerateDRBDSecret(self, ec_id):
442 f9518d38 Iustin Pop
    """Generate a DRBD secret.
443 f9518d38 Iustin Pop

444 f9518d38 Iustin Pop
    This checks the current disks for duplicates.
445 f9518d38 Iustin Pop

446 f9518d38 Iustin Pop
    """
447 afa1386e Guido Trotter
    return self._temporary_secrets.Generate(self._AllDRBDSecrets(),
448 afa1386e Guido Trotter
                                            utils.GenerateSecret,
449 afa1386e Guido Trotter
                                            ec_id)
450 8d9c3bef Michael Hanselmann
451 34e54ebc Iustin Pop
  def _AllLVs(self):
452 923b1523 Iustin Pop
    """Compute the list of all LVs.
453 923b1523 Iustin Pop

454 923b1523 Iustin Pop
    """
455 923b1523 Iustin Pop
    lvnames = set()
456 923b1523 Iustin Pop
    for instance in self._config_data.instances.values():
457 923b1523 Iustin Pop
      node_data = instance.MapLVsByNode()
458 923b1523 Iustin Pop
      for lv_list in node_data.values():
459 923b1523 Iustin Pop
        lvnames.update(lv_list)
460 923b1523 Iustin Pop
    return lvnames
461 923b1523 Iustin Pop
462 b87a9c5f Christos Stavrakakis
  def _AllDisks(self):
463 79780863 Michele Tartara
    """Compute the list of all Disks (recursively, including children).
464 b87a9c5f Christos Stavrakakis

465 b87a9c5f Christos Stavrakakis
    """
466 79780863 Michele Tartara
    def DiskAndAllChildren(disk):
467 79780863 Michele Tartara
      """Returns a list containing the given disk and all of his children.
468 79780863 Michele Tartara

469 79780863 Michele Tartara
      """
470 79780863 Michele Tartara
      disks = [disk]
471 79780863 Michele Tartara
      if disk.children:
472 79780863 Michele Tartara
        for child_disk in disk.children:
473 79780863 Michele Tartara
          disks.extend(DiskAndAllChildren(child_disk))
474 79780863 Michele Tartara
      return disks
475 79780863 Michele Tartara
476 b87a9c5f Christos Stavrakakis
    disks = []
477 b87a9c5f Christos Stavrakakis
    for instance in self._config_data.instances.values():
478 79780863 Michele Tartara
      for disk in instance.disks:
479 79780863 Michele Tartara
        disks.extend(DiskAndAllChildren(disk))
480 b87a9c5f Christos Stavrakakis
    return disks
481 b87a9c5f Christos Stavrakakis
482 b87a9c5f Christos Stavrakakis
  def _AllNICs(self):
483 b87a9c5f Christos Stavrakakis
    """Compute the list of all NICs.
484 b87a9c5f Christos Stavrakakis

485 b87a9c5f Christos Stavrakakis
    """
486 b87a9c5f Christos Stavrakakis
    nics = []
487 b87a9c5f Christos Stavrakakis
    for instance in self._config_data.instances.values():
488 b87a9c5f Christos Stavrakakis
      nics.extend(instance.nics)
489 b87a9c5f Christos Stavrakakis
    return nics
490 b87a9c5f Christos Stavrakakis
491 34e54ebc Iustin Pop
  def _AllIDs(self, include_temporary):
492 34e54ebc Iustin Pop
    """Compute the list of all UUIDs and names we have.
493 34e54ebc Iustin Pop

494 34e54ebc Iustin Pop
    @type include_temporary: boolean
495 34e54ebc Iustin Pop
    @param include_temporary: whether to include the _temporary_ids set
496 34e54ebc Iustin Pop
    @rtype: set
497 34e54ebc Iustin Pop
    @return: a set of IDs
498 34e54ebc Iustin Pop

499 34e54ebc Iustin Pop
    """
500 34e54ebc Iustin Pop
    existing = set()
501 34e54ebc Iustin Pop
    if include_temporary:
502 4fae38c5 Guido Trotter
      existing.update(self._temporary_ids.GetReserved())
503 34e54ebc Iustin Pop
    existing.update(self._AllLVs())
504 34e54ebc Iustin Pop
    existing.update(self._config_data.instances.keys())
505 34e54ebc Iustin Pop
    existing.update(self._config_data.nodes.keys())
506 76d5d3a3 Iustin Pop
    existing.update([i.uuid for i in self._AllUUIDObjects() if i.uuid])
507 34e54ebc Iustin Pop
    return existing
508 34e54ebc Iustin Pop
509 4fae38c5 Guido Trotter
  def _GenerateUniqueID(self, ec_id):
510 430b923c Iustin Pop
    """Generate an unique UUID.
511 923b1523 Iustin Pop

512 923b1523 Iustin Pop
    This checks the current node, instances and disk names for
513 923b1523 Iustin Pop
    duplicates.
514 923b1523 Iustin Pop

515 c41eea6e Iustin Pop
    @rtype: string
516 c41eea6e Iustin Pop
    @return: the unique id
517 923b1523 Iustin Pop

518 923b1523 Iustin Pop
    """
519 4fae38c5 Guido Trotter
    existing = self._AllIDs(include_temporary=False)
520 4fae38c5 Guido Trotter
    return self._temporary_ids.Generate(existing, utils.NewUUID, ec_id)
521 923b1523 Iustin Pop
522 430b923c Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
523 4fae38c5 Guido Trotter
  def GenerateUniqueID(self, ec_id):
524 430b923c Iustin Pop
    """Generate an unique ID.
525 430b923c Iustin Pop

526 430b923c Iustin Pop
    This is just a wrapper over the unlocked version.
527 430b923c Iustin Pop

528 4fae38c5 Guido Trotter
    @type ec_id: string
529 4fae38c5 Guido Trotter
    @param ec_id: unique id for the job to reserve the id to
530 34d657ba Iustin Pop

531 34d657ba Iustin Pop
    """
532 4fae38c5 Guido Trotter
    return self._GenerateUniqueID(ec_id)
533 34d657ba Iustin Pop
534 a8083063 Iustin Pop
  def _AllMACs(self):
535 a8083063 Iustin Pop
    """Return all MACs present in the config.
536 a8083063 Iustin Pop

537 c41eea6e Iustin Pop
    @rtype: list
538 c41eea6e Iustin Pop
    @return: the list of all MACs
539 c41eea6e Iustin Pop

540 a8083063 Iustin Pop
    """
541 a8083063 Iustin Pop
    result = []
542 a8083063 Iustin Pop
    for instance in self._config_data.instances.values():
543 a8083063 Iustin Pop
      for nic in instance.nics:
544 a8083063 Iustin Pop
        result.append(nic.mac)
545 a8083063 Iustin Pop
546 a8083063 Iustin Pop
    return result
547 a8083063 Iustin Pop
548 f9518d38 Iustin Pop
  def _AllDRBDSecrets(self):
549 f9518d38 Iustin Pop
    """Return all DRBD secrets present in the config.
550 f9518d38 Iustin Pop

551 c41eea6e Iustin Pop
    @rtype: list
552 c41eea6e Iustin Pop
    @return: the list of all DRBD secrets
553 c41eea6e Iustin Pop

554 f9518d38 Iustin Pop
    """
555 f9518d38 Iustin Pop
    def helper(disk, result):
556 f9518d38 Iustin Pop
      """Recursively gather secrets from this disk."""
557 f9518d38 Iustin Pop
      if disk.dev_type == constants.DT_DRBD8:
558 f9518d38 Iustin Pop
        result.append(disk.logical_id[5])
559 f9518d38 Iustin Pop
      if disk.children:
560 f9518d38 Iustin Pop
        for child in disk.children:
561 f9518d38 Iustin Pop
          helper(child, result)
562 f9518d38 Iustin Pop
563 f9518d38 Iustin Pop
    result = []
564 f9518d38 Iustin Pop
    for instance in self._config_data.instances.values():
565 f9518d38 Iustin Pop
      for disk in instance.disks:
566 f9518d38 Iustin Pop
        helper(disk, result)
567 f9518d38 Iustin Pop
568 f9518d38 Iustin Pop
    return result
569 f9518d38 Iustin Pop
570 a57e502a Thomas Thrainer
  def _CheckDiskIDs(self, disk, l_ids):
571 4b98ac29 Iustin Pop
    """Compute duplicate disk IDs
572 4b98ac29 Iustin Pop

573 4b98ac29 Iustin Pop
    @type disk: L{objects.Disk}
574 4b98ac29 Iustin Pop
    @param disk: the disk at which to start searching
575 4b98ac29 Iustin Pop
    @type l_ids: list
576 4b98ac29 Iustin Pop
    @param l_ids: list of current logical ids
577 4b98ac29 Iustin Pop
    @rtype: list
578 4b98ac29 Iustin Pop
    @return: a list of error messages
579 4b98ac29 Iustin Pop

580 4b98ac29 Iustin Pop
    """
581 4b98ac29 Iustin Pop
    result = []
582 25ae22e4 Iustin Pop
    if disk.logical_id is not None:
583 25ae22e4 Iustin Pop
      if disk.logical_id in l_ids:
584 25ae22e4 Iustin Pop
        result.append("duplicate logical id %s" % str(disk.logical_id))
585 25ae22e4 Iustin Pop
      else:
586 25ae22e4 Iustin Pop
        l_ids.append(disk.logical_id)
587 4b98ac29 Iustin Pop
588 4b98ac29 Iustin Pop
    if disk.children:
589 4b98ac29 Iustin Pop
      for child in disk.children:
590 a57e502a Thomas Thrainer
        result.extend(self._CheckDiskIDs(child, l_ids))
591 4b98ac29 Iustin Pop
    return result
592 4b98ac29 Iustin Pop
593 4a89c54a Iustin Pop
  def _UnlockedVerifyConfig(self):
594 a8efbb40 Iustin Pop
    """Verify function.
595 a8efbb40 Iustin Pop

596 4a89c54a Iustin Pop
    @rtype: list
597 4a89c54a Iustin Pop
    @return: a list of error messages; a non-empty list signifies
598 4a89c54a Iustin Pop
        configuration errors
599 4a89c54a Iustin Pop

600 a8083063 Iustin Pop
    """
601 b459a848 Andrea Spadaccini
    # pylint: disable=R0914
602 a8083063 Iustin Pop
    result = []
603 a8083063 Iustin Pop
    seen_macs = []
604 48ce9fd9 Iustin Pop
    ports = {}
605 a8083063 Iustin Pop
    data = self._config_data
606 7e01d204 Iustin Pop
    cluster = data.cluster
607 4b98ac29 Iustin Pop
    seen_lids = []
608 9a5fba23 Guido Trotter
609 9a5fba23 Guido Trotter
    # global cluster checks
610 7e01d204 Iustin Pop
    if not cluster.enabled_hypervisors:
611 9a5fba23 Guido Trotter
      result.append("enabled hypervisors list doesn't have any entries")
612 7e01d204 Iustin Pop
    invalid_hvs = set(cluster.enabled_hypervisors) - constants.HYPER_TYPES
613 9a5fba23 Guido Trotter
    if invalid_hvs:
614 9a5fba23 Guido Trotter
      result.append("enabled hypervisors contains invalid entries: %s" %
615 3da6e141 Helga Velroyen
                    utils.CommaJoin(invalid_hvs))
616 7e01d204 Iustin Pop
    missing_hvp = (set(cluster.enabled_hypervisors) -
617 7e01d204 Iustin Pop
                   set(cluster.hvparams.keys()))
618 9f3ac970 Iustin Pop
    if missing_hvp:
619 9f3ac970 Iustin Pop
      result.append("hypervisor parameters missing for the enabled"
620 9f3ac970 Iustin Pop
                    " hypervisor(s) %s" % utils.CommaJoin(missing_hvp))
621 9a5fba23 Guido Trotter
622 3da6e141 Helga Velroyen
    if not cluster.enabled_disk_templates:
623 3da6e141 Helga Velroyen
      result.append("enabled disk templates list doesn't have any entries")
624 3da6e141 Helga Velroyen
    invalid_disk_templates = set(cluster.enabled_disk_templates) \
625 3da6e141 Helga Velroyen
                               - constants.DISK_TEMPLATES
626 3da6e141 Helga Velroyen
    if invalid_disk_templates:
627 3da6e141 Helga Velroyen
      result.append("enabled disk templates list contains invalid entries:"
628 3da6e141 Helga Velroyen
                    " %s" % utils.CommaJoin(invalid_disk_templates))
629 3da6e141 Helga Velroyen
630 7e01d204 Iustin Pop
    if cluster.master_node not in data.nodes:
631 9a5fba23 Guido Trotter
      result.append("cluster has invalid primary node '%s'" %
632 7e01d204 Iustin Pop
                    cluster.master_node)
633 9a5fba23 Guido Trotter
634 26f2fd8d Iustin Pop
    def _helper(owner, attr, value, template):
635 26f2fd8d Iustin Pop
      try:
636 26f2fd8d Iustin Pop
        utils.ForceDictType(value, template)
637 26f2fd8d Iustin Pop
      except errors.GenericError, err:
638 26f2fd8d Iustin Pop
        result.append("%s has invalid %s: %s" % (owner, attr, err))
639 26f2fd8d Iustin Pop
640 26f2fd8d Iustin Pop
    def _helper_nic(owner, params):
641 26f2fd8d Iustin Pop
      try:
642 26f2fd8d Iustin Pop
        objects.NIC.CheckParameterSyntax(params)
643 26f2fd8d Iustin Pop
      except errors.ConfigurationError, err:
644 26f2fd8d Iustin Pop
        result.append("%s has invalid nicparams: %s" % (owner, err))
645 26f2fd8d Iustin Pop
646 da5f09ef Bernardo Dal Seno
    def _helper_ipolicy(owner, ipolicy, iscluster):
647 918eb80b Agata Murawska
      try:
648 da5f09ef Bernardo Dal Seno
        objects.InstancePolicy.CheckParameterSyntax(ipolicy, iscluster)
649 918eb80b Agata Murawska
      except errors.ConfigurationError, err:
650 918eb80b Agata Murawska
        result.append("%s has invalid instance policy: %s" % (owner, err))
651 da5f09ef Bernardo Dal Seno
      for key, value in ipolicy.items():
652 da5f09ef Bernardo Dal Seno
        if key == constants.ISPECS_MINMAX:
653 41044e04 Bernardo Dal Seno
          for k in range(len(value)):
654 41044e04 Bernardo Dal Seno
            _helper_ispecs(owner, "ipolicy/%s[%s]" % (key, k), value[k])
655 da5f09ef Bernardo Dal Seno
        elif key == constants.ISPECS_STD:
656 da5f09ef Bernardo Dal Seno
          _helper(owner, "ipolicy/" + key, value,
657 da5f09ef Bernardo Dal Seno
                  constants.ISPECS_PARAMETER_TYPES)
658 2cc673a3 Iustin Pop
        else:
659 2cc673a3 Iustin Pop
          # FIXME: assuming list type
660 ff6c5e55 Iustin Pop
          if key in constants.IPOLICY_PARAMETERS:
661 ff6c5e55 Iustin Pop
            exp_type = float
662 ff6c5e55 Iustin Pop
          else:
663 ff6c5e55 Iustin Pop
            exp_type = list
664 ff6c5e55 Iustin Pop
          if not isinstance(value, exp_type):
665 2cc673a3 Iustin Pop
            result.append("%s has invalid instance policy: for %s,"
666 ff6c5e55 Iustin Pop
                          " expecting %s, got %s" %
667 ff6c5e55 Iustin Pop
                          (owner, key, exp_type.__name__, type(value)))
668 918eb80b Agata Murawska
669 da5f09ef Bernardo Dal Seno
    def _helper_ispecs(owner, parentkey, params):
670 da5f09ef Bernardo Dal Seno
      for (key, value) in params.items():
671 da5f09ef Bernardo Dal Seno
        fullkey = "/".join([parentkey, key])
672 da5f09ef Bernardo Dal Seno
        _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
673 da5f09ef Bernardo Dal Seno
674 26f2fd8d Iustin Pop
    # check cluster parameters
675 26f2fd8d Iustin Pop
    _helper("cluster", "beparams", cluster.SimpleFillBE({}),
676 26f2fd8d Iustin Pop
            constants.BES_PARAMETER_TYPES)
677 26f2fd8d Iustin Pop
    _helper("cluster", "nicparams", cluster.SimpleFillNIC({}),
678 26f2fd8d Iustin Pop
            constants.NICS_PARAMETER_TYPES)
679 26f2fd8d Iustin Pop
    _helper_nic("cluster", cluster.SimpleFillNIC({}))
680 26f2fd8d Iustin Pop
    _helper("cluster", "ndparams", cluster.SimpleFillND({}),
681 26f2fd8d Iustin Pop
            constants.NDS_PARAMETER_TYPES)
682 da5f09ef Bernardo Dal Seno
    _helper_ipolicy("cluster", cluster.ipolicy, True)
683 26f2fd8d Iustin Pop
684 6488e5bc Santi Raffa
    for disk_template in cluster.diskparams:
685 6488e5bc Santi Raffa
      if disk_template not in constants.DTS_HAVE_ACCESS:
686 6488e5bc Santi Raffa
        continue
687 6488e5bc Santi Raffa
688 6488e5bc Santi Raffa
      access = cluster.diskparams[disk_template].get(constants.LDP_ACCESS,
689 6488e5bc Santi Raffa
                                                     constants.DISK_KERNELSPACE)
690 294254b1 Raffa Santi
      if access not in constants.DISK_VALID_ACCESS_MODES:
691 294254b1 Raffa Santi
        result.append(
692 294254b1 Raffa Santi
          "Invalid value of '%s:%s': '%s' (expected one of %s)" % (
693 6488e5bc Santi Raffa
            disk_template, constants.LDP_ACCESS, access,
694 294254b1 Raffa Santi
            utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
695 294254b1 Raffa Santi
          )
696 294254b1 Raffa Santi
        )
697 294254b1 Raffa Santi
698 9a5fba23 Guido Trotter
    # per-instance checks
699 da4a52a3 Thomas Thrainer
    for instance_uuid in data.instances:
700 da4a52a3 Thomas Thrainer
      instance = data.instances[instance_uuid]
701 da4a52a3 Thomas Thrainer
      if instance.uuid != instance_uuid:
702 da4a52a3 Thomas Thrainer
        result.append("instance '%s' is indexed by wrong UUID '%s'" %
703 da4a52a3 Thomas Thrainer
                      (instance.name, instance_uuid))
704 a8083063 Iustin Pop
      if instance.primary_node not in data.nodes:
705 8522ceeb Iustin Pop
        result.append("instance '%s' has invalid primary node '%s'" %
706 da4a52a3 Thomas Thrainer
                      (instance.name, instance.primary_node))
707 a8083063 Iustin Pop
      for snode in instance.secondary_nodes:
708 a8083063 Iustin Pop
        if snode not in data.nodes:
709 8522ceeb Iustin Pop
          result.append("instance '%s' has invalid secondary node '%s'" %
710 da4a52a3 Thomas Thrainer
                        (instance.name, snode))
711 a8083063 Iustin Pop
      for idx, nic in enumerate(instance.nics):
712 a8083063 Iustin Pop
        if nic.mac in seen_macs:
713 8522ceeb Iustin Pop
          result.append("instance '%s' has NIC %d mac %s duplicate" %
714 da4a52a3 Thomas Thrainer
                        (instance.name, idx, nic.mac))
715 a8083063 Iustin Pop
        else:
716 a8083063 Iustin Pop
          seen_macs.append(nic.mac)
717 26f2fd8d Iustin Pop
        if nic.nicparams:
718 26f2fd8d Iustin Pop
          filled = cluster.SimpleFillNIC(nic.nicparams)
719 26f2fd8d Iustin Pop
          owner = "instance %s nic %d" % (instance.name, idx)
720 26f2fd8d Iustin Pop
          _helper(owner, "nicparams",
721 26f2fd8d Iustin Pop
                  filled, constants.NICS_PARAMETER_TYPES)
722 26f2fd8d Iustin Pop
          _helper_nic(owner, filled)
723 26f2fd8d Iustin Pop
724 3da6e141 Helga Velroyen
      # disk template checks
725 3da6e141 Helga Velroyen
      if not instance.disk_template in data.cluster.enabled_disk_templates:
726 3da6e141 Helga Velroyen
        result.append("instance '%s' uses the disabled disk template '%s'." %
727 da4a52a3 Thomas Thrainer
                      (instance.name, instance.disk_template))
728 3da6e141 Helga Velroyen
729 26f2fd8d Iustin Pop
      # parameter checks
730 26f2fd8d Iustin Pop
      if instance.beparams:
731 26f2fd8d Iustin Pop
        _helper("instance %s" % instance.name, "beparams",
732 26f2fd8d Iustin Pop
                cluster.FillBE(instance), constants.BES_PARAMETER_TYPES)
733 48ce9fd9 Iustin Pop
734 48ce9fd9 Iustin Pop
      # gather the drbd ports for duplicate checks
735 e2569c1d Michael Hanselmann
      for (idx, dsk) in enumerate(instance.disks):
736 66a37e7a Helga Velroyen
        if dsk.dev_type in constants.DTS_DRBD:
737 48ce9fd9 Iustin Pop
          tcp_port = dsk.logical_id[2]
738 48ce9fd9 Iustin Pop
          if tcp_port not in ports:
739 48ce9fd9 Iustin Pop
            ports[tcp_port] = []
740 e2569c1d Michael Hanselmann
          ports[tcp_port].append((instance.name, "drbd disk %s" % idx))
741 48ce9fd9 Iustin Pop
      # gather network port reservation
742 48ce9fd9 Iustin Pop
      net_port = getattr(instance, "network_port", None)
743 48ce9fd9 Iustin Pop
      if net_port is not None:
744 48ce9fd9 Iustin Pop
        if net_port not in ports:
745 48ce9fd9 Iustin Pop
          ports[net_port] = []
746 48ce9fd9 Iustin Pop
        ports[net_port].append((instance.name, "network port"))
747 48ce9fd9 Iustin Pop
748 332d0e37 Iustin Pop
      # instance disk verify
749 332d0e37 Iustin Pop
      for idx, disk in enumerate(instance.disks):
750 332d0e37 Iustin Pop
        result.extend(["instance '%s' disk %d error: %s" %
751 332d0e37 Iustin Pop
                       (instance.name, idx, msg) for msg in disk.Verify()])
752 a57e502a Thomas Thrainer
        result.extend(self._CheckDiskIDs(disk, seen_lids))
753 332d0e37 Iustin Pop
754 82c54b5b Michael Hanselmann
      wrong_names = _CheckInstanceDiskIvNames(instance.disks)
755 82c54b5b Michael Hanselmann
      if wrong_names:
756 82c54b5b Michael Hanselmann
        tmp = "; ".join(("name of disk %s should be '%s', but is '%s'" %
757 82c54b5b Michael Hanselmann
                         (idx, exp_name, actual_name))
758 82c54b5b Michael Hanselmann
                        for (idx, exp_name, actual_name) in wrong_names)
759 82c54b5b Michael Hanselmann
760 82c54b5b Michael Hanselmann
        result.append("Instance '%s' has wrongly named disks: %s" %
761 82c54b5b Michael Hanselmann
                      (instance.name, tmp))
762 82c54b5b Michael Hanselmann
763 48ce9fd9 Iustin Pop
    # cluster-wide pool of free ports
764 7e01d204 Iustin Pop
    for free_port in cluster.tcpudp_port_pool:
765 48ce9fd9 Iustin Pop
      if free_port not in ports:
766 48ce9fd9 Iustin Pop
        ports[free_port] = []
767 48ce9fd9 Iustin Pop
      ports[free_port].append(("cluster", "port marked as free"))
768 48ce9fd9 Iustin Pop
769 48ce9fd9 Iustin Pop
    # compute tcp/udp duplicate ports
770 48ce9fd9 Iustin Pop
    keys = ports.keys()
771 48ce9fd9 Iustin Pop
    keys.sort()
772 48ce9fd9 Iustin Pop
    for pnum in keys:
773 48ce9fd9 Iustin Pop
      pdata = ports[pnum]
774 48ce9fd9 Iustin Pop
      if len(pdata) > 1:
775 1f864b60 Iustin Pop
        txt = utils.CommaJoin(["%s/%s" % val for val in pdata])
776 48ce9fd9 Iustin Pop
        result.append("tcp/udp port %s has duplicates: %s" % (pnum, txt))
777 48ce9fd9 Iustin Pop
778 48ce9fd9 Iustin Pop
    # highest used tcp port check
779 48ce9fd9 Iustin Pop
    if keys:
780 7e01d204 Iustin Pop
      if keys[-1] > cluster.highest_used_port:
781 48ce9fd9 Iustin Pop
        result.append("Highest used port mismatch, saved %s, computed %s" %
782 7e01d204 Iustin Pop
                      (cluster.highest_used_port, keys[-1]))
783 a8efbb40 Iustin Pop
784 7e01d204 Iustin Pop
    if not data.nodes[cluster.master_node].master_candidate:
785 3a26773f Iustin Pop
      result.append("Master node is not a master candidate")
786 3a26773f Iustin Pop
787 4a89c54a Iustin Pop
    # master candidate checks
788 e623dbe3 Guido Trotter
    mc_now, mc_max, _ = self._UnlockedGetMasterCandidateStats()
789 ec0292f1 Iustin Pop
    if mc_now < mc_max:
790 ec0292f1 Iustin Pop
      result.append("Not enough master candidates: actual %d, target %d" %
791 ec0292f1 Iustin Pop
                    (mc_now, mc_max))
792 48ce9fd9 Iustin Pop
793 5bf07049 Iustin Pop
    # node checks
794 1c3231aa Thomas Thrainer
    for node_uuid, node in data.nodes.items():
795 1c3231aa Thomas Thrainer
      if node.uuid != node_uuid:
796 1c3231aa Thomas Thrainer
        result.append("Node '%s' is indexed by wrong UUID '%s'" %
797 1c3231aa Thomas Thrainer
                      (node.name, node_uuid))
798 5bf07049 Iustin Pop
      if [node.master_candidate, node.drained, node.offline].count(True) > 1:
799 5bf07049 Iustin Pop
        result.append("Node %s state is invalid: master_candidate=%s,"
800 5bf07049 Iustin Pop
                      " drain=%s, offline=%s" %
801 3d889a7d Michael Hanselmann
                      (node.name, node.master_candidate, node.drained,
802 5bf07049 Iustin Pop
                       node.offline))
803 26f2fd8d Iustin Pop
      if node.group not in data.nodegroups:
804 26f2fd8d Iustin Pop
        result.append("Node '%s' has invalid group '%s'" %
805 26f2fd8d Iustin Pop
                      (node.name, node.group))
806 26f2fd8d Iustin Pop
      else:
807 26f2fd8d Iustin Pop
        _helper("node %s" % node.name, "ndparams",
808 26f2fd8d Iustin Pop
                cluster.FillND(node, data.nodegroups[node.group]),
809 26f2fd8d Iustin Pop
                constants.NDS_PARAMETER_TYPES)
810 3697def0 Bernardo Dal Seno
      used_globals = constants.NDC_GLOBALS.intersection(node.ndparams)
811 3697def0 Bernardo Dal Seno
      if used_globals:
812 3697def0 Bernardo Dal Seno
        result.append("Node '%s' has some global parameters set: %s" %
813 3697def0 Bernardo Dal Seno
                      (node.name, utils.CommaJoin(used_globals)))
814 5bf07049 Iustin Pop
815 6520ba14 Guido Trotter
    # nodegroups checks
816 ace16501 Guido Trotter
    nodegroups_names = set()
817 6520ba14 Guido Trotter
    for nodegroup_uuid in data.nodegroups:
818 6520ba14 Guido Trotter
      nodegroup = data.nodegroups[nodegroup_uuid]
819 6520ba14 Guido Trotter
      if nodegroup.uuid != nodegroup_uuid:
820 913cc25e Adeodato Simo
        result.append("node group '%s' (uuid: '%s') indexed by wrong uuid '%s'"
821 6520ba14 Guido Trotter
                      % (nodegroup.name, nodegroup.uuid, nodegroup_uuid))
822 485ba212 Guido Trotter
      if utils.UUID_RE.match(nodegroup.name.lower()):
823 913cc25e Adeodato Simo
        result.append("node group '%s' (uuid: '%s') has uuid-like name" %
824 485ba212 Guido Trotter
                      (nodegroup.name, nodegroup.uuid))
825 ace16501 Guido Trotter
      if nodegroup.name in nodegroups_names:
826 913cc25e Adeodato Simo
        result.append("duplicate node group name '%s'" % nodegroup.name)
827 ace16501 Guido Trotter
      else:
828 ace16501 Guido Trotter
        nodegroups_names.add(nodegroup.name)
829 81e3ab4f Agata Murawska
      group_name = "group %s" % nodegroup.name
830 8b057218 René Nussbaumer
      _helper_ipolicy(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy),
831 8b057218 René Nussbaumer
                      False)
832 26f2fd8d Iustin Pop
      if nodegroup.ndparams:
833 81e3ab4f Agata Murawska
        _helper(group_name, "ndparams",
834 26f2fd8d Iustin Pop
                cluster.SimpleFillND(nodegroup.ndparams),
835 26f2fd8d Iustin Pop
                constants.NDS_PARAMETER_TYPES)
836 26f2fd8d Iustin Pop
837 4a89c54a Iustin Pop
    # drbd minors check
838 1122eb25 Iustin Pop
    _, duplicates = self._UnlockedComputeDRBDMap()
839 4a89c54a Iustin Pop
    for node, minor, instance_a, instance_b in duplicates:
840 4a89c54a Iustin Pop
      result.append("DRBD minor %d on node %s is assigned twice to instances"
841 4a89c54a Iustin Pop
                    " %s and %s" % (minor, node, instance_a, instance_b))
842 4a89c54a Iustin Pop
843 0ce8f948 Iustin Pop
    # IP checks
844 7e01d204 Iustin Pop
    default_nicparams = cluster.nicparams[constants.PP_DEFAULT]
845 b8716596 Michael Hanselmann
    ips = {}
846 b8716596 Michael Hanselmann
847 b8716596 Michael Hanselmann
    def _AddIpAddress(ip, name):
848 b8716596 Michael Hanselmann
      ips.setdefault(ip, []).append(name)
849 b8716596 Michael Hanselmann
850 7e01d204 Iustin Pop
    _AddIpAddress(cluster.master_ip, "cluster_ip")
851 0ce8f948 Iustin Pop
852 0ce8f948 Iustin Pop
    for node in data.nodes.values():
853 b8716596 Michael Hanselmann
      _AddIpAddress(node.primary_ip, "node:%s/primary" % node.name)
854 0ce8f948 Iustin Pop
      if node.secondary_ip != node.primary_ip:
855 b8716596 Michael Hanselmann
        _AddIpAddress(node.secondary_ip, "node:%s/secondary" % node.name)
856 b8716596 Michael Hanselmann
857 b8716596 Michael Hanselmann
    for instance in data.instances.values():
858 b8716596 Michael Hanselmann
      for idx, nic in enumerate(instance.nics):
859 b8716596 Michael Hanselmann
        if nic.ip is None:
860 b8716596 Michael Hanselmann
          continue
861 b8716596 Michael Hanselmann
862 b8716596 Michael Hanselmann
        nicparams = objects.FillDict(default_nicparams, nic.nicparams)
863 b8716596 Michael Hanselmann
        nic_mode = nicparams[constants.NIC_MODE]
864 b8716596 Michael Hanselmann
        nic_link = nicparams[constants.NIC_LINK]
865 b8716596 Michael Hanselmann
866 b8716596 Michael Hanselmann
        if nic_mode == constants.NIC_MODE_BRIDGED:
867 b8716596 Michael Hanselmann
          link = "bridge:%s" % nic_link
868 b8716596 Michael Hanselmann
        elif nic_mode == constants.NIC_MODE_ROUTED:
869 b8716596 Michael Hanselmann
          link = "route:%s" % nic_link
870 b8716596 Michael Hanselmann
        else:
871 b8716596 Michael Hanselmann
          raise errors.ProgrammerError("NIC mode '%s' not handled" % nic_mode)
872 b8716596 Michael Hanselmann
873 ad4a9ae7 Dimitris Aragiorgis
        _AddIpAddress("%s/%s/%s" % (link, nic.ip, nic.network),
874 b8716596 Michael Hanselmann
                      "instance:%s/nic:%d" % (instance.name, idx))
875 0ce8f948 Iustin Pop
876 0ce8f948 Iustin Pop
    for ip, owners in ips.items():
877 0ce8f948 Iustin Pop
      if len(owners) > 1:
878 0ce8f948 Iustin Pop
        result.append("IP address %s is used by multiple owners: %s" %
879 1f864b60 Iustin Pop
                      (ip, utils.CommaJoin(owners)))
880 b8716596 Michael Hanselmann
881 a8083063 Iustin Pop
    return result
882 a8083063 Iustin Pop
883 4a89c54a Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
884 4a89c54a Iustin Pop
  def VerifyConfig(self):
885 4a89c54a Iustin Pop
    """Verify function.
886 4a89c54a Iustin Pop

887 4a89c54a Iustin Pop
    This is just a wrapper over L{_UnlockedVerifyConfig}.
888 4a89c54a Iustin Pop

889 4a89c54a Iustin Pop
    @rtype: list
890 4a89c54a Iustin Pop
    @return: a list of error messages; a non-empty list signifies
891 4a89c54a Iustin Pop
        configuration errors
892 4a89c54a Iustin Pop

893 4a89c54a Iustin Pop
    """
894 4a89c54a Iustin Pop
    return self._UnlockedVerifyConfig()
895 4a89c54a Iustin Pop
896 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
897 b2fddf63 Iustin Pop
  def AddTcpUdpPort(self, port):
898 b2fddf63 Iustin Pop
    """Adds a new port to the available port pool.
899 b2fddf63 Iustin Pop

900 3b3b1bca Dimitris Aragiorgis
    @warning: this method does not "flush" the configuration (via
901 3b3b1bca Dimitris Aragiorgis
        L{_WriteConfig}); callers should do that themselves once the
902 3b3b1bca Dimitris Aragiorgis
        configuration is stable
903 3b3b1bca Dimitris Aragiorgis

904 b2fddf63 Iustin Pop
    """
905 264bb3c5 Michael Hanselmann
    if not isinstance(port, int):
906 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Invalid type passed for port")
907 264bb3c5 Michael Hanselmann
908 b2fddf63 Iustin Pop
    self._config_data.cluster.tcpudp_port_pool.add(port)
909 264bb3c5 Michael Hanselmann
910 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
911 b2fddf63 Iustin Pop
  def GetPortList(self):
912 264bb3c5 Michael Hanselmann
    """Returns a copy of the current port list.
913 264bb3c5 Michael Hanselmann

914 264bb3c5 Michael Hanselmann
    """
915 b2fddf63 Iustin Pop
    return self._config_data.cluster.tcpudp_port_pool.copy()
916 264bb3c5 Michael Hanselmann
917 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
918 a8083063 Iustin Pop
  def AllocatePort(self):
919 a8083063 Iustin Pop
    """Allocate a port.
920 a8083063 Iustin Pop

921 b2fddf63 Iustin Pop
    The port will be taken from the available port pool or from the
922 b2fddf63 Iustin Pop
    default port range (and in this case we increase
923 b2fddf63 Iustin Pop
    highest_used_port).
924 a8083063 Iustin Pop

925 a8083063 Iustin Pop
    """
926 264bb3c5 Michael Hanselmann
    # If there are TCP/IP ports configured, we use them first.
927 b2fddf63 Iustin Pop
    if self._config_data.cluster.tcpudp_port_pool:
928 b2fddf63 Iustin Pop
      port = self._config_data.cluster.tcpudp_port_pool.pop()
929 264bb3c5 Michael Hanselmann
    else:
930 264bb3c5 Michael Hanselmann
      port = self._config_data.cluster.highest_used_port + 1
931 264bb3c5 Michael Hanselmann
      if port >= constants.LAST_DRBD_PORT:
932 3ecf6786 Iustin Pop
        raise errors.ConfigurationError("The highest used port is greater"
933 3ecf6786 Iustin Pop
                                        " than %s. Aborting." %
934 3ecf6786 Iustin Pop
                                        constants.LAST_DRBD_PORT)
935 264bb3c5 Michael Hanselmann
      self._config_data.cluster.highest_used_port = port
936 a8083063 Iustin Pop
937 a8083063 Iustin Pop
    self._WriteConfig()
938 a8083063 Iustin Pop
    return port
939 a8083063 Iustin Pop
940 6d2e83d5 Iustin Pop
  def _UnlockedComputeDRBDMap(self):
941 a81c53c9 Iustin Pop
    """Compute the used DRBD minor/nodes.
942 a81c53c9 Iustin Pop

943 4a89c54a Iustin Pop
    @rtype: (dict, list)
944 da4a52a3 Thomas Thrainer
    @return: dictionary of node_uuid: dict of minor: instance_uuid;
945 c41eea6e Iustin Pop
        the returned dict will have all the nodes in it (even if with
946 4a89c54a Iustin Pop
        an empty list), and a list of duplicates; if the duplicates
947 4a89c54a Iustin Pop
        list is not empty, the configuration is corrupted and its caller
948 4a89c54a Iustin Pop
        should raise an exception
949 a81c53c9 Iustin Pop

950 a81c53c9 Iustin Pop
    """
951 da4a52a3 Thomas Thrainer
    def _AppendUsedMinors(get_node_name_fn, instance, disk, used):
952 4a89c54a Iustin Pop
      duplicates = []
953 cd3b4ff4 Helga Velroyen
      if disk.dev_type == constants.DT_DRBD8 and len(disk.logical_id) >= 5:
954 7c4d6c7b Michael Hanselmann
        node_a, node_b, _, minor_a, minor_b = disk.logical_id[:5]
955 da4a52a3 Thomas Thrainer
        for node_uuid, minor in ((node_a, minor_a), (node_b, minor_b)):
956 b691385f Thomas Thrainer
          assert node_uuid in used, \
957 b691385f Thomas Thrainer
            ("Node '%s' of instance '%s' not found in node list" %
958 da4a52a3 Thomas Thrainer
             (get_node_name_fn(node_uuid), instance.name))
959 da4a52a3 Thomas Thrainer
          if minor in used[node_uuid]:
960 da4a52a3 Thomas Thrainer
            duplicates.append((node_uuid, minor, instance.uuid,
961 da4a52a3 Thomas Thrainer
                               used[node_uuid][minor]))
962 4a89c54a Iustin Pop
          else:
963 da4a52a3 Thomas Thrainer
            used[node_uuid][minor] = instance.uuid
964 a81c53c9 Iustin Pop
      if disk.children:
965 a81c53c9 Iustin Pop
        for child in disk.children:
966 da4a52a3 Thomas Thrainer
          duplicates.extend(_AppendUsedMinors(get_node_name_fn, instance, child,
967 da4a52a3 Thomas Thrainer
                                              used))
968 4a89c54a Iustin Pop
      return duplicates
969 a81c53c9 Iustin Pop
970 4a89c54a Iustin Pop
    duplicates = []
971 da4a52a3 Thomas Thrainer
    my_dict = dict((node_uuid, {}) for node_uuid in self._config_data.nodes)
972 79b26a7a Iustin Pop
    for instance in self._config_data.instances.itervalues():
973 79b26a7a Iustin Pop
      for disk in instance.disks:
974 da4a52a3 Thomas Thrainer
        duplicates.extend(_AppendUsedMinors(self._UnlockedGetNodeName,
975 da4a52a3 Thomas Thrainer
                                            instance, disk, my_dict))
976 da4a52a3 Thomas Thrainer
    for (node_uuid, minor), inst_uuid in self._temporary_drbds.iteritems():
977 da4a52a3 Thomas Thrainer
      if minor in my_dict[node_uuid] and my_dict[node_uuid][minor] != inst_uuid:
978 da4a52a3 Thomas Thrainer
        duplicates.append((node_uuid, minor, inst_uuid,
979 da4a52a3 Thomas Thrainer
                           my_dict[node_uuid][minor]))
980 4a89c54a Iustin Pop
      else:
981 da4a52a3 Thomas Thrainer
        my_dict[node_uuid][minor] = inst_uuid
982 4a89c54a Iustin Pop
    return my_dict, duplicates
983 a81c53c9 Iustin Pop
984 a81c53c9 Iustin Pop
  @locking.ssynchronized(_config_lock)
985 6d2e83d5 Iustin Pop
  def ComputeDRBDMap(self):
986 6d2e83d5 Iustin Pop
    """Compute the used DRBD minor/nodes.
987 6d2e83d5 Iustin Pop

988 6d2e83d5 Iustin Pop
    This is just a wrapper over L{_UnlockedComputeDRBDMap}.
989 6d2e83d5 Iustin Pop

990 da4a52a3 Thomas Thrainer
    @return: dictionary of node_uuid: dict of minor: instance_uuid;
991 6d2e83d5 Iustin Pop
        the returned dict will have all the nodes in it (even if with
992 6d2e83d5 Iustin Pop
        an empty list).
993 6d2e83d5 Iustin Pop

994 6d2e83d5 Iustin Pop
    """
995 4a89c54a Iustin Pop
    d_map, duplicates = self._UnlockedComputeDRBDMap()
996 4a89c54a Iustin Pop
    if duplicates:
997 4a89c54a Iustin Pop
      raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" %
998 4a89c54a Iustin Pop
                                      str(duplicates))
999 4a89c54a Iustin Pop
    return d_map
1000 6d2e83d5 Iustin Pop
1001 6d2e83d5 Iustin Pop
  @locking.ssynchronized(_config_lock)
1002 da4a52a3 Thomas Thrainer
  def AllocateDRBDMinor(self, node_uuids, inst_uuid):
1003 a81c53c9 Iustin Pop
    """Allocate a drbd minor.
1004 a81c53c9 Iustin Pop

1005 a81c53c9 Iustin Pop
    The free minor will be automatically computed from the existing
1006 a81c53c9 Iustin Pop
    devices. A node can be given multiple times in order to allocate
1007 a81c53c9 Iustin Pop
    multiple minors. The result is the list of minors, in the same
1008 a81c53c9 Iustin Pop
    order as the passed nodes.
1009 a81c53c9 Iustin Pop

1010 da4a52a3 Thomas Thrainer
    @type inst_uuid: string
1011 da4a52a3 Thomas Thrainer
    @param inst_uuid: the instance for which we allocate minors
1012 32388e6d Iustin Pop

1013 a81c53c9 Iustin Pop
    """
1014 da4a52a3 Thomas Thrainer
    assert isinstance(inst_uuid, basestring), \
1015 da4a52a3 Thomas Thrainer
           "Invalid argument '%s' passed to AllocateDRBDMinor" % inst_uuid
1016 32388e6d Iustin Pop
1017 4a89c54a Iustin Pop
    d_map, duplicates = self._UnlockedComputeDRBDMap()
1018 4a89c54a Iustin Pop
    if duplicates:
1019 4a89c54a Iustin Pop
      raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" %
1020 4a89c54a Iustin Pop
                                      str(duplicates))
1021 a81c53c9 Iustin Pop
    result = []
1022 1c3231aa Thomas Thrainer
    for nuuid in node_uuids:
1023 1c3231aa Thomas Thrainer
      ndata = d_map[nuuid]
1024 a81c53c9 Iustin Pop
      if not ndata:
1025 a81c53c9 Iustin Pop
        # no minors used, we can start at 0
1026 a81c53c9 Iustin Pop
        result.append(0)
1027 da4a52a3 Thomas Thrainer
        ndata[0] = inst_uuid
1028 da4a52a3 Thomas Thrainer
        self._temporary_drbds[(nuuid, 0)] = inst_uuid
1029 a81c53c9 Iustin Pop
        continue
1030 a81c53c9 Iustin Pop
      keys = ndata.keys()
1031 a81c53c9 Iustin Pop
      keys.sort()
1032 a81c53c9 Iustin Pop
      ffree = utils.FirstFree(keys)
1033 a81c53c9 Iustin Pop
      if ffree is None:
1034 a81c53c9 Iustin Pop
        # return the next minor
1035 a81c53c9 Iustin Pop
        # TODO: implement high-limit check
1036 a81c53c9 Iustin Pop
        minor = keys[-1] + 1
1037 a81c53c9 Iustin Pop
      else:
1038 a81c53c9 Iustin Pop
        minor = ffree
1039 4a89c54a Iustin Pop
      # double-check minor against current instances
1040 1c3231aa Thomas Thrainer
      assert minor not in d_map[nuuid], \
1041 4a89c54a Iustin Pop
             ("Attempt to reuse allocated DRBD minor %d on node %s,"
1042 4a89c54a Iustin Pop
              " already allocated to instance %s" %
1043 1c3231aa Thomas Thrainer
              (minor, nuuid, d_map[nuuid][minor]))
1044 da4a52a3 Thomas Thrainer
      ndata[minor] = inst_uuid
1045 4a89c54a Iustin Pop
      # double-check minor against reservation
1046 1c3231aa Thomas Thrainer
      r_key = (nuuid, minor)
1047 4a89c54a Iustin Pop
      assert r_key not in self._temporary_drbds, \
1048 4a89c54a Iustin Pop
             ("Attempt to reuse reserved DRBD minor %d on node %s,"
1049 4a89c54a Iustin Pop
              " reserved for instance %s" %
1050 1c3231aa Thomas Thrainer
              (minor, nuuid, self._temporary_drbds[r_key]))
1051 da4a52a3 Thomas Thrainer
      self._temporary_drbds[r_key] = inst_uuid
1052 4a89c54a Iustin Pop
      result.append(minor)
1053 a81c53c9 Iustin Pop
    logging.debug("Request to allocate drbd minors, input: %s, returning %s",
1054 1c3231aa Thomas Thrainer
                  node_uuids, result)
1055 a81c53c9 Iustin Pop
    return result
1056 a81c53c9 Iustin Pop
1057 da4a52a3 Thomas Thrainer
  def _UnlockedReleaseDRBDMinors(self, inst_uuid):
1058 a81c53c9 Iustin Pop
    """Release temporary drbd minors allocated for a given instance.
1059 a81c53c9 Iustin Pop

1060 da4a52a3 Thomas Thrainer
    @type inst_uuid: string
1061 da4a52a3 Thomas Thrainer
    @param inst_uuid: the instance for which temporary minors should be
1062 da4a52a3 Thomas Thrainer
                      released
1063 a81c53c9 Iustin Pop

1064 a81c53c9 Iustin Pop
    """
1065 da4a52a3 Thomas Thrainer
    assert isinstance(inst_uuid, basestring), \
1066 32388e6d Iustin Pop
           "Invalid argument passed to ReleaseDRBDMinors"
1067 da4a52a3 Thomas Thrainer
    for key, uuid in self._temporary_drbds.items():
1068 da4a52a3 Thomas Thrainer
      if uuid == inst_uuid:
1069 a81c53c9 Iustin Pop
        del self._temporary_drbds[key]
1070 a81c53c9 Iustin Pop
1071 61cf6b5e Iustin Pop
  @locking.ssynchronized(_config_lock)
1072 da4a52a3 Thomas Thrainer
  def ReleaseDRBDMinors(self, inst_uuid):
1073 61cf6b5e Iustin Pop
    """Release temporary drbd minors allocated for a given instance.
1074 61cf6b5e Iustin Pop

1075 61cf6b5e Iustin Pop
    This should be called on the error paths, on the success paths
1076 61cf6b5e Iustin Pop
    it's automatically called by the ConfigWriter add and update
1077 61cf6b5e Iustin Pop
    functions.
1078 61cf6b5e Iustin Pop

1079 61cf6b5e Iustin Pop
    This function is just a wrapper over L{_UnlockedReleaseDRBDMinors}.
1080 61cf6b5e Iustin Pop

1081 da4a52a3 Thomas Thrainer
    @type inst_uuid: string
1082 da4a52a3 Thomas Thrainer
    @param inst_uuid: the instance for which temporary minors should be
1083 da4a52a3 Thomas Thrainer
                      released
1084 61cf6b5e Iustin Pop

1085 61cf6b5e Iustin Pop
    """
1086 da4a52a3 Thomas Thrainer
    self._UnlockedReleaseDRBDMinors(inst_uuid)
1087 61cf6b5e Iustin Pop
1088 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1089 4a8b186a Michael Hanselmann
  def GetConfigVersion(self):
1090 4a8b186a Michael Hanselmann
    """Get the configuration version.
1091 4a8b186a Michael Hanselmann

1092 4a8b186a Michael Hanselmann
    @return: Config version
1093 4a8b186a Michael Hanselmann

1094 4a8b186a Michael Hanselmann
    """
1095 4a8b186a Michael Hanselmann
    return self._config_data.version
1096 4a8b186a Michael Hanselmann
1097 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1098 4a8b186a Michael Hanselmann
  def GetClusterName(self):
1099 4a8b186a Michael Hanselmann
    """Get cluster name.
1100 4a8b186a Michael Hanselmann

1101 4a8b186a Michael Hanselmann
    @return: Cluster name
1102 4a8b186a Michael Hanselmann

1103 4a8b186a Michael Hanselmann
    """
1104 4a8b186a Michael Hanselmann
    return self._config_data.cluster.cluster_name
1105 4a8b186a Michael Hanselmann
1106 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1107 4a8b186a Michael Hanselmann
  def GetMasterNode(self):
1108 1c3231aa Thomas Thrainer
    """Get the UUID of the master node for this cluster.
1109 4a8b186a Michael Hanselmann

1110 1c3231aa Thomas Thrainer
    @return: Master node UUID
1111 4a8b186a Michael Hanselmann

1112 4a8b186a Michael Hanselmann
    """
1113 4a8b186a Michael Hanselmann
    return self._config_data.cluster.master_node
1114 4a8b186a Michael Hanselmann
1115 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1116 1c3231aa Thomas Thrainer
  def GetMasterNodeName(self):
1117 1c3231aa Thomas Thrainer
    """Get the hostname of the master node for this cluster.
1118 1c3231aa Thomas Thrainer

1119 1c3231aa Thomas Thrainer
    @return: Master node hostname
1120 1c3231aa Thomas Thrainer

1121 1c3231aa Thomas Thrainer
    """
1122 1c3231aa Thomas Thrainer
    return self._UnlockedGetNodeName(self._config_data.cluster.master_node)
1123 1c3231aa Thomas Thrainer
1124 1c3231aa Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1125 b730e2a7 Thomas Thrainer
  def GetMasterNodeInfo(self):
1126 b730e2a7 Thomas Thrainer
    """Get the master node information for this cluster.
1127 b730e2a7 Thomas Thrainer

1128 b730e2a7 Thomas Thrainer
    @rtype: objects.Node
1129 b730e2a7 Thomas Thrainer
    @return: Master node L{objects.Node} object
1130 b730e2a7 Thomas Thrainer

1131 b730e2a7 Thomas Thrainer
    """
1132 b730e2a7 Thomas Thrainer
    return self._UnlockedGetNodeInfo(self._config_data.cluster.master_node)
1133 b730e2a7 Thomas Thrainer
1134 b730e2a7 Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1135 4a8b186a Michael Hanselmann
  def GetMasterIP(self):
1136 4a8b186a Michael Hanselmann
    """Get the IP of the master node for this cluster.
1137 4a8b186a Michael Hanselmann

1138 4a8b186a Michael Hanselmann
    @return: Master IP
1139 4a8b186a Michael Hanselmann

1140 4a8b186a Michael Hanselmann
    """
1141 4a8b186a Michael Hanselmann
    return self._config_data.cluster.master_ip
1142 4a8b186a Michael Hanselmann
1143 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1144 4a8b186a Michael Hanselmann
  def GetMasterNetdev(self):
1145 4a8b186a Michael Hanselmann
    """Get the master network device for this cluster.
1146 4a8b186a Michael Hanselmann

1147 4a8b186a Michael Hanselmann
    """
1148 4a8b186a Michael Hanselmann
    return self._config_data.cluster.master_netdev
1149 4a8b186a Michael Hanselmann
1150 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1151 5a8648eb Andrea Spadaccini
  def GetMasterNetmask(self):
1152 5a8648eb Andrea Spadaccini
    """Get the netmask of the master node for this cluster.
1153 5a8648eb Andrea Spadaccini

1154 5a8648eb Andrea Spadaccini
    """
1155 5a8648eb Andrea Spadaccini
    return self._config_data.cluster.master_netmask
1156 5a8648eb Andrea Spadaccini
1157 5a8648eb Andrea Spadaccini
  @locking.ssynchronized(_config_lock, shared=1)
1158 33be7576 Andrea Spadaccini
  def GetUseExternalMipScript(self):
1159 33be7576 Andrea Spadaccini
    """Get flag representing whether to use the external master IP setup script.
1160 33be7576 Andrea Spadaccini

1161 33be7576 Andrea Spadaccini
    """
1162 33be7576 Andrea Spadaccini
    return self._config_data.cluster.use_external_mip_script
1163 33be7576 Andrea Spadaccini
1164 33be7576 Andrea Spadaccini
  @locking.ssynchronized(_config_lock, shared=1)
1165 4a8b186a Michael Hanselmann
  def GetFileStorageDir(self):
1166 4a8b186a Michael Hanselmann
    """Get the file storage dir for this cluster.
1167 4a8b186a Michael Hanselmann

1168 4a8b186a Michael Hanselmann
    """
1169 4a8b186a Michael Hanselmann
    return self._config_data.cluster.file_storage_dir
1170 4a8b186a Michael Hanselmann
1171 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1172 4b97f902 Apollon Oikonomopoulos
  def GetSharedFileStorageDir(self):
1173 4b97f902 Apollon Oikonomopoulos
    """Get the shared file storage dir for this cluster.
1174 4b97f902 Apollon Oikonomopoulos

1175 4b97f902 Apollon Oikonomopoulos
    """
1176 4b97f902 Apollon Oikonomopoulos
    return self._config_data.cluster.shared_file_storage_dir
1177 4b97f902 Apollon Oikonomopoulos
1178 4b97f902 Apollon Oikonomopoulos
  @locking.ssynchronized(_config_lock, shared=1)
1179 d3e6fd0e Santi Raffa
  def GetGlusterStorageDir(self):
1180 d3e6fd0e Santi Raffa
    """Get the Gluster storage dir for this cluster.
1181 d3e6fd0e Santi Raffa

1182 d3e6fd0e Santi Raffa
    """
1183 d3e6fd0e Santi Raffa
    return self._config_data.cluster.gluster_storage_dir
1184 d3e6fd0e Santi Raffa
1185 d3e6fd0e Santi Raffa
  @locking.ssynchronized(_config_lock, shared=1)
1186 4a8b186a Michael Hanselmann
  def GetHypervisorType(self):
1187 4a8b186a Michael Hanselmann
    """Get the hypervisor type for this cluster.
1188 4a8b186a Michael Hanselmann

1189 4a8b186a Michael Hanselmann
    """
1190 066f465d Guido Trotter
    return self._config_data.cluster.enabled_hypervisors[0]
1191 4a8b186a Michael Hanselmann
1192 4a8b186a Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1193 a9542a4f Thomas Thrainer
  def GetRsaHostKey(self):
1194 a8083063 Iustin Pop
    """Return the rsa hostkey from the config.
1195 a8083063 Iustin Pop

1196 c41eea6e Iustin Pop
    @rtype: string
1197 c41eea6e Iustin Pop
    @return: the rsa hostkey
1198 a8083063 Iustin Pop

1199 a8083063 Iustin Pop
    """
1200 a8083063 Iustin Pop
    return self._config_data.cluster.rsahostkeypub
1201 a8083063 Iustin Pop
1202 bf4af505 Apollon Oikonomopoulos
  @locking.ssynchronized(_config_lock, shared=1)
1203 a9542a4f Thomas Thrainer
  def GetDsaHostKey(self):
1204 a9542a4f Thomas Thrainer
    """Return the dsa hostkey from the config.
1205 a9542a4f Thomas Thrainer

1206 a9542a4f Thomas Thrainer
    @rtype: string
1207 a9542a4f Thomas Thrainer
    @return: the dsa hostkey
1208 a9542a4f Thomas Thrainer

1209 a9542a4f Thomas Thrainer
    """
1210 a9542a4f Thomas Thrainer
    return self._config_data.cluster.dsahostkeypub
1211 a9542a4f Thomas Thrainer
1212 a9542a4f Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1213 bf4af505 Apollon Oikonomopoulos
  def GetDefaultIAllocator(self):
1214 bf4af505 Apollon Oikonomopoulos
    """Get the default instance allocator for this cluster.
1215 bf4af505 Apollon Oikonomopoulos

1216 bf4af505 Apollon Oikonomopoulos
    """
1217 bf4af505 Apollon Oikonomopoulos
    return self._config_data.cluster.default_iallocator
1218 bf4af505 Apollon Oikonomopoulos
1219 868a98ca Manuel Franceschini
  @locking.ssynchronized(_config_lock, shared=1)
1220 0359e5d0 Spyros Trigazis
  def GetDefaultIAllocatorParameters(self):
1221 0359e5d0 Spyros Trigazis
    """Get the default instance allocator parameters for this cluster.
1222 0359e5d0 Spyros Trigazis

1223 0359e5d0 Spyros Trigazis
    @rtype: dict
1224 0359e5d0 Spyros Trigazis
    @return: dict of iallocator parameters
1225 0359e5d0 Spyros Trigazis

1226 0359e5d0 Spyros Trigazis
    """
1227 0359e5d0 Spyros Trigazis
    return self._config_data.cluster.default_iallocator_params
1228 0359e5d0 Spyros Trigazis
1229 0359e5d0 Spyros Trigazis
  @locking.ssynchronized(_config_lock, shared=1)
1230 868a98ca Manuel Franceschini
  def GetPrimaryIPFamily(self):
1231 868a98ca Manuel Franceschini
    """Get cluster primary ip family.
1232 868a98ca Manuel Franceschini

1233 868a98ca Manuel Franceschini
    @return: primary ip family
1234 868a98ca Manuel Franceschini

1235 868a98ca Manuel Franceschini
    """
1236 868a98ca Manuel Franceschini
    return self._config_data.cluster.primary_ip_family
1237 868a98ca Manuel Franceschini
1238 c9f4b8e6 Andrea Spadaccini
  @locking.ssynchronized(_config_lock, shared=1)
1239 c9f4b8e6 Andrea Spadaccini
  def GetMasterNetworkParameters(self):
1240 c9f4b8e6 Andrea Spadaccini
    """Get network parameters of the master node.
1241 c9f4b8e6 Andrea Spadaccini

1242 f9d20654 Andrea Spadaccini
    @rtype: L{object.MasterNetworkParameters}
1243 f9d20654 Andrea Spadaccini
    @return: network parameters of the master node
1244 c9f4b8e6 Andrea Spadaccini

1245 c9f4b8e6 Andrea Spadaccini
    """
1246 c9f4b8e6 Andrea Spadaccini
    cluster = self._config_data.cluster
1247 5ae4945a Iustin Pop
    result = objects.MasterNetworkParameters(
1248 1c3231aa Thomas Thrainer
      uuid=cluster.master_node, ip=cluster.master_ip,
1249 5ae4945a Iustin Pop
      netmask=cluster.master_netmask, netdev=cluster.master_netdev,
1250 c79198a0 Andrea Spadaccini
      ip_family=cluster.primary_ip_family)
1251 c9f4b8e6 Andrea Spadaccini
1252 f9d20654 Andrea Spadaccini
    return result
1253 f9d20654 Andrea Spadaccini
1254 e11a1b77 Adeodato Simo
  @locking.ssynchronized(_config_lock)
1255 e11a1b77 Adeodato Simo
  def AddNodeGroup(self, group, ec_id, check_uuid=True):
1256 e11a1b77 Adeodato Simo
    """Add a node group to the configuration.
1257 e11a1b77 Adeodato Simo

1258 90e99856 Adeodato Simo
    This method calls group.UpgradeConfig() to fill any missing attributes
1259 90e99856 Adeodato Simo
    according to their default values.
1260 90e99856 Adeodato Simo

1261 e11a1b77 Adeodato Simo
    @type group: L{objects.NodeGroup}
1262 e11a1b77 Adeodato Simo
    @param group: the NodeGroup object to add
1263 e11a1b77 Adeodato Simo
    @type ec_id: string
1264 e11a1b77 Adeodato Simo
    @param ec_id: unique id for the job to use when creating a missing UUID
1265 e11a1b77 Adeodato Simo
    @type check_uuid: bool
1266 e11a1b77 Adeodato Simo
    @param check_uuid: add an UUID to the group if it doesn't have one or, if
1267 e11a1b77 Adeodato Simo
                       it does, ensure that it does not exist in the
1268 e11a1b77 Adeodato Simo
                       configuration already
1269 e11a1b77 Adeodato Simo

1270 e11a1b77 Adeodato Simo
    """
1271 e11a1b77 Adeodato Simo
    self._UnlockedAddNodeGroup(group, ec_id, check_uuid)
1272 e11a1b77 Adeodato Simo
    self._WriteConfig()
1273 e11a1b77 Adeodato Simo
1274 e11a1b77 Adeodato Simo
  def _UnlockedAddNodeGroup(self, group, ec_id, check_uuid):
1275 e11a1b77 Adeodato Simo
    """Add a node group to the configuration.
1276 e11a1b77 Adeodato Simo

1277 e11a1b77 Adeodato Simo
    """
1278 e11a1b77 Adeodato Simo
    logging.info("Adding node group %s to configuration", group.name)
1279 e11a1b77 Adeodato Simo
1280 e11a1b77 Adeodato Simo
    # Some code might need to add a node group with a pre-populated UUID
1281 e11a1b77 Adeodato Simo
    # generated with ConfigWriter.GenerateUniqueID(). We allow them to bypass
1282 e11a1b77 Adeodato Simo
    # the "does this UUID" exist already check.
1283 e11a1b77 Adeodato Simo
    if check_uuid:
1284 e11a1b77 Adeodato Simo
      self._EnsureUUID(group, ec_id)
1285 e11a1b77 Adeodato Simo
1286 18ffc0fe Stephen Shirley
    try:
1287 18ffc0fe Stephen Shirley
      existing_uuid = self._UnlockedLookupNodeGroup(group.name)
1288 18ffc0fe Stephen Shirley
    except errors.OpPrereqError:
1289 18ffc0fe Stephen Shirley
      pass
1290 18ffc0fe Stephen Shirley
    else:
1291 18ffc0fe Stephen Shirley
      raise errors.OpPrereqError("Desired group name '%s' already exists as a"
1292 18ffc0fe Stephen Shirley
                                 " node group (UUID: %s)" %
1293 18ffc0fe Stephen Shirley
                                 (group.name, existing_uuid),
1294 18ffc0fe Stephen Shirley
                                 errors.ECODE_EXISTS)
1295 18ffc0fe Stephen Shirley
1296 e11a1b77 Adeodato Simo
    group.serial_no = 1
1297 e11a1b77 Adeodato Simo
    group.ctime = group.mtime = time.time()
1298 90e99856 Adeodato Simo
    group.UpgradeConfig()
1299 e11a1b77 Adeodato Simo
1300 e11a1b77 Adeodato Simo
    self._config_data.nodegroups[group.uuid] = group
1301 e11a1b77 Adeodato Simo
    self._config_data.cluster.serial_no += 1
1302 e11a1b77 Adeodato Simo
1303 e11a1b77 Adeodato Simo
  @locking.ssynchronized(_config_lock)
1304 e11a1b77 Adeodato Simo
  def RemoveNodeGroup(self, group_uuid):
1305 e11a1b77 Adeodato Simo
    """Remove a node group from the configuration.
1306 e11a1b77 Adeodato Simo

1307 e11a1b77 Adeodato Simo
    @type group_uuid: string
1308 e11a1b77 Adeodato Simo
    @param group_uuid: the UUID of the node group to remove
1309 e11a1b77 Adeodato Simo

1310 e11a1b77 Adeodato Simo
    """
1311 e11a1b77 Adeodato Simo
    logging.info("Removing node group %s from configuration", group_uuid)
1312 e11a1b77 Adeodato Simo
1313 e11a1b77 Adeodato Simo
    if group_uuid not in self._config_data.nodegroups:
1314 e11a1b77 Adeodato Simo
      raise errors.ConfigurationError("Unknown node group '%s'" % group_uuid)
1315 e11a1b77 Adeodato Simo
1316 0389c42a Stephen Shirley
    assert len(self._config_data.nodegroups) != 1, \
1317 0389c42a Stephen Shirley
            "Group '%s' is the only group, cannot be removed" % group_uuid
1318 0389c42a Stephen Shirley
1319 e11a1b77 Adeodato Simo
    del self._config_data.nodegroups[group_uuid]
1320 e11a1b77 Adeodato Simo
    self._config_data.cluster.serial_no += 1
1321 e11a1b77 Adeodato Simo
    self._WriteConfig()
1322 e11a1b77 Adeodato Simo
1323 e85d8982 Stephen Shirley
  def _UnlockedLookupNodeGroup(self, target):
1324 412b3531 Guido Trotter
    """Lookup a node group's UUID.
1325 eaa98a04 Guido Trotter

1326 eaa98a04 Guido Trotter
    @type target: string or None
1327 412b3531 Guido Trotter
    @param target: group name or UUID or None to look for the default
1328 eaa98a04 Guido Trotter
    @rtype: string
1329 412b3531 Guido Trotter
    @return: nodegroup UUID
1330 eaa98a04 Guido Trotter
    @raises errors.OpPrereqError: when the target group cannot be found
1331 eaa98a04 Guido Trotter

1332 eaa98a04 Guido Trotter
    """
1333 eaa98a04 Guido Trotter
    if target is None:
1334 eaa98a04 Guido Trotter
      if len(self._config_data.nodegroups) != 1:
1335 913cc25e Adeodato Simo
        raise errors.OpPrereqError("More than one node group exists. Target"
1336 2ed0e208 Iustin Pop
                                   " group must be specified explicitly.")
1337 eaa98a04 Guido Trotter
      else:
1338 eaa98a04 Guido Trotter
        return self._config_data.nodegroups.keys()[0]
1339 eaa98a04 Guido Trotter
    if target in self._config_data.nodegroups:
1340 eaa98a04 Guido Trotter
      return target
1341 eaa98a04 Guido Trotter
    for nodegroup in self._config_data.nodegroups.values():
1342 eaa98a04 Guido Trotter
      if nodegroup.name == target:
1343 eaa98a04 Guido Trotter
        return nodegroup.uuid
1344 e0f9ed64 Adeodato Simo
    raise errors.OpPrereqError("Node group '%s' not found" % target,
1345 e0f9ed64 Adeodato Simo
                               errors.ECODE_NOENT)
1346 eaa98a04 Guido Trotter
1347 e85d8982 Stephen Shirley
  @locking.ssynchronized(_config_lock, shared=1)
1348 e85d8982 Stephen Shirley
  def LookupNodeGroup(self, target):
1349 e85d8982 Stephen Shirley
    """Lookup a node group's UUID.
1350 e85d8982 Stephen Shirley

1351 e85d8982 Stephen Shirley
    This function is just a wrapper over L{_UnlockedLookupNodeGroup}.
1352 e85d8982 Stephen Shirley

1353 e85d8982 Stephen Shirley
    @type target: string or None
1354 e85d8982 Stephen Shirley
    @param target: group name or UUID or None to look for the default
1355 e85d8982 Stephen Shirley
    @rtype: string
1356 e85d8982 Stephen Shirley
    @return: nodegroup UUID
1357 e85d8982 Stephen Shirley

1358 e85d8982 Stephen Shirley
    """
1359 e85d8982 Stephen Shirley
    return self._UnlockedLookupNodeGroup(target)
1360 e85d8982 Stephen Shirley
1361 5768e6a6 René Nussbaumer
  def _UnlockedGetNodeGroup(self, uuid):
1362 648e4196 Guido Trotter
    """Lookup a node group.
1363 648e4196 Guido Trotter

1364 648e4196 Guido Trotter
    @type uuid: string
1365 648e4196 Guido Trotter
    @param uuid: group UUID
1366 648e4196 Guido Trotter
    @rtype: L{objects.NodeGroup} or None
1367 648e4196 Guido Trotter
    @return: nodegroup object, or None if not found
1368 648e4196 Guido Trotter

1369 648e4196 Guido Trotter
    """
1370 648e4196 Guido Trotter
    if uuid not in self._config_data.nodegroups:
1371 648e4196 Guido Trotter
      return None
1372 648e4196 Guido Trotter
1373 648e4196 Guido Trotter
    return self._config_data.nodegroups[uuid]
1374 648e4196 Guido Trotter
1375 648e4196 Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1376 5768e6a6 René Nussbaumer
  def GetNodeGroup(self, uuid):
1377 5768e6a6 René Nussbaumer
    """Lookup a node group.
1378 5768e6a6 René Nussbaumer

1379 5768e6a6 René Nussbaumer
    @type uuid: string
1380 5768e6a6 René Nussbaumer
    @param uuid: group UUID
1381 5768e6a6 René Nussbaumer
    @rtype: L{objects.NodeGroup} or None
1382 5768e6a6 René Nussbaumer
    @return: nodegroup object, or None if not found
1383 5768e6a6 René Nussbaumer

1384 5768e6a6 René Nussbaumer
    """
1385 5768e6a6 René Nussbaumer
    return self._UnlockedGetNodeGroup(uuid)
1386 5768e6a6 René Nussbaumer
1387 6b2a2942 Petr Pudlak
  def _UnlockedGetAllNodeGroupsInfo(self):
1388 6b2a2942 Petr Pudlak
    """Get the configuration of all node groups.
1389 6b2a2942 Petr Pudlak

1390 6b2a2942 Petr Pudlak
    """
1391 6b2a2942 Petr Pudlak
    return dict(self._config_data.nodegroups)
1392 6b2a2942 Petr Pudlak
1393 5768e6a6 René Nussbaumer
  @locking.ssynchronized(_config_lock, shared=1)
1394 622444e5 Iustin Pop
  def GetAllNodeGroupsInfo(self):
1395 622444e5 Iustin Pop
    """Get the configuration of all node groups.
1396 622444e5 Iustin Pop

1397 622444e5 Iustin Pop
    """
1398 6b2a2942 Petr Pudlak
    return self._UnlockedGetAllNodeGroupsInfo()
1399 622444e5 Iustin Pop
1400 1ac6f2ad Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1401 a9f33339 Petr Pudlak
  def GetAllNodeGroupsInfoDict(self):
1402 a9f33339 Petr Pudlak
    """Get the configuration of all node groups expressed as a dictionary of
1403 a9f33339 Petr Pudlak
    dictionaries.
1404 a9f33339 Petr Pudlak

1405 a9f33339 Petr Pudlak
    """
1406 a9f33339 Petr Pudlak
    return dict(map(lambda (uuid, ng): (uuid, ng.ToDict()),
1407 a9f33339 Petr Pudlak
                    self._UnlockedGetAllNodeGroupsInfo().items()))
1408 a9f33339 Petr Pudlak
1409 a9f33339 Petr Pudlak
  @locking.ssynchronized(_config_lock, shared=1)
1410 1ac6f2ad Guido Trotter
  def GetNodeGroupList(self):
1411 1ac6f2ad Guido Trotter
    """Get a list of node groups.
1412 1ac6f2ad Guido Trotter

1413 1ac6f2ad Guido Trotter
    """
1414 1ac6f2ad Guido Trotter
    return self._config_data.nodegroups.keys()
1415 1ac6f2ad Guido Trotter
1416 dac81741 Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1417 dac81741 Michael Hanselmann
  def GetNodeGroupMembersByNodes(self, nodes):
1418 dac81741 Michael Hanselmann
    """Get nodes which are member in the same nodegroups as the given nodes.
1419 dac81741 Michael Hanselmann

1420 dac81741 Michael Hanselmann
    """
1421 1c3231aa Thomas Thrainer
    ngfn = lambda node_uuid: self._UnlockedGetNodeInfo(node_uuid).group
1422 1c3231aa Thomas Thrainer
    return frozenset(member_uuid
1423 1c3231aa Thomas Thrainer
                     for node_uuid in nodes
1424 1c3231aa Thomas Thrainer
                     for member_uuid in
1425 1c3231aa Thomas Thrainer
                       self._UnlockedGetNodeGroup(ngfn(node_uuid)).members)
1426 dac81741 Michael Hanselmann
1427 080fbeea Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1428 080fbeea Michael Hanselmann
  def GetMultiNodeGroupInfo(self, group_uuids):
1429 080fbeea Michael Hanselmann
    """Get the configuration of multiple node groups.
1430 080fbeea Michael Hanselmann

1431 080fbeea Michael Hanselmann
    @param group_uuids: List of node group UUIDs
1432 080fbeea Michael Hanselmann
    @rtype: list
1433 080fbeea Michael Hanselmann
    @return: List of tuples of (group_uuid, group_info)
1434 080fbeea Michael Hanselmann

1435 080fbeea Michael Hanselmann
    """
1436 080fbeea Michael Hanselmann
    return [(uuid, self._UnlockedGetNodeGroup(uuid)) for uuid in group_uuids]
1437 080fbeea Michael Hanselmann
1438 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1439 0debfb35 Guido Trotter
  def AddInstance(self, instance, ec_id):
1440 a8083063 Iustin Pop
    """Add an instance to the config.
1441 a8083063 Iustin Pop

1442 a8083063 Iustin Pop
    This should be used after creating a new instance.
1443 a8083063 Iustin Pop

1444 c41eea6e Iustin Pop
    @type instance: L{objects.Instance}
1445 c41eea6e Iustin Pop
    @param instance: the instance object
1446 c41eea6e Iustin Pop

1447 a8083063 Iustin Pop
    """
1448 a8083063 Iustin Pop
    if not isinstance(instance, objects.Instance):
1449 a8083063 Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to AddInstance")
1450 a8083063 Iustin Pop
1451 e00fb268 Iustin Pop
    if instance.disk_template != constants.DT_DISKLESS:
1452 e00fb268 Iustin Pop
      all_lvs = instance.MapLVsByNode()
1453 74a48621 Iustin Pop
      logging.info("Instance '%s' DISK_LAYOUT: %s", instance.name, all_lvs)
1454 923b1523 Iustin Pop
1455 e4640214 Guido Trotter
    all_macs = self._AllMACs()
1456 e4640214 Guido Trotter
    for nic in instance.nics:
1457 e4640214 Guido Trotter
      if nic.mac in all_macs:
1458 e4640214 Guido Trotter
        raise errors.ConfigurationError("Cannot add instance %s:"
1459 430b923c Iustin Pop
                                        " MAC address '%s' already in use." %
1460 430b923c Iustin Pop
                                        (instance.name, nic.mac))
1461 430b923c Iustin Pop
1462 da4a52a3 Thomas Thrainer
    self._CheckUniqueUUID(instance, include_temporary=False)
1463 e4640214 Guido Trotter
1464 b989e85d Iustin Pop
    instance.serial_no = 1
1465 d693c864 Iustin Pop
    instance.ctime = instance.mtime = time.time()
1466 da4a52a3 Thomas Thrainer
    self._config_data.instances[instance.uuid] = instance
1467 81a49123 Iustin Pop
    self._config_data.cluster.serial_no += 1
1468 da4a52a3 Thomas Thrainer
    self._UnlockedReleaseDRBDMinors(instance.uuid)
1469 e8e079f3 Dimitris Aragiorgis
    self._UnlockedCommitTemporaryIps(ec_id)
1470 a8083063 Iustin Pop
    self._WriteConfig()
1471 a8083063 Iustin Pop
1472 0debfb35 Guido Trotter
  def _EnsureUUID(self, item, ec_id):
1473 430b923c Iustin Pop
    """Ensures a given object has a valid UUID.
1474 430b923c Iustin Pop

1475 430b923c Iustin Pop
    @param item: the instance or node to be checked
1476 0debfb35 Guido Trotter
    @param ec_id: the execution context id for the uuid reservation
1477 430b923c Iustin Pop

1478 430b923c Iustin Pop
    """
1479 430b923c Iustin Pop
    if not item.uuid:
1480 4fae38c5 Guido Trotter
      item.uuid = self._GenerateUniqueID(ec_id)
1481 da4a52a3 Thomas Thrainer
    else:
1482 da4a52a3 Thomas Thrainer
      self._CheckUniqueUUID(item, include_temporary=True)
1483 da4a52a3 Thomas Thrainer
1484 da4a52a3 Thomas Thrainer
  def _CheckUniqueUUID(self, item, include_temporary):
1485 da4a52a3 Thomas Thrainer
    """Checks that the UUID of the given object is unique.
1486 da4a52a3 Thomas Thrainer

1487 da4a52a3 Thomas Thrainer
    @param item: the instance or node to be checked
1488 da4a52a3 Thomas Thrainer
    @param include_temporary: whether temporarily generated UUID's should be
1489 da4a52a3 Thomas Thrainer
              included in the check. If the UUID of the item to be checked is
1490 da4a52a3 Thomas Thrainer
              a temporarily generated one, this has to be C{False}.
1491 da4a52a3 Thomas Thrainer

1492 da4a52a3 Thomas Thrainer
    """
1493 da4a52a3 Thomas Thrainer
    if not item.uuid:
1494 da4a52a3 Thomas Thrainer
      raise errors.ConfigurationError("'%s' must have an UUID" % (item.name,))
1495 da4a52a3 Thomas Thrainer
    if item.uuid in self._AllIDs(include_temporary=include_temporary):
1496 be0fc05d Iustin Pop
      raise errors.ConfigurationError("Cannot add '%s': UUID %s already"
1497 be0fc05d Iustin Pop
                                      " in use" % (item.name, item.uuid))
1498 430b923c Iustin Pop
1499 da4a52a3 Thomas Thrainer
  def _SetInstanceStatus(self, inst_uuid, status, disks_active):
1500 6a408fb2 Iustin Pop
    """Set the instance's status to a given value.
1501 a8083063 Iustin Pop

1502 a8083063 Iustin Pop
    """
1503 da4a52a3 Thomas Thrainer
    if inst_uuid not in self._config_data.instances:
1504 3ecf6786 Iustin Pop
      raise errors.ConfigurationError("Unknown instance '%s'" %
1505 da4a52a3 Thomas Thrainer
                                      inst_uuid)
1506 da4a52a3 Thomas Thrainer
    instance = self._config_data.instances[inst_uuid]
1507 1d4a4b26 Thomas Thrainer
1508 1d4a4b26 Thomas Thrainer
    if status is None:
1509 1d4a4b26 Thomas Thrainer
      status = instance.admin_state
1510 1d4a4b26 Thomas Thrainer
    if disks_active is None:
1511 1d4a4b26 Thomas Thrainer
      disks_active = instance.disks_active
1512 1d4a4b26 Thomas Thrainer
1513 1d4a4b26 Thomas Thrainer
    assert status in constants.ADMINST_ALL, \
1514 1d4a4b26 Thomas Thrainer
           "Invalid status '%s' passed to SetInstanceStatus" % (status,)
1515 1d4a4b26 Thomas Thrainer
1516 1d4a4b26 Thomas Thrainer
    if instance.admin_state != status or \
1517 1d4a4b26 Thomas Thrainer
       instance.disks_active != disks_active:
1518 9ca8a7c5 Agata Murawska
      instance.admin_state = status
1519 1d4a4b26 Thomas Thrainer
      instance.disks_active = disks_active
1520 b989e85d Iustin Pop
      instance.serial_no += 1
1521 d693c864 Iustin Pop
      instance.mtime = time.time()
1522 455a3445 Iustin Pop
      self._WriteConfig()
1523 a8083063 Iustin Pop
1524 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1525 da4a52a3 Thomas Thrainer
  def MarkInstanceUp(self, inst_uuid):
1526 6a408fb2 Iustin Pop
    """Mark the instance status to up in the config.
1527 6a408fb2 Iustin Pop

1528 1d4a4b26 Thomas Thrainer
    This also sets the instance disks active flag.
1529 1d4a4b26 Thomas Thrainer

1530 6a408fb2 Iustin Pop
    """
1531 da4a52a3 Thomas Thrainer
    self._SetInstanceStatus(inst_uuid, constants.ADMINST_UP, True)
1532 57de31c0 Agata Murawska
1533 57de31c0 Agata Murawska
  @locking.ssynchronized(_config_lock)
1534 da4a52a3 Thomas Thrainer
  def MarkInstanceOffline(self, inst_uuid):
1535 57de31c0 Agata Murawska
    """Mark the instance status to down in the config.
1536 57de31c0 Agata Murawska

1537 1d4a4b26 Thomas Thrainer
    This also clears the instance disks active flag.
1538 1d4a4b26 Thomas Thrainer

1539 57de31c0 Agata Murawska
    """
1540 da4a52a3 Thomas Thrainer
    self._SetInstanceStatus(inst_uuid, constants.ADMINST_OFFLINE, False)
1541 6a408fb2 Iustin Pop
1542 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1543 da4a52a3 Thomas Thrainer
  def RemoveInstance(self, inst_uuid):
1544 a8083063 Iustin Pop
    """Remove the instance from the configuration.
1545 a8083063 Iustin Pop

1546 a8083063 Iustin Pop
    """
1547 da4a52a3 Thomas Thrainer
    if inst_uuid not in self._config_data.instances:
1548 da4a52a3 Thomas Thrainer
      raise errors.ConfigurationError("Unknown instance '%s'" % inst_uuid)
1549 f396ad8c Vangelis Koukis
1550 f396ad8c Vangelis Koukis
    # If a network port has been allocated to the instance,
1551 f396ad8c Vangelis Koukis
    # return it to the pool of free ports.
1552 da4a52a3 Thomas Thrainer
    inst = self._config_data.instances[inst_uuid]
1553 f396ad8c Vangelis Koukis
    network_port = getattr(inst, "network_port", None)
1554 f396ad8c Vangelis Koukis
    if network_port is not None:
1555 f396ad8c Vangelis Koukis
      self._config_data.cluster.tcpudp_port_pool.add(network_port)
1556 f396ad8c Vangelis Koukis
1557 da4a52a3 Thomas Thrainer
    instance = self._UnlockedGetInstanceInfo(inst_uuid)
1558 ced51149 Dimitris Aragiorgis
1559 ced51149 Dimitris Aragiorgis
    for nic in instance.nics:
1560 9394f4d1 Dimitris Aragiorgis
      if nic.network and nic.ip:
1561 1b68f268 Helga Velroyen
        # Return all IP addresses to the respective address pools
1562 9394f4d1 Dimitris Aragiorgis
        self._UnlockedCommitIp(constants.RELEASE_ACTION, nic.network, nic.ip)
1563 ced51149 Dimitris Aragiorgis
1564 da4a52a3 Thomas Thrainer
    del self._config_data.instances[inst_uuid]
1565 81a49123 Iustin Pop
    self._config_data.cluster.serial_no += 1
1566 a8083063 Iustin Pop
    self._WriteConfig()
1567 a8083063 Iustin Pop
1568 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1569 da4a52a3 Thomas Thrainer
  def RenameInstance(self, inst_uuid, new_name):
1570 fc95f88f Iustin Pop
    """Rename an instance.
1571 fc95f88f Iustin Pop

1572 fc95f88f Iustin Pop
    This needs to be done in ConfigWriter and not by RemoveInstance
1573 fc95f88f Iustin Pop
    combined with AddInstance as only we can guarantee an atomic
1574 fc95f88f Iustin Pop
    rename.
1575 fc95f88f Iustin Pop

1576 fc95f88f Iustin Pop
    """
1577 da4a52a3 Thomas Thrainer
    if inst_uuid not in self._config_data.instances:
1578 da4a52a3 Thomas Thrainer
      raise errors.ConfigurationError("Unknown instance '%s'" % inst_uuid)
1579 ea642319 Michael Hanselmann
1580 da4a52a3 Thomas Thrainer
    inst = self._config_data.instances[inst_uuid]
1581 fc95f88f Iustin Pop
    inst.name = new_name
1582 b23c4333 Manuel Franceschini
1583 ea642319 Michael Hanselmann
    for (idx, disk) in enumerate(inst.disks):
1584 cd3b4ff4 Helga Velroyen
      if disk.dev_type in [constants.DT_FILE, constants.DT_SHARED_FILE]:
1585 b23c4333 Manuel Franceschini
        # rename the file paths in logical and physical id
1586 b23c4333 Manuel Franceschini
        file_storage_dir = os.path.dirname(os.path.dirname(disk.logical_id[1]))
1587 ea642319 Michael Hanselmann
        disk.logical_id = (disk.logical_id[0],
1588 ea642319 Michael Hanselmann
                           utils.PathJoin(file_storage_dir, inst.name,
1589 ea642319 Michael Hanselmann
                                          "disk%s" % idx))
1590 ea642319 Michael Hanselmann
1591 1fc34c48 Michael Hanselmann
    # Force update of ssconf files
1592 1fc34c48 Michael Hanselmann
    self._config_data.cluster.serial_no += 1
1593 1fc34c48 Michael Hanselmann
1594 fc95f88f Iustin Pop
    self._WriteConfig()
1595 fc95f88f Iustin Pop
1596 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1597 da4a52a3 Thomas Thrainer
  def MarkInstanceDown(self, inst_uuid):
1598 a8083063 Iustin Pop
    """Mark the status of an instance to down in the configuration.
1599 a8083063 Iustin Pop

1600 1d4a4b26 Thomas Thrainer
    This does not touch the instance disks active flag, as shut down instances
1601 1d4a4b26 Thomas Thrainer
    can still have active disks.
1602 1d4a4b26 Thomas Thrainer

1603 1d4a4b26 Thomas Thrainer
    """
1604 da4a52a3 Thomas Thrainer
    self._SetInstanceStatus(inst_uuid, constants.ADMINST_DOWN, None)
1605 1d4a4b26 Thomas Thrainer
1606 1d4a4b26 Thomas Thrainer
  @locking.ssynchronized(_config_lock)
1607 da4a52a3 Thomas Thrainer
  def MarkInstanceDisksActive(self, inst_uuid):
1608 1d4a4b26 Thomas Thrainer
    """Mark the status of instance disks active.
1609 1d4a4b26 Thomas Thrainer

1610 1d4a4b26 Thomas Thrainer
    """
1611 da4a52a3 Thomas Thrainer
    self._SetInstanceStatus(inst_uuid, None, True)
1612 1d4a4b26 Thomas Thrainer
1613 1d4a4b26 Thomas Thrainer
  @locking.ssynchronized(_config_lock)
1614 da4a52a3 Thomas Thrainer
  def MarkInstanceDisksInactive(self, inst_uuid):
1615 1d4a4b26 Thomas Thrainer
    """Mark the status of instance disks inactive.
1616 1d4a4b26 Thomas Thrainer

1617 a8083063 Iustin Pop
    """
1618 da4a52a3 Thomas Thrainer
    self._SetInstanceStatus(inst_uuid, None, False)
1619 a8083063 Iustin Pop
1620 94bbfece Iustin Pop
  def _UnlockedGetInstanceList(self):
1621 94bbfece Iustin Pop
    """Get the list of instances.
1622 94bbfece Iustin Pop

1623 94bbfece Iustin Pop
    This function is for internal use, when the config lock is already held.
1624 94bbfece Iustin Pop

1625 94bbfece Iustin Pop
    """
1626 94bbfece Iustin Pop
    return self._config_data.instances.keys()
1627 94bbfece Iustin Pop
1628 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1629 a8083063 Iustin Pop
  def GetInstanceList(self):
1630 a8083063 Iustin Pop
    """Get the list of instances.
1631 a8083063 Iustin Pop

1632 da4a52a3 Thomas Thrainer
    @return: array of instances, ex. ['instance2-uuid', 'instance1-uuid']
1633 a8083063 Iustin Pop

1634 a8083063 Iustin Pop
    """
1635 94bbfece Iustin Pop
    return self._UnlockedGetInstanceList()
1636 a8083063 Iustin Pop
1637 a8083063 Iustin Pop
  def ExpandInstanceName(self, short_name):
1638 a8083063 Iustin Pop
    """Attempt to expand an incomplete instance name.
1639 a8083063 Iustin Pop

1640 a8083063 Iustin Pop
    """
1641 da4a52a3 Thomas Thrainer
    # Locking is done in L{ConfigWriter.GetAllInstancesInfo}
1642 da4a52a3 Thomas Thrainer
    all_insts = self.GetAllInstancesInfo().values()
1643 da4a52a3 Thomas Thrainer
    expanded_name = _MatchNameComponentIgnoreCase(
1644 da4a52a3 Thomas Thrainer
                      short_name, [inst.name for inst in all_insts])
1645 da4a52a3 Thomas Thrainer
1646 da4a52a3 Thomas Thrainer
    if expanded_name is not None:
1647 da4a52a3 Thomas Thrainer
      # there has to be exactly one instance with that name
1648 da4a52a3 Thomas Thrainer
      inst = (filter(lambda n: n.name == expanded_name, all_insts)[0])
1649 da4a52a3 Thomas Thrainer
      return (inst.uuid, inst.name)
1650 da4a52a3 Thomas Thrainer
    else:
1651 738436bf Thomas Thrainer
      return (None, None)
1652 a8083063 Iustin Pop
1653 da4a52a3 Thomas Thrainer
  def _UnlockedGetInstanceInfo(self, inst_uuid):
1654 5bbd3f7f Michael Hanselmann
    """Returns information about an instance.
1655 94bbfece Iustin Pop

1656 94bbfece Iustin Pop
    This function is for internal use, when the config lock is already held.
1657 94bbfece Iustin Pop

1658 94bbfece Iustin Pop
    """
1659 da4a52a3 Thomas Thrainer
    if inst_uuid not in self._config_data.instances:
1660 94bbfece Iustin Pop
      return None
1661 94bbfece Iustin Pop
1662 da4a52a3 Thomas Thrainer
    return self._config_data.instances[inst_uuid]
1663 94bbfece Iustin Pop
1664 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1665 da4a52a3 Thomas Thrainer
  def GetInstanceInfo(self, inst_uuid):
1666 5bbd3f7f Michael Hanselmann
    """Returns information about an instance.
1667 a8083063 Iustin Pop

1668 5bbd3f7f Michael Hanselmann
    It takes the information from the configuration file. Other information of
1669 a8083063 Iustin Pop
    an instance are taken from the live systems.
1670 a8083063 Iustin Pop

1671 da4a52a3 Thomas Thrainer
    @param inst_uuid: UUID of the instance
1672 a8083063 Iustin Pop

1673 c41eea6e Iustin Pop
    @rtype: L{objects.Instance}
1674 c41eea6e Iustin Pop
    @return: the instance object
1675 a8083063 Iustin Pop

1676 a8083063 Iustin Pop
    """
1677 da4a52a3 Thomas Thrainer
    return self._UnlockedGetInstanceInfo(inst_uuid)
1678 a8083063 Iustin Pop
1679 0b2de758 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
1680 da4a52a3 Thomas Thrainer
  def GetInstanceNodeGroups(self, inst_uuid, primary_only=False):
1681 2674690b Michael Hanselmann
    """Returns set of node group UUIDs for instance's nodes.
1682 2674690b Michael Hanselmann

1683 2674690b Michael Hanselmann
    @rtype: frozenset
1684 2674690b Michael Hanselmann

1685 2674690b Michael Hanselmann
    """
1686 da4a52a3 Thomas Thrainer
    instance = self._UnlockedGetInstanceInfo(inst_uuid)
1687 2674690b Michael Hanselmann
    if not instance:
1688 da4a52a3 Thomas Thrainer
      raise errors.ConfigurationError("Unknown instance '%s'" % inst_uuid)
1689 2674690b Michael Hanselmann
1690 2674690b Michael Hanselmann
    if primary_only:
1691 2674690b Michael Hanselmann
      nodes = [instance.primary_node]
1692 2674690b Michael Hanselmann
    else:
1693 2674690b Michael Hanselmann
      nodes = instance.all_nodes
1694 2674690b Michael Hanselmann
1695 1c3231aa Thomas Thrainer
    return frozenset(self._UnlockedGetNodeInfo(node_uuid).group
1696 1c3231aa Thomas Thrainer
                     for node_uuid in nodes)
1697 2674690b Michael Hanselmann
1698 2674690b Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1699 da4a52a3 Thomas Thrainer
  def GetInstanceNetworks(self, inst_uuid):
1700 922610c9 Dimitris Aragiorgis
    """Returns set of network UUIDs for instance's nics.
1701 922610c9 Dimitris Aragiorgis

1702 922610c9 Dimitris Aragiorgis
    @rtype: frozenset
1703 922610c9 Dimitris Aragiorgis

1704 922610c9 Dimitris Aragiorgis
    """
1705 da4a52a3 Thomas Thrainer
    instance = self._UnlockedGetInstanceInfo(inst_uuid)
1706 922610c9 Dimitris Aragiorgis
    if not instance:
1707 da4a52a3 Thomas Thrainer
      raise errors.ConfigurationError("Unknown instance '%s'" % inst_uuid)
1708 922610c9 Dimitris Aragiorgis
1709 922610c9 Dimitris Aragiorgis
    networks = set()
1710 922610c9 Dimitris Aragiorgis
    for nic in instance.nics:
1711 922610c9 Dimitris Aragiorgis
      if nic.network:
1712 922610c9 Dimitris Aragiorgis
        networks.add(nic.network)
1713 922610c9 Dimitris Aragiorgis
1714 922610c9 Dimitris Aragiorgis
    return frozenset(networks)
1715 922610c9 Dimitris Aragiorgis
1716 922610c9 Dimitris Aragiorgis
  @locking.ssynchronized(_config_lock, shared=1)
1717 da4a52a3 Thomas Thrainer
  def GetMultiInstanceInfo(self, inst_uuids):
1718 da4a52a3 Thomas Thrainer
    """Get the configuration of multiple instances.
1719 da4a52a3 Thomas Thrainer

1720 da4a52a3 Thomas Thrainer
    @param inst_uuids: list of instance UUIDs
1721 da4a52a3 Thomas Thrainer
    @rtype: list
1722 da4a52a3 Thomas Thrainer
    @return: list of tuples (instance UUID, instance_info), where
1723 da4a52a3 Thomas Thrainer
        instance_info is what would GetInstanceInfo return for the
1724 da4a52a3 Thomas Thrainer
        node, while keeping the original order
1725 da4a52a3 Thomas Thrainer

1726 da4a52a3 Thomas Thrainer
    """
1727 da4a52a3 Thomas Thrainer
    return [(uuid, self._UnlockedGetInstanceInfo(uuid)) for uuid in inst_uuids]
1728 da4a52a3 Thomas Thrainer
1729 da4a52a3 Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1730 da4a52a3 Thomas Thrainer
  def GetMultiInstanceInfoByName(self, inst_names):
1731 71333cb9 Iustin Pop
    """Get the configuration of multiple instances.
1732 71333cb9 Iustin Pop

1733 da4a52a3 Thomas Thrainer
    @param inst_names: list of instance names
1734 71333cb9 Iustin Pop
    @rtype: list
1735 71333cb9 Iustin Pop
    @return: list of tuples (instance, instance_info), where
1736 71333cb9 Iustin Pop
        instance_info is what would GetInstanceInfo return for the
1737 71333cb9 Iustin Pop
        node, while keeping the original order
1738 71333cb9 Iustin Pop

1739 71333cb9 Iustin Pop
    """
1740 da4a52a3 Thomas Thrainer
    result = []
1741 da4a52a3 Thomas Thrainer
    for name in inst_names:
1742 da4a52a3 Thomas Thrainer
      instance = self._UnlockedGetInstanceInfoByName(name)
1743 da4a52a3 Thomas Thrainer
      result.append((instance.uuid, instance))
1744 da4a52a3 Thomas Thrainer
    return result
1745 71333cb9 Iustin Pop
1746 71333cb9 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
1747 0b2de758 Iustin Pop
  def GetAllInstancesInfo(self):
1748 0b2de758 Iustin Pop
    """Get the configuration of all instances.
1749 0b2de758 Iustin Pop

1750 0b2de758 Iustin Pop
    @rtype: dict
1751 5fcc718f Iustin Pop
    @return: dict of (instance, instance_info), where instance_info is what
1752 0b2de758 Iustin Pop
              would GetInstanceInfo return for the node
1753 0b2de758 Iustin Pop

1754 0b2de758 Iustin Pop
    """
1755 da4a52a3 Thomas Thrainer
    return self._UnlockedGetAllInstancesInfo()
1756 da4a52a3 Thomas Thrainer
1757 da4a52a3 Thomas Thrainer
  def _UnlockedGetAllInstancesInfo(self):
1758 da4a52a3 Thomas Thrainer
    my_dict = dict([(inst_uuid, self._UnlockedGetInstanceInfo(inst_uuid))
1759 da4a52a3 Thomas Thrainer
                    for inst_uuid in self._UnlockedGetInstanceList()])
1760 0b2de758 Iustin Pop
    return my_dict
1761 0b2de758 Iustin Pop
1762 cc19798f Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1763 cc19798f Michael Hanselmann
  def GetInstancesInfoByFilter(self, filter_fn):
1764 cc19798f Michael Hanselmann
    """Get instance configuration with a filter.
1765 cc19798f Michael Hanselmann

1766 cc19798f Michael Hanselmann
    @type filter_fn: callable
1767 cc19798f Michael Hanselmann
    @param filter_fn: Filter function receiving instance object as parameter,
1768 cc19798f Michael Hanselmann
      returning boolean. Important: this function is called while the
1769 cc19798f Michael Hanselmann
      configuration locks is held. It must not do any complex work or call
1770 cc19798f Michael Hanselmann
      functions potentially leading to a deadlock. Ideally it doesn't call any
1771 cc19798f Michael Hanselmann
      other functions and just compares instance attributes.
1772 cc19798f Michael Hanselmann

1773 cc19798f Michael Hanselmann
    """
1774 da4a52a3 Thomas Thrainer
    return dict((uuid, inst)
1775 da4a52a3 Thomas Thrainer
                for (uuid, inst) in self._config_data.instances.items()
1776 cc19798f Michael Hanselmann
                if filter_fn(inst))
1777 cc19798f Michael Hanselmann
1778 da4a52a3 Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1779 da4a52a3 Thomas Thrainer
  def GetInstanceInfoByName(self, inst_name):
1780 da4a52a3 Thomas Thrainer
    """Get the L{objects.Instance} object for a named instance.
1781 da4a52a3 Thomas Thrainer

1782 da4a52a3 Thomas Thrainer
    @param inst_name: name of the instance to get information for
1783 da4a52a3 Thomas Thrainer
    @type inst_name: string
1784 da4a52a3 Thomas Thrainer
    @return: the corresponding L{objects.Instance} instance or None if no
1785 da4a52a3 Thomas Thrainer
          information is available
1786 da4a52a3 Thomas Thrainer

1787 da4a52a3 Thomas Thrainer
    """
1788 da4a52a3 Thomas Thrainer
    return self._UnlockedGetInstanceInfoByName(inst_name)
1789 da4a52a3 Thomas Thrainer
1790 da4a52a3 Thomas Thrainer
  def _UnlockedGetInstanceInfoByName(self, inst_name):
1791 da4a52a3 Thomas Thrainer
    for inst in self._UnlockedGetAllInstancesInfo().values():
1792 da4a52a3 Thomas Thrainer
      if inst.name == inst_name:
1793 da4a52a3 Thomas Thrainer
        return inst
1794 da4a52a3 Thomas Thrainer
    return None
1795 da4a52a3 Thomas Thrainer
1796 da4a52a3 Thomas Thrainer
  def _UnlockedGetInstanceName(self, inst_uuid):
1797 da4a52a3 Thomas Thrainer
    inst_info = self._UnlockedGetInstanceInfo(inst_uuid)
1798 da4a52a3 Thomas Thrainer
    if inst_info is None:
1799 da4a52a3 Thomas Thrainer
      raise errors.OpExecError("Unknown instance: %s" % inst_uuid)
1800 da4a52a3 Thomas Thrainer
    return inst_info.name
1801 da4a52a3 Thomas Thrainer
1802 da4a52a3 Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1803 da4a52a3 Thomas Thrainer
  def GetInstanceName(self, inst_uuid):
1804 da4a52a3 Thomas Thrainer
    """Gets the instance name for the passed instance.
1805 da4a52a3 Thomas Thrainer

1806 da4a52a3 Thomas Thrainer
    @param inst_uuid: instance UUID to get name for
1807 da4a52a3 Thomas Thrainer
    @type inst_uuid: string
1808 da4a52a3 Thomas Thrainer
    @rtype: string
1809 da4a52a3 Thomas Thrainer
    @return: instance name
1810 da4a52a3 Thomas Thrainer

1811 da4a52a3 Thomas Thrainer
    """
1812 da4a52a3 Thomas Thrainer
    return self._UnlockedGetInstanceName(inst_uuid)
1813 da4a52a3 Thomas Thrainer
1814 da4a52a3 Thomas Thrainer
  @locking.ssynchronized(_config_lock, shared=1)
1815 da4a52a3 Thomas Thrainer
  def GetInstanceNames(self, inst_uuids):
1816 da4a52a3 Thomas Thrainer
    """Gets the instance names for the passed list of nodes.
1817 da4a52a3 Thomas Thrainer

1818 da4a52a3 Thomas Thrainer
    @param inst_uuids: list of instance UUIDs to get names for
1819 da4a52a3 Thomas Thrainer
    @type inst_uuids: list of strings
1820 da4a52a3 Thomas Thrainer
    @rtype: list of strings
1821 da4a52a3 Thomas Thrainer
    @return: list of instance names
1822 da4a52a3 Thomas Thrainer

1823 da4a52a3 Thomas Thrainer
    """
1824 da4a52a3 Thomas Thrainer
    return self._UnlockedGetInstanceNames(inst_uuids)
1825 da4a52a3 Thomas Thrainer
1826 da4a52a3 Thomas Thrainer
  def _UnlockedGetInstanceNames(self, inst_uuids):
1827 da4a52a3 Thomas Thrainer
    return [self._UnlockedGetInstanceName(uuid) for uuid in inst_uuids]
1828 da4a52a3 Thomas Thrainer
1829 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1830 0debfb35 Guido Trotter
  def AddNode(self, node, ec_id):
1831 a8083063 Iustin Pop
    """Add a node to the configuration.
1832 a8083063 Iustin Pop

1833 c41eea6e Iustin Pop
    @type node: L{objects.Node}
1834 c41eea6e Iustin Pop
    @param node: a Node instance
1835 a8083063 Iustin Pop

1836 a8083063 Iustin Pop
    """
1837 099c52ad Iustin Pop
    logging.info("Adding node %s to configuration", node.name)
1838 d8470559 Michael Hanselmann
1839 0debfb35 Guido Trotter
    self._EnsureUUID(node, ec_id)
1840 430b923c Iustin Pop
1841 b989e85d Iustin Pop
    node.serial_no = 1
1842 d693c864 Iustin Pop
    node.ctime = node.mtime = time.time()
1843 1c3231aa Thomas Thrainer
    self._UnlockedAddNodeToGroup(node.uuid, node.group)
1844 1c3231aa Thomas Thrainer
    self._config_data.nodes[node.uuid] = node
1845 b9f72b4e Iustin Pop
    self._config_data.cluster.serial_no += 1
1846 a8083063 Iustin Pop
    self._WriteConfig()
1847 a8083063 Iustin Pop
1848 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock)
1849 1c3231aa Thomas Thrainer
  def RemoveNode(self, node_uuid):
1850 a8083063 Iustin Pop
    """Remove a node from the configuration.
1851 a8083063 Iustin Pop

1852 a8083063 Iustin Pop
    """
1853 1c3231aa Thomas Thrainer
    logging.info("Removing node %s from configuration", node_uuid)
1854 d8470559 Michael Hanselmann
1855 1c3231aa Thomas Thrainer
    if node_uuid not in self._config_data.nodes:
1856 1c3231aa Thomas Thrainer
      raise errors.ConfigurationError("Unknown node '%s'" % node_uuid)
1857 a8083063 Iustin Pop
1858 1c3231aa Thomas Thrainer
    self._UnlockedRemoveNodeFromGroup(self._config_data.nodes[node_uuid])
1859 1c3231aa Thomas Thrainer
    del self._config_data.nodes[node_uuid]
1860 b9f72b4e Iustin Pop
    self._config_data.cluster.serial_no += 1
1861 a8083063 Iustin Pop
    self._WriteConfig()
1862 a8083063 Iustin Pop
1863 a8083063 Iustin Pop
  def ExpandNodeName(self, short_name):
1864 1c3231aa Thomas Thrainer
    """Attempt to expand an incomplete node name into a node UUID.
1865 a8083063 Iustin Pop

1866 a8083063 Iustin Pop
    """
1867 1c3231aa Thomas Thrainer
    # Locking is done in L{ConfigWriter.GetAllNodesInfo}
1868 1c3231aa Thomas Thrainer
    all_nodes = self.GetAllNodesInfo().values()
1869 1c3231aa Thomas Thrainer
    expanded_name = _MatchNameComponentIgnoreCase(
1870 1c3231aa Thomas Thrainer
                      short_name, [node.name for node in all_nodes])
1871 a8083063 Iustin Pop
1872 1c3231aa Thomas Thrainer
    if expanded_name is not None:
1873 da4a52a3 Thomas Thrainer
      # there has to be exactly one node with that name
1874 1c3231aa Thomas Thrainer
      node = (filter(lambda n: n.name == expanded_name, all_nodes)[0])
1875 1c3231aa Thomas Thrainer
      return (node.uuid, node.name)
1876 1c3231aa Thomas Thrainer
    else:
1877 738436bf Thomas Thrainer
      return (None, None)
1878 1c3231aa Thomas Thrainer
1879 1c3231aa Thomas Thrainer
  def _UnlockedGetNodeInfo(self, node_uuid):
1880 a8083063 Iustin Pop
    """Get the configuration of a node, as stored in the config.
1881 a8083063 Iustin Pop

1882 c41eea6e Iustin Pop
    This function is for internal use, when the config lock is already
1883 c41eea6e Iustin Pop
    held.
1884 f78ede4e Guido Trotter

1885 1c3231aa Thomas Thrainer
    @param node_uuid: the node UUID
1886 a8083063 Iustin Pop

1887 c41eea6e Iustin Pop
    @rtype: L{objects.Node}
1888 c41eea6e Iustin Pop
    @return: the node object
1889 a8083063 Iustin Pop

1890 a8083063 Iustin Pop
    """
1891 1c3231aa Thomas Thrainer
    if node_uuid not in self._config_data.nodes:
1892 a8083063 Iustin Pop
      return None
1893 a8083063 Iustin Pop
1894 1c3231aa Thomas Thrainer
    return self._config_data.nodes[node_uuid]
1895 a8083063 Iustin Pop
1896 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1897 1c3231aa Thomas Thrainer
  def GetNodeInfo(self, node_uuid):
1898 f78ede4e Guido Trotter
    """Get the configuration of a node, as stored in the config.
1899 f78ede4e Guido Trotter

1900 c41eea6e Iustin Pop
    This is just a locked wrapper over L{_UnlockedGetNodeInfo}.
1901 f78ede4e Guido Trotter

1902 1c3231aa Thomas Thrainer
    @param node_uuid: the node UUID
1903 c41eea6e Iustin Pop

1904 c41eea6e Iustin Pop
    @rtype: L{objects.Node}
1905 c41eea6e Iustin Pop
    @return: the node object
1906 f78ede4e Guido Trotter

1907 f78ede4e Guido Trotter
    """
1908 1c3231aa Thomas Thrainer
    return self._UnlockedGetNodeInfo(node_uuid)
1909 f78ede4e Guido Trotter
1910 8bf9e9a5 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
1911 1c3231aa Thomas Thrainer
  def GetNodeInstances(self, node_uuid):
1912 8bf9e9a5 Iustin Pop
    """Get the instances of a node, as stored in the config.
1913 8bf9e9a5 Iustin Pop

1914 1c3231aa Thomas Thrainer
    @param node_uuid: the node UUID
1915 8bf9e9a5 Iustin Pop

1916 8bf9e9a5 Iustin Pop
    @rtype: (list, list)
1917 8bf9e9a5 Iustin Pop
    @return: a tuple with two lists: the primary and the secondary instances
1918 8bf9e9a5 Iustin Pop

1919 8bf9e9a5 Iustin Pop
    """
1920 8bf9e9a5 Iustin Pop
    pri = []
1921 8bf9e9a5 Iustin Pop
    sec = []
1922 8bf9e9a5 Iustin Pop
    for inst in self._config_data.instances.values():
1923 1c3231aa Thomas Thrainer
      if inst.primary_node == node_uuid:
1924 da4a52a3 Thomas Thrainer
        pri.append(inst.uuid)
1925 1c3231aa Thomas Thrainer
      if node_uuid in inst.secondary_nodes:
1926 da4a52a3 Thomas Thrainer
        sec.append(inst.uuid)
1927 8bf9e9a5 Iustin Pop
    return (pri, sec)
1928 8bf9e9a5 Iustin Pop
1929 c71b049c Michael Hanselmann
  @locking.ssynchronized(_config_lock, shared=1)
1930 c71b049c Michael Hanselmann
  def GetNodeGroupInstances(self, uuid, primary_only=False):
1931 c71b049c Michael Hanselmann
    """Get the instances of a node group.
1932 c71b049c Michael Hanselmann

1933 c71b049c Michael Hanselmann
    @param uuid: Node group UUID
1934 c71b049c Michael Hanselmann
    @param primary_only: Whether to only consider primary nodes
1935 c71b049c Michael Hanselmann
    @rtype: frozenset
1936 da4a52a3 Thomas Thrainer
    @return: List of instance UUIDs in node group
1937 c71b049c Michael Hanselmann

1938 c71b049c Michael Hanselmann
    """
1939 c71b049c Michael Hanselmann
    if primary_only:
1940 c71b049c Michael Hanselmann
      nodes_fn = lambda inst: [inst.primary_node]
1941 c71b049c Michael Hanselmann
    else:
1942 c71b049c Michael Hanselmann
      nodes_fn = lambda inst: inst.all_nodes
1943 c71b049c Michael Hanselmann
1944 da4a52a3 Thomas Thrainer
    return frozenset(inst.uuid
1945 c71b049c Michael Hanselmann
                     for inst in self._config_data.instances.values()
1946 1c3231aa Thomas Thrainer
                     for node_uuid in nodes_fn(inst)
1947 1c3231aa Thomas Thrainer
                     if self._UnlockedGetNodeInfo(node_uuid).group == uuid)
1948 c71b049c Michael Hanselmann
1949 def6577f Helga Velroyen
  def _UnlockedGetHvparamsString(self, hvname):
1950 def6577f Helga Velroyen
    """Return the string representation of the list of hyervisor parameters of
1951 def6577f Helga Velroyen
    the given hypervisor.
1952 def6577f Helga Velroyen

1953 def6577f Helga Velroyen
    @see: C{GetHvparams}
1954 def6577f Helga Velroyen

1955 def6577f Helga Velroyen
    """
1956 def6577f Helga Velroyen
    result = ""
1957 def6577f Helga Velroyen
    hvparams = self._config_data.cluster.hvparams[hvname]
1958 def6577f Helga Velroyen
    for key in hvparams:
1959 def6577f Helga Velroyen
      result += "%s=%s\n" % (key, hvparams[key])
1960 def6577f Helga Velroyen
    return result
1961 def6577f Helga Velroyen
1962 def6577f Helga Velroyen
  @locking.ssynchronized(_config_lock, shared=1)
1963 def6577f Helga Velroyen
  def GetHvparamsString(self, hvname):
1964 def6577f Helga Velroyen
    """Return the hypervisor parameters of the given hypervisor.
1965 def6577f Helga Velroyen

1966 def6577f Helga Velroyen
    @type hvname: string
1967 def6577f Helga Velroyen
    @param hvname: name of a hypervisor
1968 def6577f Helga Velroyen
    @rtype: string
1969 def6577f Helga Velroyen
    @return: string containing key-value-pairs, one pair on each line;
1970 def6577f Helga Velroyen
      format: KEY=VALUE
1971 def6577f Helga Velroyen

1972 def6577f Helga Velroyen
    """
1973 def6577f Helga Velroyen
    return self._UnlockedGetHvparamsString(hvname)
1974 def6577f Helga Velroyen
1975 f78ede4e Guido Trotter
  def _UnlockedGetNodeList(self):
1976 a8083063 Iustin Pop
    """Return the list of nodes which are in the configuration.
1977 a8083063 Iustin Pop

1978 c41eea6e Iustin Pop
    This function is for internal use, when the config lock is already
1979 c41eea6e Iustin Pop
    held.
1980 c41eea6e Iustin Pop

1981 c41eea6e Iustin Pop
    @rtype: list
1982 f78ede4e Guido Trotter

1983 a8083063 Iustin Pop
    """
1984 a8083063 Iustin Pop
    return self._config_data.nodes.keys()
1985 a8083063 Iustin Pop
1986 f78ede4e Guido Trotter
  @locking.ssynchronized(_config_lock, shared=1)
1987 f78ede4e Guido Trotter
  def GetNodeList(self):
1988 f78ede4e Guido Trotter
    """Return the list of nodes which are in the configuration.
1989 f78ede4e Guido Trotter

1990 f78ede4e Guido Trotter
    """
1991 f78ede4e Guido Trotter
    return self._UnlockedGetNodeList()
1992 f78ede4e Guido Trotter
1993 6819dc49 Iustin Pop
  def _UnlockedGetOnlineNodeList(self):
1994 94a02bb5 Iustin Pop
    """Return the list of nodes which are online.
1995 94a02bb5 Iustin Pop

1996 94a02bb5 Iustin Pop
    """
1997 94a02bb5 Iustin Pop
    all_nodes = [self._UnlockedGetNodeInfo(node)
1998 94a02bb5 Iustin Pop
                 for node in self._UnlockedGetNodeList()]
1999 1c3231aa Thomas Thrainer
    return [node.uuid for node in all_nodes if not node.offline]
2000 94a02bb5 Iustin Pop
2001 94a02bb5 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
2002 6819dc49 Iustin Pop
  def GetOnlineNodeList(self):
2003 6819dc49 Iustin Pop
    """Return the list of nodes which are online.
2004 6819dc49 Iustin Pop

2005 6819dc49 Iustin Pop
    """
2006 6819dc49 Iustin Pop
    return self._UnlockedGetOnlineNodeList()
2007 6819dc49 Iustin Pop
2008 6819dc49 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
2009 075b62ca Iustin Pop
  def GetVmCapableNodeList(self):
2010 075b62ca Iustin Pop
    """Return the list of nodes which are not vm capable.
2011 075b62ca Iustin Pop

2012 075b62ca Iustin Pop
    """
2013 075b62ca Iustin Pop
    all_nodes = [self._UnlockedGetNodeInfo(node)
2014 075b62ca Iustin Pop
                 for node in self._UnlockedGetNodeList()]
2015 1c3231aa Thomas Thrainer
    return [node.uuid for node in all_nodes if node.vm_capable]
2016 075b62ca Iustin Pop
2017 075b62ca Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
2018 8bf9e9a5 Iustin Pop
  def GetNonVmCapableNodeList(self):
2019 8bf9e9a5 Iustin Pop
    """Return the list of nodes which are not vm capable.
2020 8bf9e9a5 Iustin Pop

2021 8bf9e9a5 Iustin Pop
    """
2022 8bf9e9a5 Iustin Pop
    all_nodes = [self._UnlockedGetNodeInfo(node)
2023 8bf9e9a5 Iustin Pop
                 for node in self._UnlockedGetNodeList()]
2024 1c3231aa Thomas Thrainer
    return [node.uuid for node in all_nodes if not node.vm_capable]
2025 8bf9e9a5 Iustin Pop
2026 8bf9e9a5 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
2027 1c3231aa Thomas Thrainer
  def GetMultiNodeInfo(self, node_uuids):
2028 f5eaa3c1 Iustin Pop
    """Get the configuration of multiple nodes.
2029 f5eaa3c1 Iustin Pop

2030 1c3231aa Thomas Thrainer
    @param node_uuids: list of node UUIDs
2031 f5eaa3c1 Iustin Pop
    @rtype: list
2032 f5eaa3c1 Iustin Pop
    @return: list of tuples of (node, node_info), where node_info is
2033 f5eaa3c1 Iustin Pop
        what would GetNodeInfo return for the node, in the original
2034 f5eaa3c1 Iustin Pop
        order
2035 f5eaa3c1 Iustin Pop

2036 f5eaa3c1 Iustin Pop
    """
2037 1c3231aa Thomas Thrainer
    return [(uuid, self._UnlockedGetNodeInfo(uuid)) for uuid in node_uuids]
2038 1c3231aa Thomas Thrainer
2039 1c3231aa Thomas Thrainer
  def _UnlockedGetAllNodesInfo(self):
2040 1c3231aa Thomas Thrainer
    """Gets configuration of all nodes.
2041 1c3231aa Thomas Thrainer

2042 1c3231aa Thomas Thrainer
    @note: See L{GetAllNodesInfo}
2043 1c3231aa Thomas Thrainer

2044 1c3231aa Thomas Thrainer
    """
2045 1c3231aa Thomas Thrainer
    return dict([(node_uuid, self._UnlockedGetNodeInfo(node_uuid))
2046 1c3231aa Thomas Thrainer
                 for node_uuid in self._UnlockedGetNodeList()])
2047 f5eaa3c1 Iustin Pop
2048 f5eaa3c1 Iustin Pop
  @locking.ssynchronized(_config_lock, shared=1)
2049 d65e5776 Iustin Pop
  def GetAllNodesInfo(self):
2050 d65e5776 Iustin Pop
    """Get the configuration of all nodes.
2051