Revision 1d870e0d

b/Makefile.am
312 312
	lib/cmdlib/common.py \
313 313
	lib/cmdlib/base.py \
314 314
	lib/cmdlib/tags.py \
315
	lib/cmdlib/network.py
315
	lib/cmdlib/network.py \
316
	lib/cmdlib/test.py
316 317

  
317 318
hypervisor_PYTHON = \
318 319
	lib/hypervisor/__init__.py \
b/lib/cmdlib/__init__.py
34 34
import logging
35 35
import copy
36 36
import OpenSSL
37
import socket
38
import tempfile
39
import shutil
40 37
import itertools
41 38
import operator
42 39

  
......
66 63
from ganeti.cmdlib.base import ResultWithJobs, LogicalUnit, NoHooksLU, \
67 64
  Tasklet, _QueryBase
68 65
from ganeti.cmdlib.common import _ExpandInstanceName, _ExpandItemName, \
69
  _ExpandNodeName, _ShareAll, _CheckNodeGroupInstances
66
  _ExpandNodeName, _ShareAll, _CheckNodeGroupInstances, _GetWantedNodes, \
67
  _GetWantedInstances
70 68
from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel
71 69
from ganeti.cmdlib.network import LUNetworkAdd, LUNetworkRemove, \
72 70
  LUNetworkSetParams, _NetworkQuery, LUNetworkQuery, LUNetworkConnect, \
73 71
  LUNetworkDisconnect
72
from ganeti.cmdlib.test import LUTestDelay, LUTestJqueue, LUTestAllocator
74 73

  
75 74
import ganeti.masterd.instance # pylint: disable=W0611
76 75

  
......
214 213
    return names[:]
215 214

  
216 215

  
217
def _GetWantedNodes(lu, nodes):
218
  """Returns list of checked and expanded node names.
219

  
220
  @type lu: L{LogicalUnit}
221
  @param lu: the logical unit on whose behalf we execute
222
  @type nodes: list
223
  @param nodes: list of node names or None for all nodes
224
  @rtype: list
225
  @return: the list of nodes, sorted
226
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
227

  
228
  """
229
  if nodes:
230
    return [_ExpandNodeName(lu.cfg, name) for name in nodes]
231

  
232
  return utils.NiceSort(lu.cfg.GetNodeList())
233

  
234

  
235
def _GetWantedInstances(lu, instances):
236
  """Returns list of checked and expanded instance names.
237

  
238
  @type lu: L{LogicalUnit}
239
  @param lu: the logical unit on whose behalf we execute
240
  @type instances: list
241
  @param instances: list of instance names or None for all instances
242
  @rtype: list
243
  @return: the list of instances, sorted
244
  @raise errors.OpPrereqError: if the instances parameter is wrong type
245
  @raise errors.OpPrereqError: if any of the passed instances is not found
246

  
247
  """
248
  if instances:
249
    wanted = [_ExpandInstanceName(lu.cfg, name) for name in instances]
250
  else:
251
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
252
  return wanted
253

  
254

  
255 216
def _GetUpdatedParams(old_params, update_dict,
256 217
                      use_default=True, use_none=False):
257 218
  """Return the new version of a parameter dictionary.
......
15309 15270
    return ResultWithJobs(jobs)
15310 15271

  
15311 15272

  
15312
class LUTestDelay(NoHooksLU):
15313
  """Sleep for a specified amount of time.
15314

  
15315
  This LU sleeps on the master and/or nodes for a specified amount of
15316
  time.
15317

  
15318
  """
15319
  REQ_BGL = False
15320

  
15321
  def ExpandNames(self):
15322
    """Expand names and set required locks.
15323

  
15324
    This expands the node list, if any.
15325

  
15326
    """
15327
    self.needed_locks = {}
15328
    if self.op.on_nodes:
15329
      # _GetWantedNodes can be used here, but is not always appropriate to use
15330
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
15331
      # more information.
15332
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
15333
      self.needed_locks[locking.LEVEL_NODE] = self.op.on_nodes
15334

  
15335
  def _TestDelay(self):
15336
    """Do the actual sleep.
