Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / test.py @ 809a055b

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

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

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

196 9dc47292 Hrvoje Ribicic
    @rtype: bool
197 9dc47292 Hrvoje Ribicic
    @return: Whether the delay was interrupted
198 9dc47292 Hrvoje Ribicic

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

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

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

236 1d870e0d Thomas Thrainer
    @type cb: callable
237 1d870e0d Thomas Thrainer
    @param cb: Callback to send socket name to client
238 1d870e0d Thomas Thrainer
    @type errcls: class
239 1d870e0d Thomas Thrainer
    @param errcls: Exception class to use for errors
240 1d870e0d Thomas Thrainer

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

275 1d870e0d Thomas Thrainer
    @type test: string
276 1d870e0d Thomas Thrainer
    @param test: Test name
277 1d870e0d Thomas Thrainer
    @param arg: Test argument (depends on test)
278 1d870e0d Thomas Thrainer
    @type sockname: string
279 1d870e0d Thomas Thrainer
    @param sockname: Socket path
280 1d870e0d Thomas Thrainer

281 1d870e0d Thomas Thrainer
    """
282 1d870e0d Thomas Thrainer
    self.Log(constants.ELOG_JQUEUE_TEST, (sockname, test, arg))
283 1d870e0d Thomas Thrainer
284 1d870e0d Thomas Thrainer
  def _Notify(self, prereq, test, arg):
285 1d870e0d Thomas Thrainer
    """Notifies the client of a test.
286 1d870e0d Thomas Thrainer

287 1d870e0d Thomas Thrainer
    @type prereq: bool
288 1d870e0d Thomas Thrainer
    @param prereq: Whether this is a prereq-phase test
289 1d870e0d Thomas Thrainer
    @type test: string
290 1d870e0d Thomas Thrainer
    @param test: Test name
291 1d870e0d Thomas Thrainer
    @param arg: Test argument (depends on test)
292 1d870e0d Thomas Thrainer

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

350 1d870e0d Thomas Thrainer
  This LU runs the allocator tests
351 1d870e0d Thomas Thrainer

352 1d870e0d Thomas Thrainer
  """
353 1d870e0d Thomas Thrainer
  def CheckPrereq(self):
354 1d870e0d Thomas Thrainer
    """Check prerequisites.
355 1d870e0d Thomas Thrainer

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

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

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