Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / test.py @ 1c4910f7

History | View | Annotate | Download (14.6 kB)

1 1d870e0d Thomas Thrainer
#
2 1d870e0d Thomas Thrainer
#
3 1d870e0d Thomas Thrainer
4 054a9d17 Hrvoje Ribicic
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc.
5 1d870e0d Thomas Thrainer
#
6 1d870e0d Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 1d870e0d Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 1d870e0d Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 1d870e0d Thomas Thrainer
# (at your option) any later version.
10 1d870e0d Thomas Thrainer
#
11 1d870e0d Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 1d870e0d Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 1d870e0d Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 1d870e0d Thomas Thrainer
# General Public License for more details.
15 1d870e0d Thomas Thrainer
#
16 1d870e0d Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 1d870e0d Thomas Thrainer
# along with this program; if not, write to the Free Software
18 1d870e0d Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 1d870e0d Thomas Thrainer
# 02110-1301, USA.
20 1d870e0d Thomas Thrainer
21 1d870e0d Thomas Thrainer
22 1d870e0d Thomas Thrainer
"""Test logical units."""
23 1d870e0d Thomas Thrainer
24 1d870e0d Thomas Thrainer
import logging
25 1d870e0d Thomas Thrainer
import shutil
26 1d870e0d Thomas Thrainer
import socket
27 1d870e0d Thomas Thrainer
import tempfile
28 9dc47292 Hrvoje Ribicic
import time
29 1d870e0d Thomas Thrainer
30 1d870e0d Thomas Thrainer
from ganeti import compat
31 1d870e0d Thomas Thrainer
from ganeti import constants
32 1d870e0d Thomas Thrainer
from ganeti import errors
33 1d870e0d Thomas Thrainer
from ganeti import locking
34 1d870e0d Thomas Thrainer
from ganeti import utils
35 1d870e0d Thomas Thrainer
from ganeti.masterd import iallocator
36 1d870e0d Thomas Thrainer
from ganeti.cmdlib.base import NoHooksLU
37 da4a52a3 Thomas Thrainer
from ganeti.cmdlib.common import ExpandInstanceUuidAndName, GetWantedNodes, \
38 5eacbcae Thomas Thrainer
  GetWantedInstances
39 1d870e0d Thomas Thrainer
40 1d870e0d Thomas Thrainer
41 c346d0ac Hrvoje Ribicic
class TestSocketWrapper(object):
42 c346d0ac Hrvoje Ribicic
  """ Utility class that opens a domain socket and cleans up as needed.
43 c346d0ac Hrvoje Ribicic

44 c346d0ac Hrvoje Ribicic
  """
45 c346d0ac Hrvoje Ribicic
  def __init__(self):
46 c346d0ac Hrvoje Ribicic
    """ Constructor cleaning up variables to be used.
47 c346d0ac Hrvoje Ribicic

48 c346d0ac Hrvoje Ribicic
    """
49 c346d0ac Hrvoje Ribicic
    self.tmpdir = None
50 c346d0ac Hrvoje Ribicic
    self.sock = None
51 c346d0ac Hrvoje Ribicic
52 c346d0ac Hrvoje Ribicic
  def Create(self, max_connections=1):
53 c346d0ac Hrvoje Ribicic
    """ Creates a bound and ready socket, cleaning up in case of failure.
54 c346d0ac Hrvoje Ribicic

55 c346d0ac Hrvoje Ribicic
    @type max_connections: int
56 c346d0ac Hrvoje Ribicic
    @param max_connections: The number of max connections allowed for the
57 c346d0ac Hrvoje Ribicic
                            socket.
58 c346d0ac Hrvoje Ribicic

59 c346d0ac Hrvoje Ribicic
    @rtype: tuple of socket, string
60 c346d0ac Hrvoje Ribicic
    @return: The socket object and the path to reach it with.
61 c346d0ac Hrvoje Ribicic

62 c346d0ac Hrvoje Ribicic
    """
63 c346d0ac Hrvoje Ribicic
    # Using a temporary directory as there's no easy way to create temporary
64 c346d0ac Hrvoje Ribicic
    # sockets without writing a custom loop around tempfile.mktemp and
65 c346d0ac Hrvoje Ribicic
    # socket.bind