15337

  
15338
    """
15339
    if self.op.on_master:
15340
      if not utils.TestDelay(self.op.duration):
15341
        raise errors.OpExecError("Error during master delay test")
15342
    if self.op.on_nodes:
15343
      result = self.rpc.call_test_delay(self.op.on_nodes, self.op.duration)
15344
      for node, node_result in result.items():
15345
        node_result.Raise("Failure during rpc call to node %s" % node)
15346

  
15347
  def Exec(self, feedback_fn):
15348
    """Execute the test delay opcode, with the wanted repetitions.
15349

  
15350
    """
15351
    if self.op.repeat == 0:
15352
      self._TestDelay()
15353
    else:
15354
      top_value = self.op.repeat - 1
15355
      for i in range(self.op.repeat):
15356
        self.LogInfo("Test delay iteration %d/%d", i, top_value)
15357
        self._TestDelay()
15358

  
15359

  
15360 15273
class LURestrictedCommand(NoHooksLU):
15361 15274
  """Logical unit for executing restricted commands.
15362 15275

  
......
15404 15317
    return result
15405 15318

  
15406 15319

  
15407
class LUTestJqueue(NoHooksLU):
15408
  """Utility LU to test some aspects of the job queue.
15409

  
15410
  """
15411
  REQ_BGL = False
15412

  
15413
  # Must be lower than default timeout for WaitForJobChange to see whether it
15414
  # notices changed jobs
15415
  _CLIENT_CONNECT_TIMEOUT = 20.0
15416
  _CLIENT_CONFIRM_TIMEOUT = 60.0
15417

  
15418
  @classmethod
15419
  def _NotifyUsingSocket(cls, cb, errcls):
15420
    """Opens a Unix socket and waits for another program to connect.
15421

  
15422
    @type cb: callable
15423
    @param cb: Callback to send socket name to client
15424
    @type errcls: class
15425
    @param errcls: Exception class to use for errors
15426

  
15427
    """
15428
    # Using a temporary directory as there's no easy way to create temporary
15429
    # sockets without writing a custom loop around tempfile.mktemp and
15430
    # socket.bind
15431
    tmpdir = tempfile.mkdtemp()
15432
    try:
15433
      tmpsock = utils.PathJoin(tmpdir, "sock")
15434

  
15435
      logging.debug("Creating temporary socket at %s", tmpsock)
15436
      sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
15437
      try:
15438
        sock.bind(tmpsock)
15439
        sock.listen(1)
15440

  
15441
        # Send details to client
15442
        cb(tmpsock)
15443

  
15444
        # Wait for client to connect before continuing
15445
        sock.settimeout(cls._CLIENT_CONNECT_TIMEOUT)
15446
        try:
15447
          (conn, _) = sock.accept()
15448
        except socket.error, err:
15449
          raise errcls("Client didn't connect in time (%s)" % err)
15450
      finally:
15451
        sock.close()
15452
    finally:
15453
      # Remove as soon as client is connected
15454
      shutil.rmtree(tmpdir)
15455

  
15456
    # Wait for client to close
15457
    try:
15458
      try:
15459
        # pylint: disable=E1101
15460
        # Instance of '_socketobject' has no ... member
15461
        conn.settimeout(cls._CLIENT_CONFIRM_TIMEOUT)
15462
        conn.recv(1)
15463
      except socket.error, err:
15464
        raise errcls("Client failed to confirm notification (%s)" % err)
15465
    finally:
15466
      conn.close()
15467

  
15468
  def _SendNotification(self, test, arg, sockname):
15469
    """Sends a notification to the client.
15470

  
15471
    @type test: string
15472
    @param test: Test name
15473
    @param arg: Test argument (depends on test)
15474
    @type sockname: string
15475
    @param sockname: Socket path
15476

  
15477
    """
15478
    self.Log(constants.ELOG_JQUEUE_TEST, (sockname, test, arg))
15479

  
15480
  def _Notify(self, prereq, test, arg):
15481
    """Notifies the client of a test.
15482

  
15483
    @type prereq: bool
15484
    @param prereq: Whether this is a prereq-phase test
15485
    @type test: string
15486
    @param test: Test name
15487
    @param arg: Test argument (depends on test)
15488

  
15489
    """
15490
    if prereq:
15491
      errcls = errors.OpPrereqError
15492
    else:
15493
      errcls = errors.OpExecError
15494

  
15495
    return self._NotifyUsingSocket(compat.partial(self._SendNotification,
15496
                                                  test, arg),
15497
                                   errcls)
15498

  
15499
  def CheckArguments(self):
15500
    self.checkargs_calls = getattr(self, "checkargs_calls", 0) + 1
15501
    self.expandnames_calls = 0
15502

  
15503
  def ExpandNames(self):
15504
    checkargs_calls = getattr(self, "checkargs_calls", 0)
15505
    if checkargs_calls < 1:
15506
      raise errors.ProgrammerError("CheckArguments was not called")
15507

  
15508
    self.expandnames_calls += 1
15509

  
15510
    if self.op.notify_waitlock:
15511
      self._Notify(True, constants.JQT_EXPANDNAMES, None)
15512

  
15513
    self.LogInfo("Expanding names")
15514

  
15515
    # Get lock on master node (just to get a lock, not for a particular reason)
15516
    self.needed_locks = {
15517
      locking.LEVEL_NODE: self.cfg.GetMasterNode(),
15518
      }
15519

  
15520
  def Exec(self, feedback_fn):
15521
    if self.expandnames_calls < 1:
15522
      raise errors.ProgrammerError("ExpandNames was not called")
15523

  
15524
    if self.op.notify_exec:
15525
      self._Notify(False, constants.JQT_EXEC, None)
15526

  
15527
    self.LogInfo("Executing")
15528

  
15529
    if self.op.log_messages:
15530
      self._Notify(False, constants.JQT_STARTMSG, len(self.op.log_messages))
15531
      for idx, msg in enumerate(self.op.log_messages):
15532
        self.LogInfo("Sending log message %s", idx + 1)
15533
        feedback_fn(constants.JQT_MSGPREFIX + msg)
15534
        # Report how many test messages have been sent
15535
        self._Notify(False, constants.JQT_LOGMSG, idx + 1)
15536

  
15537
    if self.op.fail:
15538
      raise errors.OpExecError("Opcode failure was requested")
15539

  
15540
    return True
15541

  
15542

  
15543
class LUTestAllocator(NoHooksLU):
15544
  """Run allocator tests.
15545

  
15546
  This LU runs the allocator tests
15547

  
15548
  """
15549
  def CheckPrereq(self):
15550
    """Check prerequisites.
15551

  
15552
    This checks the opcode parameters depending on the director and mode test.
15553

  
15554
    """
15555
    if self.op.mode in (constants.IALLOCATOR_MODE_ALLOC,
15556
                        constants.IALLOCATOR_MODE_MULTI_ALLOC):
15557
      for attr in ["memory", "disks", "disk_template",
15558
                   "os", "tags", "nics", "vcpus"]:
15559
        if not hasattr(self.op, attr):
15560
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
15561
                                     attr, errors.ECODE_INVAL)
15562
      iname = self.cfg.ExpandInstanceName(self.op.name)
15563
      if iname is not None:
15564
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
15565
                                   iname, errors.ECODE_EXISTS)
15566
      if not isinstance(self.op.nics, list):
15567
        raise errors.OpPrereqError("Invalid parameter 'nics'",
15568
                                   errors.ECODE_INVAL)
15569
      if not isinstance(self.op.disks, list):
15570
        raise errors.OpPrereqError("Invalid parameter 'disks'",
15571
                                   errors.ECODE_INVAL)
15572
      for row in self.op.disks:
15573
        if (not isinstance(row, dict) or
15574
            constants.IDISK_SIZE not in row or
15575
            not isinstance(row[constants.IDISK_SIZE], int) or
15576
            constants.IDISK_MODE not in row or
15577
            row[constants.IDISK_MODE] not in constants.DISK_ACCESS_SET):
15578
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
15579
                                     " parameter", errors.ECODE_INVAL)
15580
      if self.op.hypervisor is None:
15581
        self.op.hypervisor = self.cfg.GetHypervisorType()
15582
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
15583
      fname = _ExpandInstanceName(self.cfg, self.op.name)
15584
      self.op.name = fname
15585
      self.relocate_from = \
15586
          list(self.cfg.GetInstanceInfo(fname).secondary_nodes)
15587
    elif self.op.mode in (constants.IALLOCATOR_MODE_CHG_GROUP,
15588
                          constants.IALLOCATOR_MODE_NODE_EVAC):