66 c346d0ac Hrvoje Ribicic
    self.tmpdir = tempfile.mkdtemp()
67 c346d0ac Hrvoje Ribicic
    try:
68 c346d0ac Hrvoje Ribicic
      tmpsock = utils.PathJoin(self.tmpdir, "sock")
69 c346d0ac Hrvoje Ribicic
      logging.debug("Creating temporary socket at %s", tmpsock)
70 c346d0ac Hrvoje Ribicic
      self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
71 c346d0ac Hrvoje Ribicic
      try:
72 c346d0ac Hrvoje Ribicic
        self.sock.bind(tmpsock)
73 c346d0ac Hrvoje Ribicic
        self.sock.listen(max_connections)
74 c346d0ac Hrvoje Ribicic
      except:
75 c346d0ac Hrvoje Ribicic
        self.sock.close()
76 c346d0ac Hrvoje Ribicic
        raise
77 c346d0ac Hrvoje Ribicic
    except:
78 c346d0ac Hrvoje Ribicic
      shutil.rmtree(self.tmpdir)
79 c346d0ac Hrvoje Ribicic
      raise
80 c346d0ac Hrvoje Ribicic
81 c346d0ac Hrvoje Ribicic
    return self.sock, tmpsock
82 c346d0ac Hrvoje Ribicic
83 c346d0ac Hrvoje Ribicic
  def Destroy(self):
84 c346d0ac Hrvoje Ribicic
    """ Destroys the socket and performs all necessary cleanup.
85 c346d0ac Hrvoje Ribicic

86 c346d0ac Hrvoje Ribicic
    """
87 c346d0ac Hrvoje Ribicic
    if self.tmpdir is None or self.sock is None:
88 c346d0ac Hrvoje Ribicic
      raise Exception("A socket must be created successfully before attempting "
89 c346d0ac Hrvoje Ribicic
                      "its destruction")
90 c346d0ac Hrvoje Ribicic
91 c346d0ac Hrvoje Ribicic
    try:
92 c346d0ac Hrvoje Ribicic
      self.sock.close()
93 c346d0ac Hrvoje Ribicic
    finally:
94 c346d0ac Hrvoje Ribicic
      shutil.rmtree(self.tmpdir)
95 c346d0ac Hrvoje Ribicic
96 c346d0ac Hrvoje Ribicic
97 1d870e0d Thomas Thrainer
class LUTestDelay(NoHooksLU):
98 1d870e0d Thomas Thrainer
  """Sleep for a specified amount of time.
99 1d870e0d Thomas Thrainer

100 1d870e0d Thomas Thrainer
  This LU sleeps on the master and/or nodes for a specified amount of
101 1d870e0d Thomas Thrainer
  time.
102 1d870e0d Thomas Thrainer

103 1d870e0d Thomas Thrainer
  """
104 1d870e0d Thomas Thrainer
  REQ_BGL = False
105 1d870e0d Thomas Thrainer
106 1d870e0d Thomas Thrainer
  def ExpandNames(self):
107 1d870e0d Thomas Thrainer
    """Expand names and set required locks.
108 1d870e0d Thomas Thrainer

109 1d870e0d Thomas Thrainer
    This expands the node list, if any.
110 1d870e0d Thomas Thrainer

111 1d870e0d Thomas Thrainer
    """
112 8631b46b Hrvoje Ribicic
113 8631b46b Hrvoje Ribicic
    if self.op.duration <= 0:
114 8631b46b Hrvoje Ribicic
      raise errors.OpPrereqError("Duration must be greater than zero")
115 8631b46b Hrvoje Ribicic
116 36870aa1 Hrvoje Ribicic
    self.op.on_node_uuids = []
117 1d870e0d Thomas Thrainer
    if self.op.on_nodes:
118 1d870e0d Thomas Thrainer
      # _GetWantedNodes can be used here, but is not always appropriate to use
119 1d870e0d Thomas Thrainer
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
120 1d870e0d Thomas Thrainer
      # more information.
121 1c3231aa Thomas Thrainer
      (self.op.on_node_uuids, self.op.on_nodes) = \
122 1c3231aa Thomas Thrainer
        GetWantedNodes(self, self.op.on_nodes)
123 054a9d17 Hrvoje Ribicic
124 36870aa1 Hrvoje Ribicic
    master_uuid = self.cfg.GetMasterNode()
125 36870aa1 Hrvoje Ribicic
    if self.op.on_master and master_uuid not in self.op.on_node_uuids:
126 36870aa1 Hrvoje Ribicic
      self.op.on_node_uuids.append(master_uuid)
127 36870aa1 Hrvoje Ribicic
128 36870aa1 Hrvoje Ribicic
    self.needed_locks = {}
129 36870aa1 Hrvoje Ribicic
    self.needed_locks[locking.LEVEL_NODE] = self.op.on_node_uuids
130 1d870e0d Thomas Thrainer
131 9dc47292 Hrvoje Ribicic
  def _InterruptibleDelay(self):
132 9dc47292 Hrvoje Ribicic
    """Delays but provides the mechanisms necessary to interrupt the delay as
133 9dc47292 Hrvoje Ribicic
    needed.
134 9dc47292 Hrvoje Ribicic

135 9dc47292 Hrvoje Ribicic
    """
136 9dc47292 Hrvoje Ribicic
    socket_wrapper = TestSocketWrapper()
137 9dc47292 Hrvoje Ribicic
    sock, path = socket_wrapper.Create()
138 9dc47292 Hrvoje Ribicic
139 9dc47292 Hrvoje Ribicic
    self.Log(constants.ELOG_DELAY_TEST, (path,))
140 9dc47292 Hrvoje Ribicic
141 9dc47292 Hrvoje Ribicic
    try:
142 9dc47292 Hrvoje Ribicic
      sock.settimeout(self.op.duration)
143 9dc47292 Hrvoje Ribicic
      start = time.time()
144 9dc47292 Hrvoje Ribicic
      (conn, _) = sock.accept()
145 9dc47292 Hrvoje Ribicic
    except socket.timeout, _:
146 9dc47292 Hrvoje Ribicic
      # If we timed out, all is well
147 9dc47292 Hrvoje Ribicic
      return False
148 9dc47292 Hrvoje Ribicic
    finally:
149 9dc47292 Hrvoje Ribicic
      # Destroys the original socket, but the new connection is still usable
150 9dc47292 Hrvoje Ribicic
      socket_wrapper.Destroy()
151 9dc47292 Hrvoje Ribicic
152 9dc47292 Hrvoje Ribicic
    try:
153 9dc47292 Hrvoje Ribicic
      # Change to remaining time
154 9dc47292 Hrvoje Ribicic
      time_to_go = self.op.duration - (time.time() - start)
155 9dc47292 Hrvoje Ribicic
      self.Log(constants.ELOG_MESSAGE,
156 9dc47292 Hrvoje Ribicic
               "Received connection, time to go is %d" % time_to_go)
157 9dc47292 Hrvoje Ribicic
      if time_to_go < 0:
158 9dc47292 Hrvoje Ribicic
        time_to_go = 0
159 9dc47292 Hrvoje Ribicic
      # pylint: disable=E1101
160 9dc47292 Hrvoje Ribicic
      # Instance of '_socketobject' has no ... member
161 9dc47292 Hrvoje Ribicic
      conn.settimeout(time_to_go)
162 9dc47292 Hrvoje Ribicic
      conn.recv(1)
163 9dc47292 Hrvoje Ribicic
      # pylint: enable=E1101
164 9dc47292 Hrvoje Ribicic
    except socket.timeout, _:
165 9dc47292 Hrvoje Ribicic
      # A second timeout can occur if no data is sent
166 9dc47292 Hrvoje Ribicic
      return False
167 9dc47292 Hrvoje Ribicic
    finally:
168 9dc47292 Hrvoje Ribicic
      conn.close()
169 9dc47292 Hrvoje Ribicic
170 9dc47292 Hrvoje Ribicic
    self.Log(constants.ELOG_MESSAGE,
171 9dc47292 Hrvoje Ribicic
             "Interrupted, time spent waiting: %d" % (time.time() - start))
172 9dc47292 Hrvoje Ribicic
173 9dc47292 Hrvoje Ribicic
    # Reaching this point means we were interrupted
174 9dc47292 Hrvoje Ribicic
    return True
175 9dc47292 Hrvoje Ribicic
176 9dc47292 Hrvoje Ribicic
  def _UninterruptibleDelay(self):