15589
      if not self.op.instances:
15590
        raise errors.OpPrereqError("Missing instances", errors.ECODE_INVAL)
15591
      self.op.instances = _GetWantedInstances(self, self.op.instances)
15592
    else:
15593
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
15594
                                 self.op.mode, errors.ECODE_INVAL)
15595

  
15596
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
15597
      if self.op.iallocator is None:
15598
        raise errors.OpPrereqError("Missing allocator name",
15599
                                   errors.ECODE_INVAL)
15600
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
15601
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
15602
                                 self.op.direction, errors.ECODE_INVAL)
15603

  
15604
  def Exec(self, feedback_fn):
15605
    """Run the allocator test.
15606

  
15607
    """
15608
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
15609
      req = iallocator.IAReqInstanceAlloc(name=self.op.name,
15610
                                          memory=self.op.memory,
15611
                                          disks=self.op.disks,
15612
                                          disk_template=self.op.disk_template,
15613
                                          os=self.op.os,
15614
                                          tags=self.op.tags,
15615
                                          nics=self.op.nics,
15616
                                          vcpus=self.op.vcpus,
15617
                                          spindle_use=self.op.spindle_use,
15618
                                          hypervisor=self.op.hypervisor,
15619
                                          node_whitelist=None)
15620
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
15621
      req = iallocator.IAReqRelocate(name=self.op.name,
15622
                                     relocate_from=list(self.relocate_from))
15623
    elif self.op.mode == constants.IALLOCATOR_MODE_CHG_GROUP:
15624
      req = iallocator.IAReqGroupChange(instances=self.op.instances,
15625
                                        target_groups=self.op.target_groups)
15626
    elif self.op.mode == constants.IALLOCATOR_MODE_NODE_EVAC:
15627
      req = iallocator.IAReqNodeEvac(instances=self.op.instances,
15628
                                     evac_mode=self.op.evac_mode)
15629
    elif self.op.mode == constants.IALLOCATOR_MODE_MULTI_ALLOC:
15630
      disk_template = self.op.disk_template
15631
      insts = [iallocator.IAReqInstanceAlloc(name="%s%s" % (self.op.name, idx),
15632
                                             memory=self.op.memory,
15633
                                             disks=self.op.disks,
15634
                                             disk_template=disk_template,
15635
                                             os=self.op.os,
15636
                                             tags=self.op.tags,
15637
                                             nics=self.op.nics,
15638
                                             vcpus=self.op.vcpus,
15639
                                             spindle_use=self.op.spindle_use,
15640
                                             hypervisor=self.op.hypervisor)
15641
               for idx in range(self.op.count)]
15642
      req = iallocator.IAReqMultiInstanceAlloc(instances=insts)
15643
    else:
15644
      raise errors.ProgrammerError("Uncatched mode %s in"
15645
                                   " LUTestAllocator.Exec", self.op.mode)
15646

  
15647
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
15648
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
15649
      result = ial.in_text
15650
    else:
15651
      ial.Run(self.op.iallocator, validate=False)
15652
      result = ial.out_text
15653
    return result
15654

  
15655

  
15656 15320
#: Query type implementations
15657 15321
_QUERY_IMPL = {
15658 15322
  constants.QR_CLUSTER: _ClusterQuery,
b/lib/cmdlib/common.py
82 82
                               errors.ECODE_STATE)
83 83

  
84 84
  return wanted_instances
85

  
86

  
87
def _GetWantedNodes(lu, nodes):
88
  """Returns list of checked and expanded node names.
89

  
90
  @type lu: L{LogicalUnit}
91
  @param lu: the logical unit on whose behalf we execute
92
  @type nodes: list
93
  @param nodes: list of node names or None for all nodes
94
  @rtype: list
95
  @return: the list of nodes, sorted
96
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
97

  
98
  """
99
  if nodes:
100
    return [_ExpandNodeName(lu.cfg, name) for name in nodes]
101

  
102
  return utils.NiceSort(lu.cfg.GetNodeList())