177 9dc47292 Hrvoje Ribicic
    """Delays without allowing interruptions.
178 1d870e0d Thomas Thrainer

179 1d870e0d Thomas Thrainer
    """
180 1c3231aa Thomas Thrainer
    if self.op.on_node_uuids:
181 1c3231aa Thomas Thrainer
      result = self.rpc.call_test_delay(self.op.on_node_uuids, self.op.duration)
182 1c3231aa Thomas Thrainer
      for node_uuid, node_result in result.items():
183 1c3231aa Thomas Thrainer
        node_result.Raise("Failure during rpc call to node %s" %
184 1c3231aa Thomas Thrainer
                          self.cfg.GetNodeName(node_uuid))
185 36870aa1 Hrvoje Ribicic
    else:
186 36870aa1 Hrvoje Ribicic
      if not utils.TestDelay(self.op.duration)[0]:
187 36870aa1 Hrvoje Ribicic
        raise errors.OpExecError("Error during master delay test")
188 1d870e0d Thomas Thrainer
189 9dc47292 Hrvoje Ribicic
  def _TestDelay(self):
190 9dc47292 Hrvoje Ribicic
    """Do the actual sleep.
191 9dc47292 Hrvoje Ribicic

192 9dc47292 Hrvoje Ribicic
    @rtype: bool
193 9dc47292 Hrvoje Ribicic
    @return: Whether the delay was interrupted
194 9dc47292 Hrvoje Ribicic

195 9dc47292 Hrvoje Ribicic
    """
196 9dc47292 Hrvoje Ribicic
    if self.op.interruptible:
197 9dc47292 Hrvoje Ribicic
      return self._InterruptibleDelay()
198 9dc47292 Hrvoje Ribicic
    else:
199 9dc47292 Hrvoje Ribicic
      self._UninterruptibleDelay()
200 9dc47292 Hrvoje Ribicic
      return False
201 9dc47292 Hrvoje Ribicic
202 1d870e0d Thomas Thrainer
  def Exec(self, feedback_fn):
203 1d870e0d Thomas Thrainer
    """Execute the test delay opcode, with the wanted repetitions.
204 1d870e0d Thomas Thrainer

205 1d870e0d Thomas Thrainer
    """
206 1d870e0d Thomas Thrainer
    if self.op.repeat == 0:
207 9dc47292 Hrvoje Ribicic
      i = self._TestDelay()
208 1d870e0d Thomas Thrainer
    else:
209 1d870e0d Thomas Thrainer
      top_value = self.op.repeat - 1
210 1d870e0d Thomas Thrainer
      for i in range(self.op.repeat):
211 1d870e0d Thomas Thrainer
        self.LogInfo("Test delay iteration %d/%d", i, top_value)
212 9dc47292 Hrvoje Ribicic
        # Break in case of interruption
213 9dc47292 Hrvoje Ribicic
        if self._TestDelay():
214 9dc47292 Hrvoje Ribicic
          break
215 1d870e0d Thomas Thrainer
216 1d870e0d Thomas Thrainer
217 1d870e0d Thomas Thrainer
class LUTestJqueue(NoHooksLU):
218 1d870e0d Thomas Thrainer
  """Utility LU to test some aspects of the job queue.
219 1d870e0d Thomas Thrainer

220 1d870e0d Thomas Thrainer
  """
221 1d870e0d Thomas Thrainer
  REQ_BGL = False
222 1d870e0d Thomas Thrainer
223 1d870e0d Thomas Thrainer
  # Must be lower than default timeout for WaitForJobChange to see whether it
224 1d870e0d Thomas Thrainer
  # notices changed jobs
225 1d870e0d Thomas Thrainer
  _CLIENT_CONNECT_TIMEOUT = 20.0
226 1d870e0d Thomas Thrainer
  _CLIENT_CONFIRM_TIMEOUT = 60.0
227 1d870e0d Thomas Thrainer
228 1d870e0d Thomas Thrainer
  @classmethod
229 1d870e0d Thomas Thrainer
  def _NotifyUsingSocket(cls, cb, errcls):