103

  
104

  
105
def _GetWantedInstances(lu, instances):
106
  """Returns list of checked and expanded instance names.
107

  
108
  @type lu: L{LogicalUnit}
109
  @param lu: the logical unit on whose behalf we execute
110
  @type instances: list
111
  @param instances: list of instance names or None for all instances
112
  @rtype: list
113
  @return: the list of instances, sorted
114
  @raise errors.OpPrereqError: if the instances parameter is wrong type
115
  @raise errors.OpPrereqError: if any of the passed instances is not found
116

  
117
  """
118
  if instances:
119
    wanted = [_ExpandInstanceName(lu.cfg, name) for name in instances]
120
  else:
121
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
122
  return wanted
b/lib/cmdlib/test.py
1
#
2
#
3

  
4
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Test logical units."""
23

  
24
import logging
25
import shutil
26
import socket
27
import tempfile
28

  
29
from ganeti import compat
30
from ganeti import constants
31
from ganeti import errors
32
from ganeti import locking
33
from ganeti import utils
34
from ganeti.masterd import iallocator
35
from ganeti.cmdlib.base import NoHooksLU
36
from ganeti.cmdlib.common import _ExpandInstanceName, _GetWantedNodes, \
37
  _GetWantedInstances
38

  
39

  
40
class LUTestDelay(NoHooksLU):
41
  """Sleep for a specified amount of time.
42

  
43
  This LU sleeps on the master and/or nodes for a specified amount of
44
  time.
45

  
46
  """
47
  REQ_BGL = False
48

  
49
  def ExpandNames(self):
50
    """Expand names and set required locks.
51

  
52
    This expands the node list, if any.
53

  
54
    """
55
    self.needed_locks = {}
56
    if self.op.on_nodes:
57
      # _GetWantedNodes can be used here, but is not always appropriate to use
58
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
59
      # more information.
60
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
61
      self.needed_locks[locking.LEVEL_NODE] = self.op.on_nodes
62

  
63
  def _TestDelay(self):
64
    """Do the actual sleep.
65

  
66
    """
67
    if self.op.on_master:
68
      if not utils.TestDelay(self.op.duration):
69
        raise errors.OpExecError("Error during master delay test")
70
    if self.op.on_nodes:
71
      result = self.rpc.call_test_delay(self.op.on_nodes, self.op.duration)
72
      for node, node_result in result.items():
73
        node_result.Raise("Failure during rpc call to node %s" % node)
74

  
75
  def Exec(self, feedback_fn):
76
    """Execute the test delay opcode, with the wanted repetitions.
77

  
78
    """
79
    if self.op.repeat == 0:
80
      self._TestDelay()
81
    else:
82
      top_value = self.op.repeat - 1
83
      for i in range(self.op.repeat):
84
        self.LogInfo("Test delay iteration %d/%d", i, top_value)
85
        self._TestDelay()
86

  
87

  
88
class LUTestJqueue(NoHooksLU):
89
  """Utility LU to test some aspects of the job queue.
90

  
91
  """
92
  REQ_BGL = False
93

  
94
  # Must be lower than default timeout for WaitForJobChange to see whether it
95
  # notices changed jobs
96
  _CLIENT_CONNECT_TIMEOUT = 20.0
97
  _CLIENT_CONFIRM_TIMEOUT = 60.0
98

  
99
  @classmethod
100
  def _NotifyUsingSocket(cls, cb, errcls):
101
    """Opens a Unix socket and waits for another program to connect.
102

  
103
    @type cb: callable
104
    @param cb: Callback to send socket name to client
105
    @type errcls: class
106
    @param errcls: Exception class to use for errors
107

  
108
    """
109
    # Using a temporary directory as there's no easy way to create temporary
110
    # sockets without writing a custom loop around tempfile.mktemp and
111
    # socket.bind
112
    tmpdir = tempfile.mkdtemp()
113
    try:
114
      tmpsock = utils.PathJoin(tmpdir, "sock")
115

  
116
      logging.debug("Creating temporary socket at %s", tmpsock)
117
      sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
118
      try:
119
        sock.bind(tmpsock)
120
        sock.listen(1)
121

  
122
        # Send details to client
123
        cb(tmpsock)
124

  
125
        # Wait for client to connect before continuing
126
        sock.settimeout(cls._CLIENT_CONNECT_TIMEOUT)
127
        try:
128
          (conn, _) = sock.accept()
129
        except socket.error, err:
130
          raise errcls("Client didn't connect in time (%s)" % err)
131
      finally:
132
        sock.close()
133
    finally:
134
      # Remove as soon as client is connected
135
      shutil.rmtree(tmpdir)
136

  
137
    # Wait for client to close
138
    try:
139
      try:
140
        # pylint: disable=E1101
141
        # Instance of '_socketobject' has no ... member
142
        conn.settimeout(cls._CLIENT_CONFIRM_TIMEOUT)
143
        conn.recv(1)
144
      except socket.error, err:
145
        raise errcls("Client failed to confirm notification (%s)" % err)
146
    finally:
147
      conn.close()
148

  
149
  def _SendNotification(self, test, arg, sockname):
150
    """Sends a notification to the client.
151

  
152
    @type test: string
153
    @param test: Test name
154
    @param arg: Test argument (depends on test)
155
    @type sockname: string
156
    @param sockname: Socket path
157

  
158
    """
159
    self.Log(constants.ELOG_JQUEUE_TEST, (sockname, test, arg))
160

  
161
  def _Notify(self, prereq, test, arg):
162
    """Notifies the client of a test.
163

  
164
    @type prereq: bool
165
    @param prereq: Whether this is a prereq-phase test
166
    @type test: string
167
    @param test: Test name
168
    @param arg: Test argument (depends on test)
169

  
170
    """
171
    if prereq:
172
      errcls = errors.OpPrereqError
173
    else:
174
      errcls = errors.OpExecError
175

  
176
    return self._NotifyUsingSocket(compat.partial(self._SendNotification,
177
                                                  test, arg),
178
                                   errcls)
179

  
180
  def CheckArguments(self):
181
    self.checkargs_calls = getattr(self, "checkargs_calls", 0) + 1
182
    self.expandnames_calls = 0
183

  
184
  def ExpandNames(self):
185
    checkargs_calls = getattr(self, "checkargs_calls", 0)
186
    if checkargs_calls < 1:
187
      raise errors.ProgrammerError("CheckArguments was not called")
188

  
189
    self.expandnames_calls += 1
190

  
191
    if self.op.notify_waitlock:
192
      self._Notify(True, constants.JQT_EXPANDNAMES, None)
193

  
194
    self.LogInfo("Expanding names")
195

  
196
    # Get lock on master node (just to get a lock, not for a particular reason)
197
    self.needed_locks = {
198
      locking.LEVEL_NODE: self.cfg.GetMasterNode(),
199
      }
200

  
201
  def Exec(self, feedback_fn):
202
    if self.expandnames_calls < 1:
203
      raise errors.ProgrammerError("ExpandNames was not called")
204

  
205
    if self.op.notify_exec:
206
      self._Notify(False, constants.JQT_EXEC, None)
207

  
208
    self.LogInfo("Executing")
209

  
210
    if self.op.log_messages:
211
      self._Notify(False, constants.JQT_STARTMSG, len(self.op.log_messages))
212
      for idx, msg in enumerate(self.op.log_messages):
213
        self.LogInfo("Sending log message %s", idx + 1)
214
        feedback_fn(constants.JQT_MSGPREFIX + msg)
215
        # Report how many test messages have been sent
216
        self._Notify(False, constants.JQT_LOGMSG, idx + 1)
217

  
218
    if self.op.fail:
219
      raise errors.OpExecError("Opcode failure was requested")
220

  
221
    return True
222

  
223

  
224
class LUTestAllocator(NoHooksLU):
225
  """Run allocator tests.
226

  
227
  This LU runs the allocator tests
228

  
229
  """
230
  def CheckPrereq(self):
231
    """Check prerequisites.
232

  
233
    This checks the opcode parameters depending on the director and mode test.