230 1d870e0d Thomas Thrainer
    """Opens a Unix socket and waits for another program to connect.
231 1d870e0d Thomas Thrainer

232 1d870e0d Thomas Thrainer
    @type cb: callable
233 1d870e0d Thomas Thrainer
    @param cb: Callback to send socket name to client
234 1d870e0d Thomas Thrainer
    @type errcls: class
235 1d870e0d Thomas Thrainer
    @param errcls: Exception class to use for errors
236 1d870e0d Thomas Thrainer

237 1d870e0d Thomas Thrainer
    """
238 c346d0ac Hrvoje Ribicic
239 1d870e0d Thomas Thrainer
    # Using a temporary directory as there's no easy way to create temporary
240 1d870e0d Thomas Thrainer
    # sockets without writing a custom loop around tempfile.mktemp and
241 1d870e0d Thomas Thrainer
    # socket.bind
242 1d870e0d Thomas Thrainer
243 c346d0ac Hrvoje Ribicic
    socket_wrapper = TestSocketWrapper()
244 c346d0ac Hrvoje Ribicic
    sock, path = socket_wrapper.Create()
245 c346d0ac Hrvoje Ribicic
246 c346d0ac Hrvoje Ribicic
    cb(path)
247 c346d0ac Hrvoje Ribicic
248 c346d0ac Hrvoje Ribicic
    try:
249 c346d0ac Hrvoje Ribicic
      sock.settimeout(cls._CLIENT_CONNECT_TIMEOUT)
250 c346d0ac Hrvoje Ribicic
      (conn, _) = sock.accept()
251 c346d0ac Hrvoje Ribicic
    except socket.error, err:
252 c346d0ac Hrvoje Ribicic
      raise errcls("Client didn't connect in time (%s)" % err)
253 1d870e0d Thomas Thrainer
    finally:
254 c346d0ac Hrvoje Ribicic
      socket_wrapper.Destroy()
255 1d870e0d Thomas Thrainer
256 1d870e0d Thomas Thrainer
    # Wait for client to close
257 1d870e0d Thomas Thrainer
    try:
258 1d870e0d Thomas Thrainer
      try:
259 1d870e0d Thomas Thrainer
        # pylint: disable=E1101
260 1d870e0d Thomas Thrainer
        # Instance of '_socketobject' has no ... member
261 1d870e0d Thomas Thrainer
        conn.settimeout(cls._CLIENT_CONFIRM_TIMEOUT)
262 1d870e0d Thomas Thrainer
        conn.recv(1)
263 1d870e0d Thomas Thrainer
      except socket.error, err:
264 1d870e0d Thomas Thrainer
        raise errcls("Client failed to confirm notification (%s)" % err)
265 1d870e0d Thomas Thrainer
    finally:
266 1d870e0d Thomas Thrainer
      conn.close()
267 1d870e0d Thomas Thrainer
268 1d870e0d Thomas Thrainer
  def _SendNotification(self, test, arg, sockname):
269 1d870e0d Thomas Thrainer
    """Sends a notification to the client.
270 1d870e0d Thomas Thrainer

271 1d870e0d Thomas Thrainer
    @type test: string
272 1d870e0d Thomas Thrainer
    @param test: Test name
273 1d870e0d Thomas Thrainer
    @param arg: Test argument (depends on test)
274 1d870e0d Thomas Thrainer
    @type sockname: string
275 1d870e0d Thomas Thrainer
    @param sockname: Socket path
276 1d870e0d Thomas Thrainer

277 1d870e0d Thomas Thrainer
    """
278 1d870e0d Thomas Thrainer
    self.Log(constants.ELOG_JQUEUE_TEST, (sockname, test, arg))
279 1d870e0d Thomas Thrainer
280 1d870e0d Thomas Thrainer
  def _Notify(self, prereq, test, arg):
281 1d870e0d Thomas Thrainer
    """Notifies the client of a test.
282 1d870e0d Thomas Thrainer

283 1d870e0d Thomas Thrainer
    @type prereq: bool
284 1d870e0d Thomas Thrainer
    @param prereq: Whether this is a prereq-phase test
285 1d870e0d Thomas Thrainer
    @type test: string
286 1d870e0d Thomas Thrainer
    @param test: Test name
287 1d870e0d Thomas Thrainer
    @param arg: Test argument (depends on test)
288 1d870e0d Thomas Thrainer

289 1d870e0d Thomas Thrainer
    """
290 1d870e0d Thomas Thrainer
    if prereq:
291 1d870e0d Thomas Thrainer
      errcls = errors.OpPrereqError
292 1d870e0d Thomas Thrainer
    else:
293 1d870e0d Thomas Thrainer
      errcls = errors.OpExecError
294 1d870e0d Thomas Thrainer
295 1d870e0d Thomas Thrainer
    return self._NotifyUsingSocket(compat.partial(self._SendNotification,
296 1d870e0d Thomas Thrainer
                                                  test, arg),
297 1d870e0d Thomas Thrainer
                                   errcls)
298 1d870e0d Thomas Thrainer
299 1d870e0d Thomas Thrainer
  def CheckArguments(self):
300 1d870e0d Thomas Thrainer
    self.checkargs_calls = getattr(self, "checkargs_calls", 0) + 1
301 1d870e0d Thomas Thrainer
    self.expandnames_calls = 0
302 1d870e0d Thomas Thrainer
303 1d870e0d Thomas Thrainer
  def ExpandNames(self):
304 1d870e0d Thomas Thrainer
    checkargs_calls = getattr(self, "checkargs_calls", 0)
305 1d870e0d Thomas Thrainer
    if checkargs_calls < 1:
306 1d870e0d Thomas Thrainer
      raise errors.ProgrammerError("CheckArguments was not called")
307 1d870e0d Thomas Thrainer
308 1d870e0d Thomas Thrainer
    self.expandnames_calls += 1
309 1d870e0d Thomas Thrainer
310 1d870e0d Thomas Thrainer
    if self.op.notify_waitlock:
311 1d870e0d Thomas Thrainer
      self._Notify(True, constants.JQT_EXPANDNAMES, None)
312 1d870e0d Thomas Thrainer
313 1d870e0d Thomas Thrainer
    self.LogInfo("Expanding names")
314 1d870e0d Thomas Thrainer
315 1d870e0d Thomas Thrainer
    # Get lock on master node (just to get a lock, not for a particular reason)
316 1d870e0d Thomas Thrainer
    self.needed_locks = {
317 1d870e0d Thomas Thrainer
      locking.LEVEL_NODE: self.cfg.GetMasterNode(),
318 1d870e0d Thomas Thrainer
      }
319 1d870e0d Thomas Thrainer
320 1d870e0d Thomas Thrainer
  def Exec(self, feedback_fn):
321 1d870e0d Thomas Thrainer
    if self.expandnames_calls < 1:
322 1d870e0d Thomas Thrainer
      raise errors.ProgrammerError("ExpandNames was not called")
323 1d870e0d Thomas Thrainer
324 1d870e0d Thomas Thrainer
    if self.op.notify_exec:
325 1d870e0d Thomas Thrainer
      self._Notify(False, constants.JQT_EXEC, None)
326 1d870e0d Thomas Thrainer
327 1d870e0d Thomas Thrainer
    self.LogInfo("Executing")
328 1d870e0d Thomas Thrainer
329 1d870e0d Thomas Thrainer
    if self.op.log_messages:
330 1d870e0d Thomas Thrainer
      self._Notify(False, constants.JQT_STARTMSG, len(self.op.log_messages))
331 1d870e0d Thomas Thrainer
      for idx, msg in enumerate(self.op.log_messages):
332 1d870e0d Thomas Thrainer
        self.LogInfo("Sending log message %s", idx + 1)
333 1d870e0d Thomas Thrainer
        feedback_fn(constants.JQT_MSGPREFIX + msg)
334 1d870e0d Thomas Thrainer
        # Report how many test messages have been sent
335 1d870e0d Thomas Thrainer
        self._Notify(False, constants.JQT_LOGMSG, idx + 1)
336 1d870e0d Thomas Thrainer
337 1d870e0d Thomas Thrainer
    if self.op.fail:
338 1d870e0d Thomas Thrainer
      raise errors.OpExecError("Opcode failure was requested")
339 1d870e0d Thomas Thrainer
340 1d870e0d Thomas Thrainer
    return True