234

  
235
    """
236
    if self.op.mode in (constants.IALLOCATOR_MODE_ALLOC,
237
                        constants.IALLOCATOR_MODE_MULTI_ALLOC):
238
      for attr in ["memory", "disks", "disk_template",
239
                   "os", "tags", "nics", "vcpus"]:
240
        if not hasattr(self.op, attr):
241
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
242
                                     attr, errors.ECODE_INVAL)
243
      iname = self.cfg.ExpandInstanceName(self.op.name)
244
      if iname is not None:
245
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
246
                                   iname, errors.ECODE_EXISTS)
247
      if not isinstance(self.op.nics, list):
248
        raise errors.OpPrereqError("Invalid parameter 'nics'",
249
                                   errors.ECODE_INVAL)
250
      if not isinstance(self.op.disks, list):
251
        raise errors.OpPrereqError("Invalid parameter 'disks'",
252
                                   errors.ECODE_INVAL)
253
      for row in self.op.disks:
254
        if (not isinstance(row, dict) or
255
            constants.IDISK_SIZE not in row or
256
            not isinstance(row[constants.IDISK_SIZE], int) or
257
            constants.IDISK_MODE not in row or
258
            row[constants.IDISK_MODE] not in constants.DISK_ACCESS_SET):
259
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
260
                                     " parameter", errors.ECODE_INVAL)
261
      if self.op.hypervisor is None:
262
        self.op.hypervisor = self.cfg.GetHypervisorType()
263
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
264
      fname = _ExpandInstanceName(self.cfg, self.op.name)
265
      self.op.name = fname
266
      self.relocate_from = \
267
          list(self.cfg.GetInstanceInfo(fname).secondary_nodes)
268
    elif self.op.mode in (constants.IALLOCATOR_MODE_CHG_GROUP,
269
                          constants.IALLOCATOR_MODE_NODE_EVAC):
270
      if not self.op.instances:
271
        raise errors.OpPrereqError("Missing instances", errors.ECODE_INVAL)
272
      self.op.instances = _GetWantedInstances(self, self.op.instances)
273
    else:
274
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
275
                                 self.op.mode, errors.ECODE_INVAL)
276

  
277
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
278
      if self.op.iallocator is None:
279
        raise errors.OpPrereqError("Missing allocator name",
280
                                   errors.ECODE_INVAL)
281
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
282
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
283
                                 self.op.direction, errors.ECODE_INVAL)
284

  
285
  def Exec(self, feedback_fn):
286
    """Run the allocator test.
287

  
288
    """
289
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
290
      req = iallocator.IAReqInstanceAlloc(name=self.op.name,
291
                                          memory=self.op.memory,
292
                                          disks=self.op.disks,
293
                                          disk_template=self.op.disk_template,
294
                                          os=self.op.os,
295
                                          tags=self.op.tags,
296
                                          nics=self.op.nics,
297
                                          vcpus=self.op.vcpus,
298
                                          spindle_use=self.op.spindle_use,
299
                                          hypervisor=self.op.hypervisor,
300
                                          node_whitelist=None)
301
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
302
      req = iallocator.IAReqRelocate(name=self.op.name,
303
                                     relocate_from=list(self.relocate_from))
304
    elif self.op.mode == constants.IALLOCATOR_MODE_CHG_GROUP:
305
      req = iallocator.IAReqGroupChange(instances=self.op.instances,
306
                                        target_groups=self.op.target_groups)
307
    elif self.op.mode == constants.IALLOCATOR_MODE_NODE_EVAC:
308
      req = iallocator.IAReqNodeEvac(instances=self.op.instances,
309
                                     evac_mode=self.op.evac_mode)
310
    elif self.op.mode == constants.IALLOCATOR_MODE_MULTI_ALLOC:
311
      disk_template = self.op.disk_template
312
      insts = [iallocator.IAReqInstanceAlloc(name="%s%s" % (self.op.name, idx),
313
                                             memory=self.op.memory,
314
                                             disks=self.op.disks,
315
                                             disk_template=disk_template,
316
                                             os=self.op.os,
317
                                             tags=self.op.tags,
318
                                             nics=self.op.nics,
319
                                             vcpus=self.op.vcpus,
320
                                             spindle_use=self.op.spindle_use,
321
                                             hypervisor=self.op.hypervisor)
322
               for idx in range(self.op.count)]
323
      req = iallocator.IAReqMultiInstanceAlloc(instances=insts)
324
    else:
325
      raise errors.ProgrammerError("Uncatched mode %s in"
326
                                   " LUTestAllocator.Exec", self.op.mode)
327

  
328
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
329
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
330
      result = ial.in_text
331
    else:
332
      ial.Run(self.op.iallocator, validate=False)
333
      result = ial.out_text
334
    return result

Also available in: Unified diff