341 1d870e0d Thomas Thrainer
342 1d870e0d Thomas Thrainer
343 1d870e0d Thomas Thrainer
class LUTestAllocator(NoHooksLU):
344 1d870e0d Thomas Thrainer
  """Run allocator tests.
345 1d870e0d Thomas Thrainer

346 1d870e0d Thomas Thrainer
  This LU runs the allocator tests
347 1d870e0d Thomas Thrainer

348 1d870e0d Thomas Thrainer
  """
349 1d870e0d Thomas Thrainer
  def CheckPrereq(self):
350 1d870e0d Thomas Thrainer
    """Check prerequisites.
351 1d870e0d Thomas Thrainer

352 1d870e0d Thomas Thrainer
    This checks the opcode parameters depending on the director and mode test.
353 1d870e0d Thomas Thrainer

354 1d870e0d Thomas Thrainer
    """
355 1d870e0d Thomas Thrainer
    if self.op.mode in (constants.IALLOCATOR_MODE_ALLOC,
356 1d870e0d Thomas Thrainer
                        constants.IALLOCATOR_MODE_MULTI_ALLOC):
357 da4a52a3 Thomas Thrainer
      (self.inst_uuid, iname) = self.cfg.ExpandInstanceName(self.op.name)
358 1d870e0d Thomas Thrainer
      if iname is not None:
359 1d870e0d Thomas Thrainer
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
360 1d870e0d Thomas Thrainer
                                   iname, errors.ECODE_EXISTS)
361 1d870e0d Thomas Thrainer
      for row in self.op.disks:
362 1d870e0d Thomas Thrainer
        if (not isinstance(row, dict) or
363 1d870e0d Thomas Thrainer
            constants.IDISK_SIZE not in row or
364 1d870e0d Thomas Thrainer
            not isinstance(row[constants.IDISK_SIZE], int) or
365 1d870e0d Thomas Thrainer
            constants.IDISK_MODE not in row or
366 1d870e0d Thomas Thrainer
            row[constants.IDISK_MODE] not in constants.DISK_ACCESS_SET):
367 1d870e0d Thomas Thrainer
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
368 1d870e0d Thomas Thrainer
                                     " parameter", errors.ECODE_INVAL)
369 1d870e0d Thomas Thrainer
      if self.op.hypervisor is None:
370 1d870e0d Thomas Thrainer
        self.op.hypervisor = self.cfg.GetHypervisorType()
371 1d870e0d Thomas Thrainer
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
372 e969a81f Thomas Thrainer
      (self.inst_uuid, self.op.name) = ExpandInstanceUuidAndName(self.cfg, None,
373 e969a81f Thomas Thrainer
                                                                 self.op.name)
374 1c3231aa Thomas Thrainer
      self.relocate_from_node_uuids = \
375 e969a81f Thomas Thrainer
          list(self.cfg.GetInstanceInfo(self.inst_uuid).secondary_nodes)
376 1d870e0d Thomas Thrainer
    elif self.op.mode in (constants.IALLOCATOR_MODE_CHG_GROUP,
377 1d870e0d Thomas Thrainer
                          constants.IALLOCATOR_MODE_NODE_EVAC):
378 1d870e0d Thomas Thrainer
      if not self.op.instances:
379 1d870e0d Thomas Thrainer
        raise errors.OpPrereqError("Missing instances", errors.ECODE_INVAL)
380 da4a52a3 Thomas Thrainer
      (_, self.op.instances) = GetWantedInstances(self, self.op.instances)
381 1d870e0d Thomas Thrainer
    else:
382 1d870e0d Thomas Thrainer
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
383 1d870e0d Thomas Thrainer
                                 self.op.mode, errors.ECODE_INVAL)
384 1d870e0d Thomas Thrainer
385 1d870e0d Thomas Thrainer
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
386 1d870e0d Thomas Thrainer
      if self.op.iallocator is None:
387 1d870e0d Thomas Thrainer
        raise errors.OpPrereqError("Missing allocator name",
388 1d870e0d Thomas Thrainer
                                   errors.ECODE_INVAL)
389 1d870e0d Thomas Thrainer
390 1d870e0d Thomas Thrainer
  def Exec(self, feedback_fn):
391 1d870e0d Thomas Thrainer
    """Run the allocator test.
392 1d870e0d Thomas Thrainer

393 1d870e0d Thomas Thrainer
    """
394 1d870e0d Thomas Thrainer
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
395 1d870e0d Thomas Thrainer
      req = iallocator.IAReqInstanceAlloc(name=self.op.name,
396 1d870e0d Thomas Thrainer
                                          memory=self.op.memory,
397 1d870e0d Thomas Thrainer
                                          disks=self.op.disks,
398 1d870e0d Thomas Thrainer
                                          disk_template=self.op.disk_template,
399 1d870e0d Thomas Thrainer
                                          os=self.op.os,
400 1d870e0d Thomas Thrainer
                                          tags=self.op.tags,
401 1d870e0d Thomas Thrainer
                                          nics=self.op.nics,
402 1d870e0d Thomas Thrainer
                                          vcpus=self.op.vcpus,
403 1d870e0d Thomas Thrainer
                                          spindle_use=self.op.spindle_use,
404 1d870e0d Thomas Thrainer
                                          hypervisor=self.op.hypervisor,
405 1d870e0d Thomas Thrainer
                                          node_whitelist=None)
406 1d870e0d Thomas Thrainer
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
407 1c3231aa Thomas Thrainer
      req = iallocator.IAReqRelocate(
408 da4a52a3 Thomas Thrainer
            inst_uuid=self.inst_uuid,
409 1c3231aa Thomas Thrainer
            relocate_from_node_uuids=list(self.relocate_from_node_uuids))
410 1d870e0d Thomas Thrainer
    elif self.op.mode == constants.IALLOCATOR_MODE_CHG_GROUP:
411 1d870e0d Thomas Thrainer
      req = iallocator.IAReqGroupChange(instances=self.op.instances,
412 1d870e0d Thomas Thrainer
                                        target_groups=self.op.target_groups)
413 1d870e0d Thomas Thrainer
    elif self.op.mode == constants.IALLOCATOR_MODE_NODE_EVAC:
414 1d870e0d Thomas Thrainer
      req = iallocator.IAReqNodeEvac(instances=self.op.instances,
415 1d870e0d Thomas Thrainer
                                     evac_mode=self.op.evac_mode)
416 1d870e0d Thomas Thrainer
    elif self.op.mode == constants.IALLOCATOR_MODE_MULTI_ALLOC:
417 1d870e0d Thomas Thrainer
      disk_template = self.op.disk_template
418 1d870e0d Thomas Thrainer
      insts = [iallocator.IAReqInstanceAlloc(name="%s%s" % (self.op.name, idx),
419 1d870e0d Thomas Thrainer
                                             memory=self.op.memory,
420 1d870e0d Thomas Thrainer
                                             disks=self.op.disks,
421 1d870e0d Thomas Thrainer
                                             disk_template=disk_template,
422 1d870e0d Thomas Thrainer
                                             os=self.op.os,
423 1d870e0d Thomas Thrainer
                                             tags=self.op.tags,
424 1d870e0d Thomas Thrainer
                                             nics=self.op.nics,
425 1d870e0d Thomas Thrainer
                                             vcpus=self.op.vcpus,
426 1d870e0d Thomas Thrainer
                                             spindle_use=self.op.spindle_use,
427 e969a81f Thomas Thrainer
                                             hypervisor=self.op.hypervisor,
428 e969a81f Thomas Thrainer
                                             node_whitelist=None)
429 1d870e0d Thomas Thrainer
               for idx in range(self.op.count)]
430 1d870e0d Thomas Thrainer
      req = iallocator.IAReqMultiInstanceAlloc(instances=insts)
431 1d870e0d Thomas Thrainer
    else:
432 1d870e0d Thomas Thrainer
      raise errors.ProgrammerError("Uncatched mode %s in"
433 1d870e0d Thomas Thrainer
                                   " LUTestAllocator.Exec", self.op.mode)
434 1d870e0d Thomas Thrainer
435 1d870e0d Thomas Thrainer
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
436 1d870e0d Thomas Thrainer
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
437 1d870e0d Thomas Thrainer
      result = ial.in_text
438 1d870e0d Thomas Thrainer
    else:
439 1d870e0d Thomas Thrainer
      ial.Run(self.op.iallocator, validate=False)
440 1d870e0d Thomas Thrainer
      result = ial.out_text
441 1d870e0d Thomas Thrainer
    return result